mirror of
https://github.com/renee-png/acmcc.git
synced 2026-06-21 09:50:01 +00:00
Bills import: A/P cutover guard — only post JEs dated after the GL watermark
Anything on/before buildium_gl.last_synced_date is already in the books as buildium_gl entries; ap_cutover_date freezes that boundary so direct buildium_bill/billpay postings never double-count history. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -2207,11 +2207,21 @@ Deno.serve(async (req) => {
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
const companyByAssoc = new Map<string, { id: string; gl_auto_post: boolean } | null>();
|
const companyByAssoc = new Map<string, { id: string; gl_auto_post: boolean; apCutover: string | null } | null>();
|
||||||
async function getCompanyForAssoc(assocLocalId: string) {
|
async function getCompanyForAssoc(assocLocalId: string) {
|
||||||
if (companyByAssoc.has(assocLocalId)) return companyByAssoc.get(assocLocalId)!;
|
if (companyByAssoc.has(assocLocalId)) return companyByAssoc.get(assocLocalId)!;
|
||||||
const { data } = await acct.from("companies").select("id, gl_auto_post").eq("association_id", assocLocalId).maybeSingle();
|
const { data } = await acct.from("companies").select("id, gl_auto_post, acmacc_sync_config").eq("association_id", assocLocalId).maybeSingle();
|
||||||
const out = data ? { id: data.id as string, gl_auto_post: data.gl_auto_post !== false } : null;
|
// Cutover: anything dated on/before the GL pull's watermark is already
|
||||||
|
// in the books as buildium_gl journal entries — the direct import must
|
||||||
|
// only post A/P dated AFTER it, or we'd double count the history.
|
||||||
|
const cfg = (data?.acmacc_sync_config ?? {}) as Record<string, any>;
|
||||||
|
const out = data
|
||||||
|
? {
|
||||||
|
id: data.id as string,
|
||||||
|
gl_auto_post: data.gl_auto_post !== false,
|
||||||
|
apCutover: (cfg?.buildium_gl?.ap_cutover_date ?? cfg?.buildium_gl?.last_synced_date ?? null) as string | null,
|
||||||
|
}
|
||||||
|
: null;
|
||||||
companyByAssoc.set(assocLocalId, out);
|
companyByAssoc.set(assocLocalId, out);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@@ -2533,7 +2543,7 @@ Deno.serve(async (req) => {
|
|||||||
|| [buildiumVendor?.FirstName, buildiumVendor?.LastName].filter(Boolean).join(" ").trim() || "Vendor";
|
|| [buildiumVendor?.FirstName, buildiumVendor?.LastName].filter(Boolean).join(" ").trim() || "Vendor";
|
||||||
const billDesc = `${vendorDisplayName}${invoiceNumber ? ` Inv # ${invoiceNumber}` : ""}`;
|
const billDesc = `${vendorDisplayName}${invoiceNumber ? ` Inv # ${invoiceNumber}` : ""}`;
|
||||||
|
|
||||||
if (company && !company.gl_auto_post && billLineItems.length > 0) {
|
if (company && !company.gl_auto_post && billLineItems.length > 0 && (!company.apCutover || billDate > company.apCutover)) {
|
||||||
const ap = await getApAccount(company.id);
|
const ap = await getApAccount(company.id);
|
||||||
if (ap) {
|
if (ap) {
|
||||||
const ok = await postDirectJe(
|
const ok = await postDirectJe(
|
||||||
@@ -2562,6 +2572,8 @@ Deno.serve(async (req) => {
|
|||||||
const pAmount = Array.isArray(p.Lines) ? p.Lines.reduce((s: number, l: any) => s + Number(l?.Amount || 0), 0) : 0;
|
const pAmount = Array.isArray(p.Lines) ? p.Lines.reduce((s: number, l: any) => s + Number(l?.Amount || 0), 0) : 0;
|
||||||
if (!pAmount) continue;
|
if (!pAmount) continue;
|
||||||
const pDate = String(p.EntryDate || billDate).slice(0, 10);
|
const pDate = String(p.EntryDate || billDate).slice(0, 10);
|
||||||
|
// Payments on/before the GL watermark already came in via buildium_gl
|
||||||
|
if (company.apCutover && pDate <= company.apCutover) continue;
|
||||||
const checkNo = p.CheckNumber ? String(p.CheckNumber) : null;
|
const checkNo = p.CheckNumber ? String(p.CheckNumber) : null;
|
||||||
const acctBill = await getAcctBill(finalBillId, company.id);
|
const acctBill = await getAcctBill(finalBillId, company.id);
|
||||||
await postPaymentSide(assocLocalId, company, pid, pDate, billDesc, checkNo, p.BankAccountId ?? null, pAmount, acctBill?.id ?? null, acctBill?.vendor_id ?? null);
|
await postPaymentSide(assocLocalId, company, pid, pDate, billDesc, checkNo, p.BankAccountId ?? null, pAmount, acctBill?.id ?? null, acctBill?.vendor_id ?? null);
|
||||||
@@ -2689,7 +2701,7 @@ Deno.serve(async (req) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const company = await getCompanyForAssoc(assocLocalId);
|
const company = await getCompanyForAssoc(assocLocalId);
|
||||||
if (company && !company.gl_auto_post && pubBillId) {
|
if (company && !company.gl_auto_post && pubBillId && (!company.apCutover || ckDate > company.apCutover)) {
|
||||||
const ap = await getApAccount(company.id);
|
const ap = await getApAccount(company.id);
|
||||||
if (ap) {
|
if (ap) {
|
||||||
const ok = await postDirectJe(company.id, "buildium_bill", externalKey, ckDate, desc, checkNo, [
|
const ok = await postDirectJe(company.id, "buildium_bill", externalKey, ckDate, desc, checkNo, [
|
||||||
@@ -2729,9 +2741,19 @@ Deno.serve(async (req) => {
|
|||||||
for (const companyId of directPostedCompanies) {
|
for (const companyId of directPostedCompanies) {
|
||||||
const { data: comp } = await acct.from("companies").select("acmacc_sync_config").eq("id", companyId).maybeSingle();
|
const { data: comp } = await acct.from("companies").select("acmacc_sync_config").eq("id", companyId).maybeSingle();
|
||||||
const cfg = (comp?.acmacc_sync_config ?? {}) as Record<string, any>;
|
const cfg = (comp?.acmacc_sync_config ?? {}) as Record<string, any>;
|
||||||
if (cfg?.buildium_gl?.exclude_ap) continue;
|
if (cfg?.buildium_gl?.exclude_ap && cfg?.buildium_gl?.ap_cutover_date) continue;
|
||||||
await acct.from("companies").update({
|
await acct.from("companies").update({
|
||||||
acmacc_sync_config: { ...cfg, buildium_gl: { ...(cfg.buildium_gl ?? {}), exclude_ap: true } },
|
acmacc_sync_config: {
|
||||||
|
...cfg,
|
||||||
|
buildium_gl: {
|
||||||
|
...(cfg.buildium_gl ?? {}),
|
||||||
|
exclude_ap: true,
|
||||||
|
// Freeze the cutover so the boundary never moves as the GL
|
||||||
|
// watermark advances: A/P <= cutover lives in buildium_gl
|
||||||
|
// entries, A/P > cutover comes from the direct import.
|
||||||
|
ap_cutover_date: cfg?.buildium_gl?.ap_cutover_date ?? cfg?.buildium_gl?.last_synced_date ?? "1900-01-01",
|
||||||
|
},
|
||||||
|
},
|
||||||
}).eq("id", companyId);
|
}).eq("id", companyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user