// scripts/_create_vat_v2.js // PB v0.22 schema-create via PATCH /api/collections/:id with the // `fields` key (not `schema`). Field names must be snake_case — the // SARS form-field numbers survive as suffixes (e.g. standard_rate_1). const fs = require("node:fs"); const path = require("node:path"); const ENV_PATH = path.join(__dirname, "..", ".env.local"); for (const line of fs.readFileSync(ENV_PATH, "utf-8").split(/\r?\n/)) { const m = line.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/); if (m && !process.env[m[1]]) process.env[m[1]] = m[2].trim(); } const PB_URL = process.env.PB_URL; const PB_TOKEN = process.env.PB_TOKEN; const COLLECTION_ID = "pbc_3919993741"; const fields = [ { name: "period", type: "text", required: true, options: { min: 6, max: 6, pattern: "^\\d{6}$" } }, { name: "standard_rate_1", type: "number", required: false, options: {} }, { name: "zero_rate_2", type: "number", required: false, options: {} }, { name: "exempt_and_non_supplies_3", type: "number", required: false, options: {} }, { name: "capital_goods_and_services_supplied_to_you_14", type: "number", required: false, options: {} }, { name: "other_goods_and_services_supplied_to_you_15", type: "number", required: false, options: {} }, { name: "total_payable", type: "number", required: false, options: {} }, { name: "interest_d", type: "number", required: false, options: {} }, { name: "penalties_d", type: "number", required: false, options: {} }, { name: "status", type: "select", required: true, options: { maxSelect: 1, values: ["draft", "submitted", "paid"] }, }, { name: "date_submitted", type: "date", required: false, options: { min: "", max: "" } }, { name: "date_paid", type: "date", required: false, options: { min: "", max: "" } }, { name: "due_date", type: "date", required: false, options: { min: "", max: "" } }, { name: "payment_reference", type: "text", required: false, options: { min: 0, max: 100, pattern: "" } }, // Hidden upsert key — mirrors EMP201 { name: "company_period_key", type: "text", required: false, options: { min: 0, max: 0, pattern: "" }, hidden: true }, { name: "company", type: "relation", required: true, options: { collectionId: "pbc_3748838150", // ysterbaard_companies cascadeDelete: false, minSelect: 1, maxSelect: 1, }, }, { name: "Return_Filed", type: "bool", required: false, options: {} }, { name: "last_updated", type: "date", required: false, options: { min: "", max: "" } }, { name: "notes", type: "text", required: false, options: { min: 0, max: 0, pattern: "" } }, { name: "first_name", type: "text", required: false, options: { min: 0, max: 0, pattern: "" } }, { name: "surname", type: "text", required: false, options: { min: 0, max: 0, pattern: "" } }, { name: "capacity", type: "text", required: false, options: { min: 0, max: 0, pattern: "" } }, { name: "bus_tel_no", type: "number", required: false, options: {} }, { name: "cell_no", type: "number", required: false, options: {} }, { name: "contact_email", type: "email", required: false, options: { exceptDomains: [], onlyDomains: [] } }, { name: "is_active", type: "bool", required: false, options: {} }, { name: "documents", type: "file", required: false, options: { maxSelect: 10, maxSize: 10485760, mimeTypes: ["application/pdf", "image/png", "image/jpeg"], thumbs: null, protected: false, }, }, ]; const indexes = [ "CREATE UNIQUE INDEX idx_vat201_company_period ON ysterbaard_SARS_VAT_VAT201 (company_period_key)", "CREATE INDEX idx_vat201_period ON ysterbaard_SARS_VAT_VAT201 (period)", "CREATE INDEX idx_vat201_status ON ysterbaard_SARS_VAT_VAT201 (status)", ]; (async () => { console.log(`[1/3] PATCH /api/collections/${COLLECTION_ID} (add ${fields.length} fields, key=schema)`); const r1 = await fetch(`${PB_URL}/api/collections/${COLLECTION_ID}`, { method: "PATCH", headers: { Authorization: PB_TOKEN, "Content-Type": "application/json" }, body: JSON.stringify({ schema: fields }), }); const t1 = await r1.text(); console.log(` HTTP ${r1.status}`); if (!r1.ok) { console.error(` Failed: ${t1.slice(0, 600)}`); process.exit(1); } const persisted = (JSON.parse(t1).fields || []).filter(f => !f.system).length; console.log(` fields persisted: ${persisted}`); console.log(`[2/3] PATCH /api/collections/${COLLECTION_ID} (add ${indexes.length} indexes)`); const r2 = await fetch(`${PB_URL}/api/collections/${COLLECTION_ID}`, { method: "PATCH", headers: { Authorization: PB_TOKEN, "Content-Type": "application/json" }, body: JSON.stringify({ indexes }), }); const t2 = await r2.text(); console.log(` HTTP ${r2.status}`); if (!r2.ok) { console.error(` Failed: ${t2.slice(0, 600)}`); process.exit(1); } console.log(`[3/3] GET /api/collections/${COLLECTION_ID} (verify)`); const r3 = await fetch(`${PB_URL}/api/collections/${COLLECTION_ID}`, { headers: { Authorization: PB_TOKEN } }); const final = await r3.json(); const userFields = (final.fields || final.schema || []).filter(f => !f.system); console.log(` name: ${final.name}`); console.log(` user-defined fields: ${userFields.length}`); console.log(` indexes: ${(final.indexes || []).length}`); console.log(""); console.log("Field list:"); for (const f of userFields) { console.log(` - ${f.name.padEnd(50)} ${f.type}${f.required ? " (required)" : ""}`); } console.log(""); console.log("Indexes:"); for (const ix of final.indexes || []) console.log(` - ${ix}`); process.exit(0); })().catch((err) => { console.error("Unexpected error:", err); process.exit(1); });