import { CREATE_MANIFEST as MSSQL_CREATE_MANIFEST, RETOURE_TYPE as MSSQL_RETOURE_TYPE, } from '../../providers/mssql/queries/manifestDoc.js'; import { CREATE_MANIFEST as SQLITE_CREATE_MANIFEST, RETOURE_TYPE as SQLITE_RETOURE_TYPE, } from '../../providers/sqlite3/queries/manifestDoc.js'; import { FIND_ARTICLES_FOR_HISTORY as MSSQL_FIND_ARTICLES, } from '../../providers/mssql/queries/ledger.js'; import { FIND_ARTICLES_FOR_HISTORY as SQLITE_FIND_ARTICLES, } from '../../providers/sqlite3/queries/ledger.js'; import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js'; import taxEnsure from '../tax/ensure.js'; import { insertLines, normalizeLines, parseDate } from '../manifestLines.js'; import { assertCustomerEntity, assertUniqueManifestNumber, loadDoc } from '../manifestDoc/helpers.js'; import { syncRetoureSummary } from './syncSummary.js'; import { ensureNumberType } from '../numbers/ensureType.js'; import makeRunner from '../runner.js'; export default function create(provider) { const access = resolveSelectedCompanyAccess(provider); const ensureTax = taxEnsure(provider); const isSqlite = provider?.dialect === 'sqlite3'; const createManifestSql = isSqlite ? SQLITE_CREATE_MANIFEST : MSSQL_CREATE_MANIFEST; const retoureType = isSqlite ? SQLITE_RETOURE_TYPE : MSSQL_RETOURE_TYPE; const findArticlesSql = isSqlite ? SQLITE_FIND_ARTICLES : MSSQL_FIND_ARTICLES; /** * Creates a new retoure for the user's selected company with its lines. * * @param {number} googleAuthId - The id of the Google auth user. * @param {object} body - The retoure input. * @param {string} [body.number] - The retoure number. * @param {string} body.date - The retoure date. * @param {number} [body.entityId] - The id of the customer entity. * @param {string} [body.externalNumber] - An external reference number. * @param {Array} [body.lines] - The retoure lines. * @param {object} [tx] - Optional transaction to run within. * @returns {Promise} The created retoure. */ return async (googleAuthId, body = {}, tx) => { const date = parseDate(body.date); if (!date) { throw new Error('Invalid retoure'); } const createdAt = body.createdAt ? parseDate(body.createdAt) : new Date(); if (body.createdAt && !createdAt) { throw new Error('Invalid retoure'); } const externalNumber = body.externalNumber?.trim?.() ? body.externalNumber.trim() : null; const lines = normalizeLines(body.lines ?? []); const runCreate = async (runner) => { const { companyId, companyuserId } = await access(googleAuthId, runner); let entityId = null; if (body.entityId != null) { entityId = await assertCustomerEntity( runner, companyId, body.entityId, ); } let number = body.number?.trim?.() ? body.number.trim() : null; if (!number) { const seq = await ensureNumberType(runner, companyId, 'retoure'); const numVal = seq.next ?? 1; number = (seq.prefix || 'RET-') + (seq.padding > 0 ? String(numVal).padStart(seq.padding, '0') : String(numVal)); await runner.query( isSqlite ? 'UPDATE numbers SET "next" = "next" + 1 WHERE id = @id' : 'UPDATE numbers SET [next] = [next] + 1 WHERE id = @id', { id: seq.id }, ); } await assertUniqueManifestNumber(runner, { companyId, type: retoureType, number, errorMessage: 'Retoure number already exists', }); const created = await runner.query(createManifestSql, { companyId, number, type: retoureType, entityId, externalNumber, date, createdAt, }); const manifestId = created.rows[0]?.id ?? created.insertId; await insertLines(runner, { manifestId, lines, ensureTax, }); const doc = await loadDoc(runner, { type: retoureType, companyId, id: manifestId, }); await syncRetoureSummary(runner, { companyId, manifestId }); return doc; }; if (tx) { return runCreate(makeRunner(provider, tx)); } if (typeof provider?.transaction === 'function') { return provider.transaction(runCreate); } return runCreate(makeRunner(provider)); }; }