One row per letterhead, holding the reorderable/toggleable block list for each thermal slip (sale, delivery note, cash-up) plus the delivery note's default pricing toggle. Migration already run against the live PocketBase instance.
106 lines
3.3 KiB
TypeScript
106 lines
3.3 KiB
TypeScript
/**
|
|
* One-shot migration: create the `pos_slip_layouts` collection.
|
|
*
|
|
* Run with:
|
|
*
|
|
* npx tsx scripts/migrations/2026-09-04-create-pos-slip-layouts.ts
|
|
*
|
|
* One row per letterhead, holding the till's reorderable/toggleable
|
|
* block list for each of the three thermal slips (sale, delivery
|
|
* note, cash-up) plus the delivery note's "show pricing" default.
|
|
* A new collection rather than a field on `letterhead_settings`
|
|
* because that collection is shared with the main WFDASH PDF-quote
|
|
* flow — POS-only slip layout has no business being coupled to it.
|
|
* See docs/superpowers/specs/2026-09-04-pos-slip-layout-editor-design.md.
|
|
*
|
|
* Idempotent — safe to re-run; exits early if the collection exists.
|
|
*
|
|
* Rollback: delete the `pos_slip_layouts` collection in the PB admin
|
|
* UI. No other collection references it, so nothing else is affected.
|
|
*/
|
|
import PocketBase from "pocketbase";
|
|
|
|
const PB_URL = process.env.NEXT_PUBLIC_POCKETBASE_URL || "http://127.0.0.1:8090";
|
|
const ADMIN_EMAIL = process.env.PB_ADMIN_EMAIL;
|
|
const ADMIN_PASSWORD = process.env.PB_ADMIN_PASSWORD;
|
|
|
|
async function main() {
|
|
if (!ADMIN_EMAIL || !ADMIN_PASSWORD) {
|
|
throw new Error(
|
|
"Set PB_ADMIN_EMAIL and PB_ADMIN_PASSWORD env vars (e.g. sourced from .env.local)."
|
|
);
|
|
}
|
|
|
|
const pb = new PocketBase(PB_URL);
|
|
await pb.collection("_superusers").authWithPassword(ADMIN_EMAIL, ADMIN_PASSWORD);
|
|
console.log(`[pos-slip-layouts] Authenticated against ${PB_URL}`);
|
|
|
|
const existing = await pb.collections
|
|
.getFullList()
|
|
.then((all) => all.find((c) => c.name === "pos_slip_layouts"));
|
|
|
|
if (existing) {
|
|
console.log("[pos-slip-layouts] pos_slip_layouts already exists — skipping.");
|
|
return;
|
|
}
|
|
|
|
const letterhead = await pb.collections.getOne("letterhead_settings");
|
|
|
|
await pb.collections.create({
|
|
name: "pos_slip_layouts",
|
|
type: "base",
|
|
// Mirrors letterhead_settings' own rules — any authenticated PB
|
|
// user (the POS app itself only ever talks to this through the
|
|
// admin-authenticated service layer, same as letterhead_settings).
|
|
listRule: "@request.auth.id != ''",
|
|
viewRule: "@request.auth.id != ''",
|
|
createRule: "@request.auth.id != ''",
|
|
updateRule: "@request.auth.id != ''",
|
|
deleteRule: "@request.auth.id != ''",
|
|
fields: [
|
|
{
|
|
name: "letterhead",
|
|
type: "relation",
|
|
required: true,
|
|
collectionId: letterhead.id,
|
|
cascadeDelete: true,
|
|
minSelect: 1,
|
|
maxSelect: 1,
|
|
},
|
|
{
|
|
name: "sale_blocks",
|
|
type: "json",
|
|
required: false,
|
|
maxSize: 0,
|
|
},
|
|
{
|
|
name: "delivery_blocks",
|
|
type: "json",
|
|
required: false,
|
|
maxSize: 0,
|
|
},
|
|
{
|
|
name: "cashup_blocks",
|
|
type: "json",
|
|
required: false,
|
|
maxSize: 0,
|
|
},
|
|
{
|
|
name: "delivery_show_pricing",
|
|
type: "bool",
|
|
required: false,
|
|
},
|
|
],
|
|
// One layout row per letterhead.
|
|
indexes: [
|
|
"CREATE UNIQUE INDEX idx_pos_slip_layouts_letterhead ON pos_slip_layouts (letterhead)",
|
|
],
|
|
});
|
|
|
|
console.log("[pos-slip-layouts] Created pos_slip_layouts collection. Migration complete.");
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error("[pos-slip-layouts] Migration failed:", err);
|
|
process.exit(1);
|
|
});
|