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.
70 lines
2.2 KiB
JavaScript
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);
|
|
});
|