import policy from "./invoice-party-policy.json"; import type { Invoice } from "./data"; // Which half of the register an invoice belongs to. Both pages are the SAME PocketBase // collection split by this module — see ./invoice-party-policy.json for why it is one // collection and not two. // // Deliberately pure and import-safe from client components: no server-only, no PB. The // pages filter on the server before handing plain data to the client list, and this // module is the only thing that decides which side a row lands on. export type PartyScope = "internal" | "external"; const norm = (v: unknown) => String(v ?? "").trim().toLowerCase(); // The group entities that count as internal. Matched on name OR debtor number, so an // invoice that prints "Mega Infrastructure" and one that prints only "09MIS001" both // land on the internal page. const INTERNAL = policy.internalDebtors.map((d) => ({ name: norm(d.name), debtorNo: norm(d.debtorNo), })); type PartyBearing = Pick; // True when the debtor is a known group entity. export function isInternalParty(inv: PartyBearing): boolean { const name = norm(inv.debtor); const no = norm(inv.debtor_no); if (!name && !no) return false; return INTERNAL.some((d) => (name && name === d.name) || (no && no === d.debtorNo)); } // An invoice naming no debtor cannot be placed by evidence, so it is reported as // unclassified rather than assumed internal. It still appears on the external page — // nothing may be invisible on both screens. export function isClassified(inv: PartyBearing): boolean { return Boolean(norm(inv.debtor) || norm(inv.debtor_no)); } export function partyOf(inv: PartyBearing): PartyScope { return isInternalParty(inv) ? "internal" : "external"; } export function filterByParty(invoices: T[], scope: PartyScope): T[] { return invoices.filter((i) => partyOf(i) === scope); } // Shown on the external page when a row landed there only because it named no debtor. // Keeps an unclassifiable invoice visible as a question rather than a silent filing. export function unclassifiedCount(invoices: Invoice[]): number { return invoices.filter((i) => partyOf(i) === "external" && !isClassified(i)).length; }