import { CREATE_LINE as MSSQL_CREATE_LINE } from '../providers/mssql/queries/manifestDoc.js'; import { CREATE_LINE as SQLITE_CREATE_LINE } from '../providers/sqlite3/queries/manifestDoc.js'; import makeRunner from './runner.js'; /** * Normalizes and validates an array of manifest line inputs. * * @param {Array} lines - The raw line inputs. * @returns {Array<{sku: string|null, name: string|null, pu: number, amount: number, net: number, rebate: number, taxrate: number, comment: string|null}>} The normalized lines. * @throws {Error} If the lines are invalid. */ export function normalizeLines(lines) { if (!Array.isArray(lines)) { throw new Error('Invalid lines'); } return lines.map((entry) => { const sku = entry?.sku?.trim?.() ? entry.sku.trim() : null; const name = entry?.name?.trim?.() ? entry.name.trim() : null; // Must have either an SKU or a name. if (!sku && !name) { throw new Error('Invalid lines'); } const pu = entry?.pu === undefined || entry?.pu === null ? 1 : entry.pu; const amount = entry?.amount; const net = entry?.net; const rebate = entry?.rebate === undefined || entry?.rebate === null ? 0 : entry.rebate; const taxrate = entry?.taxrate; const comment = entry?.comment === undefined || entry?.comment === null ? null : String(entry.comment); if ( !Number.isFinite(pu) || !Number.isFinite(amount) || !Number.isFinite(net) || !Number.isFinite(rebate) || !Number.isFinite(taxrate) ) { throw new Error('Invalid lines'); } return { sku, name, pu, amount, net, rebate, taxrate, comment }; }); } /** * Parses a date value (Date instance or ISO string) into a Date. * * @param {Date|string} value - The date value. * @returns {Date|null} The parsed date, or null if invalid. */ export function parseDate(value) { if (value instanceof Date && !Number.isNaN(value.getTime())) { return value; } if (typeof value === 'string' && value.trim()) { const d = new Date(value); if (!Number.isNaN(d.getTime())) { return d; } } return null; } /** * Shapes a manifestarticle row into a line object. * * @param {object} row - The manifestarticle row. * @returns {object} The shaped line. */ export function shapeLine(row) { const taxrate = Number(row.taxrate); return { id: row.id, sku: row.sku ?? null, name: row.name ?? null, pu: row.pu !== undefined && row.pu !== null ? Number(row.pu) : 1, amount: row.amount, net: row.net, rebate: row.rebate, taxrate, comment: row.comment ?? null, }; } /** * Inserts manifest lines for a document, storing each SKU and taxrate directly, * and ensuring the tax rate exists in the tax catalog. * * @param {object} runnerOrPool - The runner or mssql connection pool. * @param {object} txOrParams - The transaction or params object. * @param {object} [maybeParams] - The insert parameters. * @returns {Promise} */ export async function insertLines( runnerOrPool, txOrParams, maybeParams, ) { let runner; let params; if (maybeParams !== undefined) { runner = makeRunner(runnerOrPool, txOrParams); params = maybeParams; } else { runner = makeRunner(runnerOrPool); params = txOrParams; } const { manifestId, lines, ensureTax } = params; const isSqlite = runner?.dialect === 'sqlite3'; const createLineSql = isSqlite ? SQLITE_CREATE_LINE : MSSQL_CREATE_LINE; for (const line of lines) { if (ensureTax) { await ensureTax(line.taxrate, runner); } await runner.query(createLineSql, { manifestId, sku: line.sku ?? null, name: line.name ?? null, pu: line.pu ?? 1, amount: line.amount, net: line.net, comment: line.comment, rebate: line.rebate, taxrate: line.taxrate, }); } }