Files
accounted/app/api
Mattsson e313bfa8ec fix(invoices): ROT/RUT kontantmetoden invoices could not be marked paid (#2040)
* fix(invoices): derive mark-paid amount as customer settlement, not gross debit sum

remaining_amount on a ROT/RUT invoice is stored net of the deduction
(total - deduction_total): the customer owes only their share, and
Skatteverket's share sits on 1513 until the payout flow clears it. The
kontantmetoden payment entry correctly books two debit legs (bank =
customer share, 1513 = deduction), but both mark-paid routes summed ALL
debit lines as the payment amount, so the gross total was compared
against the net remaining and every ROT/RUT cash invoice was rejected
with MATCH_AMOUNT_EXCEEDS_REMAINING by exactly deduction_total,
stalling the whole ROT chain (unpaid invoice never becomes a payout
candidate).

New deriveCustomerSettlementAmount in lib/invoices/apply-invoice-payment
excludes the net 1513 debit, capped at the invoice's own deduction (so
invoices without a deduction keep byte-identical behavior, including
rejecting a hand-added 1513 overshoot), and both the dashboard and v1
mark-paid routes use it. The verifikat still books the full entry
including the 1513 leg; only the settlement math changes.

Reported by a user unable to mark ROT invoice 1123 as paid.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uy5xt3nCKwL1vhRFPYjAjJ

* fix(invoices): harden ROT settlement derivation per skeptic refutations

Three fixes from adversarial review of the previous commit:

1. v1 mark-paid never fetched deduction_total (the pre-flight select
   projects explicit columns), so the exclusion cap was always 0 and the
   v1 API still failed with MATCH_AMOUNT_EXCEEDS_REMAINING. Fetch it ad
   hoc next to journal_entry_id (kept out of the response contract) and
   assert the projection in the route test, since the mock harness
   ignores select strings.

2. Gate the 1513 exclusion on the invoice NOT being booked yet, in both
   routes. An invoice booked at send already debited 1513 in its
   registration entry; ungated, a cash-shaped payment entry on such an
   invoice would post (orphaned 1510, doubled 1513, double revenue and
   VAT) where the gross guard used to reject it.

3. payment-sync's reversal recompute now stores remaining_amount net of
   deduction_total, matching build-invoice-write and the DB guard.
   Recomputing gross made a storno'd ROT cash invoice permanently
   un-payable under the net settlement derivation (net payment can never
   reach a gross remaining; the cash-partial block rejects the rest).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uy5xt3nCKwL1vhRFPYjAjJ

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-30 15:12:37 +02:00
..
2026-07-25 22:56:17 +02:00
2026-07-23 16:16:55 +02:00
2026-07-05 03:05:09 +02:00
2026-07-08 09:54:46 +02:00