From fda895f75ada502b78e10eea397d02db643057c2 Mon Sep 17 00:00:00 2001 From: seb Date: Sat, 17 Oct 2026 23:59:26 +0200 Subject: [PATCH] u --- API.category.md | 2 +- API.md | 2 +- src/providers/mssql/queries/category.js | 16 ++++++++ src/providers/sqlite3/queries/category.js | 1 + src/store/category/getCategoryArticles.js | 2 +- src/store/category/queryCategoryArticles.js | 45 +++++++++++++++++++-- test/category.test.js | 2 + 7 files changed, 64 insertions(+), 6 deletions(-) diff --git a/API.category.md b/API.category.md index e7a7bf2..b6c4f7a 100644 --- a/API.category.md +++ b/API.category.md @@ -158,7 +158,7 @@ Returns the articles belonging to a single category. **Returns** -`Promise>` — The articles in the category. +`Promise, warehouses: Array<{id: number, name: string, stock: number}>}>>` — The articles in the category. **Example** diff --git a/API.md b/API.md index 2b2d55d..8261482 100644 --- a/API.md +++ b/API.md @@ -99,7 +99,7 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met - `delete(input: {googleAuthId: number, id: number, recursive?: boolean}, tx?: object): Promise` - `deleteImage(googleAuthId: number, categoryId: number, tx?: object): Promise<{id: number, thumbW: null, thumbH: null, thumbHash: null}>` - `ensureByPath(input: {googleAuthId: number, parentId: number, path: string}, tx?: object): Promise` - - `getCategoryArticles(googleAuthId: number, categoryId: number, tx?: object): Promise>` + - `getCategoryArticles(googleAuthId: number, categoryId: number, tx?: object): Promise, warehouses: Array<{id: number, name: string, stock: number}>}>>` - `getTreeForCompany(googleAuthId: number, tx?: object): Promise<{languageId: number, tree: Array<{id: number, parentId: number|null, sort: number, name: string|null, slug: string|null, fullHash: string|null, thumbW: number|null, thumbH: number|null, thumbHash: string|null, articleCount: number, posterminalIds: number[]}>, articleCount: number}>` - `move(input: {googleAuthId: number, id: number, parentId: number}, tx?: object): Promise<{id: number, parentId: number, sort: number}>` - `order(input: {googleAuthId: number, parentId: number, categoryIds: Array}, tx?: object): Promise<{categoryIds: Array}>` diff --git a/src/providers/mssql/queries/category.js b/src/providers/mssql/queries/category.js index d300337..9905728 100644 --- a/src/providers/mssql/queries/category.js +++ b/src/providers/mssql/queries/category.js @@ -68,6 +68,22 @@ WHERE ca.category_id = @categoryId ORDER BY a.id `; +export const GET_CATEGORY_ARTICLE_WAREHOUSE_SUMMARIES = ` +SELECT + aws.id, + aws.article_id AS articleId, + aws.warehouse_id AS warehouseId, + w.name AS warehouseName, + aws.stock +FROM articlewarehousesummary aws +INNER JOIN warehouse w ON w.id = aws.warehouse_id +INNER JOIN categoryarticle ca ON ca.article_id = aws.article_id +INNER JOIN article a ON a.id = ca.article_id +WHERE ca.category_id = @categoryId + AND a.parentarticle_id IS NULL +ORDER BY w.sort ASC, w.name ASC, aws.id ASC +`; + export const CREATE = ` INSERT INTO category (parent_id, sort) OUTPUT INSERTED.id, INSERTED.parent_id AS parentId, INSERTED.sort diff --git a/src/providers/sqlite3/queries/category.js b/src/providers/sqlite3/queries/category.js index 8200dc4..3f2453a 100644 --- a/src/providers/sqlite3/queries/category.js +++ b/src/providers/sqlite3/queries/category.js @@ -5,6 +5,7 @@ import { ARTICLE_LIST_COLUMNS, ARTICLE_LIST_JOINS } from './article.js'; const queries = translateQueries(source, 'category'); export const { CREATE, DELETE, GET_BY_PARENT_AND_NAME, + GET_CATEGORY_ARTICLE_WAREHOUSE_SUMMARIES, GET_NEXT_SIBLING_SORT, LIST_CHILD_IDS, MOVE, UPDATE_SORT, } = queries; diff --git a/src/store/category/getCategoryArticles.js b/src/store/category/getCategoryArticles.js index af30daa..cb67451 100644 --- a/src/store/category/getCategoryArticles.js +++ b/src/store/category/getCategoryArticles.js @@ -11,7 +11,7 @@ export default function getCategoryArticles(provider) { * @param {number} googleAuthId - The id of the Google auth user. * @param {number} categoryId - The id of the category. * @param {object} [tx] - Optional transaction to run within. - * @returns {Promise>} The articles in the category. + * @returns {Promise, warehouses: Array<{id: number, name: string, stock: number}>}>>} The articles in the category. * * @example * const articles = await store.category.getCategoryArticles(42, 5); diff --git a/src/store/category/queryCategoryArticles.js b/src/store/category/queryCategoryArticles.js index 790d0d8..4b6f46b 100644 --- a/src/store/category/queryCategoryArticles.js +++ b/src/store/category/queryCategoryArticles.js @@ -1,17 +1,48 @@ -import { GET_CATEGORY_ARTICLES as MSSQL_GET } from '../../providers/mssql/queries/category.js'; -import { GET_CATEGORY_ARTICLES as SQLITE_GET } from '../../providers/sqlite3/queries/category.js'; +import { + GET_CATEGORY_ARTICLES as MSSQL_GET, + GET_CATEGORY_ARTICLE_WAREHOUSE_SUMMARIES as MSSQL_SUMMARIES, +} from '../../providers/mssql/queries/category.js'; +import { + GET_CATEGORY_ARTICLES as SQLITE_GET, + GET_CATEGORY_ARTICLE_WAREHOUSE_SUMMARIES as SQLITE_SUMMARIES, +} from '../../providers/sqlite3/queries/category.js'; import makeRunner from '../runner.js'; export default function queryCategoryArticles(provider) { const sql = provider?.dialect === 'sqlite3' ? SQLITE_GET : MSSQL_GET; + const sqlSummaries = provider?.dialect === 'sqlite3' ? SQLITE_SUMMARIES : MSSQL_SUMMARIES; return async ({ categoryId, languageId, posCustomerGroupId }, tx) => { - const result = await makeRunner(provider, tx).query(sql, { + const runner = makeRunner(provider, tx); + const result = await runner.query(sql, { categoryId, languageId, posCustomerGroupId, }); + if (result.rows.length === 0) { + return []; + } + + const summaryResult = await runner.query(sqlSummaries, { categoryId }); + const summaryMap = new Map(); + for (const s of summaryResult.rows) { + let list = summaryMap.get(s.articleId); + if (!list) { + list = []; + summaryMap.set(s.articleId, list); + } + list.push({ + id: s.id, + articleId: s.articleId, + article_id: s.articleId, + warehouseId: s.warehouseId, + warehouse_id: s.warehouseId, + warehouseName: s.warehouseName, + stock: Number(s.stock ?? 0), + }); + } + return result.rows.map((row) => { const { brandId, @@ -22,6 +53,7 @@ export default function queryCategoryArticles(provider) { brandThumbHash, ...rest } = row; + const summaries = summaryMap.get(row.id) ?? []; return { ...rest, track_stock: Boolean(rest.track_stock ?? 0), @@ -38,7 +70,14 @@ export default function queryCategoryArticles(provider) { thumbHash: brandThumbHash ?? null, } : null, + articlewarehousesummary: summaries, + warehouses: summaries.map((s) => ({ + id: s.warehouseId, + name: s.warehouseName, + stock: s.stock, + })), }; }); }; } + diff --git a/test/category.test.js b/test/category.test.js index e29e9c5..5af522d 100644 --- a/test/category.test.js +++ b/test/category.test.js @@ -90,6 +90,8 @@ describe('store.category', () => { assert.equal(list[0].sku, art.sku); assert.equal(list[0].name, 'Listed'); assert.equal(list[0].parentArticleId, null); + assert(Array.isArray(list[0].articlewarehousesummary)); + assert(Array.isArray(list[0].warehouses)); }); it('rejects a category of another company', async () => {