From d88ca2a24c61503b65b9407d436e7b5ace56d8cb Mon Sep 17 00:00:00 2001 From: siddharthd Date: Fri, 21 Aug 2026 18:27:53 +1000 Subject: [PATCH] intake: a duplicate card that refuses a purchase must say what to do instead MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The header (merchant, date, total) is a purchase's identity here, so a genuine second identical purchase — two of the same coffee, one shop, one day — reads as a re-share and is refused. That default is right; a re-share is far commoner than a repeat. But the card said only "Nothing was changed", which is a dead end: the money is real and the ledger silently never gets it. Say to add it in the app. --- src/lib/intake-blocks.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lib/intake-blocks.ts b/src/lib/intake-blocks.ts index e591477..7dbb811 100644 --- a/src/lib/intake-blocks.ts +++ b/src/lib/intake-blocks.ts @@ -155,7 +155,12 @@ export function askCard(c: CardInput): { blocks: Block[]; text: string } { export function duplicateCard(c: { merchant: string | null; total: number | null; transactionId: number | null; captureId: number | null; batchId: string | null; currency?: string | null }): { blocks: Block[]; text: string } { const where = c.transactionId ? `transaction ${c.transactionId}` : c.captureId ? `pantry capture ${c.captureId}` : c.batchId ? `batch ${esc(c.batchId)}` : "an earlier upload"; - const text = `Already handled — ${esc(c.merchant) || "this order"} ${c.total !== null ? money(c.total, c.currency) : ""} is ${where}. Nothing was changed.`.replace(/\s+/g, " "); + // The header (merchant, date, total) IS the identity of a purchase here, so a + // genuine SECOND identical purchase — two of the same coffee, one day, one shop + // — reads as a re-share and is refused. That is the right default (a re-share is + // far commoner than a repeat) but it is a dead end without this sentence: the + // card must say what to do instead, or the ledger quietly loses the second one. + const text = `Already handled — ${esc(c.merchant) || "this order"} ${c.total !== null ? money(c.total, c.currency) : ""} is ${where}. Nothing was changed — if this really is a second, separate purchase, add it in the app.`.replace(/\s+/g, " "); return { text, blocks: [section(`:repeat: ${text}`)] }; }