feat: product catalog
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 8s
Build & Deploy / 🧪 QA (push) Failing after 2m0s
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 1s

This commit is contained in:
2026-03-01 22:35:49 +01:00
parent 56cd1fb1ba
commit 17ebde407e
4 changed files with 423 additions and 463 deletions

File diff suppressed because it is too large Load Diff

BIN
lychee Executable file

Binary file not shown.

View File

@@ -104,48 +104,50 @@ function generateExcelForProduct(product: ProductData): Buffer {
const workbook = XLSX.utils.book_new();
const l = product.locale === 'de';
// ── Sheet 1: Product Info ──
const infoData: Array<[string, string]> = [
[l ? 'Produktname' : 'Product Name', product.title],
[l ? 'Artikelnummer' : 'SKU', product.sku],
[l ? 'Kategorie' : 'Category', product.categories.join(', ') || '-'],
[l ? 'Beschreibung' : 'Description', product.description || '-'],
];
// Single sheet: all cross-sections from all voltage tables combined
const hasMultipleVoltages = product.voltageTables.length > 1;
const allRows: string[][] = [];
const infoSheet = XLSX.utils.aoa_to_sheet(infoData);
infoSheet['!cols'] = [{ wch: 25 }, { wch: 65 }];
XLSX.utils.book_append_sheet(workbook, infoSheet, l ? 'Produktinfo' : 'Product Info');
// ── Sheet 2: Technical Data ──
if (product.technicalItems.length > 0) {
const techData: Array<[string, string]> = product.technicalItems.map(item => {
const label = item.unit ? `${item.label} [${item.unit}]` : item.label;
return [label, item.value];
});
const techSheet = XLSX.utils.aoa_to_sheet([
[l ? 'Eigenschaft' : 'Property', l ? 'Wert' : 'Value'],
...techData
// Build unified header row
// Use columns from the first voltage table (they're the same across tables)
const refTable = product.voltageTables[0];
if (!refTable) {
// No voltage tables — create a minimal info sheet
const ws = XLSX.utils.aoa_to_sheet([
[product.title],
[l ? 'Keine Querschnittsdaten verfügbar' : 'No cross-section data available'],
]);
techSheet['!cols'] = [{ wch: 40 }, { wch: 60 }];
XLSX.utils.book_append_sheet(workbook, techSheet, l ? 'Technische Daten' : 'Technical Data');
ws['!cols'] = [{ wch: 40 }];
XLSX.utils.book_append_sheet(workbook, ws, product.title.substring(0, 31));
return Buffer.from(XLSX.write(workbook, { type: 'buffer', bookType: 'xlsx' }));
}
// ── Sheet 3+: Voltage Tables ──
const headers: string[] = [
l ? 'Querschnitt' : 'Cross-section',
...(hasMultipleVoltages ? [l ? 'Spannung' : 'Voltage'] : []),
...refTable.columns.map(c => c.label),
];
allRows.push(headers);
// Merge rows from all voltage tables
for (const table of product.voltageTables) {
const headers = ['Configuration/Cross-section', ...table.columns.map(c => c.label)];
const dataRows = table.crossSections.map((cs, rowIndex) => {
return [cs, ...table.columns.map(c => c.get(rowIndex) || '-')];
});
const ws = XLSX.utils.aoa_to_sheet([headers, ...dataRows]);
ws['!cols'] = headers.map(() => ({ wch: 22 }));
const safeName = table.voltageLabel.replace(/[:\\/?*[\]]/g, '-').trim();
const sheetName = safeName.substring(0, 31);
XLSX.utils.book_append_sheet(workbook, ws, sheetName);
for (let rowIdx = 0; rowIdx < table.crossSections.length; rowIdx++) {
const row: string[] = [
table.crossSections[rowIdx],
...(hasMultipleVoltages ? [table.voltageLabel] : []),
...table.columns.map(c => c.get(rowIdx) || '-'),
];
allRows.push(row);
}
}
const ws = XLSX.utils.aoa_to_sheet(allRows);
// Auto-width: first col wider for cross-section labels
ws['!cols'] = headers.map((_, i) => ({ wch: i === 0 ? 30 : 18 }));
const sheetName = product.title.substring(0, 31);
XLSX.utils.book_append_sheet(workbook, ws, sheetName);
const buffer = XLSX.write(workbook, { type: 'buffer', bookType: 'xlsx' });
return Buffer.from(buffer);
}

17
scripts/test-axios.ts Normal file
View File

@@ -0,0 +1,17 @@
import axios from 'axios';
async function test() {
const u = 'https://testing.klz-cables.com/de/blog/johannes-gleich-startet-als-senior-key-account-manager-durch';
try {
const res = await axios.get(u, {
headers: { Cookie: 'klz_gatekeeper_session=lassmichrein' },
validateStatus: (status) => status < 400
});
console.log('Status:', res.status);
console.log('Headers:', res.headers);
} catch (err: any) {
console.log('Error status:', err.response?.status);
console.log('Error data:', err.response?.data);
}
}
test();