// lib/sars-runners.ts // Registry of SARS return types the workbench knows how to run. // // One entry per return type. Adding a new return type = one entry here. // The form, the API, the results table, and the .py lookup all read // from this — the page and components stay generic. // // Per return type we record: // - The Python script that knows how to capture it (in scripts/). // - The period format the user types (e.g. "YYYYMM" for monthly). // - The period granularity, which drives the period-UX component. // - The columns to render in the results table. // - The PB collection that future per-row writes will target. // // EMP201 + VAT201 are both enabled today. The other 3 are registered // disabled so the dropdown can show them as "coming soon". The VAT201 // capture and push scripts are in scripts/ (mirrors of the EMP201 // pair) and target PB collection ysterbaard_SARS_VAT_VAT201 (note the // double-VAT in the collection name — that's the actual schema name). export type PeriodGranularity = "monthly" | "annual" | "bi-monthly"; export interface ResultColumn { /** JSON key in the .py's per-row payload. */ key: string; /** Column header. */ label: string; /** Optional Tailwind class for the cell (e.g. text-right for numbers). */ cellClassName?: string; } export interface SarsRunner { /** Machine code, matches the SARS form code (also the .py CLI value). */ code: string; /** Human-readable label shown in the dropdown. */ label: string; /** Script filename inside the scripts/ directory. */ script: string; /** Free-text period format the user types. Shown as a hint. */ periodFormat: string; /** Drives the period-UX component. */ periodGranularity: PeriodGranularity; /** Columns to render in the results table. */ resultSchema: ResultColumn[]; /** PB collection for future per-row writes (null until wired up). */ pbCollection: string | null; /** Push-to-PB script filename in scripts/. null until a push tool exists. */ pushScript: string | null; /** Whether the runner is currently wired up and runnable. */ enabled: boolean; } export const SARS_RUNNERS: SarsRunner[] = [ { code: "EMP201", label: "EMP201 (PAYE)", script: "SARS Retun EMP201 single or all pty.py", periodFormat: "YYYYMM", periodGranularity: "monthly", resultSchema: [ { key: "period", label: "Period" }, { key: "date_submitted", label: "Date Submitted", cellClassName: "font-mono text-muted" }, { key: "paye_payable", label: "PAYE", cellClassName: "text-right tabular-nums" }, { key: "sdl_payable", label: "SDL", cellClassName: "text-right tabular-nums" }, { key: "uif_payable", label: "UIF", cellClassName: "text-right tabular-nums" }, { key: "total_payable", label: "Total", cellClassName: "text-right tabular-nums font-semibold" }, { key: "payment_ref_no", label: "Payment Ref" }, ], pbCollection: "ysterbaard_SARS_EMP201_PAYE", pushScript: "SARS retun EMP201 push to PB.py", enabled: true, }, // ── Coming soon ─────────────────────────────────────────────── { code: "VAT201", label: "VAT201", script: "SARS Retun VAT201 single or all pty.py", periodFormat: "YYYYMM", // VAT201 is NOT monthly for every company. Each client's SARS // "VAT Return Every" setting (`sars_vat_returns_period`) decides which // months exist — e.g. an uneven-months client has no Feb/Apr/Jun // returns at all, they are non-existent rather than unfiled. // // `monthly` here describes the period *entry format* (the user still // types YYYYMM), not the filing frequency. The per-company cadence is // resolved from PocketBase in the run route and passed to the .py as // `--cadence`; the UI narrows the previewed months with the same table // in lib/vat-cadence.ts. periodGranularity: "monthly", resultSchema: [ { key: "period", label: "Period" }, { key: "date_filed", label: "Date Filed", cellClassName: "font-mono text-muted" }, { key: "total_payable", label: "Total (38)", cellClassName: "text-right tabular-nums font-semibold" }, { key: "standard_rate_1", label: "Std rate (1)", cellClassName: "text-right tabular-nums" }, { key: "zero_rate_2", label: "Zero rate (2)", cellClassName: "text-right tabular-nums" }, { key: "exempt_and_non_supplies_3", label: "Exempt & non (3)", cellClassName: "text-right tabular-nums" }, { key: "capital_goods_and_services_supplied_to_you_14", label: "Capital goods (14)", cellClassName: "text-right tabular-nums" }, { key: "other_goods_and_services_supplied_to_you_15", label: "Other inputs (15)", cellClassName: "text-right tabular-nums" }, { key: "payment_reference", label: "Pay Ref" }, ], pbCollection: "ysterbaard_SARS_VAT_VAT201", pushScript: "SARS retun VAT201 push to PB.py", enabled: true, }, { code: "IRP6", label: "Provisional Tax (IRP6)", script: "", periodFormat: "YYYYMM", periodGranularity: "bi-monthly", resultSchema: [], pbCollection: null, pushScript: null, enabled: false, }, { code: "ITR14", label: "Income Tax (ITR14/ITR12T/IT12EI)", script: "", periodFormat: "YYYY", periodGranularity: "annual", resultSchema: [], pbCollection: null, pushScript: null, enabled: false, }, { code: "STC", label: "STC", script: "", periodFormat: "YYYY-MM-DD", periodGranularity: "annual", resultSchema: [], pbCollection: null, pushScript: null, enabled: false, }, ]; export function getRunner(code: string): SarsRunner | undefined { return SARS_RUNNERS.find((r) => r.code === code); } export function listEnabledRunners(): SarsRunner[] { return SARS_RUNNERS.filter((r) => r.enabled); }