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:
Mattsson
2026-09-02 15:25:34 +02:00
committed by GitHub
co-authored by Claude Fable 5.1
parent 678acfe7ef
commit f1230282a9
27 changed files with 990 additions and 19 deletions
+10 -1
View File
@@ -2335,7 +2335,16 @@
"series_prefix": "Series",
"default_badge": "default",
"latest_number": "Latest no.",
"footnote": "New series are created automatically the first time they are used in bookkeeping."
"footnote": "New series are created automatically the first time they are used in bookkeeping.",
"per_account_heading": "Voucher series per bank account",
"per_account_help": "Let a bank account book into its own series, for example the main bank on A and the company card on M. Default follows the bank-transaction series above. Applies to booking bank transactions; invoice matches keep their payment series.",
"per_account_follow_default": "Default",
"per_account_loading": "Loading bank accounts",
"per_account_empty": "No active bank accounts yet. Accounts are created when you connect a bank or import transactions.",
"per_account_saved_title": "Voucher series saved",
"per_account_saved_set": "New vouchers from {account} land in series {series}.",
"per_account_saved_cleared": "{account} now follows the default bank-transaction series.",
"per_account_save_failed": "Could not save"
},
"settings_team_panel": {
"role_owner": "Owner",
+10 -1
View File
@@ -2335,7 +2335,16 @@
"series_prefix": "Serie",
"default_badge": "standard",
"latest_number": "Senaste nr",
"footnote": "Nya serier skapas automatiskt första gången de används vid bokföring."
"footnote": "Nya serier skapas automatiskt första gången de används vid bokföring.",
"per_account_heading": "Verifikationsserier per bankkonto",
"per_account_help": "Låt ett bankkonto bokföra i en egen serie, till exempel huvudbanken på A och företagskortet på M. Standard följer serien för banktransaktioner ovan. Gäller bokföring av banktransaktioner; fakturamatchningar behåller sin betalningsserie.",
"per_account_follow_default": "Standard",
"per_account_loading": "Hämtar bankkonton",
"per_account_empty": "Inga aktiva bankkonton ännu. Konton skapas när du kopplar en bank eller importerar transaktioner.",
"per_account_saved_title": "Verifikationsserie sparad",
"per_account_saved_set": "Nya verifikat från {account} hamnar i serie {series}.",
"per_account_saved_cleared": "{account} följer nu standardserien för banktransaktioner.",
"per_account_save_failed": "Kunde inte spara"
},
"settings_team_panel": {
"role_owner": "Ägare",