From c4efc305f2285ff7491bb2abfedc85cf7b5d3cae Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sun, 26 Apr 2026 08:54:45 +0000 Subject: [PATCH] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/components/cases/collections-tab.tsx | 61 ++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/components/cases/collections-tab.tsx b/src/components/cases/collections-tab.tsx index 2f5b4cc..a874af3 100644 --- a/src/components/cases/collections-tab.tsx +++ b/src/components/cases/collections-tab.tsx @@ -786,6 +786,67 @@ export function CollectionDetail({ }, }); + // ── Amounts Due Breakdown (below the ledger) ── + // Group entries by bucket → account label → subtotal + const subAccountTotals: Record> = {}; + BUCKETS.forEach((b) => (subAccountTotals[b] = {})); + entries.forEach((e: any) => { + const acctLabel = (e.account && String(e.account).trim()) || "—"; + BUCKETS.forEach((b) => { + const v = num(e[b]); + if (v) { + subAccountTotals[b][acctLabel] = (subAccountTotals[b][acctLabel] || 0) + v; + } + }); + }); + + const breakdownBody: any[] = []; + const DISPLAY_ORDER: Array = [ + "assess", "late", "admin", "legal", "viol", "interest", "bank", + ]; + DISPLAY_ORDER.forEach((b) => { + const bucketTotal = Math.max(0, computed[b] ?? 0); + const label = + b === "interest" + ? `Interest @ ${(effectiveRate || 0).toFixed(2)}%` + : BUCKET_LABEL[b]; + breakdownBody.push([ + { content: label, styles: { fontStyle: "bold", fillColor: [245, 245, 245] } }, + { content: formatCurrency(bucketTotal), styles: { halign: "right", fontStyle: "bold", fillColor: [245, 245, 245] } }, + ]); + const subs = subAccountTotals[b]; + const subKeys = Object.keys(subs); + if (subKeys.length > 0) { + subKeys + .sort((a, z) => subs[z] - subs[a]) + .forEach((sk) => { + breakdownBody.push([ + { content: ` ${sk}`, styles: { textColor: 90 } }, + { content: formatCurrency(subs[sk]), styles: { halign: "right", textColor: 90 } }, + ]); + }); + } + }); + breakdownBody.push([ + { content: "TOTAL DUE", styles: { fontStyle: "bold", fillColor: [20, 20, 20], textColor: 255 } }, + { content: formatCurrency(Math.max(0, computed.total)), styles: { halign: "right", fontStyle: "bold", fillColor: [20, 20, 20], textColor: 255 } }, + ]); + + const ledgerEndY = (doc as any).lastAutoTable?.finalY ?? txStartY; + autoTable(doc, { + startY: ledgerEndY + 20, + margin: { left: margin, right: pageWidth / 2 + 20 }, + head: [["Amounts Due Breakdown", "Amount"]], + body: breakdownBody, + styles: { fontSize: 9, cellPadding: 4 }, + headStyles: { fillColor: [20, 20, 20], textColor: 255, fontStyle: "bold" }, + columnStyles: { + 0: { cellWidth: "auto" }, + 1: { halign: "right", cellWidth: 90 }, + }, + theme: "grid", + }); + doc.save(`${name}.pdf`); toast.success("PDF exported"); };