mirror of
https://github.com/renee-png/acmcc.git
synced 2026-06-21 09:50:01 +00:00
Accounting: partymap mode + register payee backfill
Adds "partymap" mode to buildium-payee-backfill: resolves each Buildium GL transaction to a local vendor (by name) / customer (by unit_number) and stages it in accounting.buildium_party_map. The materialized bank register (accounting.transactions) is then backfilled in SQL by bridging each register row to its journal-entry bank line (bijective row-number pairing within date/amount/side groups, so same-amount/same-day payments each get a distinct owner) and pulling the resolved vendor/customer + name from staging. Applied to all five Buildium-imported associations (Village Woods, Bent Oak, Village Grove, Bridgewater, Casuarina). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -298,6 +298,51 @@ Deno.serve(async (req) => {
|
|||||||
if (name) { payeeById.set(id, name); byType[type].named++; }
|
if (name) { payeeById.set(id, name); byType[type].named++; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// partymap mode: resolve each Buildium tx to a LOCAL vendor/customer id and
|
||||||
|
// stage it (accounting.buildium_party_map) so the materialized bank register
|
||||||
|
// (accounting.transactions) can be backfilled in SQL by bridging tx→JE.
|
||||||
|
// vendor : Payee.Type=Vendor → match Payee.Name to accounting.vendors.name
|
||||||
|
// customer : tx.UnitNumber → match to accounting.customers.unit_number
|
||||||
|
if (mode === "partymap") {
|
||||||
|
const vendorByName = new Map<string, string>();
|
||||||
|
for (const v of (await supabase.schema("accounting").from("vendors").select("id,name").eq("company_id", companyId)).data ?? [])
|
||||||
|
if (v.name) vendorByName.set(norm(v.name), v.id);
|
||||||
|
const customerByUnitNo = new Map<string, string>();
|
||||||
|
for (const c of (await supabase.schema("accounting").from("customers").select("id,unit_number").eq("company_id", companyId)).data ?? [])
|
||||||
|
if (c.unit_number) customerByUnitNo.set(norm(c.unit_number), c.id);
|
||||||
|
|
||||||
|
const rows: any[] = [];
|
||||||
|
let vendorHits = 0, customerHits = 0;
|
||||||
|
for (const tx of txns) {
|
||||||
|
const id = String(tx?.Id ?? "");
|
||||||
|
if (!id) continue;
|
||||||
|
const name = payeeById.get(id) ?? null;
|
||||||
|
const payeeType = String(tx?.PaymentDetail?.Payee?.Type ?? "");
|
||||||
|
let vendor_id: string | null = null;
|
||||||
|
let customer_id: string | null = null;
|
||||||
|
if (payeeType === "Vendor" && name) vendor_id = vendorByName.get(norm(name)) ?? null;
|
||||||
|
const unitNo = tx?.UnitNumber;
|
||||||
|
if (!vendor_id && typeof unitNo === "string" && unitNo.trim()) customer_id = customerByUnitNo.get(norm(unitNo)) ?? null;
|
||||||
|
// owner payment with no UnitNumber: try the payee name against customers
|
||||||
|
if (!vendor_id && !customer_id && name && payeeType && payeeType !== "Vendor") {
|
||||||
|
// fall through — name match handled in SQL if needed; leave null here
|
||||||
|
}
|
||||||
|
if (vendor_id) vendorHits++;
|
||||||
|
if (customer_id) customerHits++;
|
||||||
|
if (name || vendor_id || customer_id)
|
||||||
|
rows.push({ company_id: companyId, external_id: id, party_name: name, vendor_id, customer_id, party_type: payeeType || null });
|
||||||
|
}
|
||||||
|
// Upsert in batches.
|
||||||
|
let staged = 0;
|
||||||
|
for (let i = 0; i < rows.length; i += 500) {
|
||||||
|
const batch = rows.slice(i, i + 500);
|
||||||
|
const { error } = await supabase.schema("accounting").from("buildium_party_map").upsert(batch, { onConflict: "company_id,external_id" });
|
||||||
|
if (error) throw error;
|
||||||
|
staged += batch.length;
|
||||||
|
}
|
||||||
|
return json({ mode, company: company.name, window: [dateFrom, dateTo], txns: txns.length, staged, vendorHits, customerHits });
|
||||||
|
}
|
||||||
|
|
||||||
// Load this company's imported entries and compute the new description.
|
// Load this company's imported entries and compute the new description.
|
||||||
const entries: { id: string; external_id: string; description: string }[] = [];
|
const entries: { id: string; external_id: string; description: string }[] = [];
|
||||||
for (let offset = 0; ; offset += 1000) {
|
for (let offset = 0; ; offset += 1000) {
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
-- Staging table for the Buildium payee/payor register backfill.
|
||||||
|
-- Maps a Buildium GL transaction id to the resolved local vendor/customer and
|
||||||
|
-- the party name, so the materialized bank register (accounting.transactions)
|
||||||
|
-- of imported-GL companies can be backfilled by bridging transaction → journal
|
||||||
|
-- entry (by bank line) → this map. Populated by the buildium-payee-backfill
|
||||||
|
-- edge function ("partymap" mode).
|
||||||
|
create table if not exists accounting.buildium_party_map (
|
||||||
|
company_id uuid not null,
|
||||||
|
external_id text not null,
|
||||||
|
party_name text,
|
||||||
|
vendor_id uuid,
|
||||||
|
customer_id uuid,
|
||||||
|
party_type text,
|
||||||
|
updated_at timestamptz not null default now(),
|
||||||
|
primary key (company_id, external_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
comment on table accounting.buildium_party_map is
|
||||||
|
'Staging: Buildium GL transaction id -> resolved local vendor/customer + name, used to backfill the materialized bank register (accounting.transactions) for imported companies.';
|
||||||
Reference in New Issue
Block a user