Operators can now type per-upload instructions for the AI extraction step in the Pricelist upload form. The notes go into a new `raw_price_list.notes` field that the n8n workflow reads and injects into the LLM user message as per-upload context. Common uses: - "Brand is JEI" → AI stamps every item with brand="JEI" - "Apply 30% markup" → Code node regexes this out for selling_price - "All prices in ZAR excl. VAT" → AI uses ZAR - "Page 4 has discount codes" → AI skips those rows Also auto-populates `raw_price_list.file_name` (the original browser-side filename) on upload — PB slugifies the upload to a token stored inside supplier_file, so without this field the operator saw the slugged version. Existing rows backfilled by the admin script. The `log_summary` field is now reserved for the AI's write-back summary (set by the n8n workflow after extraction). It was previously operator-editable on the form, which was wrong — overwriting it clobbered the AI's output. New migration: scripts/migrations/2026-06-30-add-pricelist-notes.ts (idempotent, only adds `notes` if missing — `file_name` was added manually via the PB admin UI before this commit). doc/pricelist-extraction.md updated with the n8n LLM user message shape, the markup regex, and the notes field's role in the pipeline.
148 lines
5.3 KiB
JSON
148 lines
5.3 KiB
JSON
{
|
|
"_comment": "WFDASH — PocketBase collection for the Pricelist page. Holds raw supplier price-list files (PDF / CSV / text / image) before they're parsed into structured supplier pricing. Import via Settings → Import collections in the PB admin UI, or run scripts/migrations/2026-06-30-add-raw-price-list.ts to create it idempotently. The migration script also relaxes the auth rules to match the rest of the app (any authenticated user can CRUD) — the default for a fresh collection is superuser-only, which is too strict for the Pricelist page.",
|
|
"id": "pbc_raw_price_list_NEW",
|
|
"name": "raw_price_list",
|
|
"type": "base",
|
|
"listRule": "@request.auth.id != ''",
|
|
"viewRule": "@request.auth.id != ''",
|
|
"createRule": "@request.auth.id != ''",
|
|
"updateRule": "@request.auth.id != ''",
|
|
"deleteRule": "@request.auth.id != ''",
|
|
"fields": [
|
|
{
|
|
"autogeneratePattern": "[a-z0-9]{15}",
|
|
"hidden": false,
|
|
"id": "text_rpl_id",
|
|
"max": 15,
|
|
"min": 15,
|
|
"name": "id",
|
|
"pattern": "^[a-z0-9]+$",
|
|
"presentable": false,
|
|
"primaryKey": true,
|
|
"required": true,
|
|
"system": true,
|
|
"type": "text"
|
|
},
|
|
{
|
|
"hidden": false,
|
|
"id": "autodate_rpl_created",
|
|
"name": "created",
|
|
"onCreate": true,
|
|
"onUpdate": false,
|
|
"presentable": false,
|
|
"system": true,
|
|
"type": "autodate"
|
|
},
|
|
{
|
|
"hidden": false,
|
|
"id": "autodate_rpl_updated",
|
|
"name": "updated",
|
|
"onCreate": true,
|
|
"onUpdate": true,
|
|
"presentable": false,
|
|
"system": true,
|
|
"type": "autodate"
|
|
},
|
|
{
|
|
"_comment": "The actual file. Allowed types are whatever supplier pricelists come in as — PDFs, CSVs, plain text, and the common image formats. 50 MB cap matches quote_attachments.",
|
|
"hidden": false,
|
|
"id": "file_rpl_supplier_file",
|
|
"maxSelect": 1,
|
|
"maxSize": 52428800,
|
|
"mimeTypes": [
|
|
"application/pdf",
|
|
"text/csv",
|
|
"text/plain",
|
|
"image/png",
|
|
"image/jpeg",
|
|
"image/webp",
|
|
"image/gif",
|
|
"application/vnd.ms-excel",
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
"application/octet-stream"
|
|
],
|
|
"name": "supplier_file",
|
|
"presentable": false,
|
|
"protected": false,
|
|
"required": false,
|
|
"system": false,
|
|
"thumbs": null,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"_comment": "Original browser-side filename (e.g. \"Acme-Bolts-2026-Q2.pdf\"). PB slugifies the upload to a token stored inside supplier_file, so without this field the operator sees the slugged version in the table. Auto-populated by the WFDASH page on upload.",
|
|
"autogeneratePattern": "",
|
|
"hidden": false,
|
|
"id": "text_rpl_file_name",
|
|
"max": 0,
|
|
"min": 0,
|
|
"name": "file_name",
|
|
"pattern": "",
|
|
"presentable": true,
|
|
"primaryKey": false,
|
|
"required": false,
|
|
"system": false,
|
|
"type": "text"
|
|
},
|
|
{
|
|
"_comment": "Free-text operator notes passed to the AI extraction step as additional context. Examples: 'Brand is JEI. Apply 30% markup. All prices in ZAR excl. VAT. POA for any missing values.' Read by the n8n workflow's LLM user message and by the post-extraction Code node (which can regex out a 'markup: NN%' override).",
|
|
"autogeneratePattern": "",
|
|
"hidden": false,
|
|
"id": "text_rpl_notes",
|
|
"max": 0,
|
|
"min": 0,
|
|
"name": "notes",
|
|
"pattern": "",
|
|
"presentable": false,
|
|
"primaryKey": false,
|
|
"required": false,
|
|
"system": false,
|
|
"type": "text"
|
|
},
|
|
{
|
|
"_comment": "Relation to the suppliers collection. The live collection was created with this as a relation (not free text) so the supplier name is auto-rendered in the page's expand query — no client-side join needed. The picker on the upload form uses the existing SupplierSearch combobox.",
|
|
"cascadeDelete": false,
|
|
"collectionId": "pbc_3355664324",
|
|
"hidden": false,
|
|
"id": "relation_rpl_supplier_name",
|
|
"maxSelect": 1,
|
|
"minSelect": 0,
|
|
"name": "supplier_name",
|
|
"presentable": false,
|
|
"required": false,
|
|
"system": false,
|
|
"type": "relation"
|
|
},
|
|
{
|
|
"_comment": "Workflow status. Uploaded rows start as pending; the parser/AI bumps them through processing → completed, or → failed if it can't make sense of the file. Operator can override manually.",
|
|
"hidden": false,
|
|
"id": "select_rpl_status",
|
|
"maxSelect": 0,
|
|
"name": "status",
|
|
"presentable": false,
|
|
"required": false,
|
|
"system": false,
|
|
"type": "select",
|
|
"values": ["Pending", "Processing", "Completed", "Failed"]
|
|
},
|
|
{
|
|
"_comment": "Free-text log / summary. Whatever the operator wants to remember about the row — parser output, manual notes, \"called Acme, prices valid until Aug\", etc. The UI shows a truncated preview in the table and the full text in the detail dialog.",
|
|
"autogeneratePattern": "",
|
|
"hidden": false,
|
|
"id": "text_rpl_log_summary",
|
|
"max": 0,
|
|
"min": 0,
|
|
"name": "log_summary",
|
|
"pattern": "",
|
|
"presentable": false,
|
|
"primaryKey": false,
|
|
"required": false,
|
|
"system": false,
|
|
"type": "text"
|
|
}
|
|
],
|
|
"indexes": [
|
|
"CREATE INDEX `idx_rpl_supplier_name` ON `raw_price_list` (`supplier_name`)"
|
|
],
|
|
"system": false
|
|
}
|