fix: read all sheets in Traffic Weekly Excel for complete GV data

processTrafficExcel was only reading the first sheet, missing data from
year-based sheets (e.g., "2025", "2026"). Now iterates all sheets with
auto-detection of column layout, matching the processAdsExcel pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Christian Vidal Wolf
2026-02-19 15:34:00 +01:00
co-authored by Claude Opus 4.6
parent a1dcb9b9fc
commit 31ad7fda21
+53 -33
View File
@@ -506,46 +506,66 @@ export const processTrafficExcel = async (fileOrBuffer: File | ArrayBuffer): Pro
const workbook = XLSX.read(arrayBuffer, { type: 'array' }); const workbook = XLSX.read(arrayBuffer, { type: 'array' });
const allData: TrafficRecord[] = []; const allData: TrafficRecord[] = [];
// Process first sheet only (Traffic Weekly.xlsx typically has one sheet) // Process ALL sheets (e.g., "2025", "2026") - same pattern as processAdsExcel
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, { header: 1, defval: "" }); const jsonData: any[][] = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: "" });
console.log(`Processing Traffic sheet "${sheetName}": ${jsonData.length} rows`); console.log(`Processing Traffic sheet "${sheetName}": ${jsonData.length} rows`);
// Column mapping for Traffic Weekly.xlsx: // Detect if sheet name is a valid year (multi-sheet format)
// A (0): Year const sheetYear = parseInt(sheetName);
// B (1): Week const isYearSheet = !isNaN(sheetYear) && sheetYear >= 2020 && sheetYear <= 2100;
// C (2): ASIN
// F (5): Country
// G (6): Glance Views (GV)
// Skip header row (index 0), process data rows // Auto-detect column layout from header row
for (let i = 1; i < jsonData.length; i++) { const headerRow = jsonData[0];
const row = jsonData[i]; if (!headerRow) continue;
if (!row || row.length < 7) continue;
const yearRaw = row[0]; const headers = headerRow.map((h: any) => String(h).trim().toLowerCase());
const weekRaw = row[1]; let yearIdx = headers.findIndex((h: string) => h === 'year' || h === 'año');
const asin = row[2]; let weekIdx = headers.findIndex((h: string) => h === 'week' || h === 'semana');
const countryRaw = row[5]; let asinIdx = headers.findIndex((h: string) => h === 'asin');
const gvRaw = row[6]; let countryIdx = headers.findIndex((h: string) => h === 'country' || h === 'país' || h === 'pais' || h === 'marketplace');
let gvIdx = headers.findIndex((h: string) => h.includes('glance') || h === 'gv' || h.includes('page view'));
// Skip if missing essential data // Fallback to positional mapping if headers not found
if (!asin || yearRaw === undefined || weekRaw === undefined || !countryRaw) continue; if (asinIdx === -1 || countryIdx === -1 || gvIdx === -1) {
if (isYearSheet) {
// Year-based sheets: no year column
weekIdx = 0; asinIdx = 1; countryIdx = 4; gvIdx = 5; yearIdx = -1;
} else {
// Single sheet with year column
yearIdx = 0; weekIdx = 1; asinIdx = 2; countryIdx = 5; gvIdx = 6;
}
}
const year = parseInt(String(yearRaw)); const minCols = Math.max(asinIdx, countryIdx, gvIdx) + 1;
const weekNum = parseInt(String(weekRaw));
if (isNaN(year) || year < 2020 || year > 2100) continue;
if (isNaN(weekNum) || weekNum < 1 || weekNum > 53) continue;
allData.push({ for (let i = 1; i < jsonData.length; i++) {
country: mapCountryToMarketplace(String(countryRaw)), const row = jsonData[i];
year, if (!row || row.length < minCols) continue;
week: weekNum,
asin: String(asin).trim().toUpperCase(), const yearRaw = isYearSheet ? sheetYear : (yearIdx >= 0 ? row[yearIdx] : undefined);
glanceViews: parseUnits(String(gvRaw)), const weekRaw = weekIdx >= 0 ? row[weekIdx] : undefined;
}); const asin = row[asinIdx];
const countryRaw = row[countryIdx];
const gvRaw = row[gvIdx];
if (!asin || yearRaw === undefined || weekRaw === undefined || !countryRaw) continue;
const year = typeof yearRaw === 'number' ? yearRaw : parseInt(String(yearRaw));
const weekNum = parseInt(String(weekRaw));
if (isNaN(year) || year < 2020 || year > 2100) continue;
if (isNaN(weekNum) || weekNum < 1 || weekNum > 53) continue;
allData.push({
country: mapCountryToMarketplace(String(countryRaw)),
year,
week: weekNum,
asin: String(asin).trim().toUpperCase(),
glanceViews: parseUnits(String(gvRaw)),
});
}
} }
console.log(`Total Traffic records loaded: ${allData.length}`); console.log(`Total Traffic records loaded: ${allData.length}`);