From e9b297c162a19da31d53de377b90bfd5cda1b0a7 Mon Sep 17 00:00:00 2001 From: Luca <102960244+Luca-Timo@users.noreply.github.com> Date: Thu, 18 Jun 2026 19:17:12 +0200 Subject: [PATCH] =?UTF-8?q?fix(crm):=20editor=20totals=20box=20computed=20?= =?UTF-8?q?VAT=20100=C3=97=20too=20small?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LineItemsTable's live preview did `Math.round(subtotal * vatRate) / 100` where subtotal is in major units and vatRate is a fraction (0.081) — rounding to whole units before the /100 divided the VAT by 100 (CHF 0.63 instead of 63.18). Add the missing *100 inside the round so it rounds to cents. Backend computeTotals + the PDF + the tax report were always correct; this preview-only bug just surfaced now that new invoices seed a non-zero default VAT code instead of 0%. --- frontend/src/components/admin/LineItemsTable.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/admin/LineItemsTable.tsx b/frontend/src/components/admin/LineItemsTable.tsx index 3f11d931..152cc495 100644 --- a/frontend/src/components/admin/LineItemsTable.tsx +++ b/frontend/src/components/admin/LineItemsTable.tsx @@ -251,7 +251,12 @@ export const LineItemsTable: React.FC = ({ // never roll directly into net — they only feed their parent's // auto-resolved line total. const subtotal = items.filter((li) => !isSub(li)).reduce((s, li) => s + lineTotal(li), 0); - const vatAmount = Math.round(subtotal * vatRate) / 100; + // subtotal is in MAJOR units, vatRate is a FRACTION (0.081). Round to cents: + // round(subtotal * vatRate * 100) / 100 — the *100 inside round was missing, + // which divided the VAT by 100 (CHF 0.63 instead of 63.18). Backend + // computeTotals + the PDF were always correct; only this live editor preview + // was wrong, and it only surfaced once invoices stopped defaulting to 0% VAT. + const vatAmount = Math.round(subtotal * vatRate * 100) / 100; const total = subtotal + vatAmount + (Number(shippingAmount) || 0); // Display numbering: top-level items get 1, 2, 3...; sub-items