mirror of
https://github.com/renee-png/acmcc.git
synced 2026-06-21 09:50:01 +00:00
Balance Sheet: show account numbers + parent categories (Buildium style)
B/S line items now render as '3011 SIRS Reserves - 3066 Painting/ Waterproofing' — leaf code+name prefixed by parent code+name when the account has a parent, sorted so siblings group under their parent. Adds parent_account_id to the reports accounts fetch. Codes always show (baked into the label). Budget vs Actuals already shows codes + parent hierarchy. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -131,7 +131,7 @@ export async function fetchReportData(cid: string, from: string, to: string) {
|
||||
const [inv, bills, accs, exp, custs, vends, ob, ytdInv, ytdExp, ytdBills, allBills, glRes, glCumRes, allInvRes, companyRes, periodBillItemsRes] = await Promise.all([
|
||||
accounting.from("invoices").select("number,total,paid_amount,status,issue_date,customers(name)").eq("company_id", cid).gte("issue_date", from).lte("issue_date", to),
|
||||
accounting.from("bills").select("number,total,paid_amount,status,issue_date,due_date,vendors(name)").eq("company_id", cid).gte("issue_date", from).lte("issue_date", to),
|
||||
accounting.from("accounts").select("id,name,code,type,subtype,balance,is_bank").eq("company_id", cid).eq("is_archived", false),
|
||||
accounting.from("accounts").select("id,name,code,type,subtype,balance,is_bank,parent_account_id").eq("company_id", cid).eq("is_archived", false),
|
||||
accounting.from("expenses").select("date,category,amount,vendor_name,vendors(name)").eq("company_id", cid).gte("date", from).lte("date", to),
|
||||
accounting.from("customers").select("id,name,balance,email,phone,property_address,lot_number").eq("company_id", cid).order("name"),
|
||||
accounting.from("vendors").select("id,name").eq("company_id", cid),
|
||||
@@ -1667,12 +1667,27 @@ function buildBalanceSheet(d: any, p?: any, useCompare?: boolean): StructuredRep
|
||||
const sumBal = (rows: any[]) => rows.reduce((s, a) => s + balOf(a), 0);
|
||||
const sumBalP = (rows: any[]) => (prev ? rows.reduce((s, a) => s + (prev.glByAcct.get(a.id) ?? 0), 0) : undefined);
|
||||
|
||||
// Account-number + parent-category labels (Buildium style:
|
||||
// "3011 SIRS Reserves - 3066 Painting/Waterproofing"). Codes are baked into the
|
||||
// label so they always show, and rows are sorted so siblings group by parent.
|
||||
const acctMeta = new Map<string, { code: any; name: string }>(allAccounts.map((a: any) => [a.id, { code: a.code ?? null, name: a.name }]));
|
||||
const codeName = (code: any, name: any) => `${code != null && String(code).trim() !== "" ? String(code) + " " : ""}${name ?? ""}`.trim();
|
||||
const bsLabel = (a: any) => {
|
||||
const p = a.parent_account_id ? acctMeta.get(a.parent_account_id) : null;
|
||||
return p ? `${codeName(p.code, p.name)} - ${codeName(a.code, a.name)}` : codeName(a.code, a.name);
|
||||
};
|
||||
const bsKey = (a: any) => {
|
||||
const p = a.parent_account_id ? acctMeta.get(a.parent_account_id) : null;
|
||||
return `${p ? String(p.code ?? "") : String(a.code ?? "")}|${String(a.code ?? "")}`;
|
||||
};
|
||||
const bsSort = (arr: any[]) => [...arr].sort((x, y) => bsKey(x).localeCompare(bsKey(y), undefined, { numeric: true }));
|
||||
|
||||
const rows: StructuredRow[] = [];
|
||||
|
||||
// Assets
|
||||
rows.push({ kind: "section", label: "Assets" });
|
||||
const assets = byType("asset");
|
||||
for (const a of assets) rows.push({ kind: "sub", label: a.name, code: a.code ?? undefined, amount: balOf(a), compare: cmp(balOfP(a)), accountId: a.id });
|
||||
for (const a of bsSort(assets)) rows.push({ kind: "sub", label: bsLabel(a), amount: balOf(a), compare: cmp(balOfP(a)), accountId: a.id });
|
||||
const totalA = sumBal(assets);
|
||||
rows.push({ kind: "grand", label: "TOTAL ASSETS", amount: totalA, compare: cmp(sumBalP(assets)) });
|
||||
rows.push({ kind: "spacer", label: "" });
|
||||
@@ -1680,7 +1695,7 @@ function buildBalanceSheet(d: any, p?: any, useCompare?: boolean): StructuredRep
|
||||
// Liabilities
|
||||
rows.push({ kind: "section", label: "Liabilities" });
|
||||
const liabs = byType("liability");
|
||||
for (const a of liabs) rows.push({ kind: "sub", label: a.name, code: a.code ?? undefined, amount: balOf(a), compare: cmp(balOfP(a)), accountId: a.id });
|
||||
for (const a of bsSort(liabs)) rows.push({ kind: "sub", label: bsLabel(a), amount: balOf(a), compare: cmp(balOfP(a)), accountId: a.id });
|
||||
const totalL = sumBal(liabs);
|
||||
rows.push({ kind: "total", label: "Total Liabilities", amount: totalL, compare: cmp(sumBalP(liabs)) });
|
||||
rows.push({ kind: "spacer", label: "" });
|
||||
@@ -1703,7 +1718,7 @@ function buildBalanceSheet(d: any, p?: any, useCompare?: boolean): StructuredRep
|
||||
const cyeAccts = equityAccs.filter((a) => /^\s*current\s*year\s*(earnings|income)(\s*\(.*\))?\s*$/i.test(String(a.name || "")) || /^\s*net\s*income\s*$/i.test(String(a.name || "")));
|
||||
const foldedIds = new Set([...reAccts, ...cyeAccts].map((a) => a.id));
|
||||
const otherEquity = equityAccs.filter((a) => !foldedIds.has(a.id));
|
||||
for (const a of otherEquity) rows.push({ kind: "sub", label: a.name, code: a.code ?? undefined, amount: balOf(a), compare: cmp(balOfP(a)), accountId: a.id });
|
||||
for (const a of bsSort(otherEquity)) rows.push({ kind: "sub", label: bsLabel(a), amount: balOf(a), compare: cmp(balOfP(a)), accountId: a.id });
|
||||
const rePosted = reAccts.reduce((s, a) => s + balOf(a), 0);
|
||||
const rePostedP = prev ? reAccts.reduce((s, a) => s + (prev.glByAcct.get(a.id) ?? 0), 0) : undefined;
|
||||
const cyePosted = cyeAccts.reduce((s, a) => s + balOf(a), 0);
|
||||
|
||||
Reference in New Issue
Block a user