This commit is contained in:
seb
2026-06-29 19:42:04 +02:00
parent 3bff749b49
commit b320887508
2 changed files with 51 additions and 27 deletions

View File

@@ -13,7 +13,7 @@ export function register(app, basePath = '') {
* @query {string} [filter] - Optional comma-separated category filter IDs (empty = all) * @query {string} [filter] - Optional comma-separated category filter IDs (empty = all)
* @query {number} [offset=0] - Number of results to skip * @query {number} [offset=0] - Number of results to skip
* @query {number} [maxCount=10] - Maximum number of results to return * @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 * @returns {Object} 400 - `{ error }` when target is missing
*/ */
app.get(`${basePath}/article/search`, async (req, res) => { app.get(`${basePath}/article/search`, async (req, res) => {

View File

@@ -1,9 +1,9 @@
import { getPool } from '../../db/mssqlClient.js'; 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 * as Q from '../../db/mssql/searchArticles.js';
import { bruttoFromNetto, loadSteuersatz } from '../misc/getSteuer.js'; import { bruttoFromNetto, loadSteuersatz } from '../misc/getSteuer.js';
let katMapCache; let categoryCache;
export function parseFilter(raw) { export function parseFilter(raw) {
if (raw === undefined || raw === null || raw === '') { if (raw === undefined || raw === null || raw === '') {
@@ -13,47 +13,68 @@ export function parseFilter(raw) {
return parts.length ? parts : ['']; return parts.length ? parts : [''];
} }
function getUpPath(kat, katMap) { function getUpPath(kat, parentMap) {
const list = [kat]; const list = [kat];
if (katMap[kat]) { if (parentMap[kat]) {
for (const item of getUpPath(katMap[kat], katMap)) { for (const item of getUpPath(parentMap[kat], parentMap)) {
list.push(item); list.push(item);
} }
} }
return list; return list;
} }
async function loadKatMap(pool) { async function loadCategoryCache(pool) {
if (katMapCache) { if (categoryCache) {
return katMapCache; return categoryCache;
} }
const result = await pool.request().query(LOAD_KAT_MAP); const result = await pool.request().query(LOAD_CATEGORIES);
katMapCache = {}; const byId = {};
const parentMap = {};
for (const item of result.recordset) { 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) { function buildKatAgg(recordset, parentMap) {
const katagg = {}; const counts = {};
for (const item of recordset) { for (const item of recordset) {
if (!item.katList) { if (!item.katList) {
continue; continue;
} }
for (const kat of item.katList.split(',')) { for (const kat of item.katList.split(',')) {
for (const katpart of getUpPath(kat, katMap)) { for (const katpart of getUpPath(kat, parentMap)) {
if (!katagg[katpart]) { if (!counts[katpart]) {
katagg[katpart] = 0; 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) { function shapeArticle(row, steuersaetze) {
@@ -61,7 +82,7 @@ function shapeArticle(row, steuersaetze) {
const brutto = bruttoFromNetto(row.fVKNEtto, row.kSteuerklasse, steuersaetze); const brutto = bruttoFromNetto(row.fVKNEtto, row.kSteuerklasse, steuersaetze);
return { return {
katList: row.katList, categories: row.katList,
available: row.fVerfuegbar, available: row.fVerfuegbar,
id: row.kArtikel, id: row.kArtikel,
stock: row.fBestand, stock: row.fBestand,
@@ -140,7 +161,7 @@ function buildQuery(filter, categoryFilter) {
export async function searchArticles(target, filter = [''], offset = 0, maxCount = 10) { export async function searchArticles(target, filter = [''], offset = 0, maxCount = 10) {
const trimmed = target?.toString().trim(); const trimmed = target?.toString().trim();
if (!trimmed) { if (!trimmed) {
return { katagg: {}, length: 0, recordset: [] }; return { categories: {}, length: 0, recordset: [] };
} }
const start = Math.max(0, Number(offset) || 0); 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 result = await request.query(sql);
const [katMap, steuersaetze] = await Promise.all([ const [categoryData, steuersaetze] = await Promise.all([
loadKatMap(pool), loadCategoryCache(pool),
loadSteuersatz(), loadSteuersatz(),
]); ]);
const katagg = buildKatAgg(result.recordset, katMap); const categories = shapeCategories(
buildKatAgg(result.recordset, categoryData.parentMap),
categoryData.byId
);
const length = result.recordset.length; const length = result.recordset.length;
const recordset = result.recordset const recordset = result.recordset
.slice(start, start + count) .slice(start, start + count)
.map((row) => shapeArticle(row, steuersaetze)); .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 };
} }