- /expenses/suppliers: terms (cash / 30 / 60 days), PO + petty cash totals per supplier, period filters, add/edit/delete, due dates - POs and slips resolve to a supplier by code then folded name; new PO suppliers start with terms unset, new slip suppliers as cash - Full-user guard on cash-float and job-card write routes Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
39 lines
2.1 KiB
JavaScript
39 lines
2.1 KiB
JavaScript
// Book every existing purchase order and cash-float slip against a supplier (idempotent).
|
|
// New suppliers from POs start with terms unset; ones from slips start as "cash".
|
|
// Usage: node scripts/backfill-suppliers.mjs
|
|
import PocketBase from "pocketbase";
|
|
import { readFileSync } from "node:fs";
|
|
import { supplierKey } from "../lib/supplier.ts";
|
|
for (const l of readFileSync(new URL("../.env.local", import.meta.url), "utf8").split("\n")) {
|
|
const i = l.indexOf("="); if (i > 0 && !l.trim().startsWith("#")) process.env[l.slice(0, i).trim()] = l.slice(i + 1).trim();
|
|
}
|
|
const pb = new PocketBase(process.env.NEXT_PUBLIC_PB_URL);
|
|
pb.autoCancellation(false);
|
|
await pb.collection("_superusers").authWithPassword(process.env.PB_ADMIN, process.env.PB_PASS);
|
|
|
|
const list = await pb.collection("suppliers").getFullList();
|
|
const byKey = new Map(list.map((s) => [s.key, s]));
|
|
const byCode = new Map(list.filter((s) => s.code).map((s) => [s.code.toUpperCase(), s]));
|
|
async function ensure(name, code, terms, source) {
|
|
const key = supplierKey(name);
|
|
if (!key) return null;
|
|
let s = (code && byCode.get(code.toUpperCase())) || byKey.get(key);
|
|
if (!s) {
|
|
s = await pb.collection("suppliers").create({ name: name.trim(), key, code: (code || "").toUpperCase(), terms, source });
|
|
byKey.set(key, s); if (code) byCode.set(code.toUpperCase(), s);
|
|
console.log(` + ${name.trim()} (${source}${terms ? `, ${terms}` : ", terms not set"})`);
|
|
}
|
|
return s;
|
|
}
|
|
let linked = 0;
|
|
for (const p of await pb.collection("purchases").getFullList()) {
|
|
if (p.supplier_ref) continue;
|
|
const s = await ensure(p.supplier || "", p.supplier_code || "", "", "Purchase order");
|
|
if (s) { await pb.collection("purchases").update(p.id, { supplier_ref: s.id }); linked++; }
|
|
}
|
|
for (const e of await pb.collection("cash_float_entries").getFullList({ filter: 'kind = "expense"' })) {
|
|
if (e.supplier_ref || !e.supplier) continue;
|
|
const s = await ensure(e.supplier, "", "cash", "Cash float");
|
|
if (s) { await pb.collection("cash_float_entries").update(e.id, { supplier_ref: s.id }); linked++; }
|
|
}
|
|
console.log(`✓ ${linked} record(s) booked against a supplier; ${byKey.size} supplier(s) in the list`);
|