Commit Graph
3 Commits
Author SHA1 Message Date
MattssonandClaude Opus 4.8 c6c86cded4 Mcp/template data feedback (#617)
* fix(booking-templates): scope template list to the active company

GET /api/settings/booking-templates relied solely on the btl_select RLS
policy, which is membership-wide (user_company_ids) and returns templates
from every company the user belongs to. A user who owns multiple companies
saw all their templates merged regardless of which company was active.

Narrow the list in the API layer (mirroring counterparty-templates) to
system + the active company + the active company's team. RLS stays the
security backstop; this fixes the cross-company merge within a single
user's own view (it was never a cross-tenant data leak).

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

* fix(import): show proper message for duplicate bank file upload

The bank file import page mis-parsed the structured error envelope
({ error: { code, message, details } }), so a BANK_FILE_DUPLICATE
(409) fell through to the generic "Kunde inte läsa filen" fallback.
The upload step also hardcoded that same string as the error heading,
so duplicates were doubly misreported as parse failures.

- Parse the structured envelope by error.code; surface error.message
  for all codes instead of rendering the error object.
- Add a dedicated BANK_FILE_DUPLICATE message using the importedAt /
  importedCount details the route already returns.
- Add an optional errorTitle prop to BankFileUploadStep (defaults to
  the previous text) and pass "Filen är redan importerad" for dupes.

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

* feat(tests): add comprehensive tests for recordateEntry, inbox-linking, and external-id handling

- Implemented unit tests for recordateEntry in the bookkeeping module to validate various scenarios including date changes, non-posted entries, and fiscal period restrictions.
- Created tests for inbox-linking status in pending operations to ensure correct handling of invoice inbox items and supplier invoices, addressing historical bugs related to status updates.
- Added tests for external-id utilities to ensure consistent handling of monetary amounts and deduplication keys across different transaction sources.
- Introduced new functions in external-id.ts for stable external ID generation and normalization of imported descriptions, enhancing transaction deduplication reliability.

feat(migrations): add new database migrations for transaction handling

- Created migration to exclude storno and correction vouchers from unmatched GL lines, ensuring accurate reconciliation.
- Added a migration to preserve original bank transaction descriptions in a new immutable column, allowing for user edits while maintaining audit trails and deduplication integrity.

* feat(migrations): add function to exclude storno/correction vouchers from unmatched GL lines

* feat(transactions): enhance transaction handling with improved description normalization and preloaded original entries

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 14:45:49 +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
Jakob WennbergandClaude Opus 4.7 5eee06a56d fix(reconciliation): exclude opening balance from unmatched-1930 set (#443) (#485)
* fix(reconciliation): exclude opening balance from unmatched-1930 set (#443)

Reconciliation incorrectly counted IB (source_type='opening_balance')
vouchers on 1930 as unmatched bank transactions and included them in the
GL period total. Result: an SIE-imported book always showed a phantom
unmatched voucher and a difference equal to the IB amount, even when
every real bank transaction was matched. This was the root of the
"reconciliation says broken but numbers look right" complaint.

The fix is two-sided:

- get_unlinked_1930_lines RPC now skips source_type='opening_balance'
  rows. IB has no counterpart in the bank feed by definition.
- getReconciliationStatus splits glOpeningBalance out of the period
  movement and computes difference = bankTotal − glPeriodMovement
  (was bankTotal − glBalance). gl_1930_balance is preserved unchanged
  for back-compat; new gl_1930_period_movement and
  gl_1930_opening_balance fields let the UI show both perspectives.
- BankReconciliationView shows period movement vs bank in the diff and
  folds IB into a small caption ("Ingående balans … räknas inte i
  avstämningen") only when non-zero.

Mirrors Fortnox's "Ingående saldo vid avstämningsstart" pattern — IB is
verified separately, never surfaced as unmatched.

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

* fix(reconciliation): use IS DISTINCT FROM for NULL-safe source_type filter

`source_type <> 'opening_balance'` evaluates to NULL (not TRUE) when
`source_type IS NULL` under SQL three-valued logic. journal_entries.source_type
is NOT NULL today so the practical difference is zero, but if that constraint
is ever relaxed `<>` would silently drop NULL rows from the unmatched-1930 set,
making them invisible to reconciliation.

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

* fix(test): use valid source_type 'bank_transaction' in pg-real fixture

CI pg-real failed because 'bank_import' is not in the journal_entries
source_type CHECK constraint. The valid value for bank-imported transactions
is 'bank_transaction' (per migration 20260513170001 + earlier).

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

* docs(reconciliation): deprecate gl_1930_balance on ReconciliationStatus

Mark the IB-inclusive balance field as @deprecated on both the server-side
ReconciliationStatus interface and the component-side mirror. Downstream
consumers that read this field expecting it to drive the diff will be off
by the IB amount whenever a SIE-imported opening balance exists on 1930.
The new gl_1930_period_movement field is the correct basis for the diff and
is what the difference field is computed against.

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

* refactor(reconciliation): tighten review feedback on PR #485

Three tweaks from the Swedish-accounting bot review:

1. Drop the gl_1930_period_movement ?? gl_1930_balance fallback in
   BankReconciliationView. gnubok has no persisted reconciliation snapshots
   and Vercel deploys atomically, so the old-server/new-client case can't
   occur — the fallback was defensive code for an impossible state. Per
   CLAUDE.md: don't add back-compat shims when you can just change the code.
   gl_1930_period_movement and gl_1930_opening_balance are now required on
   the type.

2. Clarify in the migration comment that source_type='opening_balance' is
   reserved for the fiscal-year IB voucher (always at period_start). The
   bot questioned whether the unconditional filter could hide a mid-year
   corrective IB entry; document the invariant — mid-year corrections use
   source_type='correction' or 'manual', never 'opening_balance'.

3. Test fixture 2099 → 2091. 2099 is årets resultat (current year);
   2091 is balanserad vinst/förlust, the realistic counterpart for a
   carried-forward bank IB. RPC filters on 1930 only so this is cosmetic
   but matches what a real SIE import would produce.

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-14 16:39:38 +02:00