import { DELETE_LINES_BY_MANIFEST as MSSQL_DELETE_LINES, GET_MANIFEST_HEADER as MSSQL_GET_HEADER, ORDER_TYPE as MSSQL_ORDER_TYPE, UPDATE_MANIFEST as MSSQL_UPDATE_MANIFEST, } from '../../providers/mssql/queries/manifestDoc.js'; import { DELETE_LINES_BY_MANIFEST as SQLITE_DELETE_LINES, GET_MANIFEST_HEADER as SQLITE_GET_HEADER, ORDER_TYPE as SQLITE_ORDER_TYPE, UPDATE_MANIFEST as SQLITE_UPDATE_MANIFEST, } from '../../providers/sqlite3/queries/manifestDoc.js'; import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js'; import taxEnsure from '../tax/ensure.js'; import { insertLines, normalizeLines, parseDate } from '../manifestLines.js'; import { assertCustomerEntity, loadDoc, shapeSummary } from '../manifestDoc/helpers.js'; import makeRunner from '../runner.js'; export default function update(provider) { const access = resolveSelectedCompanyAccess(provider); const ensureTax = taxEnsure(provider); const isSqlite = provider?.dialect === 'sqlite3'; const deleteLinesSql = isSqlite ? SQLITE_DELETE_LINES : MSSQL_DELETE_LINES; const getHeaderSql = isSqlite ? SQLITE_GET_HEADER : MSSQL_GET_HEADER; const orderType = isSqlite ? SQLITE_ORDER_TYPE : MSSQL_ORDER_TYPE; const updateManifestSql = isSqlite ? SQLITE_UPDATE_MANIFEST : MSSQL_UPDATE_MANIFEST; /** * Updates an order's header and/or lines. * * @param {number} googleAuthId - The id of the Google auth user. * @param {number} id - The id of the order to update. * @param {object} patch - The update patch. * @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<{sku?: string, name?: string, pu?: number, amount: number, net: number, rebate?: number, taxrate: number, comment?: string|null}>} [patch.lines] - The new order lines. * @param {object} [tx] - Optional transaction to run within. * @returns {Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array<{id: number, sku: string|null, name: string|null, pu: number, amount: number, net: number, rebate: number, taxrate: number, comment: string|null}>}>} The updated order. * @throws {Error} If the order is not found. * * @example * const order = await store.order.update(42, 5, { number: 'B-2026-002', lines: [...] }); * // => { id, number, type, entityId, date, lines: [...] } */ return async (googleAuthId, id, patch = {}, tx) => { if (!Number.isFinite(id)) { throw new Error('Order not found'); } const hasNumber = Object.prototype.hasOwnProperty.call(patch, 'number'); const hasDate = Object.prototype.hasOwnProperty.call(patch, 'date'); const hasCreatedAt = Object.prototype.hasOwnProperty.call(patch, 'createdAt'); 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 && !hasCreatedAt && !hasEntityId && !hasExternalNumber && !hasLines) { throw new Error('Invalid order'); } let normalizedLines; if (hasLines) { normalizedLines = normalizeLines(patch.lines); } const runUpdate = async (runner) => { const { companyId } = await access(googleAuthId, runner); const existing = await runner.query(getHeaderSql, { id, companyId, type: orderType, }); const current = existing.rows[0]; if (!current) { throw new Error('Order not found'); } const summary = shapeSummary(orderType, current); let number = summary.number; if (hasNumber) { number = patch.number?.trim?.() ? patch.number.trim() : null; if (!number) { throw new Error('Invalid order'); } } let date = summary.date; if (hasDate) { date = parseDate(patch.date); if (!date) { throw new Error('Invalid order'); } } let createdAt = summary.createdAt ? parseDate(summary.createdAt) : null; if (hasCreatedAt) { createdAt = parseDate(patch.createdAt); if (!createdAt) { throw new Error('Invalid order'); } } let entityId = summary.entityId; if (hasEntityId) { entityId = await assertCustomerEntity( runner, companyId, patch.entityId ?? null, ); } let externalNumber = summary.externalNumber; if (hasExternalNumber) { externalNumber = patch.externalNumber?.trim?.() ? patch.externalNumber.trim() : null; } await runner.query(updateManifestSql, { id, companyId, type: orderType, number, entityId, externalNumber, date, createdAt, }); if (hasLines) { await runner.query(deleteLinesSql, { manifestId: id, }); await insertLines(runner, { manifestId: id, lines: normalizedLines, ensureTax, }); } const doc = await loadDoc(runner, { type: orderType, companyId, id }); return doc; }; if (tx) { return runUpdate(makeRunner(provider, tx)); } if (typeof provider?.transaction === 'function') { return provider.transaction(runUpdate); } return runUpdate(makeRunner(provider)); }; }