import * as mssqlArticle from '../../providers/mssql/queries/article.js'; import * as sqliteArticle from '../../providers/sqlite3/queries/article.js'; import { GET_CHILD_COUNT as MSSQL_GET_CHILD_COUNT } from '../../providers/mssql/queries/articleDelete.js'; import { GET_CHILD_COUNT as SQLITE_GET_CHILD_COUNT } from '../../providers/sqlite3/queries/articleDelete.js'; import { INSERT as MSSQL_INSERT_HISTORY } from '../../providers/mssql/queries/articlehistory.js'; import { INSERT as SQLITE_INSERT_HISTORY } from '../../providers/sqlite3/queries/articlehistory.js'; import queryBySku from './queryBySku.js'; import resolveArticleBySku from './resolveArticleBySku.js'; import makeRunner from '../runner.js'; export default function setFatherBySku(provider) { const resolve = resolveArticleBySku(provider); const load = queryBySku(provider); const isSqlite = provider?.dialect === 'sqlite3'; const queries = isSqlite ? sqliteArticle : mssqlArticle; const getChildCountSql = isSqlite ? SQLITE_GET_CHILD_COUNT : MSSQL_GET_CHILD_COUNT; const insertHistorySql = isSqlite ? SQLITE_INSERT_HISTORY : MSSQL_INSERT_HISTORY; /** * Links an article to a father article (V/K compound) by their SKUs. * * @param {number} googleAuthId - The id of the Google auth user. * @param {string} sku - The child article SKU. * @param {string|null} fatherSku - The father article SKU, or `null` to unlink. * @param {object} [tx] - Optional transaction to run within. * @returns {Promise} The updated child article. * @throws {Error} If the article or father is not found, or the link is invalid. * * @example * const article = await store.article.setFatherBySku(42, '42001190-1', '42001190'); * // => { id, sku, name, fatherSku: '42001190', ... } */ return async (googleAuthId, sku, fatherSku, tx) => { const runSet = async (runner) => { const { articleId, languageId, companyId, companyuserId } = await resolve(googleAuthId, sku, runner); const childTextRes = await runner.query( 'SELECT name FROM articletext WHERE article_id = @articleId AND language_id = @languageId', { articleId, languageId }, ); const childName = childTextRes.rows[0]?.name || sku; if (fatherSku == null || fatherSku === '') { const prevFatherRes = await runner.query( 'SELECT fatherarticle_id FROM article WHERE id = @articleId', { articleId }, ); const prevFatherId = prevFatherRes.rows[0]?.fatherarticle_id; await runner.query(queries.UPDATE_FATHER_BY_SKU, { sku, companyId, fatherArticleId: null, }); if (prevFatherId) { const prevFatherTextRes = await runner.query( 'SELECT sku FROM article WHERE id = @prevFatherId', { prevFatherId }, ); const prevFatherSku = prevFatherTextRes.rows[0]?.sku || String(prevFatherId); await runner.query(insertHistorySql, { articleId, companyuserId, text: `Artikel "${sku}" von Vaterartikel "${prevFatherSku}" getrennt`, }); await runner.query(insertHistorySql, { articleId: prevFatherId, companyuserId, text: `Variante "${childName}" (${sku}) getrennt`, }); } const unlinked = await load(articleId, languageId, runner); if (!unlinked) { throw new Error('Article not found'); } return unlinked; } const father = await runner.query( 'SELECT id, is_father, sku FROM article WHERE sku = @sku AND (@companyId IS NULL OR company_id = @companyId)', { sku: fatherSku, companyId }, ); const fatherRow = father.rows[0]; const fatherId = fatherRow?.id; if (!fatherId) { throw new Error('Father not found'); } if (fatherId === articleId) { throw new Error('Invalid father'); } const wasFather = Boolean(fatherRow.is_father); const existingSortsRes = await runner.query( 'SELECT fathersort FROM article WHERE fatherarticle_id = @fatherId ORDER BY fathersort ASC', { fatherId }, ); const usedSorts = new Set(existingSortsRes.rows.map((r) => Number(r.fathersort))); let fathersort = 0; while (usedSorts.has(fathersort)) { fathersort++; } await runner.query(queries.UPDATE_FATHER_BY_SKU, { sku, companyId, fatherArticleId: fatherId, fathersort, }); await runner.query(queries.SET_IS_FATHER, { articleId: fatherId, }); if (!wasFather) { await runner.query(insertHistorySql, { articleId: fatherId, companyuserId, text: 'Artikel zu Vaterartikel konvertiert', }); } await runner.query(insertHistorySql, { articleId: fatherId, companyuserId, text: `Variante "${childName}" (${sku}) hinzugefügt`, }); await runner.query(insertHistorySql, { articleId, companyuserId, text: `Artikel "${sku}" als Variante von "${fatherSku}" zugewiesen`, }); const article = await load(articleId, languageId, runner); if (!article) { throw new Error('Article not found'); } return article; }; if (tx) { return runSet(makeRunner(provider, tx)); } if (typeof provider?.transaction === 'function') { return provider.transaction(runSet); } return runSet(makeRunner(provider)); }; }