T 115
uid: T-115 title: Receipt Register XLSX β surface the Substantiating Notes column status: done area: records-export created: 2026-06-25 updated: 2026-06-25 related: T-114, T-046
Why¶
Every confirmed receipt carries a substantiation note β the "who attended + business purpose" text the assessor expects on F&B / entertainment claims per HK IRD DIPN 21. It's required at confirm time for category β {fnb, entertainment} and optional elsewhere; the writer carries it into lines[].memo on the auto-posted journal entry so it survives even if the receipt is later deleted (lib/telegram/receiptStore.ts:178-186).
The Records β Receipts: Expense β Export (Register of Expense Receipts XLSX) was emitting the receipt's date, merchant, category, GL, currency, total, and the file link β but not the substantiation note. The export is the audit artifact bookkeepers hand to the assessor, so the note belongs on it. Without it, the assessor has to click through every receipt's PDF or cross-reference journal memos.
Owner, 2026-06-25 (verbatim): "Substantiating Notes need to be included in the Receipt Register"
What changed¶
lib/accounting/expenseRecordsRow.tsβ extended the unifiedExpenseRecordRowwithnote: string | null. Populated fromr.noteinmapReceiptToExpenseRecord; set tonullinmapServiceInvoiceToExpenseRecord(vendor invoices carry their own substantiation on the invoice/PO, not in a separate note field).components/records/RecordsApp.tsxβ added aSubstantiating Notescolumn to the Receipts export betweenTotalandFile. Empty string when the receipt has no note (the export already shows''for absent fields elsewhere β matches AGENTS.md UI convention that missing data renders as a blank dash, not crashes).
Why it's built this way¶
- Column position between Total and File: keeps the "data the assessor reads from left to right" together (date β merchant β category β GL β currency β total β why β evidence).
- Field name
noteonExpenseRecordRowmirrors the underlyingTelegramReceipt.notedirectly β no renaming. The XLSX header is the human-facing "Substantiating Notes" so auditors don't need to learn our internal term. - No on-screen column added. The drawer already shows the note prominently with a DIPN 21 explainer; the row table stays unchanged so this PR is just the export-artifact fix the owner asked for.
Decision log¶
2026-06-25 β opened + implemented¶
- β
Attestation (Records (Infrastructure)): read
AGENTS.md; scope-scanned the board β T-046 is the Bank Transaction Register XLSX overhaul (different register); T-007 dropped the "use the note as a fingerprint" idea (different concern). No covering task for "surface the substantiation note on the Receipt Register." - Source: Records (Infrastructure) Β· https://claude.ai/code/session_018RDB37kCqfouHdygVXTAtD
- Proposed by: the owner β verbatim above. Approved by: the owner (same line).
- Branch / PR:
claude/receipts-export-substantiating-notesβ PR tomain(branch policy 2026-06-24: π’main/ π΄nightly). - Verification: could not run
tscin-sandbox (nonode_modules); the change is a small data plumb + one column entry β symmetric with existing columns + with thenotefield already onTelegramReceipt. Owner to confirm post-deploy: re-export the Receipts register β the new column appears between Total and File, populated for receipts that carry a note. - Blast radius:
ExpenseRecordRow.noteis additive (no removed/renamed field), so any other consumer ofExpenseRecordRowthat doesn't readnoteis unaffected. Service-invoice rows always setnote: null, matching their data model. The on-screen receipts table is unchanged. - Cross-link: T-114 is the sibling export fix (durable Invoice Number hyperlink in the Service Invoice register).
Commit index (backfilled 2026-07-01, best-effort Β· Coaching (Diagnostic))¶
Candidate related commits, auto-backfilled from git on main: commits whose message references this task's UID or a PR number it cites. Not verified β this squash-merged history can't yield a precise per-task list, so rows tagged (mentions only) name the task in passing (may be tangential) and untagged work commits may be missing. Treat as a starting point: verify, prune tangential rows, and append any real ones per the AGENTS.md "record every related SHA" policy.
60a75e92026-06-25 β feat(t-115): vendor template clean-up + live-sync templates β transactions (mentions only)3f5d7952026-06-25 β Merge #810: feat(records) β Substantiating Notes column on the Receipt Register XLSX (mentions only)44c91072026-06-25 β fix(records): read receipt.note from metadata (not top-level) β T-115 follow-up12964c12026-06-25 β Merge: fix(records) β read receipt.note from metadata, not top-level (T-115 follow-up)51f20202026-06-25 β Merge main + renumber T-114βT-117, T-115βT-118 (renumber-on-merge)