From 4f307e9517f60aa2ed2f9533837aa3f13832ee88 Mon Sep 17 00:00:00 2001 From: siddharthd Date: Sat, 15 Aug 2026 19:11:50 +1000 Subject: [PATCH] docs: what importing a BNPL account changes, and the Zip data decisions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 24 Zip statements landed (Dec 2020 - Jun 2026), all balance-asserting at $0.00. Zip is a credit account, so three existing row types had to be re-read. Data changes applied via transaction_overrides; this records why. A ZIPPAY debit leaving the bank duplicates the Zip statement's purchases only where a Zip statement covers that period. 2 of 8 do, and are now transfers ($125.97). The other six stay spend: for those periods the bank debit is the only record the purchase happened, so moving them would have deleted $703.35 of real spend. 'Account Credit' is cashback, confirmed by the owner and consistent with Zip labelling its other money-in types explicitly (Payment = repayment, 'Refund ' = merchant refund). 34 rows, $740, round amounts, no matching bank debit. Gemini split the identical description 23 'other' (subtracts from spend) / 11 'transfers' (excluded), so one thing did two opposite things. Now all 34 shopping+credit, netting against spend the way refunds already do. Income was rejected for the reason the Up item sales note gives. Prezzee gift cards ($1,580) stay spend — stored value only nets out if every downstream purchase is logged, and for 2020 it is not. Same reasoning as the ATM-withdrawal rule. 31 uncategorised debits mapped by merchant with merchant_normalized set too, since the raw descriptions carry card numbers and order UUIDs. All 137 Zip rows are now categorised; $11,135.11 net spend, $10,085.11 transfers. Flags statement 200 (Sept 2021): extracted without billing_end_date or balances, so it is the one statement uq_statement_identity cannot cover (the index is partial on billing_end_date IS NOT NULL) and a re-import would duplicate it. --- CLAUDE.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index d6a6cea..1af8267 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -685,6 +685,44 @@ in a review table. Consents expire annually, so expect it. Undo an import: `DELETE FROM transactions WHERE source = ''`. +### Zip, and the three things a BNPL account needs (2026-08-15) + +24 statements, Dec 2020 → Jun 2026, all balance-asserting at $0.00. Zip is a +credit account, so importing it changes how three existing row types must read. + +**1. A repayment leaving the bank is a duplicate ONLY where a Zip statement +covers the purchases.** Zip's own `Payment` rows are already `transfers`. On the +bank side, `ZIPPAY*` debits are the same money — but only 2 of 8 fall inside a +Zip statement period. Those two are now `transfers`; **the other six must stay as +spend**, because for those periods the bank debit is the only record the purchase +ever happened. Moving all eight would have deleted $703.35 of real spend. Same +statement-coverage rule as the CSV importer, and the same trap. + +**2. `Account Credit` is cashback, and Zip labels its three money-in types +differently.** `Payment` = repayment from the bank. `Refund ` = a +genuine merchant refund. `Account Credit` = Zip cashback — 34 rows, $740, round +amounts ($20 ×20, $30 ×10, $10 ×4), with no matching debit from any bank account. + +Gemini filed the identical description two ways — 23 as `other` (which *subtracts* +from spend) and 11 as `transfers` (excluded entirely) — so one thing was doing two +opposite things. All 34 are now `shopping` + `credit`, **netting against spend**: +cashback lowers what a purchase actually cost, which is how `NET_SPEND_ROWS` / +`SPEND_SIGNED` already treat a refund. Filing it as `income` was rejected for the +reason the Up item sales note gives — it flatters `net = income − spent` and mixes +non-earnings into the salary line. Ties to the **Cashback tracking (ING-6)** epic; +a dedicated `cashback` category would need the CHECK constraint, the TS mirror, +and a decision in every analytics fragment, so it was not done here. + +**3. A gift card stays spend.** Prezzee is $1,580 of the history. Stored value is +tempting to call `transfers`, but that only works if every downstream purchase is +logged — it is not, for 2020. Identical reasoning to the ATM-withdrawal rule. + +All 137 Zip rows are categorised; net spend is $11,135.11 against $10,085.11 of +`transfers`. **Statement 200 (Sept 2021) came through incomplete** — no +`billing_end_date`, no balances, 2 rows — so it is the one statement not covered +by `uq_statement_identity` (the index is partial on `billing_end_date IS NOT +NULL`) and a re-import would duplicate it. Worth re-processing paperless doc 296. + ### Trusting extracted statement data **Balance assertions are the check that works.** `getStatements` computes