- Rewrite JSDoc across all store methods to document the actual async methods (real params, returns, throws) instead of the internal wrappers - Split quote/order into individual module files backed by shared manifestDoc helpers; remove the createStore factory and thin wrappers - Deduplicate manifest line helpers into src/store/manifestLines.js - Extend generate-api-doc.js to render parameter/return/throws types and emit per-namespace API.<module>.md files with an API.md index - Regenerate all API docs
179 lines
5.5 KiB
JavaScript
179 lines
5.5 KiB
JavaScript
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<object>} 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;
|
|
};
|
|
}
|