feat(bookkeeping): verifikationsserie per bankkonto for bank-transaction bookings (#2160)
* feat(bookkeeping): verifikationsserie per bankkonto for bank-transaction bookings A company running several bank accounts (main bank on A, company card on M, both imported via CSV) could not route each account's bookings into its own series: every bank_transaction booking took the single company-wide default from default_voucher_series_per_source_type. - cash_accounts.voucher_series (nullable, single letter): per-account override, editable under Inställningar → Bokföring → Verifikationsserier per bankkonto (new PATCH /api/cash-accounts/[id]). - resolveCashAccountVoucherSeries(): step 2 of the resolution order (explicit pick → account override → per-type map → A). Wired into the book route and createTransactionJournalEntry, which covers categorize, the agent, pending operations and the v1 API. - Booking dialog gets the series picker, seeded from the server via /voucher-sequences/next?source_type&cash_account_id so dialog and route can never disagree. An unresolved embedded picker omits voucher_series so a stray 'A' never overrides the account's series. Scope: bank_transaction bookings only. Invoice settlements matched from the bank keep their payment series; bulk-book resolves inside its RPC (see DECISIONS.md). Migration applied to staging as 20260902121420. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JWSLbQc3jgpfqnxWe6nteh * fix(bookkeeping): audit and document the per-bankkonto series, tighten preview and PATCH Consolidated pass over the PR #2160 findings (skeptics, CodeRabbit, Swedish compliance review): - Behandlingshistorik (BFNAR 2013:2 p. 9.16): changing cash_accounts.voucher_series is a behandlingsregel that outranks the audited per-type map. New trigger audit_cash_accounts_voucher_series (UPDATE only, WHEN the series changes, so bank-sync churn never logs), cash_accounts added to AUDITED_TABLES and the audit_log filter, "Bankkonto ... Verifikationsserie: (tomt) -> M" events in the report, pg-real test. Applied to staging as 20260902124513. - Systemdokumentation (p. 9.2-9.15): revision/systemdokumentation.json gains a verifikationsserier_regler block with the resolution order and the two exceptions (invoice settlements, samlingsverifikat); the per-account mapping itself is in data/cash_accounts.json. - Settings picker uses the same closed list as the manual verifikat form (presets plus letters already in use) instead of all 26 letters; strings moved to messages/sv.json and messages/en.json. - /voucher-sequences/next applies the account override only for source_type=bank_transaction (CodeRabbit), so a manual-entry preview cannot show a series the entry will not get. - Book route resolves the series from the account the row ends up on after a stranded-row repoint, not the stale one. - PATCH /api/cash-accounts/[id] answers 404 for a non-UUID id instead of a Postgres cast 500; the series lookup logs a warning when it fails open. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JWSLbQc3jgpfqnxWe6nteh --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
678acfe7ef
commit
f1230282a9
@@ -0,0 +1,19 @@
|
||||
-- Verifikationsserie per bankkonto.
|
||||
--
|
||||
-- A company that runs several bank accounts (main bank on series A, a
|
||||
-- company-card account on series M, both imported via CSV) wants entries
|
||||
-- booked from each account to land in that account's own series. Until now
|
||||
-- every bank-transaction booking took the single company-wide default from
|
||||
-- company_settings.default_voucher_series_per_source_type.bank_transaction.
|
||||
--
|
||||
-- NULL means "no override": the engine keeps resolving the series from the
|
||||
-- per-source-type map, so existing accounts and bookings are untouched.
|
||||
-- Single uppercase letter, same rule as journal_entries.voucher_series.
|
||||
ALTER TABLE public.cash_accounts
|
||||
ADD COLUMN IF NOT EXISTS voucher_series text
|
||||
CHECK (voucher_series IS NULL OR voucher_series ~ '^[A-Z]$');
|
||||
|
||||
COMMENT ON COLUMN public.cash_accounts.voucher_series IS
|
||||
'Optional verifikationsserie (single letter A-Z) for entries booked from this bank account. NULL = follow the per-source-type default in company_settings.';
|
||||
|
||||
NOTIFY pgrst, 'reload schema';
|
||||
@@ -0,0 +1,18 @@
|
||||
-- Behandlingshistorik for the per-bankkonto verifikationsserie.
|
||||
--
|
||||
-- cash_accounts.voucher_series (20260902121420) takes precedence over the
|
||||
-- company-wide default_voucher_series_per_source_type map, which is already
|
||||
-- audited and reported as a behandlingsregel (BFNAR 2013:2 p. 9.16 second
|
||||
-- paragraph: changes that affect how bokföringsposter are processed, and when
|
||||
-- they were introduced). The override must leave the same dated trace.
|
||||
--
|
||||
-- UPDATE only, and only when the series itself changes: cash_accounts rows are
|
||||
-- created and touched by bank sync (balances, names, enabled flags) many times
|
||||
-- a day, and none of that is a behandlingsregel. Same WHEN pattern as the
|
||||
-- categorization_templates learning filter in 20260901103000.
|
||||
DROP TRIGGER IF EXISTS audit_cash_accounts_voucher_series ON public.cash_accounts;
|
||||
CREATE TRIGGER audit_cash_accounts_voucher_series
|
||||
AFTER UPDATE ON public.cash_accounts
|
||||
FOR EACH ROW
|
||||
WHEN (OLD.voucher_series IS DISTINCT FROM NEW.voucher_series)
|
||||
EXECUTE FUNCTION public.write_audit_log();
|
||||
Reference in New Issue
Block a user