u
This commit is contained in:
@@ -78,8 +78,11 @@ export default function addChild(provider) {
|
||||
let finalValue = null;
|
||||
|
||||
if (options.attributeValueId != null) {
|
||||
if (typeof options.attributeValueId !== 'number' || !Number.isInteger(options.attributeValueId) || options.attributeValueId <= 0) {
|
||||
throw new Error('Invalid attributeValueId');
|
||||
}
|
||||
const valRes = await runner.query(attrValQueries.GET_BY_ID_AND_COMPANY, {
|
||||
id: Number(options.attributeValueId),
|
||||
id: options.attributeValueId,
|
||||
companyId,
|
||||
});
|
||||
const row = valRes.rows[0];
|
||||
|
||||
@@ -9,43 +9,71 @@ export default function del(provider) {
|
||||
const queries = isSqlite ? sqliteQueries : mssqlQueries;
|
||||
|
||||
/**
|
||||
* Deletes an article by its SKU, refusing when it still has children.
|
||||
* Deletes an article by its SKU, refusing when it still has children unless cascade is true.
|
||||
*
|
||||
* @param {number} googleAuthId - The id of the Google auth user.
|
||||
* @param {string} sku - The article SKU.
|
||||
* @param {object} [tx] - Optional transaction to run within.
|
||||
* @param {object|*} [optionsOrTx] - Options object ({ cascade?: boolean }) or optional transaction.
|
||||
* @param {object} [maybeTx] - Optional transaction if options was passed.
|
||||
* @returns {Promise<void>}
|
||||
* @throws {Error} If the article has children or is not found.
|
||||
* @throws {Error} If the article has children (when cascade=false) or is not found.
|
||||
*
|
||||
* @example
|
||||
* await store.article.delete(42, 'SKU-1');
|
||||
* await store.article.delete(42, 'SKU-1', { cascade: true });
|
||||
*/
|
||||
return async (googleAuthId, sku, tx) => {
|
||||
return async (googleAuthId, sku, optionsOrTx, maybeTx) => {
|
||||
let options = {};
|
||||
let tx;
|
||||
if (optionsOrTx && typeof optionsOrTx === 'object' && typeof optionsOrTx.query !== 'function') {
|
||||
options = optionsOrTx;
|
||||
tx = maybeTx;
|
||||
} else {
|
||||
tx = optionsOrTx;
|
||||
}
|
||||
const cascade = Boolean(options.cascade);
|
||||
|
||||
const runDelete = async (runner) => {
|
||||
const { articleId } = await resolve(googleAuthId, sku, runner);
|
||||
|
||||
const deleteArticleAndLists = async (id) => {
|
||||
const listIds = await runner.query(queries.GET_LIST_IDS, { articleId: id });
|
||||
const { articlelistId, optionslistId } = listIds.rows[0] ?? {};
|
||||
|
||||
await runner.query(queries.DELETE_PICS_BY_ARTICLE, { articleId: id });
|
||||
|
||||
const deleted = await runner.query(queries.DELETE_BY_ID, { articleId: id });
|
||||
if (!deleted.rowsAffected) {
|
||||
throw new Error('Article not found');
|
||||
}
|
||||
|
||||
if (articlelistId != null) {
|
||||
await runner.query(queries.DELETE_ARTICLELIST, { id: articlelistId });
|
||||
}
|
||||
|
||||
if (optionslistId != null) {
|
||||
await runner.query(queries.DELETE_OPTIONSLIST, { id: optionslistId });
|
||||
}
|
||||
};
|
||||
|
||||
const deleteSubtree = async (id) => {
|
||||
const children = await runner.query(queries.GET_CHILDREN_IDS, { id });
|
||||
for (const child of children.rows) {
|
||||
await deleteSubtree(child.id);
|
||||
}
|
||||
await deleteArticleAndLists(id);
|
||||
};
|
||||
|
||||
const childCount = await runner.query(queries.GET_CHILD_COUNT, { articleId });
|
||||
if (childCount.rows[0].count > 0) {
|
||||
throw new Error('Article has children');
|
||||
if (!cascade) {
|
||||
throw new Error('Article has children');
|
||||
}
|
||||
await deleteSubtree(articleId);
|
||||
return;
|
||||
}
|
||||
|
||||
const listIds = await runner.query(queries.GET_LIST_IDS, { articleId });
|
||||
const { articlelistId, optionslistId } = listIds.rows[0] ?? {};
|
||||
|
||||
await runner.query(queries.DELETE_PICS_BY_ARTICLE, { articleId });
|
||||
|
||||
const deleted = await runner.query(queries.DELETE_BY_ID, { articleId });
|
||||
if (!deleted.rowsAffected) {
|
||||
throw new Error('Article not found');
|
||||
}
|
||||
|
||||
if (articlelistId != null) {
|
||||
await runner.query(queries.DELETE_ARTICLELIST, { id: articlelistId });
|
||||
}
|
||||
|
||||
if (optionslistId != null) {
|
||||
await runner.query(queries.DELETE_OPTIONSLIST, { id: optionslistId });
|
||||
}
|
||||
await deleteArticleAndLists(articleId);
|
||||
};
|
||||
|
||||
if (tx) {
|
||||
|
||||
@@ -22,6 +22,7 @@ export default function removeChild(provider) {
|
||||
* @param {string} childSku - The child article SKU.
|
||||
* @param {object} [options]
|
||||
* @param {boolean} [options.deleteArticle=false] - Whether to delete the child article entity entirely.
|
||||
* @param {boolean} [options.cascade=true] - Whether to cascade delete child subtrees when deleteArticle is true.
|
||||
* @param {object} [tx] - Optional transaction.
|
||||
* @returns {Promise<{success: boolean, fatherSku: string, childSku: string, deleted: boolean}>}
|
||||
*/
|
||||
@@ -45,7 +46,8 @@ export default function removeChild(provider) {
|
||||
}
|
||||
|
||||
if (options.deleteArticle) {
|
||||
await del(googleAuthId, childSku, runner);
|
||||
const cascade = options.cascade !== undefined ? Boolean(options.cascade) : true;
|
||||
await del(googleAuthId, childSku, { cascade }, runner);
|
||||
return {
|
||||
success: true,
|
||||
fatherSku,
|
||||
|
||||
@@ -40,8 +40,8 @@ export default function setBrandIdBySku(provider) {
|
||||
runner,
|
||||
);
|
||||
|
||||
if (brandId !== null && !Number.isFinite(brandId)) {
|
||||
throw new Error('Brand not found');
|
||||
if (brandId !== null && (typeof brandId !== 'number' || !Number.isInteger(brandId) || brandId <= 0)) {
|
||||
throw new Error('Invalid brandId');
|
||||
}
|
||||
|
||||
let resolvedBrandId = null;
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
ADD_EAN as SQLITE_ADD_EAN,
|
||||
DELETE_EANS_BY_ARTICLE as SQLITE_DELETE_EANS,
|
||||
} from '../../providers/sqlite3/queries/article.js';
|
||||
import { isUniqueConstraintError } from '../../providers/provider.js';
|
||||
import queryBySku from './queryBySku.js';
|
||||
import resolveArticleBySku from './resolveArticleBySku.js';
|
||||
import makeRunner from '../runner.js';
|
||||
@@ -55,8 +56,15 @@ export default function setEansBySku(provider) {
|
||||
|
||||
await runner.query(deleteEansSql, { articleId });
|
||||
|
||||
for (const ean of normalized) {
|
||||
await runner.query(addEanSql, { articleId, ean });
|
||||
try {
|
||||
for (const ean of normalized) {
|
||||
await runner.query(addEanSql, { articleId, ean });
|
||||
}
|
||||
} catch (err) {
|
||||
if (isUniqueConstraintError(err)) {
|
||||
throw new Error('EAN already in use');
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
||||
const article = await load(articleId, languageId, runner);
|
||||
|
||||
@@ -27,10 +27,11 @@ function normalizePrices(prices) {
|
||||
? 1
|
||||
: entry.minmultiplier;
|
||||
|
||||
if (!Number.isFinite(price) || !Number.isFinite(tax) || !Number.isFinite(minmultiplier)) {
|
||||
throw new Error('Invalid prices');
|
||||
}
|
||||
if (minmultiplier <= 0) {
|
||||
if (
|
||||
typeof price !== 'number' || !Number.isFinite(price) || price < 0 ||
|
||||
typeof tax !== 'number' || !Number.isFinite(tax) || tax < 0 ||
|
||||
typeof minmultiplier !== 'number' || !Number.isFinite(minmultiplier) || minmultiplier <= 0
|
||||
) {
|
||||
throw new Error('Invalid prices');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user