- 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
236 lines
No EOL
6.3 KiB
JavaScript
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);
|
|
}) |