export const ARTICLE_LIST_JOINS = ` LEFT JOIN articletext at ON at.article_id = a.id AND at.language_id = @languageId LEFT JOIN price pr ON pr.article_id = a.id AND pr.customergroup_id = @posCustomerGroupId AND pr.minmultiplier = 1 LEFT JOIN tax t ON t.id = pr.tax_id OUTER APPLY ( SELECT TOP 1 ap.pic_id FROM articlepic ap WHERE ap.article_id = a.id ORDER BY ap.sort ASC, ap.id ASC ) first_pic LEFT JOIN pic ON pic.id = first_pic.pic_id LEFT JOIN article father ON father.id = a.fatherarticle_id `; export const ARTICLE_LIST_COLUMNS = ` a.id, a.sku, at.name, at.slug, pr.net, t.rate AS taxRate, CASE WHEN a.optionslist_id IS NOT NULL THEN ( SELECT COUNT(*) FROM optionslistarticle ola WHERE ola.optionslist_id = a.optionslist_id ) ELSE 0 END AS optionsCount, CASE WHEN a.articlelist_id IS NOT NULL THEN ( SELECT COUNT(*) FROM articlelistarticle ala WHERE ala.articlelist_id = a.articlelist_id ) ELSE 0 END AS articleListCount, ( SELECT COUNT(*) FROM article child WHERE child.fatherarticle_id = a.id ) AS childCount, a.fatherarticle_id AS fatherArticleId, father.sku AS fatherSku, pic.hash AS fullHash, pic.thumbw AS thumbW, pic.thumbh AS thumbH, pic.thumbhash AS thumbHash `; export const GET_CATEGORY_ID_BY_SKU = ` SELECT TOP 1 ca.category_id AS categoryId, a.id AS articleId FROM article a INNER JOIN categoryarticle ca ON ca.article_id = a.id WHERE a.sku = @sku AND (@companyId IS NULL OR a.company_id = @companyId) `; /** Resolve an article id by sku (used to wire father/child compound links). */ export const GET_ID_BY_SKU = ` SELECT TOP 1 id AS articleId FROM article WHERE sku = @sku AND (@companyId IS NULL OR company_id = @companyId) `; /** True if an EAN is already assigned to any article (duplicate guard). */ export const EAN_EXISTS = ` SELECT TOP 1 1 AS used FROM articleean WHERE ean = @ean `; /** Link an article to its father article and mark the father. */ export const UPDATE_FATHER_BY_SKU = ` UPDATE article SET fatherarticle_id = @fatherArticleId, fathersort = COALESCE(@fathersort, 0) WHERE sku = @sku AND (@companyId IS NULL OR company_id = @companyId) `; export const SET_IS_FATHER = ` UPDATE article SET is_father = 1 WHERE id = @articleId `; export const SET_FATHER_SORT = ` UPDATE article SET fathersort = @fathersort WHERE id = @articleId AND fatherarticle_id = @fatherArticleId `; /** SKU → article/category + company auth in one round-trip. */ export const RESOLVE_ARTICLE_ACCESS_BY_SKU = ` SELECT TOP 1 a.id AS articleId, ca.category_id AS categoryId, co.root_category_id AS rootCategoryId, co.id AS companyId, co.default_language_id AS languageId, co.poscustomergroup_id AS posCustomerGroupId, cu.id AS companyuserId FROM article a INNER JOIN company co ON co.id = a.company_id INNER JOIN google_auth ga ON ga.id = @googleAuthId INNER JOIN companyuser cu ON cu.company_id = a.company_id AND cu.google_auth_id = @googleAuthId LEFT JOIN categoryarticle ca ON ca.article_id = a.id WHERE a.sku = @sku AND (ga.selected_company IS NULL OR a.company_id = ga.selected_company) `; export const UPDATE_WEIGHT = ` UPDATE article SET weight = @weight WHERE id = @articleId `; export const UPDATE_BRAND = ` UPDATE article SET brand_id = @brandId WHERE id = @articleId `; export const UPDATE_UNIT = ` UPDATE article SET unit_id = @unitId WHERE id = @articleId `; export const UPDATE_UNITAMOUNT = ` UPDATE article SET unitamount = @unitamount WHERE id = @articleId `; export const UPDATE_UNIT_AND_AMOUNT = ` UPDATE article SET unit_id = @unitId, unitamount = @unitamount WHERE id = @articleId `; export const CREATE = ` INSERT INTO article (company_id, sku, unit_id, unitamount, weight) OUTPUT INSERTED.id VALUES (@companyId, @sku, @unitId, @unitamount, @weight) `; export const DELETE_EANS_BY_ARTICLE = ` DELETE FROM articleean WHERE article_id = @articleId `; export const ADD_EAN = ` INSERT INTO articleean (article_id, ean) VALUES (@articleId, @ean) `; export const DELETE_CATEGORIES_BY_ARTICLE = ` DELETE FROM categoryarticle WHERE article_id = @articleId `; export const ADD_CATEGORY = ` INSERT INTO categoryarticle (category_id, article_id) VALUES (@categoryId, @articleId) `; export const GET_BRAND_BY_COMPANY_AND_ID = ` SELECT id FROM brand WHERE id = @brandId AND company_id = @companyId `; /** * Company-wide article search index. * Returns one row per article with id, sku, name, and all eans as a JSON array. * Used by the client for local search / autocomplete. */ export const SEARCH_ARTICLES = ` ;WITH category_tree AS ( SELECT id FROM category WHERE id = @rootCategoryId UNION ALL SELECT c.id FROM category c INNER JOIN category_tree ct ON c.parent_id = ct.id ) SELECT a.id, a.sku, at.name, ( SELECT ae.ean FROM articleean ae WHERE ae.article_id = a.id ORDER BY ae.ean FOR JSON PATH ) AS eansJson, ( SELECT ca2.category_id FROM categoryarticle ca2 WHERE ca2.article_id = a.id ORDER BY ca2.category_id FOR JSON PATH ) AS categoryIdsJson FROM article a LEFT JOIN articletext at ON at.article_id = a.id AND at.language_id = @languageId WHERE EXISTS ( SELECT 1 FROM categoryarticle ca INNER JOIN category_tree ct ON ct.id = ca.category_id WHERE ca.article_id = a.id ) ORDER BY a.id `; /** * Flat category tree (id, parentId, name) for a root category, used to resolve * breadcrumbs for the article export. */ export const GET_CATEGORY_TREE_FLAT = ` ;WITH tree AS ( SELECT id, parent_id, sort FROM category WHERE id = @rootId UNION ALL SELECT c.id, c.parent_id, c.sort FROM category c INNER JOIN tree t ON c.parent_id = t.id ) SELECT t.id, t.parent_id AS parentId, ct.name FROM tree t LEFT JOIN categorytext ct ON ct.category_id = t.id AND ct.language_id = @languageId `; /** * Export rows for every article in a category subtree (root = @categoryId). * One row per article with the columns used by the export CSV, including the * POS price (minmultiplier = 1 for the company poscustomergroup), brand, unit, * eans, categoryIds and all photo hashes as JSON arrays. */ export const GET_ARTICLE_EXPORT = ` ;WITH category_tree AS ( SELECT id FROM category WHERE id = @categoryId UNION ALL SELECT c.id FROM category c INNER JOIN category_tree ct ON c.parent_id = ct.id ) SELECT a.id, a.sku, at.name, at.slug, u.si AS unitSi, ut.symbol AS unitSymbol, a.unitamount, b.name AS brandName, b.name AS brandName, pr.net AS net, t.rate AS taxRate, ( SELECT ae.ean FROM articleean ae WHERE ae.article_id = a.id ORDER BY ae.ean FOR JSON PATH ) AS eansJson, ( SELECT ca2.category_id FROM categoryarticle ca2 WHERE ca2.article_id = a.id ORDER BY ca2.category_id FOR JSON PATH ) AS categoryIdsJson, ( SELECT p.hash FROM articlepic ap INNER JOIN pic p ON p.id = ap.pic_id WHERE ap.article_id = a.id ORDER BY ap.sort ASC, ap.id ASC FOR JSON PATH ) AS fullHashesJson FROM article a INNER JOIN categoryarticle ca ON ca.article_id = a.id INNER JOIN category_tree ct ON ct.id = ca.category_id LEFT JOIN articletext at ON at.article_id = a.id AND at.language_id = @languageId LEFT JOIN unit u ON u.id = a.unit_id LEFT JOIN unittext ut ON ut.unit_id = u.id AND ut.language_id = @languageId LEFT JOIN brand b ON b.id = a.brand_id LEFT JOIN price pr ON pr.article_id = a.id AND pr.customergroup_id = @posCustomerGroupId AND pr.minmultiplier = 1 LEFT JOIN tax t ON t.id = pr.tax_id ORDER BY a.id `; /** * Single-query replacement for resolveArticleBySku + queryBySku. * Resolves SKU → article + company + auth, then loads full article detail * including categories, photos, eans, and prices via FOR JSON sub-queries. * Returns one row with articleJson, or empty if not found/unauthorized. */ export const GET_ARTICLE_BY_SKU_FULL = ` ;WITH auth AS ( SELECT TOP 1 a.id AS articleId, ca.category_id AS categoryId, co.root_category_id AS rootCategoryId, co.id AS companyId, co.default_language_id AS languageId, co.poscustomergroup_id AS posCustomerGroupId, cu.id AS companyuserId FROM article a INNER JOIN company co ON co.id = a.company_id INNER JOIN google_auth ga ON ga.id = @googleAuthId INNER JOIN companyuser cu ON cu.company_id = a.company_id AND cu.google_auth_id = @googleAuthId LEFT JOIN categoryarticle ca ON ca.article_id = a.id WHERE a.sku = @sku AND (ga.selected_company IS NULL OR a.company_id = ga.selected_company) ) SELECT auth.articleId, auth.categoryId, auth.rootCategoryId, auth.companyId, auth.languageId, auth.posCustomerGroupId, auth.companyuserId, ( SELECT a.id, a.sku, at.name, at.slug, a.unitamount, a.weight, u.si AS unitSi, u.basesi AS unitBasesi, u.basesifactor AS unitBasesifactor, ut.symbol AS unitSymbol, ut.name AS unitName, b.name AS brandName, bp.thumbw AS brandThumbW, bp.thumbh AS brandThumbH, bp.thumbhash AS brandThumbHash, ( SELECT COUNT(*) FROM optionslistarticle ola WHERE ola.optionslist_id = a.optionslist_id ) AS optionsCount, ( SELECT COUNT(*) FROM articlelistarticle ala WHERE ala.articlelist_id = a.articlelist_id ) AS articleListCount, ( SELECT COUNT(*) FROM article child WHERE child.fatherarticle_id = a.id ) AS childCount, a.fatherarticle_id AS fatherArticleId, fa.sku AS fatherSku, ( SELECT ca2.category_id FROM categoryarticle ca2 WHERE ca2.article_id = a.id ORDER BY ca2.category_id FOR JSON PATH ) AS categoryIdsJson, ( SELECT ap.sort, p.hash AS fullHash, p.w AS fullW, p.h AS fullH, p.size AS fullSize, p.thumbw AS thumbW, p.thumbh AS thumbH, p.thumbhash AS thumbHash FROM articlepic ap INNER JOIN pic p ON p.id = ap.pic_id WHERE ap.article_id = a.id ORDER BY ap.sort ASC, ap.id ASC FOR JSON PATH ) AS photosJson, ( SELECT ae.ean FROM articleean ae WHERE ae.article_id = a.id ORDER BY ae.ean FOR JSON PATH ) AS eansJson, ( SELECT pr.minmultiplier, pr.net, t.rate AS taxRate, pr.customergroup_id AS customergroupId FROM price pr INNER JOIN tax t ON t.id = pr.tax_id WHERE pr.article_id = a.id ORDER BY pr.customergroup_id, pr.minmultiplier FOR JSON PATH ) AS pricesJson, ( SELECT asup.id, asup.article_id AS articleId, asup.entity_id AS entityId, e.name AS supplierName, asup.sku, asup.pu, asup.stock, asup.sort, asup.price_id AS priceId, p.net AS [price.net], p.tax_id AS [price.taxId], t.rate AS [price.taxRate] FROM articlesupplier asup INNER JOIN entity e ON e.id = asup.entity_id LEFT JOIN price p ON p.id = asup.price_id LEFT JOIN tax t ON t.id = p.tax_id WHERE asup.article_id = a.id ORDER BY asup.sort ASC, asup.id ASC FOR JSON PATH ) AS suppliersJson, ( SELECT w.id, w.name, COALESCE(stock_calc.stock, 0) AS stock FROM warehouse w LEFT JOIN ( SELECT l.warehouse_id, SUM(l.amount) AS stock FROM ledger l INNER JOIN manifestarticle ma ON ma.id = l.manifestarticle_id INNER JOIN manifest m ON m.id = ma.manifest_id WHERE m.company_id = a.company_id AND ( ma.sku = a.sku OR ma.sku IN (SELECT asup.sku FROM articlesupplier asup WHERE asup.article_id = a.id) ) GROUP BY l.warehouse_id ) stock_calc ON stock_calc.warehouse_id = w.id WHERE w.company_id = a.company_id ORDER BY w.name ASC FOR JSON PATH ) AS warehousesJson FROM article a LEFT JOIN articletext at ON at.article_id = a.id AND at.language_id = auth.languageId LEFT JOIN unit u ON u.id = a.unit_id LEFT JOIN unittext ut ON ut.unit_id = u.id AND ut.language_id = auth.languageId LEFT JOIN brand b ON b.id = a.brand_id OUTER APPLY ( SELECT TOP 1 bp2.pic_id FROM brandpic bp2 WHERE bp2.brand_id = b.id ORDER BY bp2.sort ASC, bp2.id ASC ) first_brand_pic LEFT JOIN pic bp ON bp.id = first_brand_pic.pic_id LEFT JOIN article fa ON fa.id = a.fatherarticle_id WHERE a.id = auth.articleId FOR JSON PATH, WITHOUT_ARRAY_WRAPPER ) AS articleJson FROM auth `;