Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com>
This commit is contained in:
gpt-engineer-app[bot]
2026-04-26 08:29:25 +00:00
co-authored by renee-png
parent d05d33dd7f
commit c0035b2dc8
+54 -4
View File
@@ -1,13 +1,13 @@
// Priority order for payment allocation: Bank → Interest → Late → Legal → Admin → Violations → Assessments
export const BUCKETS = ["bank", "interest", "late", "legal", "admin", "viol", "assess"] as const;
// Priority order for payment allocation: Bank → Interest → Late → Admin → Legal → Violations → Assessments
export const BUCKETS = ["bank", "interest", "late", "admin", "legal", "viol", "assess"] as const;
export type Bucket = (typeof BUCKETS)[number];
export const BUCKET_LABEL: Record<Bucket, string> = {
bank: "Bank Fees",
interest: "Interest",
late: "Late Fees",
legal: "Legal Fees",
admin: "Admin Fees",
legal: "Legal Fees",
viol: "Violations",
assess: "Assessments",
};
@@ -16,8 +16,8 @@ export const BUCKET_SHORT: Record<Bucket, string> = {
bank: "Bank",
interest: "Int",
late: "Late",
legal: "Legal",
admin: "Admin",
legal: "Legal",
viol: "Viol",
assess: "Assess",
};
@@ -93,3 +93,53 @@ export function withRunningBalance(entries: LedgerEntry[], opening = 0) {
return { ...e, runningBalance: bal };
});
}
/**
* For each row, compute:
* - runningBalance (overall)
* - allocations: Record<Bucket, number> — how much of THIS row's payment was
* applied to each bucket (in priority order). Empty / zero for non-payment rows.
* - bucketBalancesAfter: per-bucket remaining balance after this row.
*/
export function withAllocations(entries: LedgerEntry[], opening = 0) {
const bal: Record<Bucket, number> = {
bank: 0, interest: 0, late: 0, admin: 0, legal: 0, viol: 0, assess: 0,
};
bal.assess += opening;
let running = opening;
return entries.map((e) => {
// First add this row's charges
BUCKETS.forEach((b) => { bal[b] += num((e as any)[b]); });
running += rowCharges(e);
// Then allocate this row's payment in priority order
const allocations: Record<Bucket, number> = {
bank: 0, interest: 0, late: 0, admin: 0, legal: 0, viol: 0, assess: 0,
};
let pay = num(e.payment);
if (pay > 0) {
for (const b of BUCKETS) {
if (pay <= 0) break;
if (bal[b] <= 0) continue;
const take = Math.min(bal[b], pay);
bal[b] -= take;
allocations[b] += take;
pay -= take;
}
// leftover overpayment → reduce assess (creates credit)
if (pay > 0) {
bal.assess -= pay;
allocations.assess += pay;
}
running -= num(e.payment);
}
return {
...e,
runningBalance: running,
allocations,
bucketBalancesAfter: { ...bal },
};
});
}