Workflow-App/Workflow/lib/sars-runs.ts
sjcoetzeesj-coder 11d0178ab1 feat: commit Workflow app source; move CIPC credentials to env
Adds the full Next.js app (app/, components/, lib/, scripts/, assets/,
docs/, Dockerfile, compose, configs) to version control.

Security:
- CIPC BizPortal customer-code logins (Login 1 + Login 3) now read
  CIPC_LOGIN1_CODE / CIPC_LOGIN1_PASSWORD / CIPC_LOGIN3_CODE /
  CIPC_LOGIN3_PASSWORD from .env.local instead of source.
- BizPortal personal login in apply-bizportal route reads
  BIZPORTAL_ID_NO / BIZPORTAL_PASSWORD.
- Added .env.example as the committed template.

.gitignore excludes .env*, node_modules, .next, logs, sqlite, Playwright
storage_state.json (live CIPC cookies), scratch dirs, client PDFs and
debug screenshots.
2026-10-18 15:21:45 +02:00

77 lines
2.5 KiB
TypeScript

// lib/sars-runs.ts
// Tiny wrapper around the sars_runs PocketBase collection.
//
// One record per SARS capture run, written at run start (status="running")
// and patched at run end (status="completed"|"failed" + counts + result_path).
// Per-row data writes to the per-return-type collection (e.g.
// ysterbaard_SARS_EMP201_PAYE) are still a separate future sprint.
//
// The collection schema is documented in:
// - the .env.local header comment
// - the user memory entry "PocketBase auth gotcha" (refreshed 2026-09-10)
// - the request to the user when the sars_runs collection was first created
import "server-only";
import { createRecord, updateRecord, type PBRecord } from "./pb";
const COLLECTION = "sars_runs";
interface RunStartInput {
run_id: string;
started_at: string; // ISO timestamp
return_type: string;
period_start: string;
period_end: string;
periods_requested: string[];
companies: string[] | null; // null when allActive
companies_count: number;
created_by?: string;
}
interface RunEndInput {
finished_at: string;
status: "completed" | "failed";
result_path: string | null;
ok_count: number;
error_count: number;
error_message?: string | null;
}
/**
* Create a sars_runs record at the start of a run. Returns the PB
* record id so we can patch it later. Throws on failure — the caller
* is expected to handle the error and either abort the run or
* continue without PB audit.
*/
export async function createRunRecord(input: RunStartInput): Promise<string> {
const record = await createRecord<PBRecord>(COLLECTION, {
run_id: input.run_id,
started_at: input.started_at,
return_type: input.return_type,
period_start: input.period_start,
period_end: input.period_end,
periods_requested: input.periods_requested,
companies: input.companies,
companies_count: input.companies_count,
status: "running",
created_by: input.created_by ?? "sj",
});
return record.id;
}
/**
* Patch a sars_runs record at the end of a run. Best-effort: the
* caller should log but not throw on failure (the .py already
* produced the result file, and a missing audit row is recoverable
* from the result_path on disk).
*/
export async function finishRunRecord(recordId: string, input: RunEndInput): Promise<void> {
await updateRecord<PBRecord>(COLLECTION, recordId, {
finished_at: input.finished_at,
status: input.status,
result_path: input.result_path,
ok_count: input.ok_count,
error_count: input.error_count,
error_message: input.error_message ?? null,
});
}