// lib/vat-cadence.server.ts // SERVER-ONLY PocketBase lookup for company VAT cadences. // // Split out from `vat-cadence.ts` because that module must stay client-safe // (the Returns workbench is a client component and needs the period maths), // while `lib/pb.ts` carries `import "server-only"`. import { fetchCollection, PBRecord } from "./pb"; import { CompanyCadence, toCompanyCadence } from "./vat-cadence"; /** * Load cadence for the named companies (or every VAT client when * `allActive`), in ONE PB round-trip. * * Returns `null` when PB is unavailable — callers treat that as * "cadence unknown" and fall back to the old unfiltered behaviour rather * than failing the run outright. Failing soft here matters: a PB outage * must not make it impossible to capture a return. */ export async function loadCompanyCadences( names: string[] | null, allActive: boolean ): Promise<{ byName: Map; all: CompanyCadence[] } | null> { try { const wanted = new Set((names ?? []).map((n) => n.trim().toUpperCase()).filter(Boolean)); let data: { items: PBRecord[] }; if (allActive) { // VAT201 applies to VAT-registered entities — mirror the .py's gate. data = await fetchCollection("ysterbaard_companies", { perPage: 500, filter: "is_client=true", fields: "id,enterprise_name,sars_vat_no,sars_vat_returns_period", }); } else { if (wanted.size === 0) return { byName: new Map(), all: [] }; const filter = [...wanted] .map((n) => `enterprise_name = "${n.replace(/"/g, '\\"')}"`) .join(" || "); data = await fetchCollection("ysterbaard_companies", { perPage: 500, filter, fields: "id,enterprise_name,sars_vat_no,sars_vat_returns_period", }); } const all: CompanyCadence[] = data.items .map((r) => toCompanyCadence({ id: (r.id as string) || "", enterprise_name: (r.enterprise_name as string) || "", sars_vat_no: (r.sars_vat_no as string) ?? "", sars_vat_returns_period: (r.sars_vat_returns_period as number | null) ?? null, }) ) // An explicit selection keeps clients with no VAT number so the caller // can report WHY each one was skipped ("no SARS VAT number") instead of // implying the record is missing. For --all-active the selection means // "every VAT client", so that filter does apply. .filter((c) => c.name && (allActive ? c.hasVatNo : true)); const byName = new Map(); for (const c of all) byName.set(c.name.trim().toUpperCase(), c); return { byName, all }; } catch (err) { console.error("[vat-cadence] failed to load company cadences:", err); return null; } }