import { UPDATE_UNIT, UPDATE_UNITAMOUNT, UPDATE_UNIT_AND_AMOUNT, } from '../../sql/article.js'; import { INSERT as INSERT_HISTORY } from '../../sql/articlehistory.js'; import { UPDATE_BY_ARTICLE_AND_LANGUAGE } from '../../sql/articletext.js'; import { GET_DETAIL_BY_ARTICLE_ID } from '../../sql/articleDetail.js'; import { GET_FULL_BY_SI } from '../../sql/unit.js'; import request from '../request.js'; import queryBySku from './queryBySku.js'; import resolveArticleBySku from './resolveArticleBySku.js'; import slugify from '../slugify.js'; function formatUnitLabel(amount, symbol) { const sym = symbol ?? ''; if (amount == null || !Number.isFinite(Number(amount))) { return sym; } return `${Number(amount)}${sym}`; } export default function updateBySku(pool) { const resolve = resolveArticleBySku(pool); const load = queryBySku(pool); /** * Updates an article's name and/or unit (SI and amount), recording history. * * @param {number} googleAuthId - The id of the Google auth user. * @param {string} sku - The article SKU. * @param {object} patch - The update patch. * @param {string} [patch.name] - The new article name. * @param {string} [patch.unitSi] - The new unit SI code. * @param {number} [patch.unitamount] - The new unit amount (must be > 0). * @returns {Promise} The updated article. * @throws {Error} If no valid field is provided or the article is not found. * * @example * const article = await store.article.updateBySku(42, 'SKU-1', { name: 'Cola 1L', unitSi: 'l', unitamount: 1 }); * // => { id, sku, name, ... } */ return async (googleAuthId, sku, patch = {}) => { const hasName = Object.prototype.hasOwnProperty.call(patch, 'name'); const hasUnitamount = Object.prototype.hasOwnProperty.call(patch, 'unitamount'); const hasUnitSi = Object.prototype.hasOwnProperty.call(patch, 'unitSi'); if (!hasName && !hasUnitamount && !hasUnitSi) { throw new Error('Name required'); } if (hasName && !patch.name?.trim()) { throw new Error('Name required'); } if (hasUnitamount && (!Number.isFinite(patch.unitamount) || patch.unitamount <= 0)) { throw new Error('Invalid unitamount'); } const { articleId, languageId, companyId, companyuserId } = await resolve( googleAuthId, sku, ); const currentResult = await pool .request() .input('articleId', articleId) .input('languageId', languageId) .query(GET_DETAIL_BY_ARTICLE_ID); const current = currentResult.recordset[0]; if (!current) { throw new Error('Article not found'); } let unitId; let newUnitSymbol = current.unitSymbol ?? current.unitSi ?? ''; if (hasUnitSi) { if (!patch.unitSi?.trim()) { throw new Error('Unit not found'); } const unit = await pool .request() .input('companyId', companyId) .input('si', patch.unitSi.trim()) .input('languageId', languageId) .query(GET_FULL_BY_SI); const unitRow = unit.recordset[0]; unitId = unitRow?.id; if (!unitId) { throw new Error('Unit not found'); } newUnitSymbol = unitRow.symbol ?? unitRow.si ?? ''; } const historyLines = []; if (hasName) { const oldName = current.name ?? ''; const newName = patch.name.trim(); if (oldName !== newName) { historyLines.push(`Name geändert von "${oldName}" auf "${newName}"`); } } if (hasUnitSi || hasUnitamount) { const oldLabel = formatUnitLabel( current.unitamount, current.unitSymbol ?? current.unitSi ?? '', ); const newLabel = formatUnitLabel( hasUnitamount ? patch.unitamount : current.unitamount, newUnitSymbol, ); if (oldLabel !== newLabel) { historyLines.push(`Einheit geändert von "${oldLabel}" auf "${newLabel}"`); } } const tx = pool.transaction(); await tx.begin(); try { if (hasName) { const slug = slugify(patch.name); const update = await request(pool, tx) .input('articleId', articleId) .input('languageId', languageId) .input('name', patch.name.trim()) .input('slug', slug) .query(UPDATE_BY_ARTICLE_AND_LANGUAGE); if (!update.rowsAffected[0]) { throw new Error('Article not found'); } } if (hasUnitSi && hasUnitamount) { await request(pool, tx) .input('articleId', articleId) .input('unitId', unitId) .input('unitamount', patch.unitamount) .query(UPDATE_UNIT_AND_AMOUNT); } else if (hasUnitSi) { await request(pool, tx) .input('articleId', articleId) .input('unitId', unitId) .query(UPDATE_UNIT); } else if (hasUnitamount) { await request(pool, tx) .input('articleId', articleId) .input('unitamount', patch.unitamount) .query(UPDATE_UNITAMOUNT); } if (historyLines.length) { await request(pool, tx) .input('articleId', articleId) .input('companyuserId', companyuserId) .input('text', historyLines.join('\n')) .query(INSERT_HISTORY); } await tx.commit(); } catch (err) { try { await tx.rollback(); } catch { // ignore } throw err; } const article = await load(articleId, languageId); if (!article) { throw new Error('Article not found'); } return article; }; }