* feat(bookkeeping): show per-account saldo on journal entry form
Adds a "Saldo" column to the journal entry form so bookkeepers can see
the current balance of each account as of the entry date while drafting
a voucher. Useful context for booking bank withdrawals, VAT clearings,
and other balance-sensitive operations.
- New GET /api/bookkeeping/account-balances?accounts=...&as_of=...
returns per-account net (debit - credit) over posted entries up to
and including the requested date. Batched in chunks of 200 entry IDs
to stay under PostgREST IN-list limits.
- JournalEntryForm fetches balances debounced 150ms on changes to the
set of selected account numbers or the entry date; carries forward
previously-known values so the cell doesn't flash to a skeleton on
re-fetch.
- Saldo is reference-only: it reflects "balance before this entry" and
intentionally ignores the draft lines the user is currently editing.
- Renders in both desktop (table column) and mobile (per-line caption)
layouts. Tabular-nums, muted, right-aligned.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(bookkeeping): correct saldo semantics — IB + period-only, BS vs P&L
Address Swedish compliance review on PR #562:
1. P&L accounts (class 3-8) no longer show a since-inception cumulative
sum. They reset each räkenskapsår per BFNAR 2013:2; the saldo now
reflects current-period activity only, matching trial-balance
semantics. BS accounts (class 1-2) continue to include IB.
2. Opening balances are now sourced via the canonical
getOpeningBalances() helper, which reads the explicit
opening_balance_entry_id set by year-end closing or SIE import.
Previously, summing journal_entry_lines from inception returned 0
for SIE-imported companies whose IB lives in a separate entry that
the old query happened to include — and the wrong value once
year-end ran and an OB entry was set without exclusion logic.
3. Relabel "Saldo" -> "Saldo (före)" / "Balance (before)" so the UI
communicates that the figure excludes the draft being edited
(BFNAR 2013:2 kap 8 self-documentation requirement).
4. Stop forwarding raw Supabase error.message to the client; log
server-side via the structured logger and return a generic
'Internal server error' to avoid leaking schema details.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(bookkeeping): reject future as_of dates on account-balances endpoint
Both compliance reviewers on PR #562 flagged this independently: a
future as_of date would include posted entries dated after today in
the activity window, producing a misleading "balance before this
entry" hint that could drive incorrect verifikat entries
(swedish-compliance-review-bot) or be used for future-date probing
(SOC 2 PI1.1, GDPR Art.25(2)).
- AccountBalancesQuerySchema.as_of now refines to <= today.
- JournalEntryForm collapses the loading skeleton to 0 on any non-OK
response so the saldo column doesn't get stuck spinning when a
user enters a future entry_date (which the form's separate period
validation already handles).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(bookkeeping): compare as_of guard against Europe/Stockholm date
swedish-compliance-review-bot caught this on the previous fix: the
future-date guard used new Date().toISOString().slice(0, 10), which is
UTC. Between 00:00–02:00 CET (or 00:00–03:00 CEST), a Swedish
bookkeeper's local "today" is one day ahead of UTC, so entering their
Stockholm-local date would be rejected as a future date.
Compare against Europe/Stockholm-local date via toLocaleDateString
('sv-SE'), which renders YYYY-MM-DD natively, so string comparison
remains correct across DST.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>