This commit is contained in:
seb
2026-07-06 01:31:11 +02:00
commit 917930d0fa
34 changed files with 2912 additions and 0 deletions

View File

@@ -0,0 +1,149 @@
const PFAND_ATTR_IDS = [
'Pfandartikel',
'Pfandart (Bezeichnung auf Ausdruck)',
'Pfandbetrag',
];
let pfandMetaCache = null;
let activeShopsCache = null;
async function getPfandMetadata(pool) {
if (!pfandMetaCache) {
const result = await pool.request().query(`
SELECT
a.kAttribut,
a.cAttributId,
a.nSortierung,
a.kFeldTyp,
a.cGruppeName,
s.cName
FROM dbo.tAttribut a
INNER JOIN dbo.tAttributSprache s ON s.kAttribut = a.kAttribut AND s.kSprache = 0
WHERE a.cGruppeName = 'JTL-POS'
AND a.cAttributId IN ('Pfandartikel', 'Pfandart (Bezeichnung auf Ausdruck)', 'Pfandbetrag')
`);
pfandMetaCache = result.recordset;
}
return pfandMetaCache;
}
async function getActiveShops(pool) {
if (!activeShopsCache) {
const result = await pool.request().query(`
WITH ActiveShops AS (
SELECT ss.kShop, s.kKategorie AS rootKategorie
FROM dbo.tShopSubshop ss
INNER JOIN dbo.tShop s ON s.kShop = ss.kShop
WHERE ss.nGesperrt = 0
)
SELECT DISTINCT ash.kShop FROM ActiveShops ash
`);
activeShopsCache = result.recordset.map((row) => row.kShop);
}
return activeShopsCache;
}
function attributesSql(articleIds, activeShops, pfandKAttribute) {
const shopList = activeShops.length ? activeShops.join(',') : 'NULL';
const pfandList = pfandKAttribute.length ? pfandKAttribute.join(',') : 'NULL';
return `
SELECT
aa.kArtikel AS articleId,
aa.kAttribut,
aa.kShop,
at.nSortierung,
at.kFeldTyp,
at.cGruppeName,
at.cAttributId,
ats.cName,
aas.cWertVarchar,
aas.nWertInt,
aas.fWertDecimal
FROM dbo.tArtikelAttribut aa
INNER JOIN dbo.tArtikelAttributSprache aas
ON aas.kArtikelAttribut = aa.kArtikelAttribut AND aas.kSprache = 0
INNER JOIN dbo.tAttribut at ON at.kAttribut = aa.kAttribut
INNER JOIN dbo.tAttributSprache ats ON ats.kAttribut = at.kAttribut AND ats.kSprache = 0
WHERE aa.kArtikel IN (${articleIds.join(',')})
AND (
aa.kShop = 0
OR (
aa.kShop IN (${shopList})
AND aa.kAttribut IN (${pfandList})
)
)
ORDER BY aa.kArtikel, at.nSortierung, aa.kShop;
`;
}
function mergeArticleAttributes(rows) {
const byAttribute = new Map();
for (const row of rows) {
byAttribute.set(row.kAttribut, row);
}
return [...byAttribute.values()].sort((a, b) => a.nSortierung - b.nSortierung);
}
function toPosAttribute(row) {
return {
aname: row.cName,
aprice: '0.0',
asort: String(row.nSortierung),
atype: String(row.kFeldTyp),
agroup: row.cGruppeName ?? '',
};
}
function deriveDepositFields(rows) {
const byId = new Map(rows.map((row) => [row.cAttributId, row]));
const pfandArtikel = byId.get('Pfandartikel');
const pfandArt = byId.get('Pfandart (Bezeichnung auf Ausdruck)');
const pfandBetrag = byId.get('Pfandbetrag');
if (!pfandArtikel && !pfandArt && !pfandBetrag) {
return null;
}
return {
deposit: pfandArtikel?.nWertInt === 1 ? '1' : '0',
deposit_name: pfandArt?.cWertVarchar ?? '',
d_price:
pfandBetrag?.fWertDecimal != null
? Number(pfandBetrag.fWertDecimal).toFixed(2)
: '0.0',
};
}
export async function getProductAttributes(pool, articleIds) {
if (!articleIds.length) {
return new Map();
}
const [pfandMeta, activeShops] = await Promise.all([
getPfandMetadata(pool),
getActiveShops(pool),
]);
const pfandKAttribute = pfandMeta.map((row) => row.kAttribut);
const result = await pool.request().query(attributesSql(articleIds, activeShops, pfandKAttribute));
const rowsByArticle = new Map();
for (const row of result.recordset) {
if (!rowsByArticle.has(row.articleId)) {
rowsByArticle.set(row.articleId, []);
}
rowsByArticle.get(row.articleId).push(row);
}
const attributesByArticle = new Map();
for (const [articleId, rows] of rowsByArticle) {
const merged = mergeArticleAttributes(rows);
attributesByArticle.set(articleId, {
attributes: merged.map(toPosAttribute),
deposit: deriveDepositFields(merged),
});
}
return attributesByArticle;
}