feat(expenses): expense claims module (utlägg) (#2145)

Contributed by @joakimhew. Maintainer commits on top: migration re-versioned to 20260904170000 (main's 20260901210000 took the original version), payout batches booked atomically through the create_expense_payout_batch RPC, accounted-api skill regenerated, main merged. Closes #2143.
This commit is contained in:
Joakim Hansson
2026-09-05 13:36:51 +02:00
committed by GitHub
parent f7f40c04e4
commit 397a3b9bca
24 changed files with 5085 additions and 5 deletions
+2
View File
@@ -1500,6 +1500,8 @@ One line per decision: `[YYYY-MM-DD] <decision>: <why>`. Appended by agents and
[2026-09-02] parties phase 0, golden set stays out of git: the labelling sample is prod voucher text with person names (salary, expense claims) and the repo is public, so the draw SQL is versioned but the rows and labels live in gitignored dev_docs/parties/golden/.
[2026-09-02] parties substrate: customers and suppliers keep their tables and gain party_id; parties dedupe on normalised org number only, never on name at insert time. A name merge is a recorded human decision because the July measurement showed a majority of generic keys still map to one real vendor, so an automatic name merge would fuse unrelated suppliers.
[2026-09-02] MCP eager-auth flag (`auth=required`) on the claude.ai connector links instead of reverting lazy auth: claude.ai's two-step Add-custom-connector dialog probes the URL without credentials and pre-fills Authentication "None" when the lazy handshake answers 200, which blocks the sign-in later; per Anthropic's docs a 401 is the only answer it reads as OAuth. The flag lives in the URL, so the links we control (Settings, onboarding checklist, both docs pages, website) get OAuth detected while the bare URL keeps lazy auth for Claude Code, the plugin, Cursor and ChatGPT, and existing connector records stay untouched. Rejected: keying eager auth off `client=claude-connector` (documented as telemetry-only) and sniffing the probe's user agent (fragile, undocumented).
[2026-09-01] Balance badge in the expense booking dialog uses non-breaking spaces instead of whitespace-nowrap: the nowrap-in-dialog guard forbids the class inside DialogContent, and the label is a single semantic token, so NBSP fixes the wrap without touching the guard allowlist.
[2026-09-05] Expense payout batches book through the create_expense_payout_batch RPC (claims locked FOR UPDATE, verifikat via commit_journal_entry, claims marked paid, one transaction) instead of the application-side select/insert/post/link/mark sequence with storno compensation: three concurrent identical payout requests each booked a transfer for the same claims in the local end-to-end run, and compensation cannot prevent a race that a row lock prevents by construction.
[2026-09-02] Recurring gross deductions keep is_vacation_basis=false on the deduction row (the semester base is NOT reduced): matches the common loneväxling agreement where vacation pay stays on the pre-exchange salary, and diverges deliberately from the manual-line default which follows the row flags as entered. Flagged by review on #2044; change requires a per-line toggle, not a different default.
[2026-09-02] Recurring 'other' additions removed from #2042/#2044 scope: calculateSalary only treats ADDITION_TYPES as additions, so a recurring taxable addition would render on the payslip without entering gross/tax/AGA or AGI. Re-add only together with engine support and engine tests.
[2026-09-02] Offert detail actions: Acceptera + Skapa faktura in the header, Avboj in the overflow menu: convention 9 (one obvious next step, alternatives behind the caret); declining is the rarer branch.