From ee10f747532129081ed283d11434a5828ff1d6a4 Mon Sep 17 00:00:00 2001 From: renee-png Date: Fri, 19 Jun 2026 00:55:13 -0400 Subject: [PATCH] Prepaid Homeowners + AR Aging (Property): roll ledger up to the unit, show current owner Owner-ledger entries tied only to an old owner_id grouped separately, so former owners showed big prepaid balances and current owners were missing. Map each entry to its unit (via the owner's unit when the entry has no unit_id) so balances net per unit, and label each unit with its current (active, primary) owner. Co-Authored-By: Claude Opus 4.8 --- .../accounting/components/ARAgingPropertyReport.tsx | 7 +++++-- .../components/PrepaidHomeownersReport.tsx | 13 +++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/pages/accounting/components/ARAgingPropertyReport.tsx b/src/pages/accounting/components/ARAgingPropertyReport.tsx index 8c05b2e..98e1569 100644 --- a/src/pages/accounting/components/ARAgingPropertyReport.tsx +++ b/src/pages/accounting/components/ARAgingPropertyReport.tsx @@ -99,10 +99,13 @@ export function ARAgingPropertyReport({ companyId, companyName, logoUrl, to: pro if (c.owner_id && !collByOwner.has(c.owner_id)) collByOwner.set(c.owner_id, c.status); } - // Group ledger entries per unit (fall back to owner when the entry has no unit) + // Group ledger entries per unit. Entries tied only to an owner_id (often a + // former owner) are mapped to that owner's unit so the balance rolls into + // the unit and shows under its current owner — not a separate old-owner row. const byUnit = new Map(); for (const e of entries) { - const key = e.unit_id ? `u:${e.unit_id}` : e.owner_id ? `o:${e.owner_id}` : null; + const unitId = e.unit_id ?? (e.owner_id ? ownerById.get(e.owner_id)?.unit_id ?? null : null); + const key = unitId ? `u:${unitId}` : e.owner_id ? `o:${e.owner_id}` : null; if (!key) continue; const list = byUnit.get(key) ?? []; list.push(e); diff --git a/src/pages/accounting/components/PrepaidHomeownersReport.tsx b/src/pages/accounting/components/PrepaidHomeownersReport.tsx index 8d43906..72cd048 100644 --- a/src/pages/accounting/components/PrepaidHomeownersReport.tsx +++ b/src/pages/accounting/components/PrepaidHomeownersReport.tsx @@ -46,12 +46,21 @@ export function PrepaidHomeownersReport({ companyId, companyName, logoUrl, to: p for (const u of data.units) unitById.set(u.id, u); const ownerById = new Map(); for (const o of data.owners) ownerById.set(o.id, o); + // Current owner per unit (active + primary first) so balances aren't tagged + // to a moved-out owner. + const ownerRank = (o: OwnerInfo) => + ((o.status == null || o.status === "active") ? 0 : 2) + (o.is_primary ? 0 : 1); const ownerByUnit = new Map(); - for (const o of data.owners) if (o.unit_id && !ownerByUnit.has(o.unit_id)) ownerByUnit.set(o.unit_id, o); + for (const o of [...data.owners].sort((a, b) => ownerRank(a) - ownerRank(b))) + if (o.unit_id && !ownerByUnit.has(o.unit_id)) ownerByUnit.set(o.unit_id, o); + // Roll every entry up to its UNIT (funds attach to the unit). Entries tied + // only to an owner_id (often a former owner) are mapped to that owner's unit + // so old-owner credits net against the unit instead of showing separately. const bal = new Map(); for (const e of data.entries) { - const key = e.unit_id ? `u:${e.unit_id}` : e.owner_id ? `o:${e.owner_id}` : null; + const unitId = e.unit_id ?? (e.owner_id ? ownerById.get(e.owner_id)?.unit_id ?? null : null); + const key = unitId ? `u:${unitId}` : e.owner_id ? `o:${e.owner_id}` : null; if (!key) continue; bal.set(key, (bal.get(key) ?? 0) + e.debit - e.credit); }