Files
dashlibstorage/src/providers/mssql/queries/article.js
2026-09-30 09:48:01 +02:00

616 lines
19 KiB
JavaScript

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 brand b ON b.id = a.brand_id
OUTER APPLY (
SELECT TOP 1 bp.pic_id
FROM brandpic bp
WHERE bp.brand_id = b.id
ORDER BY bp.sort ASC, bp.id ASC
) first_brand_pic
LEFT JOIN pic brand_pic ON brand_pic.id = first_brand_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,
a.track_stock,
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,
b.id AS brandId,
b.name AS brandName,
brand_pic.hash AS brandFullHash,
brand_pic.thumbw AS brandThumbW,
brand_pic.thumbh AS brandThumbH,
brand_pic.thumbhash AS brandThumbHash
`;
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 TOGGLE_FATHER = `
UPDATE article
SET is_father = @isFather,
fatherattributename_id = @fatherAttributeNameId
WHERE id = @articleId
`;
export const CREATE_CHILD = `
INSERT INTO article (
company_id, sku, unit_id, unitamount, weight, track_stock, brand_id, is_father, fatherarticle_id, fathersort
)
OUTPUT INSERTED.id
VALUES (
@companyId, @sku, @unitId, @unitamount, @weight, @trackStock, @brandId, 0, @fatherArticleId, @fathersort
)
`;
export const UNLINK_CHILD = `
UPDATE article
SET fatherarticle_id = NULL,
fathersort = 0
WHERE id = @articleId AND fatherarticle_id = @fatherArticleId
`;
export const LIST_CHILDREN_BY_FATHER_ID = `
SELECT
child.id,
child.sku,
child.fathersort,
child.track_stock AS trackStock,
child.unitamount,
child.weight,
at_child.name,
at_child.slug,
av.id AS attributeValueId,
av.value AS attributeValue
FROM article child
LEFT JOIN articletext at_child ON at_child.article_id = child.id AND at_child.language_id = @languageId
LEFT JOIN articleattributevalue aav ON aav.article_id = child.id
LEFT JOIN attributevalue av ON av.id = aav.attributevalue_id AND av.attribute_id = @attributeId
WHERE child.fatherarticle_id = @fatherArticleId
ORDER BY child.fathersort ASC, child.id ASC
`;
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, updated_at = SYSUTCDATETIME()
WHERE id = @articleId
`;
export const UPDATE_TRACK_STOCK = `
UPDATE article
SET track_stock = @trackStock, updated_at = SYSUTCDATETIME()
WHERE id = @articleId
`;
export const UPDATE_BRAND = `
UPDATE article
SET brand_id = @brandId, updated_at = SYSUTCDATETIME()
WHERE id = @articleId
`;
export const UPDATE_UNIT = `
UPDATE article
SET unit_id = @unitId, updated_at = SYSUTCDATETIME()
WHERE id = @articleId
`;
export const UPDATE_UNITAMOUNT = `
UPDATE article
SET unitamount = @unitamount, updated_at = SYSUTCDATETIME()
WHERE id = @articleId
`;
export const UPDATE_UNIT_AND_AMOUNT = `
UPDATE article
SET unit_id = @unitId, unitamount = @unitamount, updated_at = SYSUTCDATETIME()
WHERE id = @articleId
`;
export const CREATE = `
INSERT INTO article (company_id, sku, unit_id, unitamount, weight, track_stock)
OUTPUT INSERTED.id
VALUES (@companyId, @sku, @unitId, @unitamount, @weight, @trackStock)
`;
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,
a.track_stock,
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,
a.track_stock,
u.si AS unitSi,
u.basesi AS unitBasesi,
u.basesifactor AS unitBasesifactor,
ut.symbol AS unitSymbol,
ut.name AS unitName,
b.id AS brandId,
b.name AS brandName,
bp.hash AS brandFullHash,
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,
a.optionslist_id AS optionslistId,
(
SELECT
ola.id,
ola.article_id AS articleId,
a_opt.sku,
at_opt.name,
ola.count,
ola.sort,
ola.mandated
FROM optionslistarticle ola
INNER JOIN article a_opt ON a_opt.id = ola.article_id
LEFT JOIN articletext at_opt ON at_opt.article_id = a_opt.id AND at_opt.language_id = auth.languageId
WHERE ola.optionslist_id = a.optionslist_id
ORDER BY ola.sort ASC, ola.id ASC
FOR JSON PATH
) AS optionslistItemsJson,
(
SELECT COUNT(*)
FROM articlelistarticle ala
WHERE ala.articlelist_id = a.articlelist_id
) AS articleListCount,
a.articlelist_id AS articlelistId,
(
SELECT
ala.id,
ala.article_id AS articleId,
a_item.sku,
at_item.name,
ala.count,
ala.sort
FROM articlelistarticle ala
INNER JOIN article a_item ON a_item.id = ala.article_id
LEFT JOIN articletext at_item ON at_item.article_id = a_item.id AND at_item.language_id = auth.languageId
WHERE ala.articlelist_id = a.articlelist_id
ORDER BY ala.sort ASC, ala.id ASC
FOR JSON PATH
) AS articlelistItemsJson,
(
SELECT COUNT(*)
FROM article child
WHERE child.fatherarticle_id = a.id
) AS childCount,
a.is_father AS isFather,
a.fatherattributename_id AS fatherAttributeNameId,
fan.name AS fatherAttributeName,
fan.exclusive AS fatherAttributeExclusive,
a.fatherarticle_id AS fatherArticleId,
fa.sku AS fatherSku,
(
SELECT
child.id,
child.sku,
child.fathersort,
at_child.name,
av.id AS attributeValueId,
av.value AS attributeValue
FROM article child
LEFT JOIN articletext at_child ON at_child.article_id = child.id AND at_child.language_id = auth.languageId
LEFT JOIN articleattributevalue aav ON aav.article_id = child.id
LEFT JOIN attributevalue av ON av.id = aav.attributevalue_id AND av.attribute_id = a.fatherattributename_id
WHERE child.fatherarticle_id = a.id
ORDER BY child.fathersort ASC, child.id ASC
FOR JSON PATH
) AS childrenJson,
(
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,
w.sort,
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.sort ASC, 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
LEFT JOIN attributename fan ON fan.id = a.fatherattributename_id
WHERE a.id = auth.articleId
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
) AS articleJson
FROM auth
`;