ci / lint-test (push) Successful in 41s
getPendingReconciliations treated every unreconciled manual transaction as awaiting a matching statement row. Cash never appears on a statement, so a cash entry sat in the queue indefinitely being offered matches within 3 days and 1% on amount - and accepting one is silently destructive: reconciled manual rows are filtered out of every query, so the cash spend disappears while the card transaction it matched claims to be that same spend. Migration 0016 adds transactions.payment_method (card | cash | bank_transfer | other, NULL = unknown) with a CHECK constraint and a partial index. The notCash() fragment excludes cash from both halves of the reconciliation query - the pending list and the candidate match subquery, which aliases the manual row as m. Only cash is excluded. Bank transfers do appear on a statement now that transaction accounts are imported, and NULL means unknown, so both stay candidates and every pre-existing row behaves exactly as before. ATM withdrawals deliberately stay categorised as spend rather than transfers. Treating them as transfers is only correct if every cash purchase is logged; with partial logging it silently deletes the unlogged remainder from spend.
36 lines
1.7 KiB
SQL
36 lines
1.7 KiB
SQL
-- How a transaction was paid for, so cash can be told apart from everything else.
|
|
--
|
|
-- The problem this solves: getPendingReconciliations treats every unreconciled
|
|
-- manual transaction as awaiting a matching statement row. A cash purchase never
|
|
-- appears on a statement, so it sits in the queue forever and is offered matches
|
|
-- within 3 days and 1% on amount. Accepting one is silently destructive --
|
|
-- reconciled manual rows are excluded from every query, so the cash spend
|
|
-- disappears while the card transaction it matched claims to be that same spend.
|
|
--
|
|
-- NULL means unknown, which is treated as reconcilable -- the existing behaviour
|
|
-- for every row already in the table.
|
|
--
|
|
-- Only 'cash' is excluded from reconciliation. A bank transfer DOES appear on a
|
|
-- statement now that transaction accounts are being imported, so it stays a
|
|
-- reconciliation candidate.
|
|
|
|
ALTER TABLE transactions
|
|
ADD COLUMN IF NOT EXISTS payment_method TEXT;
|
|
|
|
ALTER TABLE transactions DROP CONSTRAINT IF EXISTS transactions_payment_method_check;
|
|
ALTER TABLE transactions ADD CONSTRAINT transactions_payment_method_check
|
|
CHECK (payment_method IS NULL
|
|
OR payment_method IN ('card', 'cash', 'bank_transfer', 'other'));
|
|
|
|
-- Partial index: the reconciliation query filters on this, and cash is expected
|
|
-- to stay a small minority of rows.
|
|
CREATE INDEX IF NOT EXISTS idx_transactions_payment_method
|
|
ON transactions (payment_method) WHERE payment_method IS NOT NULL;
|
|
|
|
-- Backfill the one row that is unambiguously cash. Statement-linked rows are
|
|
-- left NULL: they came from a statement, so by definition they are not cash.
|
|
UPDATE transactions
|
|
SET payment_method = 'cash'
|
|
WHERE statement_id IS NULL
|
|
AND description ILIKE '%cash transaction%';
|