Files
accounted/supabase/migrations/20260906210100_invoice_rows_completed_event.sql
T
6906bc4aa2 feat(compliance): InvoiceRowsCompleted behandlingshistorik event for migrated invoice rows (#2312) (#2357)
Every migrated sales invoice whose rows complete_invoice_rows writes, from
the migration wizard or the hourly row-completion pass, now leaves one
InvoiceRowsCompleted row in processing_history on a new Invoice aggregate:
the writer, the provider, the consent, the row count, and the header VAT
split before and after when the pass rewrote it (BFL 5 kap 11 §, BFNAR
2013:2 p. 9.16). One run shares one correlation id.

lib/invoices/complete-invoice-rows.ts is the one TypeScript call site for
the RPC and the one emitter: it appends only on wrote = true, records
nothing for already_filled or failed, and keeps the append best-effort
(logged, eventId null) like every other processing_history writer. The
wizard runs on the user's session client, so MigrationOptions takes a lazy
createHistoryClient for the service role. Invoice numbers stay out of the
payload (the personnummer guard would drop ten-digit ones).

Migration 20260906210100 widens the aggregate_type CHECK with Invoice and
registers the event type; pg test covers the catalog row, the aggregate,
and that the CHECK still refuses unknown aggregates.


Claude-Session: https://claude.ai/code/session_01LvMaHcTnwAfxzgYD1fGYX1

Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-06 21:04:53 +02:00

55 lines
2.3 KiB
SQL

-- InvoiceRowsCompleted: the behandlingshistorik event for a migrated sales
-- invoice whose rows were written by complete_invoice_rows (migration
-- 20260906135730), from either of its writers: the migration wizard or the
-- hourly row-completion pass (#2291, #2312).
--
-- The pass inserts invoice_items and rewrites the header VAT split on
-- invoices whose stored split held no evidence. It writes no bokföringspost,
-- so BFL 5 kap 5 § (rättelse) does not bind it, but it is automated
-- processing of räkenskapsinformation, which BFL 5 kap 11 § and BFNAR 2013:2
-- p. 9.16 want in the behandlingshistorik: what was processed, when, and by
-- what. Until now the only trail was a log line per invoice in Vercel, and
-- the migration that wrote the invoices in the first place records no event
-- either.
--
-- One event per completed invoice, emitted by lib/invoices/complete-invoice-
-- rows.ts (the one TypeScript call site for the RPC, so a writer cannot reach
-- the RPC without the trail). Payload: the writer, the provider, the consent,
-- the row count, and the header split before and after when it was
-- rewritten. UUIDs, counts, amounts and enum strings only.
--
-- The aggregate is the invoice, which the aggregate_type CHECK did not admit
-- (no invoice-level event existed before). 'Invoice' is added the way
-- 20260423140500 added the AI streams; every value already in the constraint
-- stays. The catalog row goes in as for every other event type:
-- processing_history.event_type has an FK to it and the append is
-- best-effort, so an unregistered type would be lost silently
-- (lib/processing-history/append.ts, tests/pg/processing-event-types.pg.test.ts).
--
-- pg-test: tests/pg/invoice-rows-completed-event.pg.test.ts
ALTER TABLE public.processing_history
DROP CONSTRAINT IF EXISTS processing_history_aggregate_type_check;
ALTER TABLE public.processing_history
ADD CONSTRAINT processing_history_aggregate_type_check
CHECK (aggregate_type IN (
'Document',
'BankTransaction',
'MatchProposal',
'Verifikation',
'CounterpartyTemplate',
'Period',
'Migration',
'System',
'AIProposal',
'AIRequest',
'Invoice'
));
INSERT INTO public.processing_event_types (event_type)
VALUES ('InvoiceRowsCompleted')
ON CONFLICT (event_type) DO NOTHING;
NOTIFY pgrst, 'reload schema';