New /delivery-pool page, a clone of the Collection Pool for deliveries with no pending stage. Invoiced lines are grouped per company, one card per customer invoice; a card expands to its lines. Assign a driver and day per invoice (or bulk per company); uploading the signed copy adds it to every line, marks the lines completed + delivered_at, and closes a delivery note once none of its lines is still open. - Driver lives in new order_items.delivery_driver / delivery_assigned_at (npm run pb:migrate:delivery-pool), never drv_id (collection driver). - Pool starts at DELIVERY_POOL_START (2026-10-30); lines whose DN is already completed/cancelled (POS counter sales) are left out. - Service + /api/v1/delivery-pool routes (browser session); the service 503s until the migration has run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
67 lines
2.3 KiB
TypeScript
67 lines
2.3 KiB
TypeScript
/**
|
|
* One-shot migration: fields for the Delivery Pool.
|
|
*
|
|
* order_items.delivery_driver relation → users (single)
|
|
* order_items.delivery_assigned_at date
|
|
*
|
|
* Kept apart from `drv_id` / `assigned_at` so assigning a delivery never
|
|
* overwrites the driver who collected the goods.
|
|
*
|
|
* Run with:
|
|
*
|
|
* npm run pb:migrate:delivery-pool
|
|
*
|
|
* Idempotent — fields that already exist are skipped. Manual step on the
|
|
* live PB (like select values and pb_hooks), BEFORE deploying the page.
|
|
*
|
|
* Rollback: delete the fields in the PB admin UI.
|
|
*/
|
|
import "./_env-loader";
|
|
import PocketBase from "pocketbase";
|
|
|
|
const PB_URL = process.env.NEXT_PUBLIC_POCKETBASE_URL || process.env.PB_URL || "http://127.0.0.1:8090";
|
|
const ADMIN_EMAIL = process.env.PB_ADMIN_EMAIL;
|
|
const ADMIN_PASSWORD = process.env.PB_ADMIN_PASSWORD;
|
|
|
|
type FieldDef = Record<string, unknown> & { name: string };
|
|
|
|
async function main() {
|
|
if (!ADMIN_EMAIL || !ADMIN_PASSWORD) {
|
|
throw new Error("Set PB_ADMIN_EMAIL and PB_ADMIN_PASSWORD (e.g. from .env.local).");
|
|
}
|
|
const pb = new PocketBase(PB_URL);
|
|
await pb.collection("_superusers").authWithPassword(ADMIN_EMAIL, ADMIN_PASSWORD);
|
|
console.log(`[delivery-pool] Authenticated against ${PB_URL}`);
|
|
|
|
const users = await pb.collections.getOne("users");
|
|
const wanted: FieldDef[] = [
|
|
{
|
|
name: "delivery_driver",
|
|
type: "relation",
|
|
required: false,
|
|
presentable: false,
|
|
collectionId: users.id,
|
|
cascadeDelete: false,
|
|
minSelect: 0,
|
|
maxSelect: 1,
|
|
},
|
|
{ name: "delivery_assigned_at", type: "date", required: false, presentable: false },
|
|
];
|
|
|
|
const collection = await pb.collections.getOne("order_items");
|
|
const existing = new Set(collection.fields.map((f: { name: string }) => f.name));
|
|
const missing = wanted.filter((f) => !existing.has(f.name));
|
|
for (const f of wanted) {
|
|
if (existing.has(f.name)) console.log(`[delivery-pool] order_items.${f.name} already exists — skipping.`);
|
|
}
|
|
if (missing.length > 0) {
|
|
await pb.collections.update(collection.id, { fields: [...collection.fields, ...missing] });
|
|
for (const f of missing) console.log(`[delivery-pool] order_items.${f.name} added.`);
|
|
}
|
|
console.log("[delivery-pool] Done.");
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error("[delivery-pool] Migration failed:", err);
|
|
process.exit(1);
|
|
});
|