diff --git a/public/invoice-view.js b/public/invoice-view.js index b881948..b1356cc 100644 --- a/public/invoice-view.js +++ b/public/invoice-view.js @@ -128,6 +128,15 @@ function getFilteredInvoices() { return f; } +// Effective amount: for unpaid/partial show balance, for paid show total +function effectiveAmount(inv) { + const total = parseFloat(inv.total) || 0; + const amountPaid = parseFloat(inv.amount_paid) || 0; + if (inv.paid_date) return total; // Paid → show full total + if (amountPaid > 0) return total - amountPaid; // Partial → show balance + return total; // Unpaid → show total +} + function groupInvoices(filtered) { if (groupBy === 'none') return null; const groups = new Map(); @@ -147,7 +156,7 @@ function groupInvoices(filtered) { if (!groups.has(key)) groups.set(key, { label, invoices: [], total: 0 }); const g = groups.get(key); g.invoices.push(inv); - g.total += parseFloat(inv.total) || 0; + g.total += effectiveAmount(inv); }); for (const g of groups.values()) { g.invoices.sort((a, b) => (parseLocalDate(b.invoice_date) || 0) - (parseLocalDate(a.invoice_date) || 0)); @@ -277,7 +286,7 @@ export function renderInvoiceView() { $${grandTotal.toFixed(2)}`; } } else { - filtered.forEach(inv => { html += renderInvoiceRow(inv); grandTotal += parseFloat(inv.total) || 0; }); + filtered.forEach(inv => { html += renderInvoiceRow(inv); grandTotal += effectiveAmount(inv); }); if (filtered.length > 0) { html += ` Total (${filtered.length} invoices):