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.
121 lines
3.4 KiB
TypeScript
121 lines
3.4 KiB
TypeScript
// app/api/compliance/route.ts
|
|
// GET /api/compliance?groupId=<group_id>
|
|
// Fetches client companies + annual returns + IRP6/IncomeTax + PAYE EMP201 data
|
|
|
|
import { NextRequest, NextResponse } from "next/server";
|
|
import { fetchCollection, type PBRecord } from "@/lib/pb";
|
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
type ComplianceCompany = PBRecord & {
|
|
enterprise_name: string;
|
|
enterprise_no: string;
|
|
registration_date: string;
|
|
financial_year_end_month: number;
|
|
groups: string[];
|
|
sars_paye_no: string | null;
|
|
};
|
|
|
|
type AnnualReturn = PBRecord & {
|
|
company: string;
|
|
ar_year: number;
|
|
ar_month: string;
|
|
is_filed: boolean;
|
|
date_filed: string;
|
|
amount_paid: number;
|
|
};
|
|
|
|
type IRP6Record = PBRecord & {
|
|
company: string;
|
|
return_type: string;
|
|
period: string;
|
|
date_filed: string;
|
|
amount_paid: number;
|
|
};
|
|
|
|
type PayeRecord = PBRecord & {
|
|
company: string;
|
|
period: string;
|
|
Return_Filed: boolean;
|
|
total_payable: number;
|
|
paye_amount: number;
|
|
sdl_amount: number;
|
|
uif_amount: number;
|
|
date_submitted: string;
|
|
date_paid: string;
|
|
due_date: string;
|
|
payment_reference: string;
|
|
status: string;
|
|
last_updated: string;
|
|
};
|
|
|
|
type VatRecord = PBRecord & {
|
|
company: string;
|
|
period: string;
|
|
Return_Filed: boolean;
|
|
total_payable: number;
|
|
date_submitted: string;
|
|
date_paid: string;
|
|
due_date: string;
|
|
payment_reference: string;
|
|
status: string;
|
|
last_updated: string;
|
|
};
|
|
|
|
export async function GET(req: NextRequest) {
|
|
const groupId = new URL(req.url).searchParams.get("groupId") ?? "";
|
|
|
|
try {
|
|
const filterParts: string[] = ["is_client = true"];
|
|
if (groupId) filterParts.push(`groups ?~ '${groupId}'`);
|
|
|
|
const companies = await fetchCollection<ComplianceCompany>("ysterbaard_companies", {
|
|
filter: filterParts.join(" && "),
|
|
sort: "enterprise_name",
|
|
perPage: 500,
|
|
fields:
|
|
"id,enterprise_name,enterprise_no,registration_date,financial_year_end_month,groups,sars_paye_no,sars_vat_no,sars_vat_returns_period",
|
|
});
|
|
|
|
const companyIds = companies.items.map((c) => c.id);
|
|
if (companyIds.length === 0) {
|
|
return NextResponse.json({ companies: [], annualReturns: [], irp6Records: [], payeRecords: [], vatRecords: [] });
|
|
}
|
|
|
|
const companyIdFilter = companyIds.map((id) => `company = '${id}'`).join(" || ");
|
|
|
|
const [annualReturns, irp6Records, payeRecords, vatRecords] = await Promise.all([
|
|
fetchCollection<AnnualReturn>("ysterbaard_annual_returns", {
|
|
filter: `(${companyIdFilter})`,
|
|
perPage: 1000,
|
|
sort: "-ar_year,-ar_month",
|
|
}),
|
|
fetchCollection<IRP6Record>("ysterbaard_sars_irp6_income_tax", {
|
|
filter: `(${companyIdFilter})`,
|
|
perPage: 2000,
|
|
sort: "-period",
|
|
}),
|
|
fetchCollection<PayeRecord>("ysterbaard_SARS_EMP201_PAYE", {
|
|
filter: `(${companyIdFilter})`,
|
|
perPage: 2000,
|
|
sort: "-period",
|
|
}),
|
|
fetchCollection<VatRecord>("ysterbaard_SARS_VAT_VAT201", {
|
|
filter: `(${companyIdFilter})`,
|
|
perPage: 2000,
|
|
sort: "-period",
|
|
}),
|
|
]);
|
|
|
|
return NextResponse.json({
|
|
companies: companies.items,
|
|
annualReturns: annualReturns.items,
|
|
irp6Records: irp6Records.items,
|
|
payeRecords: payeRecords.items,
|
|
vatRecords: vatRecords.items,
|
|
});
|
|
} catch (err) {
|
|
console.error("[/api/compliance]", err);
|
|
return NextResponse.json({ error: String(err) }, { status: 500 });
|
|
}
|
|
}
|