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 * as mssqlAttr from '../../providers/mssql/queries/attributename.js'; import * as sqliteAttr from '../../providers/sqlite3/queries/attributename.js'; import resolveArticleBySku from './resolveArticleBySku.js'; import getBySku from './getBySku.js'; import makeRunner from '../runner.js'; export default function toggleFather(provider) { const resolve = resolveArticleBySku(provider); const load = getBySku(provider); const isSqlite = provider?.dialect === 'sqlite3'; const queries = isSqlite ? sqliteArticle : mssqlArticle; const getChildCountSql = isSqlite ? SQLITE_GET_CHILD_COUNT : MSSQL_GET_CHILD_COUNT; const attrQueries = isSqlite ? sqliteAttr : mssqlAttr; /** * Toggles an article into or out of father mode. * * @param {number} googleAuthId - The id of the Google auth user. * @param {string} sku - The article SKU. * @param {object} options * @param {boolean} options.isFather - Whether the article should be a father article. * @param {number} [options.attributeNameId] - The attribute name id required when enabling father mode. * @param {number} [options.fatherAttributeNameId] - Alias for attributeNameId. * @param {object} [tx] - Optional transaction. * @returns {Promise} The updated article detail. */ return async (googleAuthId, sku, { isFather, attributeNameId, fatherAttributeNameId } = {}, tx) => { const run = async (runner) => { const { articleId, companyId } = await resolve(googleAuthId, sku, runner); const targetIsFather = Boolean(isFather); const targetAttrId = attributeNameId ?? fatherAttributeNameId; if (targetIsFather) { if (!targetAttrId || Number(targetAttrId) <= 0) { throw new Error('attributeNameId is required to become a father article'); } // Verify article is not a child of another article const currentRes = await runner.query( 'SELECT fatherarticle_id FROM article WHERE id = @articleId', { articleId }, ); if (currentRes.rows[0]?.fatherarticle_id != null) { throw new Error('A child article cannot become a father'); } // Verify attribute exists and belongs to company const attrRes = await runner.query(attrQueries.GET_BY_COMPANY_AND_ID, { id: Number(targetAttrId), companyId, }); if (!attrRes.rows[0]) { throw new Error('Attribute name not found'); } await runner.query(queries.TOGGLE_FATHER, { articleId, isFather: 1, fatherAttributeNameId: Number(targetAttrId), }); } else { // Disabling father: verify zero children const childCountRes = await runner.query(getChildCountSql, { articleId }); const childCount = childCountRes.rows[0]?.count ?? 0; if (childCount > 0) { throw new Error('Cannot disable father mode on an article that still has children'); } await runner.query(queries.TOGGLE_FATHER, { articleId, isFather: 0, fatherAttributeNameId: null, }); } return load(googleAuthId, sku, runner); }; if (tx) { return run(makeRunner(provider, tx)); } if (typeof provider?.transaction === 'function') { return provider.transaction(run); } return run(makeRunner(provider)); }; }