JEISA-WEBAPP/pocketbase/pb_migrations/1786200001_created_customer_pos.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

236 lines
No EOL
6.3 KiB
JavaScript

/// <reference path="../pb_data/types.d.ts" />
// =========================================================================
// customer_pos — incoming POs from customers, received via email
// =========================================================================
//
// This is what the n8N IMAP workflow creates when a customer emails a
// purchase order PDF to the JEI orders inbox. The PDF is stored in `po_pdf`
// and parsed line items go into `customer_po_lines`.
//
// NOTE on naming: the existing `orders` collection (pbc_3527180448) is the
// operational / sales order system (fulfillment, drivers, deliveries). This
// collection is INCOMING POs from clients — different lifecycle, different
// fields, different ownership. Hence the distinct name `customer_pos`.
//
// Status lifecycle:
// new → email received, PDF saved, not yet inspected
// parsed → line items extracted, ready for invoicing
// invoiced → linked invoice created and sent
// cancelled → ignored (wrong sender / duplicate)
// error → workflow failed, see `error_message`
// =========================================================================
migrate((app) => {
const collection = new Collection({
"createRule": "@request.auth.id != ''",
"deleteRule": "@request.auth.id != ''",
"listRule": "@request.auth.id != ''",
"name": "customer_pos",
"system": false,
"type": "base",
"updateRule": "@request.auth.id != ''",
"viewRule": "@request.auth.id != ''",
"fields": [
{
"cascadeDelete": false,
"collectionId": "pbc_108570809",
"hidden": false,
"id": "rel_cpo_customer",
"maxSelect": 1,
"minSelect": 0,
"name": "customer",
"presentable": false,
"required": false,
"system": false,
"type": "relation"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "txt_cpo_po_number",
"max": 100,
"min": 0,
"name": "po_number",
"pattern": "",
"presentable": true,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
},
{
"hidden": false,
"id": "file_cpo_po_pdf",
"maxSelect": 10,
"maxSize": 20971520,
"mimeTypes": ["application/pdf", "image/png", "image/jpeg"],
"name": "po_pdf",
"presentable": false,
"protected": false,
"required": false,
"system": false,
"thumbs": [],
"type": "file"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "txt_cpo_email_from",
"max": 500,
"min": 0,
"name": "source_email_from",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "txt_cpo_email_subject",
"max": 500,
"min": 0,
"name": "source_email_subject",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
},
{
"hidden": false,
"id": "dt_cpo_email_received",
"max": "",
"min": "",
"name": "source_email_received_at",
"presentable": false,
"required": false,
"system": false,
"type": "date"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "txt_cpo_email_uid",
"max": 200,
"min": 0,
"name": "source_email_uid",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
},
{
"hidden": false,
"id": "sel_cpo_status",
"maxSelect": 1,
"name": "status",
"presentable": true,
"required": false,
"system": false,
"type": "select",
"values": ["new", "parsed", "invoiced", "cancelled", "error"]
},
{
"cascadeDelete": false,
"collectionId": "pbc_1342968361",
"hidden": false,
"id": "rel_cpo_purchase_order",
"maxSelect": 1,
"minSelect": 0,
"name": "matched_purchase_order",
"presentable": false,
"required": false,
"system": false,
"type": "relation"
},
{
"hidden": false,
"id": "json_cpo_parsed_lines",
"maxSize": 200000,
"name": "parsed_lines",
"presentable": false,
"required": false,
"system": false,
"type": "json"
},
{
"hidden": false,
"id": "num_cpo_total",
"max": null,
"min": null,
"name": "total_amount",
"onlyInt": false,
"presentable": false,
"required": false,
"system": false,
"type": "number"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "txt_cpo_currency",
"max": 10,
"min": 0,
"name": "currency",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "txt_cpo_notes",
"max": 0,
"min": 0,
"name": "notes",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
},
{
"hidden": false,
"id": "dt_cpo_processed",
"max": "",
"min": "",
"name": "processed_at",
"presentable": false,
"required": false,
"system": false,
"type": "date"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "txt_cpo_error",
"max": 0,
"min": 0,
"name": "error_message",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
}
],
"indexes": []
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("customer_pos");
return app.delete(collection);
})