From ee09434ea9adf94b0a5ba7754700e7108c9206a7 Mon Sep 17 00:00:00 2001 From: seb Date: Sun, 12 Jul 2026 21:46:49 +0200 Subject: [PATCH] u --- .env.example | 2 ++ server.js | 3 +++ src/queries/category-count.js | 1 + src/queries/category-list.js | 1 + src/queries/category-tree.js | 6 +++++- src/queries/composite-product-count.js | 7 +++++++ src/queries/composite-product-list.js | 7 +++++++ src/queries/product-count.js | 1 + src/queries/product-list.js | 7 +++++++ src/shop.js | 20 ++++++++++++++++++++ 10 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/shop.js diff --git a/.env.example b/.env.example index 9d406d1..f41b575 100644 --- a/.env.example +++ b/.env.example @@ -24,6 +24,8 @@ IMAGE_SHOP_ID=0 # Product sync (tSteuerzone.cName used to look up tax rates per tSteuerklasse) TAX_ZONE_NAME=Zone-EU +# Shop filter: active shop is queried from tShopSubshop at startup + # MSSQL (connection data for JTL-Wawi database) MSSQL_SERVER=localhost MSSQL_PORT=1433 diff --git a/server.js b/server.js index 722ce9d..9e46dd4 100644 --- a/server.js +++ b/server.js @@ -10,6 +10,7 @@ import { createPairingStore } from './src/pairing.js'; import { closeOrderLog } from './src/order-log.js'; import { closeRequestLog, logRequest } from './src/request-log.js'; import { logger } from './src/logger.js'; +import { fetchActiveShop } from './src/shop.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); @@ -125,6 +126,8 @@ async function start() { try { await connectDb(); logger.success(`MSSQL connected: ${process.env.MSSQL_SERVER}/${process.env.MSSQL_DATABASE}`); + const activeShop = await fetchActiveShop(); + logger.info(`Active shop ID: ${activeShop}`); } catch (err) { logger.warn(`MSSQL connection skipped: ${err.message}`); logger.warn('POS handshake will still work; sync from database is not available yet.'); diff --git a/src/queries/category-count.js b/src/queries/category-count.js index 2feb5ac..4bca338 100644 --- a/src/queries/category-count.js +++ b/src/queries/category-count.js @@ -7,6 +7,7 @@ ${CATEGORY_TREE_CTE} SELECT COUNT(*) AS CategoryCount FROM dbo.tKategorie k WHERE k.kKategorie IN (SELECT kKategorie FROM CategoryTree) + AND (@kShop = 0 OR EXISTS (SELECT 1 FROM dbo.tKategorieShop ks WHERE ks.kKategorie = k.kKategorie AND ks.kShop = @kShop)) AND CONVERT(BIGINT, k.bRowversion) > @cursor; `; diff --git a/src/queries/category-list.js b/src/queries/category-list.js index 5a5dba2..813c7ba 100644 --- a/src/queries/category-list.js +++ b/src/queries/category-list.js @@ -22,6 +22,7 @@ LEFT JOIN dbo.tKategoriebildPlattform kbp LEFT JOIN dbo.tBild b ON b.kBild = kbp.kBild WHERE k.kKategorie IN (SELECT kKategorie FROM CategoryTree WHERE kKategorie <> @rootCategoryId) AND k.cAktiv = 'Y' + AND (@kShop = 0 OR EXISTS (SELECT 1 FROM dbo.tKategorieShop ks2 WHERE ks2.kKategorie = k.kKategorie AND ks2.kShop = @kShop)) AND CONVERT(BIGINT, k.bRowversion) > @cursor ORDER BY lastChanged ASC; `; diff --git a/src/queries/category-tree.js b/src/queries/category-tree.js index 7a52409..b89a4a3 100644 --- a/src/queries/category-tree.js +++ b/src/queries/category-tree.js @@ -1,4 +1,5 @@ import sql from 'mssql'; +import { getActiveShopId } from '../shop.js'; export const CATEGORY_TREE_CTE = ` WITH CategoryTree AS ( @@ -14,5 +15,8 @@ export function getRootCategoryId() { } export function categoryTreeRequest(pool, rootCategoryId = getRootCategoryId()) { - return pool.request().input('rootCategoryId', sql.Int, rootCategoryId); + return pool + .request() + .input('rootCategoryId', sql.Int, rootCategoryId) + .input('kShop', sql.Int, getActiveShopId()); } diff --git a/src/queries/composite-product-count.js b/src/queries/composite-product-count.js index 34fb32b..d0fd59d 100644 --- a/src/queries/composite-product-count.js +++ b/src/queries/composite-product-count.js @@ -1,11 +1,17 @@ import sql from 'mssql'; import { getPool } from '../db.js'; +import { getActiveShopId } from '../shop.js'; const COMPOSITE_PRODUCT_COUNT_SQL = ` SELECT COUNT(DISTINCT a.kArtikel) AS CompositeProductCount FROM dbo.tArtikel a INNER JOIN dbo.tStueckliste s ON s.kStueckliste = a.kStueckliste WHERE a.kStueckliste <> 0 + AND (@kShop = 0 OR EXISTS ( + SELECT 1 FROM dbo.tKategorieArtikel ka + INNER JOIN dbo.tKategorieShop ks ON ks.kKategorie = ka.kKategorie AND ks.kShop = @kShop + WHERE ka.kArtikel = a.kArtikel + )) AND CONVERT(BIGINT, a.bRowversion) > @cursor; `; @@ -13,6 +19,7 @@ export async function getCompositeProductCount({ cursor = 0 } = {}) { const result = await getPool() .request() .input('cursor', sql.BigInt, cursor) + .input('kShop', sql.Int, getActiveShopId()) .query(COMPOSITE_PRODUCT_COUNT_SQL); return result.recordset[0]?.CompositeProductCount ?? 0; } diff --git a/src/queries/composite-product-list.js b/src/queries/composite-product-list.js index d3334ce..cd514d8 100644 --- a/src/queries/composite-product-list.js +++ b/src/queries/composite-product-list.js @@ -1,5 +1,6 @@ import sql from 'mssql'; import { getPool } from '../db.js'; +import { getActiveShopId } from '../shop.js'; const COMPOSITE_PRODUCT_LIST_SQL = ` SELECT TOP (@limit) @@ -10,6 +11,11 @@ SELECT TOP (@limit) FROM dbo.tStueckliste s INNER JOIN dbo.tArtikel a ON a.kArtikel = s.kVaterArtikel WHERE a.kStueckliste <> 0 + AND (@kShop = 0 OR EXISTS ( + SELECT 1 FROM dbo.tKategorieArtikel ka + INNER JOIN dbo.tKategorieShop ks ON ks.kKategorie = ka.kKategorie AND ks.kShop = @kShop + WHERE ka.kArtikel = a.kArtikel + )) AND CONVERT(BIGINT, a.bRowversion) > @cursor ORDER BY lastChanged ASC; `; @@ -19,6 +25,7 @@ export async function getCompositeProductList({ cursor = 0, limit = 100 } = {}) .request() .input('cursor', sql.BigInt, cursor) .input('limit', sql.Int, limit) + .input('kShop', sql.Int, getActiveShopId()) .query(COMPOSITE_PRODUCT_LIST_SQL); return result.recordset.map((row) => ({ diff --git a/src/queries/product-count.js b/src/queries/product-count.js index a482736..94e47f0 100644 --- a/src/queries/product-count.js +++ b/src/queries/product-count.js @@ -9,6 +9,7 @@ FROM dbo.tArtikel a INNER JOIN dbo.tKategorieArtikel ka ON ka.kArtikel = a.kArtikel WHERE a.cAktiv = 'Y' AND ka.kKategorie IN (SELECT kKategorie FROM CategoryTree) + AND (@kShop = 0 OR EXISTS (SELECT 1 FROM dbo.tKategorieShop ks WHERE ks.kKategorie = ka.kKategorie AND ks.kShop = @kShop)) AND CONVERT(BIGINT, a.bRowversion) > @cursor; `; diff --git a/src/queries/product-list.js b/src/queries/product-list.js index b91e498..971b22e 100644 --- a/src/queries/product-list.js +++ b/src/queries/product-list.js @@ -2,6 +2,7 @@ import sql from 'mssql'; import { getPool } from '../db.js'; import { getCustomerGroupIds } from './customer-groups.js'; import { getProductAttributes } from './product-attributes.js'; +import { getActiveShopId } from '../shop.js'; const LANGUAGE_ID = Number(process.env.LANGUAGE_ID) || 1; const TAX_ZONE_NAME = process.env.TAX_ZONE_NAME || 'Zone-EU'; @@ -48,6 +49,11 @@ FROM dbo.tArtikel a INNER JOIN dbo.tArtikelBeschreibung ab ON ab.kArtikel = a.kArtikel AND ab.kSprache = @languageId LEFT JOIN TaxRates tr ON tr.kSteuerklasse = a.kSteuerklasse WHERE a.cAktiv = 'Y' + AND (@kShop = 0 OR EXISTS ( + SELECT 1 FROM dbo.tKategorieArtikel ka + INNER JOIN dbo.tKategorieShop ks ON ks.kKategorie = ka.kKategorie AND ks.kShop = @kShop + WHERE ka.kArtikel = a.kArtikel + )) AND CONVERT(BIGINT, a.bRowversion) > @cursor ORDER BY lastChanged ASC; `; @@ -87,6 +93,7 @@ export async function getProductList({ cursor = 0, limit = 20 } = {}) { .input('taxZoneName', sql.NVarChar, TAX_ZONE_NAME) .input('imagePlatformId', sql.Int, IMAGE_PLATFORM_ID) .input('imageShopId', sql.Int, IMAGE_SHOP_ID) + .input('kShop', sql.Int, getActiveShopId()) .query(PRODUCT_LIST_SQL), getCustomerGroupIds(), ]); diff --git a/src/shop.js b/src/shop.js new file mode 100644 index 0000000..808510a --- /dev/null +++ b/src/shop.js @@ -0,0 +1,20 @@ +import sql from 'mssql'; + +let activeShopId = 0; + +export function setActiveShop(id) { + activeShopId = id; +} + +export function getActiveShopId() { + return activeShopId; +} + +export async function fetchActiveShop(pool) { + const result = await pool.request().query(` + SELECT TOP 1 kShop FROM dbo.tShopSubshop WHERE nGesperrt = 0 ORDER BY kShop + `); + const id = result.recordset[0]?.kShop ?? 0; + setActiveShop(id); + return id; +}