From 890dbccdf5816ee7b3b690b98f966728a0906bfc 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 09:02:52 +0000 Subject: [PATCH] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/components/cases/collections-tab.tsx | 49 ++++++++++++++++++++---- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/src/components/cases/collections-tab.tsx b/src/components/cases/collections-tab.tsx index 634eaee..2482752 100644 --- a/src/components/cases/collections-tab.tsx +++ b/src/components/cases/collections-tab.tsx @@ -832,18 +832,52 @@ export function CollectionDetail({ }); // ── Amounts Due Breakdown (below the ledger) ── - // Group entries by bucket → account label → subtotal - const subAccountTotals: Record> = {}; - BUCKETS.forEach((b) => (subAccountTotals[b] = {})); + // Group entries by bucket → account label → charged subtotal, + // then subtract payments proportionally so each sub-account shows + // its remaining (net of payments) balance. + const subAccountCharges: Record> = {}; + const subAccountPayments: Record> = {}; + BUCKETS.forEach((b) => { + subAccountCharges[b] = {}; + subAccountPayments[b] = {}; + }); + // 1) Sum charges per bucket / account 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; + if (v > 0) { + subAccountCharges[b][acctLabel] = (subAccountCharges[b][acctLabel] || 0) + v; } }); }); + // 2) Distribute each payment's bucket allocation proportionally + // across sub-accounts by their share of charges in that bucket. + withRunning.forEach((e: any) => { + if (!(num(e.payment) > 0) || !e.allocations) return; + BUCKETS.forEach((b) => { + const allocAmt = num(e.allocations[b]); + if (allocAmt <= 0) return; + const charges = subAccountCharges[b]; + const totalCharged = Object.values(charges).reduce((s, v) => s + v, 0); + if (totalCharged <= 0) return; + Object.keys(charges).forEach((acctLabel) => { + const share = charges[acctLabel] / totalCharged; + subAccountPayments[b][acctLabel] = + (subAccountPayments[b][acctLabel] || 0) + allocAmt * share; + }); + }); + }); + // 3) Net remaining = charges − payments per sub-account + const subAccountNet: Record> = {}; + BUCKETS.forEach((b) => { + subAccountNet[b] = {}; + Object.keys(subAccountCharges[b]).forEach((acctLabel) => { + const charged = subAccountCharges[b][acctLabel] || 0; + const paid = subAccountPayments[b][acctLabel] || 0; + subAccountNet[b][acctLabel] = charged - paid; + }); + }); const breakdownBody: any[] = []; const DISPLAY_ORDER: Array = [ @@ -859,8 +893,9 @@ export function CollectionDetail({ { 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); + const subs = subAccountNet[b]; + // Hide sub-accounts that are fully paid off (≤ 0.005 to avoid float noise) + const subKeys = Object.keys(subs).filter((k) => Math.abs(subs[k]) > 0.005); if (subKeys.length > 0) { subKeys .sort((a, z) => subs[z] - subs[a])