fix(received-invoices): treat amount as gross (VAT-inclusive), back-calc VAT

The amount on a received invoice is the GROSS total the user pays (VAT
included), and VAT is the portion contained within it — not a net base with
VAT added on top. Switch the formula from amount*rate/100 to the
VAT-inclusive amount*rate/(100+rate) via a shared, tested vatFromGross()
helper used by both the create (manual upload + AI import share this
endpoint) and edit paths. Rate 0 → no VAT.

- AI extraction now asks Claude for the total INCLUDING VAT (was "základ bez
  DPH"), reinforced in the structured-output schema description.
- Label the amount field "Částka s DPH" in the AI review card and the manual
  upload/edit forms so the gross convention is explicit.
- Add unit tests with the user-confirmed figures (22 542,91 @ 21% → 3 912,41,
  base 18 630,50) plus other rates and the no-VAT case.

Existing rows keep their stored (gross) amounts; their vat_amount recomputes
on next edit. A one-shot backfill can correct historical vat_amount if wanted.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-06-08 16:27:56 +02:00
parent 58e5fd2b1d
commit f4bc038f8b
5 changed files with 55 additions and 16 deletions

View File

@@ -932,7 +932,7 @@ export default function ReceivedInvoices({
<Box sx={{ display: "flex", gap: 1.5, alignItems: "flex-start" }}>
<Box sx={{ flex: 1 }}>
<Field
label="Částka"
label="Částka s DPH"
required
error={uploadErrors[idx]?.amount}
>
@@ -1096,7 +1096,7 @@ export default function ReceivedInvoices({
sx={{ display: "flex", gap: 1.5, alignItems: "flex-start" }}
>
<Box sx={{ flex: 1 }}>
<Field label="Částka" required>
<Field label="Částka s DPH" required>
<TextField
type="number"
slotProps={{