mmm-modeler_app / src /utils /pastResultParser.js
aashish-bindal's picture
Initial commit: Dabur MMM Modeler React app
425a907
import * as XLSX from 'xlsx';
const _nrm = v => String(v || '').trim();
const _nrl = v => _nrm(v).toLowerCase();
const _nrk = v => _nrl(v).replace(/[_\s]/g, '');
function xlsRows(wb, name) {
if (!name) return [];
return XLSX.utils.sheet_to_json(wb.Sheets[name], { defval: '' });
}
export function parsePastXLSX(arrayBuffer) {
try {
const wb = XLSX.read(arrayBuffer, { type: 'array' });
const result = { panels: null, vars: null, contributions: null, mapping: null, fixedVars: null, config: null };
// Sheet 1 — Panel Selection
const s1n = wb.SheetNames.find(n => ['page 1','panel'].every(k => n.toLowerCase().includes(k)));
if (s1n) {
const rows = xlsRows(wb, s1n);
if (rows.length) {
result.panels = rows.map(r => Object.fromEntries(Object.entries(r).map(([k,v]) => [_nrm(k), _nrm(v)])));
}
}
// Sheet 2 — Dictionary / selected vars (PRIMARY_METRICS = Y)
const s2n = wb.SheetNames.find(n => ['page 2','dict'].every(k => n.toLowerCase().includes(k)));
if (s2n) {
const rows = xlsRows(wb, s2n);
if (rows.length) {
const keys = Object.keys(rows[0]);
const varKey = keys.find(k => _nrl(k) === 'variable');
const pmKey = keys.find(k => _nrl(k) === 'primary_metrics');
if (varKey && pmKey) {
result.vars = new Set();
rows.forEach(r => {
const v = _nrm(r[varKey]);
if (v && _nrm(r[pmKey]).toUpperCase() === 'Y') result.vars.add(v);
});
}
}
}
// Sheet 3 — Contributions
const s3n = wb.SheetNames.find(n => ['page 3','contrib'].every(k => n.toLowerCase().includes(k)));
if (s3n) {
const rows = xlsRows(wb, s3n);
if (rows.length) {
const keys = Object.keys(rows[0]);
const actKey = keys.find(k => _nrk(k).includes('activitylevel') || _nrk(k).includes('activity1'));
const mnKey = keys.find(k => _nrl(k).includes('min'));
const mxKey = keys.find(k => _nrl(k).includes('max'));
if (actKey && mnKey && mxKey) {
result.contributions = {};
rows.forEach(r => {
const act = _nrm(r[actKey]); if (!act) return;
const mn = parseFloat(r[mnKey]) || 0;
const mx = parseFloat(r[mxKey]) || 50;
if (!result.contributions[act]) result.contributions[act] = { min: mn, max: mx };
});
}
}
}
// Sheet 4 — Panel Mapping
const s4n = wb.SheetNames.find(n => ['page 4','mapping'].every(k => n.toLowerCase().includes(k)));
if (s4n) {
const rows = xlsRows(wb, s4n);
if (rows.length) {
const keys = Object.keys(rows[0]);
const rmKey = keys.find(k => _nrk(k).includes('removevar'));
if (rmKey) {
result.mapping = rows.map(r => {
const vars = _nrm(r[rmKey]).split(',').map(v => v.trim()).filter(Boolean);
const pd = {};
keys.forEach(k => { if (k !== rmKey) pd[_nrm(k)] = _nrm(r[k]); });
return { panelData: pd, removedVars: vars };
});
}
}
}
// Sheet 5 — Fixed Variables
const s5n = wb.SheetNames.find(n => ['page 5','fixed'].every(k => n.toLowerCase().includes(k)));
if (s5n) {
const rows = xlsRows(wb, s5n);
if (rows.length) {
const keys = Object.keys(rows[0]);
const fvKey = keys.find(k => _nrk(k).includes('fixvar'));
if (fvKey) {
result.fixedVars = rows.map(r => {
const vars = _nrm(r[fvKey]).split(',').map(v => v.trim()).filter(Boolean);
const pd = {};
keys.forEach(k => { if (k !== fvKey) pd[_nrm(k)] = _nrm(r[k]); });
return { panelData: pd, vars };
});
} else {
result.fixedVars = [];
}
}
}
// Config_Params sheet
const cfgSheet = wb.SheetNames.find(n => n.toLowerCase().replace(/[\s_]/g,'').includes('configparam'));
if (cfgSheet) {
try {
const cfgRows = XLSX.utils.sheet_to_json(wb.Sheets[cfgSheet], { header: 1, defval: '' });
const jsonStr = cfgRows[1] && cfgRows[1][0] ? String(cfgRows[1][0]).trim() : '';
if (jsonStr) result.config = JSON.parse(jsonStr);
} catch (e) { /* ignore */ }
}
// Build synthesised panelCSV from Sheet 1
if (result.panels && result.panels.length) {
const pHeaders = Object.keys(result.panels[0]);
const parsedPanelRows = result.panels.map((r, i) => {
const o = { __id: i + 1 };
pHeaders.forEach(h => { o[h] = _nrm(r[h]); });
return o;
});
result.synthPanelCSV = { headers: pHeaders, rows: parsedPanelRows };
}
// Build synthesised dictCSV from Sheet 2 (only selected variables)
const s2nRaw = wb.SheetNames.find(n => ['page 2','dict'].every(k => n.toLowerCase().includes(k)));
if (s2nRaw) {
const rawRows = XLSX.utils.sheet_to_json(wb.Sheets[s2nRaw], { defval: '' });
if (rawRows.length) {
const dHeaders = Object.keys(rawRows[0]);
const parsedDictRows = rawRows.map((r, i) => {
const o = { __id: i + 1 };
dHeaders.forEach(h => { o[h] = String(r[h] ?? '').trim(); });
o._sel = (o['PRIMARY_METRICS'] || '').toUpperCase() === 'Y';
return o;
});
result.synthDictCSV = { headers: dHeaders, rows: parsedDictRows };
}
}
return result;
} catch (e) {
console.error('[PastResult] parse error', e);
return null;
}
}