Cash Disbursement: resolve vendor/bill for imported (Buildium GL) payments

The report only enriched app-posted (acmacc_txn) entries with vendor/bill, so
import-mode payments (buildium_gl) always showed 'No vendor on record'. It now
also pulls the vendor/bill from the register transaction linked to each GL bank
line (journal_entry_line_id), so matched imported disbursements show the vendor
(Robertson's, City of Titusville, Avria, FPL...) and bill instead of A/P.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-13 22:27:46 -04:00
parent ac454e8f5e
commit fa9671b4f5
@@ -72,8 +72,9 @@ export function CashDisbursementReport({ companyId, companyName, logoUrl, from:
]); ]);
const accounts = (accountsRes.data ?? []) as GLAccount[]; const accounts = (accountsRes.data ?? []) as GLAccount[];
const lines = (linesRes.data ?? []) as any[]; const lines = (linesRes.data ?? []) as any[];
const bankIds = new Set(accounts.filter((a) => a.is_bank).map((a) => a.id));
// Enrich register-posted entries with check # / vendor / bill from banking // Enrich app-posted (acmacc_txn) entries with check #/vendor/bill from banking.
const txnIds = [...new Set(lines const txnIds = [...new Set(lines
.filter((l) => l.journal_entries?.external_source === "acmacc_txn" && l.journal_entries?.external_id) .filter((l) => l.journal_entries?.external_source === "acmacc_txn" && l.journal_entries?.external_id)
.map((l) => String(l.journal_entries.external_id)))]; .map((l) => String(l.journal_entries.external_id)))];
@@ -85,7 +86,20 @@ export function CashDisbursementReport({ companyId, companyName, logoUrl, from:
.in("id", txnIds); .in("id", txnIds);
txns = t ?? []; txns = t ?? [];
} }
return { accounts, lines, txns };
// Buildium-GL (and any) payments carry their vendor/bill on the register
// transaction linked to the GL bank line via journal_entry_line_id. Pull those
// so imported disbursements show the matched vendor/bill, not "No vendor".
const bankLineIds = lines.filter((l) => Number(l.credit || 0) > 0 && bankIds.has(l.account_id)).map((l) => String(l.id));
const linkedTxns: any[] = [];
for (let i = 0; i < bankLineIds.length; i += 200) {
const { data: tl } = await accounting
.from("transactions")
.select("journal_entry_line_id,reference,description,vendor_id,bill_id,vendors(name),bills(number,issue_date,vendors(name))")
.in("journal_entry_line_id", bankLineIds.slice(i, i + 200));
if (tl) linkedTxns.push(...tl);
}
return { accounts, lines, txns, linkedTxns };
}, },
}); });
@@ -95,6 +109,8 @@ export function CashDisbursementReport({ companyId, companyName, logoUrl, from:
for (const a of data.accounts) acctById.set(a.id, a); for (const a of data.accounts) acctById.set(a.id, a);
const txnById = new Map<string, any>(); const txnById = new Map<string, any>();
for (const t of data.txns) txnById.set(String(t.id), t); for (const t of data.txns) txnById.set(String(t.id), t);
const txnByLineId = new Map<string, any>();
for (const t of (data.linkedTxns ?? [])) if (t.journal_entry_line_id) txnByLineId.set(String(t.journal_entry_line_id), t);
// Group lines per journal entry // Group lines per journal entry
const byJe = new Map<string, { je: any; lines: any[] }>(); const byJe = new Map<string, { je: any; lines: any[] }>();
@@ -123,7 +139,9 @@ export function CashDisbursementReport({ companyId, companyName, logoUrl, from:
const mainBank = bankCredits.reduce((a, b) => (Number(b.credit) > Number(a.credit) ? b : a)); const mainBank = bankCredits.reduce((a, b) => (Number(b.credit) > Number(a.credit) ? b : a));
const bankLabel = acctLabel(acctById.get(mainBank.account_id)); const bankLabel = acctLabel(acctById.get(mainBank.account_id));
const txn = je.external_source === "acmacc_txn" && je.external_id ? txnById.get(String(je.external_id)) : null; let txn = je.external_source === "acmacc_txn" && je.external_id ? txnById.get(String(je.external_id)) : null;
// For imported (Buildium GL) payments, resolve the register txn linked to a bank line.
if (!txn) { for (const bc of bankCredits) { const lt = txnByLineId.get(String(bc.id)); if (lt) { txn = lt; break; } } }
const bill = txn?.bills ?? null; const bill = txn?.bills ?? null;
// Only attribute a vendor when it's reliably linked (payment→vendor or // Only attribute a vendor when it's reliably linked (payment→vendor or
// payment→bill→vendor). GL-pull (Buildium) disbursements carry no vendor, // payment→bill→vendor). GL-pull (Buildium) disbursements carry no vendor,