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