Commit Graph
3 Commits
Author SHA1 Message Date
Jonas Flodén a3491b6d89 fix(transactions): resolve bank account from cash_account_id in bulk-book and direct-book dialogs (#770)
Follow-up to #769: applies the same fetch-on-open + resolveAccount pattern to
BulkBookDialog (manual tab bank-leg pre-fill) and BookDirectlyDialog (settlement
line in buildPrefillLines). Both dialogs now fetch /api/cash-accounts when they
open, gate the pre-fill on the fetch resolving, and resolve the correct BAS
ledger account per transaction instead of always emitting '1930'.

Adds lib/cash-accounts/resolve-account.ts (cherry of the utility from #769)
since that PR is not yet merged into main.

Signed-off-by: Jonas Flodén <jonas@floden.nu>
2026-06-25 12:40:09 +02:00
Jakob WennbergandClaude Opus 4.7 a586cc8a58 feat(transactions): show all library templates in picker; fix PSD2 seed-row collision (#596)
* feat(transactions): show all library templates in picker; fix PSD2 seed-row collision

- Booking template picker: surface every active library template, not
  only the convertible 2-account shapes. Multi-leg/complex templates
  route to the manual journal editor pre-filled via applyTemplate
  instead of being hidden. Drop direction filtering for user
  templates (inferred direction is unreliable); the curated static
  catalog still respects it. Add an "Aktivera och bokfor" recovery
  toast for TX_CATEGORIZE_INVALID_ACCOUNT mirroring the existing
  ACCOUNTS_NOT_IN_CHART flow. CreateTemplateForm reflows to one card
  per line so trash buttons stop colliding on narrow screens.

- cash_accounts.upsertFromPsd2: the seed_default_cash_account
  migration plants a manual (bank_connection_id IS NULL) row on the
  same ledger_account, so the first PSD2 sync's upsert on
  (company_id, bank_connection_id, external_uid) cannot match it
  (NULL != NULL) and falls through to INSERT, tripping the
  (company_id, ledger_account) UNIQUE constraint. Look up and
  promote the seed row in place first.

- Tests: pin the TX_CATEGORIZE_INVALID_ACCOUNT error shape the
  recovery toast parses; cover applyTemplate on shapes the
  converter rejects (split-expense and all-'business'-typed).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(transactions): PR review — currency metadata, MRU ordering, observable promote, BAS validation

- TransactionBookingDialog.buildInitialLinesFromTemplate: attach
  buildCurrencyMetadata to settlement lines for foreign-currency
  transactions so the journal entry retains the original currency,
  amount, and exchange_rate. Without this, non-SEK transactions
  routed through a non-convertible template were recorded in SEK
  only with no foreign-currency annotation. (Greptile #2)

- TemplatePicker.handleSelectLibraryRaw: only bump the MRU after
  confirming the click will actually do something (i.e. converted
  OR a callback is wired). Future consumers that omit
  onPickLibraryTemplate would otherwise corrupt MRU ordering for
  templates the user never successfully applied. (Greptile #1)

- cash_accounts.upsertFromPsd2 promote-seed: add .select('id') so
  a zero-row UPDATE is observable. If the seed row vanishes
  between the SELECT and UPDATE (concurrent ops), fall through to
  the normal upsert instead of silently returning success without
  persisting anything. (Greptile #3, compliance A.8.9)

- transactions/page.tsx TX_CATEGORIZE_INVALID_ACCOUNT toast:
  validate accountNumber against /^\d{4}$/ before embedding in any
  fetch URL/body. Defense-in-depth against a malformed server
  error envelope. (compliance V8.2.1)

- categorize route test: switch the not-in-chart fixture from
  '4535' (Inköp av varor från annat EU-land — reverse-charge) to
  '5420' (Programvaror) so the example doesn't imply a domestic
  override against an EU-reverse-charge account would be valid
  without its paired moms legs. (Swedish compliance review #3)

Other review items deliberately not addressed in this PR:
- Validate-on-save that every VAT-rated template has a 'vat'
  line — overrides existing CreateTemplateForm UX, separate PR.
- vat_rate enum guard in applyTemplate — defensive; the editor
  dropdown only surfaces legal rates and is the only write path
  in production today.
- Imbalance UI warning — already handled: JournalEntryForm
  computes isBalanced and gates submission; DB trigger
  check_journal_entry_balance enforces BFL 5 kap server-side.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 22:57:59 +02:00
Mattsson 8a6ce7093e feat: implement skattekonto drift detection and alerting (#525)
* feat: implement skattekonto drift detection and alerting

- Add skattekonto drift computation logic to compare Skatteverket's saldo with GL 1630 sum.
- Implement alerting mechanism for significant drift changes, with throttling to prevent alert spamming.
- Introduce database functions to sum GL 1630 entries and list unbooked skattekonto rows.

feat: create own account transfer detection

- Develop logic to detect transfers between a company's own cash accounts based on counterparty IBAN.
- Implement tests to validate detection logic under various scenarios, including matching and non-matching IBANs.

feat: establish cash accounts as a first-class entity

- Create cash_accounts table to manage routable cash accounts, replacing ad-hoc JSONB structures.
- Implement functions for listing, upserting, and managing cash accounts, including primary account designation.

feat: enhance GL line reconciliation functionality

- Modify get_unlinked_1930_lines RPC to accept any account number for reconciliation, improving flexibility for different currencies.
- Update related functions to ensure compatibility with the new cash_accounts structure.

feat: capture counterparty IBAN in transactions

- Add counterparty_iban column to transactions table to facilitate intra-account transfer detection.
- Create index for efficient lookups based on counterparty IBAN.

* feat: Enhance cash account handling and reconciliation processes

- Updated reconciliation routes to enforce cash account validation for all account numbers, including '1930'.
- Improved error handling for unknown cash accounts in reconciliation status and unmatched entries routes.
- Changed CashAccountSelector to use sessionStorage instead of localStorage for better data privacy.
- Fixed mapping for employer payroll taxes to route to the correct account (2730 instead of 2731).
- Added safety checks for company IDs in the guessCounterAccount function to prevent injection vulnerabilities.
- Introduced atomic RPC for setting primary cash accounts to avoid intermediate states during updates.
- Seeded default cash accounts for new companies to ensure reconciliation routes are accessible from day one.
- Updated email notifications for drift detection to avoid exposing sensitive financial data.
- Enhanced bank reconciliation logic to handle multi-currency transactions correctly.
- Renamed and updated tests to reflect changes in the underlying RPCs and ensure accurate coverage.
- Migrated existing cash account rules to correct mappings in compliance with Swedish accounting standards.
2026-05-19 16:10:18 +02:00