JEISA-WEBAPP/pocketbase/pb_migrations/1786200007_updated_purchase_orders.js
Dave 0b8f003f87 feat(po): add MCP server, agent-friendly PO API, and PDF rendering
- server/pb-mcp.mjs: 15-tool MCP server for purchase-order workflow
  (CRUD, suppliers, stock, customers, customer POs, validate_draft,
  generate_order_number)
- src/lib/api/purchaseOrders.ts: typed helpers shared by UI + MCP + n8n
- src/components/purchase-orders/pdf.ts: jsPDF PO generator
- src/components/purchase-orders/ViewOrderDialog.tsx: read-only dialog
- src/components/purchase-orders/AttachmentsDialog.tsx: attachment mgmt
- src/components/purchase-orders/NumberInput.tsx: numeric input
- scripts/mcp-create-po.mjs: end-to-end driver (MCP stdio smoke test)
- pocketbase/pb_migrations/1786200007_*: schema migration
- docs/MCP_AND_N8N.md: MCP + n8n integration guide

Verified end-to-end via MCP: generate_order_number → create_purchase_order
with snapshot_items for an actual quote (DRILL-19042 / 161053).
2026-09-07 11:12:13 +02:00

62 lines
2.4 KiB
JavaScript

/// <reference path="../pb_data/types.d.ts" />
// =========================================================================
// purchase_orders — extend status enum + add soft-delete flag
// =========================================================================
//
// What this migration does:
// 1. Extends the `status` select enum with `Approved` and `Rejected`
// so the row-menu "Approve" / "Reject" actions stop failing with 400.
// 2. Adds a `deleted` boolean (default false). The Purchase Orders list
// filters it out so soft-deletes don't clutter the table.
// (We avoid hard-deletes so historical invoices / attachments remain
// traceable; the record is hidden from the UI, not erased from PB.)
// =========================================================================
migrate((app) => {
const collection = app.findCollectionByNameOrId("purchase_orders");
if (!collection) {
throw new Error("purchase_orders collection not found — aborting.");
}
// -- 1. extend status enum ---------------------------------------------
const statusField = collection.fields.find((f) => f.name === "status");
if (statusField && statusField.type === "select") {
const wanted = ["Pending", "Pending Approval", "Approved", "Ordered", "Received", "Rejected"];
const current = Array.isArray(statusField.values) ? statusField.values : [];
const merged = Array.from(new Set([...current, ...wanted]));
statusField.values = merged;
}
// -- 2. add `deleted` bool ---------------------------------------------
const hasDeleted = collection.fields.some((f) => f.name === "deleted");
if (!hasDeleted) {
collection.fields.push({
hidden: false,
id: "bool_po_deleted",
name: "deleted",
presentable: false,
required: false,
system: false,
type: "bool",
});
}
return app.save(collection);
}, (app) => {
// Rollback: remove the values we added (keep historical ones intact) and
// drop the `deleted` field.
const collection = app.findCollectionByNameOrId("purchase_orders");
if (!collection) return;
const statusField = collection.fields.find((f) => f.name === "status");
if (statusField && Array.isArray(statusField.values)) {
statusField.values = statusField.values.filter(
(v) => v !== "Approved" && v !== "Rejected" && v !== "Pending Approval",
);
}
collection.fields = collection.fields.filter((f) => f.name !== "deleted");
return app.save(collection);
});