mirror of
https://github.com/christianvidalwolf-prog/CrazeAnalytix.git
synced 2026-08-03 12:45:23 +02:00
feat(data): update sell-out parser mapping and validation for new structure
This commit is contained in:
@@ -270,8 +270,32 @@ const isAllowedCustomer = (customer: string): boolean => {
|
|||||||
|
|
||||||
// --- SALES / SELL OUT MAPPING ---
|
// --- SALES / SELL OUT MAPPING ---
|
||||||
|
|
||||||
|
export const validateSellOutHeaders = (headers: string[]) => {
|
||||||
|
const normHeaders = headers.map(h => String(h).trim().toLowerCase());
|
||||||
|
|
||||||
|
const hasYear = normHeaders.includes('year');
|
||||||
|
const hasTime = normHeaders.includes('month') || normHeaders.includes('week');
|
||||||
|
const hasCustomerRef = normHeaders.includes('customer reference') || normHeaders.includes('asin');
|
||||||
|
const hasEan = normHeaders.includes('ean');
|
||||||
|
const hasUnits = normHeaders.includes('units');
|
||||||
|
const hasAmount = normHeaders.includes('amount_eur') || normHeaders.includes('amount');
|
||||||
|
|
||||||
|
const missing = [];
|
||||||
|
if (!hasYear) missing.push('YEAR');
|
||||||
|
if (!hasTime) missing.push('MONTH or WEEK');
|
||||||
|
if (!hasCustomerRef) missing.push('CUSTOMER REFERENCE');
|
||||||
|
if (!hasEan) missing.push('EAN');
|
||||||
|
if (!hasUnits) missing.push('UNITS');
|
||||||
|
if (!hasAmount) missing.push('AMOUNT_EUR');
|
||||||
|
|
||||||
|
if (missing.length > 0) {
|
||||||
|
throw new Error(`Invalid or missing critical columns in Sell-Out Report. Missing: ${missing.join(', ')}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const mapRowToRecord = (row: any, index: number): SalesRecord => {
|
const mapRowToRecord = (row: any, index: number): SalesRecord => {
|
||||||
const customer = getColumnValue(row, ['NEW CUSTOMER', 'Customer', 'Client', 'Account', 'Partner', 'COUNTRY', 'Country', 'Market']) || 'Unknown';
|
// Add exact matches to the front of getColumnValue arrays
|
||||||
|
const customer = getColumnValue(row, ['NEW CUSTOMER', 'COUNTRY', 'Customer', 'Client', 'Account', 'Partner', 'Country', 'Market']) || 'Unknown';
|
||||||
const yearStr = getColumnValue(row, ['YEAR', 'Year', 'D']);
|
const yearStr = getColumnValue(row, ['YEAR', 'Year', 'D']);
|
||||||
// Sanitize year string before parsing (remove commas/dots e.g. "2,023")
|
// Sanitize year string before parsing (remove commas/dots e.g. "2,023")
|
||||||
let year = parseInt(yearStr.replace(/[,.]/g, '')) || 0;
|
let year = parseInt(yearStr.replace(/[,.]/g, '')) || 0;
|
||||||
@@ -299,11 +323,11 @@ const mapRowToRecord = (row: any, index: number): SalesRecord => {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
const sku = getColumnValue(row, ['RAW ARTICLE NO.', 'SKU', 'Sku', 'Item No']);
|
const sku = getColumnValue(row, ['RAW ARTICLE NO.', 'SKU', 'Sku', 'Item No']);
|
||||||
const title = getColumnValue(row, ['ARTICLE NAME (Craze)', 'Title', 'TITLE', 'Product Title', 'Article Name', 'ArticleName']);
|
const title = getColumnValue(row, ['ARTICLE NAME (Customer)', 'ARTICLE NAME (Craze)', 'Title', 'TITLE', 'Product Title', 'Article Name']);
|
||||||
const articleName = getColumnValue(row, ['ARTICLE NAME (Craze)', 'Article Name', 'ArticleName', 'Title']);
|
const articleName = getColumnValue(row, ['ARTICLE NAME (Craze)', 'ARTICLE NAME (Customer)', 'Article Name', 'ArticleName', 'Title']);
|
||||||
|
|
||||||
const unitsRaw = getColumnValue(row, ['UNITS', 'Units', 'Quantity', 'Qty']);
|
const unitsRaw = getColumnValue(row, ['UNITS', 'Units', 'Quantity', 'Qty']);
|
||||||
const sellOutRaw = getColumnValue(row, ['AMOUNT', 'Sell Out', 'SellOut', 'Revenue', 'Sales', 'Turnover']);
|
const sellOutRaw = getColumnValue(row, ['AMOUNT_EUR', 'AMOUNT', 'Sell Out', 'SellOut', 'Revenue', 'Sales', 'Turnover']);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: `row-${index}`,
|
id: `row-${index}`,
|
||||||
@@ -329,6 +353,12 @@ export const processCSV = (fileOrContent: File | string): Promise<SalesRecord[]>
|
|||||||
skipEmptyLines: true,
|
skipEmptyLines: true,
|
||||||
complete: (results: any) => {
|
complete: (results: any) => {
|
||||||
try {
|
try {
|
||||||
|
if (results.meta && results.meta.fields) {
|
||||||
|
validateSellOutHeaders(results.meta.fields);
|
||||||
|
} else if (results.data && results.data.length > 0) {
|
||||||
|
validateSellOutHeaders(Object.keys(results.data[0]));
|
||||||
|
}
|
||||||
|
|
||||||
const data: SalesRecord[] = results.data.map((row: any, index: number) => {
|
const data: SalesRecord[] = results.data.map((row: any, index: number) => {
|
||||||
return mapRowToRecord(row, index);
|
return mapRowToRecord(row, index);
|
||||||
})
|
})
|
||||||
@@ -353,6 +383,10 @@ export const processExcel = async (file: File): Promise<SalesRecord[]> => {
|
|||||||
const worksheet = workbook.Sheets[firstSheetName];
|
const worksheet = workbook.Sheets[firstSheetName];
|
||||||
const jsonData = XLSX.utils.sheet_to_json(worksheet, { defval: "" });
|
const jsonData = XLSX.utils.sheet_to_json(worksheet, { defval: "" });
|
||||||
|
|
||||||
|
if (jsonData.length > 0) {
|
||||||
|
validateSellOutHeaders(Object.keys(jsonData[0] as object));
|
||||||
|
}
|
||||||
|
|
||||||
const data: SalesRecord[] = jsonData.map((row: any, index: number) => {
|
const data: SalesRecord[] = jsonData.map((row: any, index: number) => {
|
||||||
return mapRowToRecord(row, index);
|
return mapRowToRecord(row, index);
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user