diff --git a/DECISIONS.md b/DECISIONS.md index c15cafd8..a70b8d31 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -166,3 +166,4 @@ One line per decision: `[YYYY-MM-DD] : `. Appended by agents and [2026-07-15] Credit note creation uses a completion marker plus unique company guards instead of a large creation RPC: incomplete parents are never returned, concurrent requests converge, and all journal writes remain in the bookkeeping engine. [2026-07-16] Two bugs from one customer report (an AB). Bug 1 (acct 2893 showed 2393's "langfristig del" memo after an andringsverifikation): root cause = CorrectionEntryDialog never re-derived line_description on account change (JournalEntryForm does). Fixed forward via a pure helper (correction-line-description.ts) that refreshes the memo only when it is empty or still equals the prev account's name (preserves hand-typed memos). Chose NO prod data repair: the wrong memo sits on a POSTED verifikat (immutable per migration-017 trigger); it is cosmetic (account number + amounts correct, all reports key off the number); ~26 posted lines across 11 cos share this stale-echo pattern, all fix-forward only. Deferred the twin entry-level header fix (#1031). Bug 2 (auto tax-deadlines never appeared): root cause = generation only fired on a settings save where a TAX field CHANGED value (didTaxFieldsChange); settings are filled once at onboarding so re-saving generated nothing -> only 5/776 real cos had system deadlines. Chose count-based self-heal (regenerate when the company has 0 system deadlines) over always-regenerate, because generateTaxDeadlinesForUser deletes+reinserts and would reset is_completed/status on every unrelated save. Also wired the /deadlines empty-state to the existing (dead) /api/tax-deadlines/generate route, and fixed a 1000-row PostgREST cap in the annual cron. Backfilled 771 real cos with zero system deadlines via scripts/backfill-tax-deadlines.ts. Deferred moms_period=yearly config (#1030, 295 filers, largest VAT cohort): helarsmoms deadline (SFL 26 kap. 33-33b) depends on EU-trade status (no flag in CompanySettingsForDeadlines) and, for AB, the income-tax-return date. +[2026-07-15] Repaired the single legacy paid credit note blocking invoices_credit_note_not_paid validation by normalizing its invoice metadata to sent, clearing payment fields, setting zero payable remainder, and linking its existing balanced posted V44 reversal: the immutable voucher already exactly reversed V42 and was not edited or duplicated. diff --git a/supabase/migrations/20260715181301_reconcile_credit_note_paid_status.sql b/supabase/migrations/20260715181301_reconcile_credit_note_paid_status.sql new file mode 100644 index 00000000..ea34c292 --- /dev/null +++ b/supabase/migrations/20260715181301_reconcile_credit_note_paid_status.sql @@ -0,0 +1,24 @@ +-- The linked production database contained one legacy credit note in the +-- ordinary payment lifecycle. It was reconciled before this migration by +-- linking its existing balanced reversal voucher and normalizing the invoice +-- metadata. Keep an explicit forward migration that verifies the repaired +-- invariant before the remaining migration chain proceeds. +-- pg-test: covered-by lib/invoices/__tests__/credit-note-not-payable.pg.test.ts +DO $reconcile$ +BEGIN + IF EXISTS ( + SELECT 1 + FROM public.invoices + WHERE credited_invoice_id IS NOT NULL + AND status IN ('paid', 'partially_paid') + ) THEN + RAISE EXCEPTION + 'Legacy credit notes still use ordinary customer-payment states'; + END IF; +END +$reconcile$; + +ALTER TABLE public.invoices + VALIDATE CONSTRAINT invoices_credit_note_not_paid; + +NOTIFY pgrst, 'reload schema';