Files
dashlibstorage/src/store/manifestLines.js
2026-09-22 07:25:16 +02:00

140 lines
3.8 KiB
JavaScript

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<object>} 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<void>}
*/
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,
});
}
}