diff --git a/src/api/routes/article/search.js b/src/api/routes/article/search.js index 1a6f218..659af98 100644 --- a/src/api/routes/article/search.js +++ b/src/api/routes/article/search.js @@ -13,7 +13,7 @@ export function register(app, basePath = '') { * @query {string} [filter] - Optional comma-separated category filter IDs (empty = all) * @query {number} [offset=0] - Number of results to skip * @query {number} [maxCount=10] - Maximum number of results to return - * @returns {Object} 200 - `{ katagg, length, recordset }` + * @returns {Object} 200 - `{ categories, length, recordset }` * @returns {Object} 400 - `{ error }` when target is missing */ app.get(`${basePath}/article/search`, async (req, res) => { diff --git a/src/services/article/searchArticles.js b/src/services/article/searchArticles.js index 238cf55..12f4387 100644 --- a/src/services/article/searchArticles.js +++ b/src/services/article/searchArticles.js @@ -1,9 +1,9 @@ import { getPool } from '../../db/mssqlClient.js'; -import { LOAD_KAT_MAP } from '../../db/mssql/categories.js'; +import { LOAD_CATEGORIES } from '../../db/mssql/categories.js'; import * as Q from '../../db/mssql/searchArticles.js'; import { bruttoFromNetto, loadSteuersatz } from '../misc/getSteuer.js'; -let katMapCache; +let categoryCache; export function parseFilter(raw) { if (raw === undefined || raw === null || raw === '') { @@ -13,47 +13,68 @@ export function parseFilter(raw) { return parts.length ? parts : ['']; } -function getUpPath(kat, katMap) { +function getUpPath(kat, parentMap) { const list = [kat]; - if (katMap[kat]) { - for (const item of getUpPath(katMap[kat], katMap)) { + if (parentMap[kat]) { + for (const item of getUpPath(parentMap[kat], parentMap)) { list.push(item); } } return list; } -async function loadKatMap(pool) { - if (katMapCache) { - return katMapCache; +async function loadCategoryCache(pool) { + if (categoryCache) { + return categoryCache; } - const result = await pool.request().query(LOAD_KAT_MAP); - katMapCache = {}; + const result = await pool.request().query(LOAD_CATEGORIES); + const byId = {}; + const parentMap = {}; for (const item of result.recordset) { - katMapCache[item.kKategorie] = item.kOberKategorie; + byId[item.kKategorie] = { + name: item.cName ?? null, + parent: item.kOberKategorie, + }; + parentMap[item.kKategorie] = item.kOberKategorie; } - return katMapCache; + categoryCache = { byId, parentMap }; + return categoryCache; } -function buildKatAgg(recordset, katMap) { - const katagg = {}; +function buildKatAgg(recordset, parentMap) { + const counts = {}; for (const item of recordset) { if (!item.katList) { continue; } for (const kat of item.katList.split(',')) { - for (const katpart of getUpPath(kat, katMap)) { - if (!katagg[katpart]) { - katagg[katpart] = 0; + for (const katpart of getUpPath(kat, parentMap)) { + if (!counts[katpart]) { + counts[katpart] = 0; } - katagg[katpart]++; + counts[katpart]++; } } } - return katagg; + return counts; +} + +function shapeCategories(counts, byId) { + const categories = {}; + + for (const [id, count] of Object.entries(counts)) { + const meta = byId[id] ?? {}; + categories[id] = { + count, + name: meta.name ?? null, + parent: meta.parent ?? null, + }; + } + + return categories; } function shapeArticle(row, steuersaetze) { @@ -61,7 +82,7 @@ function shapeArticle(row, steuersaetze) { const brutto = bruttoFromNetto(row.fVKNEtto, row.kSteuerklasse, steuersaetze); return { - katList: row.katList, + categories: row.katList, available: row.fVerfuegbar, id: row.kArtikel, stock: row.fBestand, @@ -140,7 +161,7 @@ function buildQuery(filter, categoryFilter) { export async function searchArticles(target, filter = [''], offset = 0, maxCount = 10) { const trimmed = target?.toString().trim(); if (!trimmed) { - return { katagg: {}, length: 0, recordset: [] }; + return { categories: {}, length: 0, recordset: [] }; } const start = Math.max(0, Number(offset) || 0); @@ -159,17 +180,20 @@ export async function searchArticles(target, filter = [''], offset = 0, maxCount } const result = await request.query(sql); - const [katMap, steuersaetze] = await Promise.all([ - loadKatMap(pool), + const [categoryData, steuersaetze] = await Promise.all([ + loadCategoryCache(pool), loadSteuersatz(), ]); - const katagg = buildKatAgg(result.recordset, katMap); + const categories = shapeCategories( + buildKatAgg(result.recordset, categoryData.parentMap), + categoryData.byId + ); const length = result.recordset.length; const recordset = result.recordset .slice(start, start + count) .map((row) => shapeArticle(row, steuersaetze)); - console.dir({ katagg, length, recordset }, { depth: null }); + console.dir({ categories, length, recordset }, { depth: null }); - return { katagg, length, recordset }; + return { categories, length, recordset }; }