fix(database): unblock credit note constraint validation (#1024)

* docs: record legacy credit note migration repair

* fix(database): assert repaired credit note state

---------

Co-authored-by: Jakob Wennberg <jakob.wennberg@gmail.com>
This commit is contained in:
Mattsson
2026-07-16 16:04:06 +02:00
committed by GitHub
parent edef48471c
commit aa5edd3aa7
2 changed files with 25 additions and 0 deletions
+1
View File
@@ -166,3 +166,4 @@ One line per decision: `[YYYY-MM-DD] <decision>: <why>`. 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.
@@ -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';