import { DELETE_PRICE, GET_BY_ID_AND_ARTICLE_ID, UPDATE as UPDATE_ARTICLE_SUPPLIER, UPDATE_PRICE, } from '../../sql/articlesupplier.js'; import { CREATE as CREATE_PRICE } from '../../sql/price.js'; import request from '../request.js'; import resolveArticleBySku from '../article/resolveArticleBySku.js'; import ensureLieferantenGroup from '../supplier/ensureLieferantenGroup.js'; import taxEnsure from '../tax/ensure.js'; import { optionalString, resolveCompanyDefaultTax, shapeArticleSupplier, } from './helpers.js'; export default function update(pool) { const resolve = resolveArticleBySku(pool); const ensureTax = taxEnsure(pool); /** * Updates an existing supplier assignment and its associated purchase price. * * @param {number} googleAuthId - The id of the Google auth user. * @param {string} sku - The article SKU. * @param {number} id - The id of the articlesupplier record. * @param {object} patch - The fields to update. * @param {string|null} [patch.sku] - The supplier's item number/SKU. * @param {number} [patch.pu] - Packaging unit (> 0). * @param {number|null} [patch.stock] - Current stock at the supplier. * @param {number|null} [patch.netPrice] - Net purchase price. * @param {number} [patch.taxId] - The tax id for the purchase price. * @param {number} [patch.taxRate] - The tax rate in percent. * @returns {Promise<{id: number, articleId: number, entityId: number, supplierName: string|null, sku: string|null, pu: number, stock: number|null, priceId: number|null, price: {net: number, taxId: number, taxRate?: number}|null}>} The updated assignment. * @throws {Error} If input is invalid or supplier assignment is not found. * * @example * const updated = await store.articlesupplier.update(42, 'SKU-1', 12, { * sku: 'MET-44910-B', * pu: 6, * netPrice: 22.50, * }); * // => { id, articleId, entityId, supplierName, sku, pu, stock, priceId, price } */ return async (googleAuthId, sku, id, patch = {}) => { if (id == null || !Number.isFinite(id)) { throw new Error('Supplier assignment not found'); } if (patch.pu !== undefined) { if (!Number.isFinite(patch.pu) || patch.pu <= 0) { throw new Error('Invalid pu'); } } if (patch.stock !== undefined && patch.stock !== null) { if (!Number.isFinite(patch.stock)) { throw new Error('Invalid stock'); } } if (patch.netPrice !== undefined && patch.netPrice !== null) { if (!Number.isFinite(patch.netPrice)) { throw new Error('Invalid price'); } } const { articleId, companyId } = await resolve(googleAuthId, sku); const existingRes = await pool .request() .input('id', id) .input('articleId', articleId) .input('companyId', companyId) .query(GET_BY_ID_AND_ARTICLE_ID); const existing = existingRes.recordset[0]; if (!existing) { throw new Error('Supplier assignment not found'); } const tx = pool.transaction(); await tx.begin(); try { let priceId = existing.priceId; if (patch.netPrice !== undefined) { if (patch.netPrice === null) { if (priceId != null) { const oldPriceId = priceId; priceId = null; await request(pool, tx) .input('id', id) .input('articleId', articleId) .input('sku', existing.sku) .input('stock', existing.stock) .input('pu', existing.pu) .input('priceId', null) .query(UPDATE_ARTICLE_SUPPLIER); await request(pool, tx) .input('id', oldPriceId) .input('articleId', articleId) .query(DELETE_PRICE); } } else { // netPrice is a valid number if (priceId != null) { let taxId = patch.taxId; if (taxId == null || !Number.isFinite(taxId)) { if (patch.taxRate != null && Number.isFinite(patch.taxRate)) { taxId = await ensureTax(patch.taxRate, tx); } else { taxId = existing.priceTaxId; } } await request(pool, tx) .input('id', priceId) .input('articleId', articleId) .input('net', patch.netPrice) .input('taxId', taxId) .query(UPDATE_PRICE); } else { // create new price row let taxId = patch.taxId; if (taxId == null || !Number.isFinite(taxId)) { if (patch.taxRate != null && Number.isFinite(patch.taxRate)) { taxId = await ensureTax(patch.taxRate, tx); } else { const defaultTaxId = await resolveCompanyDefaultTax( pool, tx, companyId, ); taxId = defaultTaxId != null ? defaultTaxId : await ensureTax(0, tx); } } const customerGroupId = await ensureLieferantenGroup( pool, companyId, tx, ); const priceRes = await request(pool, tx) .input('taxId', taxId) .input('articleId', articleId) .input('minmultiplier', 1) .input('customerGroupId', customerGroupId) .input('net', patch.netPrice) .query(CREATE_PRICE); priceId = priceRes.recordset[0].id; } } } const nextSku = patch.sku !== undefined ? optionalString(patch.sku) : existing.sku; const nextStock = patch.stock !== undefined ? patch.stock === null ? null : patch.stock : existing.stock; const nextPu = patch.pu !== undefined ? patch.pu : existing.pu; await request(pool, tx) .input('id', id) .input('articleId', articleId) .input('sku', nextSku) .input('stock', nextStock) .input('pu', nextPu) .input('priceId', priceId) .query(UPDATE_ARTICLE_SUPPLIER); await tx.commit(); const loadRes = await pool .request() .input('id', id) .input('articleId', articleId) .input('companyId', companyId) .query(GET_BY_ID_AND_ARTICLE_ID); return shapeArticleSupplier(loadRes.recordset[0]); } catch (err) { try { await tx.rollback(); } catch { // ignore } throw err; } }; }