From 29099b2a16456ed71c8a8506ee742463a9a68e7c Mon Sep 17 00:00:00 2001 From: seb Date: Sat, 8 Aug 2026 09:13:20 +0200 Subject: [PATCH] feat(manifest): add externalNumber reference to quote/order/delivery - Add `external_number NVARCHAR(100)` column to the `manifest` table. - Thread `externalNumber` through manifestDoc and delivery SQL (list, header, create, update). - Include `externalNumber` in shapeSummary and quote/order/delivery create/update/list/getById handlers (optional, clearable on update). - Update README type definitions and regenerate API/schema docs. --- API.delivery.md | 16 +-- API.order.md | 16 +-- API.quote.md | 16 +-- README.md | 15 +-- schema-graph.dot | 4 +- schema-graph.svg | 176 ++++++++++++++++--------------- src/schema.js | 1 + src/sql/delivery.js | 7 +- src/sql/manifestDoc.js | 7 +- src/store/delivery/create.js | 9 +- src/store/delivery/getById.js | 4 +- src/store/delivery/helpers.js | 1 + src/store/delivery/list.js | 4 +- src/store/delivery/update.js | 14 ++- src/store/manifestDoc/helpers.js | 1 + src/store/order/create.js | 9 +- src/store/order/getById.js | 4 +- src/store/order/list.js | 4 +- src/store/order/update.js | 14 ++- src/store/quote/create.js | 9 +- src/store/quote/getById.js | 4 +- src/store/quote/list.js | 4 +- src/store/quote/update.js | 14 ++- 23 files changed, 210 insertions(+), 143 deletions(-) diff --git a/API.delivery.md b/API.delivery.md index 20629c8..8acfbcf 100644 --- a/API.delivery.md +++ b/API.delivery.md @@ -17,11 +17,12 @@ Creates a new delivery for the user's selected company with its lines. | `body.number` | `string` | The delivery number. | | `body.date` | `string` | The delivery date. | | `body.supplierId` | `number` | The id of the supplier. | +| `[body.externalNumber]` | `string` | An external (supplier) reference number. | | `[body.lines]` | `Array` | The delivery lines. | **Returns** -`Promise<{id: number, number: string, type: string, entityId: number, date: string, lines: Array}>` — The created delivery. +`Promise<{id: number, number: string, type: string, entityId: number, externalNumber: string|null, date: string, lines: Array}>` — The created delivery. **Throws** @@ -31,7 +32,7 @@ Creates a new delivery for the user's selected company with its lines. ```js const delivery = await store.delivery.create(42, { number: 'D-1', date: '2026-01-01', supplierId: 5, lines: [...] }); -// => { id, number, type, entityId, date, lines: [...] } +// => { id, number, type, entityId, externalNumber, date, lines: [...] } ``` ## `delivery.delete` @@ -76,7 +77,7 @@ Returns a single delivery by its id within the user's selected company. **Returns** -`Promise<{id: number, number: string, type: string, entityId: number, date: string, lines: Array}>` — The delivery. +`Promise<{id: number, number: string, type: string, entityId: number, externalNumber: string|null, date: string, lines: Array}>` — The delivery. **Throws** @@ -86,7 +87,7 @@ Returns a single delivery by its id within the user's selected company. ```js const delivery = await store.delivery.getById(42, 5); -// => { id, number, type, entityId, date, lines: [...] } +// => { id, number, type, entityId, externalNumber, date, lines: [...] } ``` ## `delivery.list` @@ -103,13 +104,13 @@ Lists the deliveries of the user's selected company. **Returns** -`Promise>` — The deliveries. +`Promise>` — The deliveries. **Example** ```js const deliveries = await store.delivery.list(42); -// => [{ id, number, type, entityId, date }] +// => [{ id, number, type, entityId, externalNumber, date }] ``` ## `delivery.update` @@ -128,11 +129,12 @@ Updates a delivery's header and/or lines. | `[patch.number]` | `string` | The new delivery number. | | `[patch.date]` | `string` | The new delivery date. | | `[patch.supplierId]` | `number` | The new supplier id. | +| `[patch.externalNumber]` | `string` | The new external (supplier) reference number. | | `[patch.lines]` | `Array` | The new delivery lines. | **Returns** -`Promise<{id: number, number: string, type: string, entityId: number, date: string, lines: Array}>` — The updated delivery. +`Promise<{id: number, number: string, type: string, entityId: number, externalNumber: string|null, date: string, lines: Array}>` — The updated delivery. **Throws** diff --git a/API.order.md b/API.order.md index 2d04a2e..537f20c 100644 --- a/API.order.md +++ b/API.order.md @@ -17,11 +17,12 @@ Creates a new order for the user's selected company with its lines. | `body.number` | `string` | The order number. | | `body.date` | `string` | The order date. | | `[body.entityId]` | `number` | The id of the customer entity. | +| `[body.externalNumber]` | `string` | An external (customer) reference number. | | `[body.lines]` | `Array` | The order lines. | **Returns** -`Promise<{id: number, number: string, type: string, entityId: number|null, date: string, lines: Array}>` — The created order. +`Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array}>` — The created order. **Throws** @@ -31,7 +32,7 @@ Creates a new order for the user's selected company with its lines. ```js const order = await store.order.create(42, { number: 'B-2026-001', date: '2026-09-15', entityId: 12, lines: [...] }); -// => { id, number, type, entityId, date, lines: [...] } +// => { id, number, type, entityId, externalNumber, date, lines: [...] } ``` ## `order.delete` @@ -76,7 +77,7 @@ Returns a single order by its id within the user's selected company. **Returns** -`Promise<{id: number, number: string, type: string, entityId: number|null, date: string, lines: Array}>` — The order with its lines. +`Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array}>` — The order with its lines. **Throws** @@ -86,7 +87,7 @@ Returns a single order by its id within the user's selected company. ```js const order = await store.order.getById(42, 5); -// => { id, number, type, entityId, date, lines: [...] } +// => { id, number, type, entityId, externalNumber, date, lines: [...] } ``` ## `order.list` @@ -103,13 +104,13 @@ Lists the orders of the user's selected company. **Returns** -`Promise>` — The orders. +`Promise>` — The orders. **Example** ```js const orders = await store.order.list(42); -// => [{ id, number, type, entityId, date }] +// => [{ id, number, type, entityId, externalNumber, date }] ``` ## `order.update` @@ -128,11 +129,12 @@ Updates an order's header and/or lines. | `[patch.number]` | `string` | The new order number. | | `[patch.date]` | `string` | The new order date. | | `[patch.entityId]` | `number` | The new customer entity id. | +| `[patch.externalNumber]` | `string` | The new external (customer) reference number. | | `[patch.lines]` | `Array` | The new order lines. | **Returns** -`Promise<{id: number, number: string, type: string, entityId: number|null, date: string, lines: Array}>` — The updated order. +`Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array}>` — The updated order. **Throws** diff --git a/API.quote.md b/API.quote.md index ac5eac6..ec8b210 100644 --- a/API.quote.md +++ b/API.quote.md @@ -17,11 +17,12 @@ Creates a new quote for the user's selected company with its lines. | `body.number` | `string` | The quote number. | | `body.date` | `string` | The quote date. | | `[body.entityId]` | `number` | The id of the customer entity. | +| `[body.externalNumber]` | `string` | An external (customer) reference number. | | `[body.lines]` | `Array` | The quote lines. | **Returns** -`Promise<{id: number, number: string, type: string, entityId: number|null, date: string, lines: Array}>` — The created quote. +`Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array}>` — The created quote. **Throws** @@ -31,7 +32,7 @@ Creates a new quote for the user's selected company with its lines. ```js const quote = await store.quote.create(42, { number: 'A-2026-001', date: '2026-09-01', entityId: 12, lines: [...] }); -// => { id, number, type, entityId, date, lines: [...] } +// => { id, number, type, entityId, externalNumber, date, lines: [...] } ``` ## `quote.delete` @@ -76,7 +77,7 @@ Returns a single quote by its id within the user's selected company. **Returns** -`Promise<{id: number, number: string, type: string, entityId: number|null, date: string, lines: Array}>` — The quote with its lines. +`Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array}>` — The quote with its lines. **Throws** @@ -86,7 +87,7 @@ Returns a single quote by its id within the user's selected company. ```js const quote = await store.quote.getById(42, 5); -// => { id, number, type, entityId, date, lines: [...] } +// => { id, number, type, entityId, externalNumber, date, lines: [...] } ``` ## `quote.list` @@ -103,13 +104,13 @@ Lists the quotes of the user's selected company. **Returns** -`Promise>` — The quotes. +`Promise>` — The quotes. **Example** ```js const quotes = await store.quote.list(42); -// => [{ id, number, type, entityId, date }] +// => [{ id, number, type, entityId, externalNumber, date }] ``` ## `quote.update` @@ -128,11 +129,12 @@ Updates a quote's header and/or lines. | `[patch.number]` | `string` | The new quote number. | | `[patch.date]` | `string` | The new quote date. | | `[patch.entityId]` | `number` | The new customer entity id. | +| `[patch.externalNumber]` | `string` | The new external (customer) reference number. | | `[patch.lines]` | `Array` | The new quote lines. | **Returns** -`Promise<{id: number, number: string, type: string, entityId: number|null, date: string, lines: Array}>` — The updated quote. +`Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array}>` — The updated quote. **Throws** diff --git a/README.md b/README.md index 8f70d05..d058ab0 100644 --- a/README.md +++ b/README.md @@ -293,8 +293,8 @@ Company-scoped goods receipts on `manifest` / `manifestarticle` with fixed `type | --- | --- | --- | | `list` | `(googleAuthId)` | `DeliverySummary[]` | | `getById` | `(googleAuthId, id)` | `Delivery` | -| `create` | `(googleAuthId, { number, date, supplierId?, lines })` | `Delivery` | -| `update` | `(googleAuthId, id, { number?, date?, supplierId?, lines? })` | `Delivery` | +| `create` | `(googleAuthId, { number, date, supplierId?, externalNumber?, lines })` | `Delivery` | +| `update` | `(googleAuthId, id, { number?, date?, supplierId?, externalNumber?, lines? })` | `Delivery` | | `delete` | `(googleAuthId, id)` | `void` | ```ts @@ -303,6 +303,7 @@ type DeliverySummary = { number: string, type: 'delivery', supplierId: number | null, // manifest.entity_id + externalNumber: string | null, // manifest.external_number date: Date, } @@ -336,8 +337,8 @@ Company-scoped quotes on `manifest` / `manifestarticle` with fixed `type = 'quot | --- | --- | --- | | `list` | `(googleAuthId)` | `QuoteSummary[]` | | `getById` | `(googleAuthId, id)` | `Quote` | -| `create` | `(googleAuthId, { number, date, entityId?, lines })` | `Quote` | -| `update` | `(googleAuthId, id, { number?, date?, entityId?, lines? })` | `Quote` | +| `create` | `(googleAuthId, { number, date, entityId?, externalNumber?, lines })` | `Quote` | +| `update` | `(googleAuthId, id, { number?, date?, entityId?, externalNumber?, lines? })` | `Quote` | | `delete` | `(googleAuthId, id)` | `void` | ```ts @@ -346,6 +347,7 @@ type QuoteSummary = { number: string, type: 'quote', entityId: number | null, // manifest.entity_id — customer + externalNumber: string | null, // manifest.external_number date: Date, } @@ -377,8 +379,8 @@ Company-scoped orders on `manifest` / `manifestarticle` with fixed `type = 'orde | --- | --- | --- | | `list` | `(googleAuthId)` | `OrderSummary[]` | | `getById` | `(googleAuthId, id)` | `Order` | -| `create` | `(googleAuthId, { number, date, entityId?, lines })` | `Order` | -| `update` | `(googleAuthId, id, { number?, date?, entityId?, lines? })` | `Order` | +| `create` | `(googleAuthId, { number, date, entityId?, externalNumber?, lines })` | `Order` | +| `update` | `(googleAuthId, id, { number?, date?, entityId?, externalNumber?, lines? })` | `Order` | | `delete` | `(googleAuthId, id)` | `void` | ```ts @@ -387,6 +389,7 @@ type OrderSummary = { number: string, type: 'order', entityId: number | null, + externalNumber: string | null, // manifest.external_number date: Date, } diff --git a/schema-graph.dot b/schema-graph.dot index 7a68f3a..11ad118 100644 --- a/schema-graph.dot +++ b/schema-graph.dot @@ -61,7 +61,7 @@ digraph schema { fontcolor="#1a365d"; margin=14; ledger [label=<
ledger
idINT PK
manifestarticle_idINT FK
transaction_typeNVARCHAR(100)
amountFLOAT
transaction_textNVARCHAR(MAX)
hash_versionINT
prev_hash?NVARCHAR(128)
>]; manifestarticle [label=<
manifestarticle
idINT PK
manifest_idINT FK
tax_idINT FK
article_id?INT FK
amountFLOAT
netFLOAT
comment?NVARCHAR(MAX)
rebateFLOAT
>]; - manifest [label=<
manifest
idINT PK
entity_id?INT FK
company_idINT FK
numberNVARCHAR(100)
typeNVARCHAR(100)
dateDATETIME2
>]; + manifest [label=<
manifest
idINT PK
entity_id?INT FK
company_idINT FK
numberNVARCHAR(100)
typeNVARCHAR(100)
external_number?NVARCHAR(100)
dateDATETIME2
>]; price [label=<
price
idINT PK
tax_idINT FK
customergroup_idINT FK
article_idINT FK
minmultiplierDECIMAL(18,4)
netFLOAT
>]; tax [label=<
tax
idINT PK
rateDECIMAL(18,4)
>]; } @@ -118,7 +118,7 @@ digraph schema { categorytext:language_id:e -> language:in3:n [color="#1a365d", fontcolor="#1a365d", tooltip="FK_categorytext_language", constraint=false, weight=1]; articletext:article_id:e -> article:in9:n [color="#702459", fontcolor="#702459", tooltip="FK_articletext_article", weight=3]; articletext:language_id:w -> language:in2:n [color="#744210", fontcolor="#744210", tooltip="FK_articletext_language", constraint=false, weight=1]; - price:tax_id:nw -> tax:in1:n [color="#285e61", fontcolor="#285e61", tooltip="FK_price_tax", constraint=false, weight=1]; + price:tax_id:sw -> tax:in1:n [color="#285e61", fontcolor="#285e61", tooltip="FK_price_tax", constraint=false, weight=1]; price:article_id:w -> article:in1:n [color="#d53f8c", fontcolor="#d53f8c", tooltip="FK_price_article", weight=3]; price:customergroup_id:se -> customergroup:in0:n [color="#dd6b20", fontcolor="#dd6b20", tooltip="FK_price_customergroup", constraint=false, weight=1]; manifest:company_id:e -> company:in0:n [color="#38a169", fontcolor="#38a169", tooltip="FK_manifest_company", weight=3]; diff --git a/schema-graph.svg b/schema-graph.svg index 6718ae4..979d3d3 100644 --- a/schema-graph.svg +++ b/schema-graph.svg @@ -1513,54 +1513,54 @@ manifestarticle - - - -manifestarticle - - -id -INT -PK - - -manifest_id -INT -FK - - -tax_id -INT -FK - - -article_id -? -INT -FK - - -amount -FLOAT - - -net -FLOAT - - -comment? -NVARCHAR(MAX) - - -rebate -FLOAT + + + +manifestarticle + + +id +INT +PK + + +manifest_id +INT +FK + + +tax_id +INT +FK + + +article_id +? +INT +FK + + +amount +FLOAT + + +net +FLOAT + + +comment? +NVARCHAR(MAX) + + +rebate +FLOAT ledger:ne->manifestarticle:n - - + + @@ -1568,7 +1568,7 @@ manifestarticle:e->article:n - + @@ -1576,45 +1576,49 @@ manifest - - - -manifest - - -id -INT -PK - - -entity_id -? -INT -FK - - -company_id -INT -FK - - -number -NVARCHAR(100) - - -type -NVARCHAR(100) - - -date -DATETIME2 + + + +manifest + + +id +INT +PK + + +entity_id +? +INT +FK + + +company_id +INT +FK + + +number +NVARCHAR(100) + + +type +NVARCHAR(100) + + +external_number? +NVARCHAR(100) + + +date +DATETIME2 manifestarticle:sw->manifest:n - - + + @@ -1622,8 +1626,8 @@ manifestarticle:sw->tax:n - - + + @@ -1631,7 +1635,7 @@ manifest:e->entity:n - + @@ -1640,8 +1644,8 @@ manifest:e->company:n - - + + @@ -1700,10 +1704,10 @@ -price:nw->tax:n +price:sw->tax:n - - + + diff --git a/src/schema.js b/src/schema.js index f7a9367..9f4dd40 100644 --- a/src/schema.js +++ b/src/schema.js @@ -537,6 +537,7 @@ BEGIN [number] NVARCHAR(100) NOT NULL, [type] NVARCHAR(100) NOT NULL, entity_id INT NULL, + external_number NVARCHAR(100) NULL, [date] DATETIME2 NOT NULL CONSTRAINT DF_manifest_date DEFAULT SYSUTCDATETIME(), CONSTRAINT FK_manifest_company FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE NO ACTION, CONSTRAINT FK_manifest_entity FOREIGN KEY (entity_id) REFERENCES entity(id) ON DELETE SET NULL diff --git a/src/sql/delivery.js b/src/sql/delivery.js index 5afc8c9..c5095eb 100644 --- a/src/sql/delivery.js +++ b/src/sql/delivery.js @@ -6,6 +6,7 @@ SELECT m.[number], m.[type], m.entity_id AS supplierId, + m.external_number AS externalNumber, m.[date] FROM manifest m WHERE m.company_id = @companyId @@ -19,6 +20,7 @@ SELECT m.[number], m.[type], m.entity_id AS supplierId, + m.external_number AS externalNumber, m.[date] FROM manifest m WHERE m.id = @id @@ -44,9 +46,9 @@ ORDER BY ma.id `; export const CREATE_MANIFEST = ` -INSERT INTO manifest (company_id, [number], [type], entity_id, [date]) +INSERT INTO manifest (company_id, [number], [type], entity_id, external_number, [date]) OUTPUT INSERTED.id -VALUES (@companyId, @number, @type, @entityId, @date) +VALUES (@companyId, @number, @type, @entityId, @externalNumber, @date) `; export const UPDATE_MANIFEST = ` @@ -54,6 +56,7 @@ UPDATE manifest SET [number] = @number, entity_id = @entityId, + external_number = @externalNumber, [date] = @date WHERE id = @id AND company_id = @companyId diff --git a/src/sql/manifestDoc.js b/src/sql/manifestDoc.js index 8078b5b..fb6523c 100644 --- a/src/sql/manifestDoc.js +++ b/src/sql/manifestDoc.js @@ -12,6 +12,7 @@ SELECT m.[number], m.[type], m.entity_id AS entityId, + m.external_number AS externalNumber, m.[date] FROM manifest m WHERE m.company_id = @companyId @@ -25,6 +26,7 @@ SELECT m.[number], m.[type], m.entity_id AS entityId, + m.external_number AS externalNumber, m.[date] FROM manifest m WHERE m.id = @id @@ -50,9 +52,9 @@ ORDER BY ma.id `; export const CREATE_MANIFEST = ` -INSERT INTO manifest (company_id, [number], [type], entity_id, [date]) +INSERT INTO manifest (company_id, [number], [type], entity_id, external_number, [date]) OUTPUT INSERTED.id -VALUES (@companyId, @number, @type, @entityId, @date) +VALUES (@companyId, @number, @type, @entityId, @externalNumber, @date) `; export const UPDATE_MANIFEST = ` @@ -60,6 +62,7 @@ UPDATE manifest SET [number] = @number, entity_id = @entityId, + external_number = @externalNumber, [date] = @date WHERE id = @id AND company_id = @companyId diff --git a/src/store/delivery/create.js b/src/store/delivery/create.js index 3d3e4dc..1d690cb 100644 --- a/src/store/delivery/create.js +++ b/src/store/delivery/create.js @@ -18,13 +18,14 @@ export default function create(pool) { * @param {string} body.number - The delivery number. * @param {string} body.date - The delivery date. * @param {number} body.supplierId - The id of the supplier. + * @param {string} [body.externalNumber] - An external (supplier) reference number. * @param {Array} [body.lines] - The delivery lines. - * @returns {Promise<{id: number, number: string, type: string, entityId: number, date: string, lines: Array}>} The created delivery. + * @returns {Promise<{id: number, number: string, type: string, entityId: number, externalNumber: string|null, date: string, lines: Array}>} The created delivery. * @throws {Error} If the delivery is invalid. * * @example * const delivery = await store.delivery.create(42, { number: 'D-1', date: '2026-01-01', supplierId: 5, lines: [...] }); - * // => { id, number, type, entityId, date, lines: [...] } + * // => { id, number, type, entityId, externalNumber, date, lines: [...] } */ return async (googleAuthId, body = {}) => { const number = body.number?.trim?.() ? body.number.trim() : null; @@ -32,6 +33,9 @@ export default function create(pool) { if (!number || !date) { throw new Error('Invalid delivery'); } + const externalNumber = body.externalNumber?.trim?.() + ? body.externalNumber.trim() + : null; const lines = normalizeLines(body.lines ?? []); @@ -53,6 +57,7 @@ export default function create(pool) { .input('number', number) .input('type', DELIVERY_TYPE) .input('entityId', supplierId) + .input('externalNumber', externalNumber) .input('date', date) .query(CREATE_MANIFEST); diff --git a/src/store/delivery/getById.js b/src/store/delivery/getById.js index 9885a0a..bfaebc3 100644 --- a/src/store/delivery/getById.js +++ b/src/store/delivery/getById.js @@ -9,12 +9,12 @@ export default function getById(pool) { * * @param {number} googleAuthId - The id of the Google auth user. * @param {number} id - The id of the delivery. - * @returns {Promise<{id: number, number: string, type: string, entityId: number, date: string, lines: Array}>} The delivery. + * @returns {Promise<{id: number, number: string, type: string, entityId: number, externalNumber: string|null, date: string, lines: Array}>} The delivery. * @throws {Error} If the delivery is not found. * * @example * const delivery = await store.delivery.getById(42, 5); - * // => { id, number, type, entityId, date, lines: [...] } + * // => { id, number, type, entityId, externalNumber, date, lines: [...] } */ return async (googleAuthId, id) => { if (!Number.isFinite(id)) { diff --git a/src/store/delivery/helpers.js b/src/store/delivery/helpers.js index 33517b0..fa6ec1d 100644 --- a/src/store/delivery/helpers.js +++ b/src/store/delivery/helpers.js @@ -12,6 +12,7 @@ export function shapeSummary(row) { number: row.number, type: DELIVERY_TYPE, supplierId: row.supplierId ?? null, + externalNumber: row.externalNumber ?? null, date: row.date, }; } diff --git a/src/store/delivery/list.js b/src/store/delivery/list.js index 60ca299..aa5beac 100644 --- a/src/store/delivery/list.js +++ b/src/store/delivery/list.js @@ -9,11 +9,11 @@ export default function list(pool) { * Lists the deliveries of the user's selected company. * * @param {number} googleAuthId - The id of the Google auth user. - * @returns {Promise>} The deliveries. + * @returns {Promise>} The deliveries. * * @example * const deliveries = await store.delivery.list(42); - * // => [{ id, number, type, entityId, date }] + * // => [{ id, number, type, entityId, externalNumber, date }] */ return async (googleAuthId) => { const { companyId } = await access(googleAuthId); diff --git a/src/store/delivery/update.js b/src/store/delivery/update.js index 03dccfa..c6ee940 100644 --- a/src/store/delivery/update.js +++ b/src/store/delivery/update.js @@ -24,8 +24,9 @@ export default function update(pool) { * @param {string} [patch.number] - The new delivery number. * @param {string} [patch.date] - The new delivery date. * @param {number} [patch.supplierId] - The new supplier id. + * @param {string} [patch.externalNumber] - The new external (supplier) reference number. * @param {Array} [patch.lines] - The new delivery lines. - * @returns {Promise<{id: number, number: string, type: string, entityId: number, date: string, lines: Array}>} The updated delivery. + * @returns {Promise<{id: number, number: string, type: string, entityId: number, externalNumber: string|null, date: string, lines: Array}>} The updated delivery. * @throws {Error} If the delivery is not found. * * @example @@ -43,9 +44,10 @@ export default function update(pool) { patch, 'supplierId', ); + const hasExternalNumber = Object.prototype.hasOwnProperty.call(patch, 'externalNumber'); const hasLines = Object.prototype.hasOwnProperty.call(patch, 'lines'); - if (!hasNumber && !hasDate && !hasSupplierId && !hasLines) { + if (!hasNumber && !hasDate && !hasSupplierId && !hasExternalNumber && !hasLines) { throw new Error('Invalid delivery'); } @@ -99,12 +101,20 @@ export default function update(pool) { ); } + let externalNumber = summary.externalNumber; + if (hasExternalNumber) { + externalNumber = patch.externalNumber?.trim?.() + ? patch.externalNumber.trim() + : null; + } + await request(pool, tx) .input('id', id) .input('companyId', companyId) .input('type', DELIVERY_TYPE) .input('number', number) .input('entityId', supplierId) + .input('externalNumber', externalNumber) .input('date', date) .query(UPDATE_MANIFEST); diff --git a/src/store/manifestDoc/helpers.js b/src/store/manifestDoc/helpers.js index 9eaa869..c6525cc 100644 --- a/src/store/manifestDoc/helpers.js +++ b/src/store/manifestDoc/helpers.js @@ -16,6 +16,7 @@ export function shapeSummary(type, row) { number: row.number, type, entityId: row.entityId ?? null, + externalNumber: row.externalNumber ?? null, date: row.date, }; } diff --git a/src/store/order/create.js b/src/store/order/create.js index 8370074..ee78e04 100644 --- a/src/store/order/create.js +++ b/src/store/order/create.js @@ -17,13 +17,14 @@ export default function create(pool) { * @param {string} body.number - The order number. * @param {string} body.date - The order date. * @param {number} [body.entityId] - The id of the customer entity. + * @param {string} [body.externalNumber] - An external (customer) reference number. * @param {Array} [body.lines] - The order lines. - * @returns {Promise<{id: number, number: string, type: string, entityId: number|null, date: string, lines: Array}>} The created order. + * @returns {Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array}>} The created order. * @throws {Error} If the order is invalid. * * @example * const order = await store.order.create(42, { number: 'B-2026-001', date: '2026-09-15', entityId: 12, lines: [...] }); - * // => { id, number, type, entityId, date, lines: [...] } + * // => { id, number, type, entityId, externalNumber, date, lines: [...] } */ return async (googleAuthId, body = {}) => { const number = body.number?.trim?.() ? body.number.trim() : null; @@ -31,6 +32,9 @@ export default function create(pool) { if (!number || !date) { throw new Error('Invalid order'); } + const externalNumber = body.externalNumber?.trim?.() + ? body.externalNumber.trim() + : null; const lines = normalizeLines(body.lines ?? []); const { companyId, rootCategoryId } = await access(googleAuthId); @@ -51,6 +55,7 @@ export default function create(pool) { .input('number', number) .input('type', ORDER_TYPE) .input('entityId', entityId) + .input('externalNumber', externalNumber) .input('date', date) .query(CREATE_MANIFEST); diff --git a/src/store/order/getById.js b/src/store/order/getById.js index 5b2f8a3..f1d3e36 100644 --- a/src/store/order/getById.js +++ b/src/store/order/getById.js @@ -10,12 +10,12 @@ export default function getById(pool) { * * @param {number} googleAuthId - The id of the Google auth user. * @param {number} id - The id of the order. - * @returns {Promise<{id: number, number: string, type: string, entityId: number|null, date: string, lines: Array}>} The order with its lines. + * @returns {Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array}>} The order with its lines. * @throws {Error} If the order is not found. * * @example * const order = await store.order.getById(42, 5); - * // => { id, number, type, entityId, date, lines: [...] } + * // => { id, number, type, entityId, externalNumber, date, lines: [...] } */ return async (googleAuthId, id) => { if (!Number.isFinite(id)) { diff --git a/src/store/order/list.js b/src/store/order/list.js index 529eb29..78a8441 100644 --- a/src/store/order/list.js +++ b/src/store/order/list.js @@ -9,11 +9,11 @@ export default function list(pool) { * Lists the orders of the user's selected company. * * @param {number} googleAuthId - The id of the Google auth user. - * @returns {Promise>} The orders. + * @returns {Promise>} The orders. * * @example * const orders = await store.order.list(42); - * // => [{ id, number, type, entityId, date }] + * // => [{ id, number, type, entityId, externalNumber, date }] */ return async (googleAuthId) => { const { companyId } = await access(googleAuthId); diff --git a/src/store/order/update.js b/src/store/order/update.js index 20b93fb..131dbb5 100644 --- a/src/store/order/update.js +++ b/src/store/order/update.js @@ -23,8 +23,9 @@ export default function update(pool) { * @param {string} [patch.number] - The new order number. * @param {string} [patch.date] - The new order date. * @param {number} [patch.entityId] - The new customer entity id. + * @param {string} [patch.externalNumber] - The new external (customer) reference number. * @param {Array} [patch.lines] - The new order lines. - * @returns {Promise<{id: number, number: string, type: string, entityId: number|null, date: string, lines: Array}>} The updated order. + * @returns {Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array}>} The updated order. * @throws {Error} If the order is not found. * * @example @@ -39,9 +40,10 @@ export default function update(pool) { const hasNumber = Object.prototype.hasOwnProperty.call(patch, 'number'); const hasDate = Object.prototype.hasOwnProperty.call(patch, 'date'); const hasEntityId = Object.prototype.hasOwnProperty.call(patch, 'entityId'); + const hasExternalNumber = Object.prototype.hasOwnProperty.call(patch, 'externalNumber'); const hasLines = Object.prototype.hasOwnProperty.call(patch, 'lines'); - if (!hasNumber && !hasDate && !hasEntityId && !hasLines) { + if (!hasNumber && !hasDate && !hasEntityId && !hasExternalNumber && !hasLines) { throw new Error('Invalid order'); } @@ -95,12 +97,20 @@ export default function update(pool) { ); } + let externalNumber = summary.externalNumber; + if (hasExternalNumber) { + externalNumber = patch.externalNumber?.trim?.() + ? patch.externalNumber.trim() + : null; + } + await request(pool, tx) .input('id', id) .input('companyId', companyId) .input('type', ORDER_TYPE) .input('number', number) .input('entityId', entityId) + .input('externalNumber', externalNumber) .input('date', date) .query(UPDATE_MANIFEST); diff --git a/src/store/quote/create.js b/src/store/quote/create.js index 2389e68..42eaf58 100644 --- a/src/store/quote/create.js +++ b/src/store/quote/create.js @@ -17,13 +17,14 @@ export default function create(pool) { * @param {string} body.number - The quote number. * @param {string} body.date - The quote date. * @param {number} [body.entityId] - The id of the customer entity. + * @param {string} [body.externalNumber] - An external (customer) reference number. * @param {Array} [body.lines] - The quote lines. - * @returns {Promise<{id: number, number: string, type: string, entityId: number|null, date: string, lines: Array}>} The created quote. + * @returns {Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array}>} The created quote. * @throws {Error} If the quote is invalid. * * @example * const quote = await store.quote.create(42, { number: 'A-2026-001', date: '2026-09-01', entityId: 12, lines: [...] }); - * // => { id, number, type, entityId, date, lines: [...] } + * // => { id, number, type, entityId, externalNumber, date, lines: [...] } */ return async (googleAuthId, body = {}) => { const number = body.number?.trim?.() ? body.number.trim() : null; @@ -31,6 +32,9 @@ export default function create(pool) { if (!number || !date) { throw new Error('Invalid quote'); } + const externalNumber = body.externalNumber?.trim?.() + ? body.externalNumber.trim() + : null; const lines = normalizeLines(body.lines ?? []); const { companyId, rootCategoryId } = await access(googleAuthId); @@ -51,6 +55,7 @@ export default function create(pool) { .input('number', number) .input('type', QUOTE_TYPE) .input('entityId', entityId) + .input('externalNumber', externalNumber) .input('date', date) .query(CREATE_MANIFEST); diff --git a/src/store/quote/getById.js b/src/store/quote/getById.js index a5f9a47..6f1d1eb 100644 --- a/src/store/quote/getById.js +++ b/src/store/quote/getById.js @@ -10,12 +10,12 @@ export default function getById(pool) { * * @param {number} googleAuthId - The id of the Google auth user. * @param {number} id - The id of the quote. - * @returns {Promise<{id: number, number: string, type: string, entityId: number|null, date: string, lines: Array}>} The quote with its lines. + * @returns {Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array}>} The quote with its lines. * @throws {Error} If the quote is not found. * * @example * const quote = await store.quote.getById(42, 5); - * // => { id, number, type, entityId, date, lines: [...] } + * // => { id, number, type, entityId, externalNumber, date, lines: [...] } */ return async (googleAuthId, id) => { if (!Number.isFinite(id)) { diff --git a/src/store/quote/list.js b/src/store/quote/list.js index 42dd836..fcbd968 100644 --- a/src/store/quote/list.js +++ b/src/store/quote/list.js @@ -9,11 +9,11 @@ export default function list(pool) { * Lists the quotes of the user's selected company. * * @param {number} googleAuthId - The id of the Google auth user. - * @returns {Promise>} The quotes. + * @returns {Promise>} The quotes. * * @example * const quotes = await store.quote.list(42); - * // => [{ id, number, type, entityId, date }] + * // => [{ id, number, type, entityId, externalNumber, date }] */ return async (googleAuthId) => { const { companyId } = await access(googleAuthId); diff --git a/src/store/quote/update.js b/src/store/quote/update.js index 2298f8a..aacb9db 100644 --- a/src/store/quote/update.js +++ b/src/store/quote/update.js @@ -23,8 +23,9 @@ export default function update(pool) { * @param {string} [patch.number] - The new quote number. * @param {string} [patch.date] - The new quote date. * @param {number} [patch.entityId] - The new customer entity id. + * @param {string} [patch.externalNumber] - The new external (customer) reference number. * @param {Array} [patch.lines] - The new quote lines. - * @returns {Promise<{id: number, number: string, type: string, entityId: number|null, date: string, lines: Array}>} The updated quote. + * @returns {Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array}>} The updated quote. * @throws {Error} If the quote is not found. * * @example @@ -39,9 +40,10 @@ export default function update(pool) { const hasNumber = Object.prototype.hasOwnProperty.call(patch, 'number'); const hasDate = Object.prototype.hasOwnProperty.call(patch, 'date'); const hasEntityId = Object.prototype.hasOwnProperty.call(patch, 'entityId'); + const hasExternalNumber = Object.prototype.hasOwnProperty.call(patch, 'externalNumber'); const hasLines = Object.prototype.hasOwnProperty.call(patch, 'lines'); - if (!hasNumber && !hasDate && !hasEntityId && !hasLines) { + if (!hasNumber && !hasDate && !hasEntityId && !hasExternalNumber && !hasLines) { throw new Error('Invalid quote'); } @@ -95,12 +97,20 @@ export default function update(pool) { ); } + let externalNumber = summary.externalNumber; + if (hasExternalNumber) { + externalNumber = patch.externalNumber?.trim?.() + ? patch.externalNumber.trim() + : null; + } + await request(pool, tx) .input('id', id) .input('companyId', companyId) .input('type', QUOTE_TYPE) .input('number', number) .input('entityId', entityId) + .input('externalNumber', externalNumber) .input('date', date) .query(UPDATE_MANIFEST);