JEISA-WEBAPP/pocketbase/pb_migrations/1786200002_created_customer_po_lines.js
Dave c272526d67 feat(automation): add PO-to-invoice pipeline
- 6 new PocketBase migrations: customer_pos, customer_po_lines, invoices,
  invoice_items, email_inbox, workflow_runs
- n8N workflow JSON: 01-customer-po-to-parsed.json + 02-parsed-po-to-invoice.json
- MCP server config (.cursor/mcp.json + .mcp.json) for AI agent PB access
- .env.example template with all required credentials documented
- n8n/README.md with deployment, testing, and customization notes
2026-09-06 23:40:33 +02:00

161 lines
No EOL
4.1 KiB
JavaScript

/// <reference path="../pb_data/types.d.ts" />
// =========================================================================
// customer_po_lines — one record per line item on an incoming customer PO
// =========================================================================
//
// Splits the `parsed_lines` json blob on a `customer_pos` record into
// individual rows. n8N writes these after extracting SKU, qty, price from
// the customer's PDF. The stock-decrement node reads from here.
//
// Note: `app.findCollectionByNameOrId` is wrapped so this migration applies
// even if `stock_items` isn't present in the local DB. In production (hosted
// PB), `customer_pos` and `stock_items` both exist.
// =========================================================================
migrate((app) => {
const safeFind = (name) => {
try { return app.findCollectionByNameOrId(name); }
catch (e) { return null; }
};
const cpoCol = safeFind("customer_pos");
if (!cpoCol) {
throw new Error("Required collection 'customer_pos' not found — apply migrations in order.");
}
const stockItemsCol = safeFind("stock_items");
const schema = [
{
"cascadeDelete": true,
"collectionId": cpoCol.id,
"hidden": false,
"id": "rel_cpol_cpo",
"maxSelect": 1,
"minSelect": 1,
"name": "customer_po",
"presentable": false,
"required": true,
"system": false,
"type": "relation"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "txt_cpol_sku",
"max": 100,
"min": 0,
"name": "sku",
"pattern": "",
"presentable": true,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "txt_cpol_description",
"max": 500,
"min": 0,
"name": "description",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
},
{
"hidden": false,
"id": "num_cpol_qty",
"max": null,
"min": null,
"name": "quantity",
"onlyInt": false,
"presentable": false,
"required": false,
"system": false,
"type": "number"
},
{
"hidden": false,
"id": "num_cpol_unit_price",
"max": null,
"min": null,
"name": "unit_price",
"onlyInt": false,
"presentable": false,
"required": false,
"system": false,
"type": "number"
},
{
"hidden": false,
"id": "num_cpol_line_total",
"max": null,
"min": null,
"name": "line_total",
"onlyInt": false,
"presentable": false,
"required": false,
"system": false,
"type": "number"
},
{
"hidden": false,
"id": "bool_cpol_stock_decremented",
"name": "stock_decremented",
"presentable": false,
"required": false,
"system": false,
"type": "bool"
},
{
"hidden": false,
"id": "dt_cpol_stock_decremented",
"max": "",
"min": "",
"name": "stock_decremented_at",
"presentable": false,
"required": false,
"system": false,
"type": "date"
}
];
if (stockItemsCol) {
schema.splice(1, 0, {
"cascadeDelete": false,
"collectionId": stockItemsCol.id,
"hidden": false,
"id": "rel_cpol_stock",
"maxSelect": 1,
"minSelect": 0,
"name": "stock_item",
"presentable": false,
"required": false,
"system": false,
"type": "relation"
});
}
const collection = new Collection({
"createRule": "@request.auth.id != ''",
"deleteRule": "@request.auth.id != ''",
"listRule": "@request.auth.id != ''",
"name": "customer_po_lines",
"system": false,
"type": "base",
"updateRule": "@request.auth.id != ''",
"viewRule": "@request.auth.id != ''",
"fields": schema,
"indexes": []
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("customer_po_lines");
return app.delete(collection);
})