mirror of
https://github.com/christianvidalwolf-prog/CrazeAnalytix.git
synced 2026-08-03 18:05:23 +02:00
fix(bsr): fix regex bug and expand column aliases in processBSRExcel
- Fix critical regex bug: /\\d+/ was matching literal '\d' instead of digits, causing all rows to be rejected (week always = 0) - Add VendorCSV format support: 'Top Level Category (Rank)', 'Date', etc. - Derive ISO week number from Date column when no Week column exists - Process all sheets (not just first) to handle multi-tab workbooks - Log column names on load to aid future debugging Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
17a3df9fb3
commit
702bb021f8
+58
-31
@@ -667,43 +667,70 @@ export const processBSRExcel = async (fileOrBuffer: File | ArrayBuffer): Promise
|
|||||||
const workbook = XLSX.read(arrayBuffer, { type: 'array' });
|
const workbook = XLSX.read(arrayBuffer, { type: 'array' });
|
||||||
const allData: BSRRecord[] = [];
|
const allData: BSRRecord[] = [];
|
||||||
|
|
||||||
// Typically BSR is in the first sheet
|
// Process all sheets — markets may be split across tabs
|
||||||
const sheetName = workbook.SheetNames[0];
|
for (const sheetName of workbook.SheetNames) {
|
||||||
const worksheet = workbook.Sheets[sheetName];
|
const worksheet = workbook.Sheets[sheetName];
|
||||||
const jsonData: any[] = XLSX.utils.sheet_to_json(worksheet, { defval: "" });
|
const jsonData: any[] = XLSX.utils.sheet_to_json(worksheet, { defval: "" });
|
||||||
|
if (jsonData.length === 0) continue;
|
||||||
|
|
||||||
console.log(`Processing BSR sheet "${sheetName}": ${jsonData.length} rows`);
|
console.log(`[BSR] Processing sheet "${sheetName}": ${jsonData.length} rows. Columns:`, Object.keys(jsonData[0]));
|
||||||
|
|
||||||
for (let i = 0; i < jsonData.length; i++) {
|
for (const row of jsonData) {
|
||||||
const row = jsonData[i];
|
const marketRaw = getColumnValue(row, ['market', 'country', 'marketplace', 'Market', 'Country', 'Marketplace']);
|
||||||
|
const asinRaw = getColumnValue(row, ['asin', 'ASIN']);
|
||||||
|
if (!marketRaw || !asinRaw) continue;
|
||||||
|
|
||||||
const weekRaw = getColumnValue(row, ['week', 'woche', 'semana']);
|
// Week: try direct week column first, else derive from Date column
|
||||||
const marketRaw = getColumnValue(row, ['market', 'country', 'marketplace']);
|
let week = 0;
|
||||||
const asinRaw = getColumnValue(row, ['asin']);
|
const weekRaw = getColumnValue(row, ['week', 'woche', 'semana', 'week number', 'weeknumber', 'Week', 'Week Number']);
|
||||||
const topLevelBSRRaw = getColumnValue(row, ['Mean Weekly Top Level BSR']);
|
if (weekRaw) {
|
||||||
const topLevelNameRaw = getColumnValue(row, ['Top Level Category Name']);
|
week = parseInt(String(weekRaw).match(/\d+/)?.[0] || '0', 10);
|
||||||
const detailLevelBSRRaw = getColumnValue(row, ['Mean Weekly Detail Level BSR']);
|
}
|
||||||
const detailLevelNameRaw = getColumnValue(row, ['Detail Level Category Name']);
|
if (!week) {
|
||||||
const avgRatingRaw = getColumnValue(row, ['Mean Weekly Average Rating']);
|
const dateRaw = getColumnValue(row, ['date', 'fecha', 'datum', 'Date']);
|
||||||
|
if (dateRaw) {
|
||||||
|
const d = new Date(dateRaw);
|
||||||
|
if (!isNaN(d.getTime())) {
|
||||||
|
// ISO week number
|
||||||
|
const tmp = new Date(d);
|
||||||
|
tmp.setHours(0, 0, 0, 0);
|
||||||
|
tmp.setDate(tmp.getDate() + 3 - ((tmp.getDay() + 6) % 7));
|
||||||
|
const w1 = new Date(tmp.getFullYear(), 0, 4);
|
||||||
|
week = 1 + Math.round(((tmp.getTime() - w1.getTime()) / 86400000 - 3 + ((w1.getDay() + 6) % 7)) / 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!week) continue;
|
||||||
|
|
||||||
if (!weekRaw || !marketRaw || !asinRaw) continue;
|
allData.push({
|
||||||
|
week,
|
||||||
const week = parseInt(String(weekRaw).match(/\\d+/)?.[0] || '0', 10);
|
market: String(marketRaw).trim(),
|
||||||
if (isNaN(week) || week === 0) continue;
|
asin: String(asinRaw).trim(),
|
||||||
|
topLevelBSR: parseIntSafe(getColumnValue(row, [
|
||||||
allData.push({
|
'Mean Weekly Top Level BSR', 'Top Level Category (Rank)', 'Top Level BSR',
|
||||||
week,
|
'TopLevelBSR', 'bsr top', 'BSR Top Level', 'top level bsr',
|
||||||
market: String(marketRaw).trim(),
|
])),
|
||||||
asin: String(asinRaw).trim(),
|
topLevelName: getColumnValue(row, [
|
||||||
topLevelBSR: parseIntSafe(String(topLevelBSRRaw)),
|
'Top Level Category Name', 'Top Level Category (Name)',
|
||||||
topLevelName: topLevelNameRaw ? String(topLevelNameRaw).trim() : null,
|
'TopLevelName', 'top category name', 'Top Category',
|
||||||
detailLevelBSR: parseIntSafe(String(detailLevelBSRRaw)),
|
]) || null,
|
||||||
detailLevelName: detailLevelNameRaw ? String(detailLevelNameRaw).trim() : null,
|
detailLevelBSR: parseIntSafe(getColumnValue(row, [
|
||||||
avgRating: parseFloat(String(avgRatingRaw)) || null,
|
'Mean Weekly Detail Level BSR', 'Detail Level Category (Rank)', 'Detail Level BSR',
|
||||||
});
|
'DetailLevelBSR', 'bsr detail', 'BSR Detail Level', 'detail level bsr',
|
||||||
|
])),
|
||||||
|
detailLevelName: getColumnValue(row, [
|
||||||
|
'Detail Level Category Name', 'Detail Level Category (Name)',
|
||||||
|
'DetailLevelName', 'detail category name', 'Detail Category',
|
||||||
|
]) || null,
|
||||||
|
avgRating: parseFloat(getColumnValue(row, [
|
||||||
|
'Mean Weekly Average Rating', 'Average Rating', 'AvgRating',
|
||||||
|
'Rating', 'avg rating',
|
||||||
|
])) || null,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Total BSR records loaded: ${allData.length}`);
|
console.log(`[BSR] Total records loaded: ${allData.length}`);
|
||||||
return allData;
|
return allData;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error processing BSR Excel:", error);
|
console.error("Error processing BSR Excel:", error);
|
||||||
|
|||||||
Reference in New Issue
Block a user