Configurable tax model & per-line Vorsteuer booking #15

Merged
julian merged 1 commit from feat/booking-logic into main 2026-06-23 20:17:43 +02:00
Owner

Summary

Makes the booking pipeline's tax handling fully admin-configurable and corrects the postings for receipts (a cost → Vorsteuer).

Tax codes are authoritative

  • Per-merchant tax codes (managed in a new admin Tax codes tab) are the single source of a line's rate + bracket (reduced | full | none). The extractor's guessed rate is ignored — fixes the wrong 1 = 19% default.
  • A code a merchant hasn't configured → review, never booked.

Booking (per line, gross → net + VAT)

  • Net → resolved main account (e.g. 3300/3400).
  • VAT → the configured input-tax (Vorsteuer) account for the bracket. A receipt is a cost, so Vorsteuer — not Umsatzsteuer. none books net-only.
  • Missing tax account → review (won't book before the data exists).
  • Small unidentified lines (≤ tolerance) absorb into the dominant account even with unknown rate (fixes Pfand).
  • Receipt positions show Group | rate | account (X where undetermined).

Admin board

  • Tax codes tab (per merchant: code → rate + bracket).
  • Parameters: 4 tax accounts (Vorsteuer + Umsatzsteuer, reduced/full) + unidentified tolerance.
  • Allocate rewritten: two toggle views over all users' receipt lines (unallocated / all with freetext filter).
  • Groups & Merchants as tables. New write paths gated by is_admin() RLS.

Also

  • Cloud extraction upgraded to claude-opus-4-8 with adaptive thinking (better line/amount association + hi-res vision).
  • Admin checksum (sum of line items vs receipt total).
  • Scan → save now lands on the receipt detail.
  • Pipeline persisted in a single atomic insert (fixes an insert/update race that dropped harmonized/booking — why the admin allocate screen was empty).
  • Web output set to single-page SPA.

Verification

  • Booking determinism suite: 52/52.
  • tsc clean, expo lint 0 errors, web build compiles.
  • Migrations 2026062312000020260623170000 applied to the live DB; apply_all.sql regenerated; assign-groups / extract-receipt deployed.

🤖 Generated with Claude Code

## Summary Makes the booking pipeline's tax handling fully admin-configurable and corrects the postings for receipts (a cost → Vorsteuer). ### Tax codes are authoritative - Per-merchant tax codes (managed in a new admin **Tax codes** tab) are the single source of a line's **rate + bracket** (`reduced` | `full` | `none`). The extractor's guessed rate is ignored — fixes the wrong `1 = 19%` default. - A code a merchant hasn't configured → **review, never booked**. ### Booking (per line, gross → net + VAT) - **Net** → resolved main account (e.g. 3300/3400). - **VAT** → the configured **input-tax (Vorsteuer)** account for the bracket. A receipt is a cost, so Vorsteuer — not Umsatzsteuer. `none` books net-only. - Missing tax account → review (won't book before the data exists). - Small unidentified lines (≤ tolerance) absorb into the dominant account even with unknown rate (fixes Pfand). - Receipt positions show **`Group | rate | account`** (`X` where undetermined). ### Admin board - **Tax codes** tab (per merchant: code → rate + bracket). - **Parameters**: 4 tax accounts (Vorsteuer + Umsatzsteuer, reduced/full) + unidentified tolerance. - **Allocate** rewritten: two toggle views over **all users'** receipt lines (unallocated / all with freetext filter). - Groups & Merchants as tables. New write paths gated by `is_admin()` RLS. ### Also - Cloud extraction upgraded to **`claude-opus-4-8`** with adaptive thinking (better line/amount association + hi-res vision). - Admin **checksum** (sum of line items vs receipt total). - Scan → save now lands on the **receipt detail**. - Pipeline persisted in a **single atomic insert** (fixes an insert/update race that dropped harmonized/booking — why the admin allocate screen was empty). - Web output set to single-page SPA. ## Verification - Booking determinism suite: **52/52**. - `tsc` clean, `expo lint` 0 errors, web build compiles. - Migrations `20260623120000`–`20260623170000` applied to the live DB; `apply_all.sql` regenerated; `assign-groups` / `extract-receipt` deployed. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Booking engine — tax codes are now the authoritative source of a line's rate +
bracket; the extractor's guessed rate is ignored (fixes the "1 = 19%" default).
A code a merchant hasn't configured → review, never booked. Each line books its
NET to the resolved main account and its VAT to the configured input-tax
(Vorsteuer) account for its bracket (reduced/full/none) — a receipt is a cost,
so Vorsteuer, not Umsatzsteuer. Missing tax account → review.

Tax brackets are reduced | full | none; none books net-only with no VAT.
Small unidentified lines (≤ tolerance) absorb into the dominant account even
with an unknown rate (fixes Pfand). Per-line resolved accounts are exposed on
the booking snapshot; receipt positions show "Group | rate | account".

Admin board — new Tax codes tab (per-merchant code → rate + bracket) and tax
accounts in Parameters (4 accounts, string-valued booking_parameters). Allocate
tab rewritten with two views over all users' receipt lines; Groups/Merchants as
tables. Admin-only RLS via is_admin() on the new write paths.

Also: cloud extraction upgraded to claude-opus-4-8 with adaptive thinking;
admin checksum (line sum vs receipt total); scan→save now lands on the receipt
detail; pipeline persisted in a single atomic insert (fixes an insert/update
race that dropped harmonized/booking); web output set to single-page SPA.

Migrations 20260623120000–20260623170000 added; apply_all regenerated. Booking
determinism suite: 52/52.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
julian merged commit 2c77d1c050 into main 2026-06-23 20:17:43 +02:00
julian deleted branch feat/booking-logic 2026-06-23 20:17:59 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
julian/quickfin!15
No description provided.