This commit is contained in:
seb
2026-07-12 21:46:49 +02:00
parent 7f6095013b
commit ee09434ea9
10 changed files with 54 additions and 1 deletions

View File

@@ -24,6 +24,8 @@ IMAGE_SHOP_ID=0
# Product sync (tSteuerzone.cName used to look up tax rates per tSteuerklasse) # Product sync (tSteuerzone.cName used to look up tax rates per tSteuerklasse)
TAX_ZONE_NAME=Zone-EU TAX_ZONE_NAME=Zone-EU
# Shop filter: active shop is queried from tShopSubshop at startup
# MSSQL (connection data for JTL-Wawi database) # MSSQL (connection data for JTL-Wawi database)
MSSQL_SERVER=localhost MSSQL_SERVER=localhost
MSSQL_PORT=1433 MSSQL_PORT=1433

View File

@@ -10,6 +10,7 @@ import { createPairingStore } from './src/pairing.js';
import { closeOrderLog } from './src/order-log.js'; import { closeOrderLog } from './src/order-log.js';
import { closeRequestLog, logRequest } from './src/request-log.js'; import { closeRequestLog, logRequest } from './src/request-log.js';
import { logger } from './src/logger.js'; import { logger } from './src/logger.js';
import { fetchActiveShop } from './src/shop.js';
const __dirname = path.dirname(fileURLToPath(import.meta.url)); const __dirname = path.dirname(fileURLToPath(import.meta.url));
@@ -125,6 +126,8 @@ async function start() {
try { try {
await connectDb(); await connectDb();
logger.success(`MSSQL connected: ${process.env.MSSQL_SERVER}/${process.env.MSSQL_DATABASE}`); logger.success(`MSSQL connected: ${process.env.MSSQL_SERVER}/${process.env.MSSQL_DATABASE}`);
const activeShop = await fetchActiveShop();
logger.info(`Active shop ID: ${activeShop}`);
} catch (err) { } catch (err) {
logger.warn(`MSSQL connection skipped: ${err.message}`); logger.warn(`MSSQL connection skipped: ${err.message}`);
logger.warn('POS handshake will still work; sync from database is not available yet.'); logger.warn('POS handshake will still work; sync from database is not available yet.');

View File

@@ -7,6 +7,7 @@ ${CATEGORY_TREE_CTE}
SELECT COUNT(*) AS CategoryCount SELECT COUNT(*) AS CategoryCount
FROM dbo.tKategorie k FROM dbo.tKategorie k
WHERE k.kKategorie IN (SELECT kKategorie FROM CategoryTree) 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; AND CONVERT(BIGINT, k.bRowversion) > @cursor;
`; `;

View File

@@ -22,6 +22,7 @@ LEFT JOIN dbo.tKategoriebildPlattform kbp
LEFT JOIN dbo.tBild b ON b.kBild = kbp.kBild LEFT JOIN dbo.tBild b ON b.kBild = kbp.kBild
WHERE k.kKategorie IN (SELECT kKategorie FROM CategoryTree WHERE kKategorie <> @rootCategoryId) WHERE k.kKategorie IN (SELECT kKategorie FROM CategoryTree WHERE kKategorie <> @rootCategoryId)
AND k.cAktiv = 'Y' 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 AND CONVERT(BIGINT, k.bRowversion) > @cursor
ORDER BY lastChanged ASC; ORDER BY lastChanged ASC;
`; `;

View File

@@ -1,4 +1,5 @@
import sql from 'mssql'; import sql from 'mssql';
import { getActiveShopId } from '../shop.js';
export const CATEGORY_TREE_CTE = ` export const CATEGORY_TREE_CTE = `
WITH CategoryTree AS ( WITH CategoryTree AS (
@@ -14,5 +15,8 @@ export function getRootCategoryId() {
} }
export function categoryTreeRequest(pool, rootCategoryId = 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());
} }

View File

@@ -1,11 +1,17 @@
import sql from 'mssql'; import sql from 'mssql';
import { getPool } from '../db.js'; import { getPool } from '../db.js';
import { getActiveShopId } from '../shop.js';
const COMPOSITE_PRODUCT_COUNT_SQL = ` const COMPOSITE_PRODUCT_COUNT_SQL = `
SELECT COUNT(DISTINCT a.kArtikel) AS CompositeProductCount SELECT COUNT(DISTINCT a.kArtikel) AS CompositeProductCount
FROM dbo.tArtikel a FROM dbo.tArtikel a
INNER JOIN dbo.tStueckliste s ON s.kStueckliste = a.kStueckliste INNER JOIN dbo.tStueckliste s ON s.kStueckliste = a.kStueckliste
WHERE a.kStueckliste <> 0 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; AND CONVERT(BIGINT, a.bRowversion) > @cursor;
`; `;
@@ -13,6 +19,7 @@ export async function getCompositeProductCount({ cursor = 0 } = {}) {
const result = await getPool() const result = await getPool()
.request() .request()
.input('cursor', sql.BigInt, cursor) .input('cursor', sql.BigInt, cursor)
.input('kShop', sql.Int, getActiveShopId())
.query(COMPOSITE_PRODUCT_COUNT_SQL); .query(COMPOSITE_PRODUCT_COUNT_SQL);
return result.recordset[0]?.CompositeProductCount ?? 0; return result.recordset[0]?.CompositeProductCount ?? 0;
} }

View File

@@ -1,5 +1,6 @@
import sql from 'mssql'; import sql from 'mssql';
import { getPool } from '../db.js'; import { getPool } from '../db.js';
import { getActiveShopId } from '../shop.js';
const COMPOSITE_PRODUCT_LIST_SQL = ` const COMPOSITE_PRODUCT_LIST_SQL = `
SELECT TOP (@limit) SELECT TOP (@limit)
@@ -10,6 +11,11 @@ SELECT TOP (@limit)
FROM dbo.tStueckliste s FROM dbo.tStueckliste s
INNER JOIN dbo.tArtikel a ON a.kArtikel = s.kVaterArtikel INNER JOIN dbo.tArtikel a ON a.kArtikel = s.kVaterArtikel
WHERE a.kStueckliste <> 0 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 AND CONVERT(BIGINT, a.bRowversion) > @cursor
ORDER BY lastChanged ASC; ORDER BY lastChanged ASC;
`; `;
@@ -19,6 +25,7 @@ export async function getCompositeProductList({ cursor = 0, limit = 100 } = {})
.request() .request()
.input('cursor', sql.BigInt, cursor) .input('cursor', sql.BigInt, cursor)
.input('limit', sql.Int, limit) .input('limit', sql.Int, limit)
.input('kShop', sql.Int, getActiveShopId())
.query(COMPOSITE_PRODUCT_LIST_SQL); .query(COMPOSITE_PRODUCT_LIST_SQL);
return result.recordset.map((row) => ({ return result.recordset.map((row) => ({

View File

@@ -9,6 +9,7 @@ FROM dbo.tArtikel a
INNER JOIN dbo.tKategorieArtikel ka ON ka.kArtikel = a.kArtikel INNER JOIN dbo.tKategorieArtikel ka ON ka.kArtikel = a.kArtikel
WHERE a.cAktiv = 'Y' WHERE a.cAktiv = 'Y'
AND ka.kKategorie IN (SELECT kKategorie FROM CategoryTree) 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; AND CONVERT(BIGINT, a.bRowversion) > @cursor;
`; `;

View File

@@ -2,6 +2,7 @@ import sql from 'mssql';
import { getPool } from '../db.js'; import { getPool } from '../db.js';
import { getCustomerGroupIds } from './customer-groups.js'; import { getCustomerGroupIds } from './customer-groups.js';
import { getProductAttributes } from './product-attributes.js'; import { getProductAttributes } from './product-attributes.js';
import { getActiveShopId } from '../shop.js';
const LANGUAGE_ID = Number(process.env.LANGUAGE_ID) || 1; const LANGUAGE_ID = Number(process.env.LANGUAGE_ID) || 1;
const TAX_ZONE_NAME = process.env.TAX_ZONE_NAME || 'Zone-EU'; 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 INNER JOIN dbo.tArtikelBeschreibung ab ON ab.kArtikel = a.kArtikel AND ab.kSprache = @languageId
LEFT JOIN TaxRates tr ON tr.kSteuerklasse = a.kSteuerklasse LEFT JOIN TaxRates tr ON tr.kSteuerklasse = a.kSteuerklasse
WHERE a.cAktiv = 'Y' 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 AND CONVERT(BIGINT, a.bRowversion) > @cursor
ORDER BY lastChanged ASC; ORDER BY lastChanged ASC;
`; `;
@@ -87,6 +93,7 @@ export async function getProductList({ cursor = 0, limit = 20 } = {}) {
.input('taxZoneName', sql.NVarChar, TAX_ZONE_NAME) .input('taxZoneName', sql.NVarChar, TAX_ZONE_NAME)
.input('imagePlatformId', sql.Int, IMAGE_PLATFORM_ID) .input('imagePlatformId', sql.Int, IMAGE_PLATFORM_ID)
.input('imageShopId', sql.Int, IMAGE_SHOP_ID) .input('imageShopId', sql.Int, IMAGE_SHOP_ID)
.input('kShop', sql.Int, getActiveShopId())
.query(PRODUCT_LIST_SQL), .query(PRODUCT_LIST_SQL),
getCustomerGroupIds(), getCustomerGroupIds(),
]); ]);

20
src/shop.js Normal file
View File

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