JEISA-WEBAPP/pocketbase/pb_migrations/1786300001_fixed_quotes_items_field.js
Dave d606345de4 fix(quotes,po): repair item storage, totals and PDF line items
Quotes and purchase orders were silently losing their line items.

Quote items field was a multi-relation to stock_items, but PocketBase
stored only the last id as a plain string no matter how it was sent
(JSON string via FormData, raw array, or repeated FormData entries).
Every quote created through the UI had `items: ""` or `items: "<id>"`.
Recreated the field as JSON so an array of stock_item ids round-trips
(companion fields quantities/unitPrices already line up with it).

PO snapshot_items had the same class of bug from the other direction:
String(obj) coerced the snapshot array to "[object Object]", which
PocketBase stored verbatim, rendering the PO as N rows of
"Unknown / £0.00". The form now sends JSON-stringified arrays, and
the reader only trusts a snapshot whose rows actually carry a name.

Also fixes:
- Quote item lines are hydrated from stock_items; the parallel
  quantities/unitPrices arrays are the source of truth, so quotes
  written before the schema fix still render and total correctly.
- Quote form rejects stock rows where no item was actually picked
  from the dropdown, instead of saving an empty stockItemId.
- PO PDF filename is now the plain order number (PO-20261015-001.pdf).

Adds the quotes.items schema migration plus three dev scripts for
creating a quote, re-applying the field fix and rendering a test PDF.
2026-10-20 20:13:46 +02:00

70 lines
2.2 KiB
JavaScript

/// <reference path="../pb_data/types.d.ts" />
/**
* Fix the `items` field on the `quotes` collection.
*
* Background:
* The `items` field on quotes is declared as a multi-relation to stock_items
* (maxSelect=0). However, regardless of how the value is sent — JSON-stringified
* array via FormData, raw array via JSON body, or multiple FormData entries —
* PocketBase stores only the LAST id as a plain string. Every quote ever
* created via the UI has `items: ""` or `items: "<one id>"`.
*
* Fix:
* Drop the broken relation and recreate the field as `json` so that an array
* of stock_item ids round-trips correctly. The companion fields
* `quantities` and `unitPrices` (already JSON) line up with this array.
*
* NOTE: this migration is applied directly to the live PB instance.
* Once written, the quotes collection will accept `items: [...]` arrays.
*/
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_134296766");
// Find existing `items` field (relation, broken) and remove it
const oldField = collection.fields.find((f) => f.name === "items");
if (oldField) {
collection.fields.removeById(oldField.id);
}
// Add the replacement `items` field as JSON (maxSize matches quantities/unitPrices)
collection.fields.addAt(
collection.fields.length,
new Field({
name: "items",
type: "json",
required: false,
presentable: false,
hidden: false,
system: false,
options: { maxSize: 2_000_000 },
})
);
return app.save(collection);
}, (app) => {
// Rollback: restore `items` as a relation to stock_items
const collection = app.findCollectionByNameOrId("pbc_134296766");
const jsonField = collection.fields.find((f) => f.name === "items");
if (jsonField) collection.fields.removeById(jsonField.id);
collection.fields.addAt(
collection.fields.length,
new Field({
name: "items",
type: "relation",
required: false,
presentable: false,
hidden: false,
system: false,
options: {
collectionId: "pbc_2382354120",
cascadeDelete: false,
minSelect: 0,
maxSelect: 0,
},
})
);
return app.save(collection);
});