This commit is contained in:
seb
2026-10-17 23:59:26 +02:00
parent ce5da810a5
commit fda895f75a
7 changed files with 64 additions and 6 deletions

View File

@@ -158,7 +158,7 @@ Returns the articles belonging to a single category.
**Returns**
`Promise<Array<{id: number, sku: string, name: string, slug: string, net: number|null, taxRate: number|null, optionsCount: number, articleListCount: number, childCount: number, parentArticleId: number|null, parentSku: string|null, fullHash: string|null, thumbW: number|null, thumbH: number|null, thumbHash: string|null, brand: {id: number|null, name: string, fullHash: string|null, thumbW: number|null, thumbH: number|null, thumbHash: string|null}|null}>>` — The articles in the category.
`Promise<Array<{id: number, sku: string, name: string, slug: string, net: number|null, taxRate: number|null, optionsCount: number, articleListCount: number, childCount: number, parentArticleId: number|null, parentSku: string|null, fullHash: string|null, thumbW: number|null, thumbH: number|null, thumbHash: string|null, brand: {id: number|null, name: string, fullHash: string|null, thumbW: number|null, thumbH: number|null, thumbHash: string|null}|null, articlewarehousesummary: Array<{id: number, articleId: number, warehouseId: number, warehouseName: string, stock: number}>, warehouses: Array<{id: number, name: string, stock: number}>}>>` — The articles in the category.
**Example**

2
API.md
View File

@@ -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<void>`
- `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<number>`
- `getCategoryArticles(googleAuthId: number, categoryId: number, tx?: object): Promise<Array<{id: number, sku: string, name: string, slug: string, net: number|null, taxRate: number|null, optionsCount: number, articleListCount: number, childCount: number, parentArticleId: number|null, parentSku: string|null, fullHash: string|null, thumbW: number|null, thumbH: number|null, thumbHash: string|null, brand: {id: number|null, name: string, fullHash: string|null, thumbW: number|null, thumbH: number|null, thumbHash: string|null}|null}>>`
- `getCategoryArticles(googleAuthId: number, categoryId: number, tx?: object): Promise<Array<{id: number, sku: string, name: string, slug: string, net: number|null, taxRate: number|null, optionsCount: number, articleListCount: number, childCount: number, parentArticleId: number|null, parentSku: string|null, fullHash: string|null, thumbW: number|null, thumbH: number|null, thumbHash: string|null, brand: {id: number|null, name: string, fullHash: string|null, thumbW: number|null, thumbH: number|null, thumbHash: string|null}|null, articlewarehousesummary: Array<{id: number, articleId: number, warehouseId: number, warehouseName: string, stock: number}>, 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<number>}, tx?: object): Promise<{categoryIds: Array<number>}>`

View File

@@ -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

View File

@@ -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;

View File

@@ -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<Array<{id: number, sku: string, name: string, slug: string, net: number|null, taxRate: number|null, optionsCount: number, articleListCount: number, childCount: number, parentArticleId: number|null, parentSku: string|null, fullHash: string|null, thumbW: number|null, thumbH: number|null, thumbHash: string|null, brand: {id: number|null, name: string, fullHash: string|null, thumbW: number|null, thumbH: number|null, thumbHash: string|null}|null}>>} The articles in the category.
* @returns {Promise<Array<{id: number, sku: string, name: string, slug: string, net: number|null, taxRate: number|null, optionsCount: number, articleListCount: number, childCount: number, parentArticleId: number|null, parentSku: string|null, fullHash: string|null, thumbW: number|null, thumbH: number|null, thumbHash: string|null, brand: {id: number|null, name: string, fullHash: string|null, thumbW: number|null, thumbH: number|null, thumbHash: string|null}|null, articlewarehousesummary: Array<{id: number, articleId: number, warehouseId: number, warehouseName: string, stock: number}>, warehouses: Array<{id: number, name: string, stock: number}>}>>} The articles in the category.
*
* @example
* const articles = await store.category.getCategoryArticles(42, 5);

View File

@@ -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,
})),
};
});
};
}

View File

@@ -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 () => {