2026-03-27 11:34:09 +01:00
|
|
|
export type ExcelRow = any[];
|
|
|
|
|
|
|
|
|
|
export interface AppState {
|
|
|
|
|
headers: string[];
|
|
|
|
|
data: ExcelRow[];
|
|
|
|
|
fileName: string;
|
|
|
|
|
fileDate: Date | null;
|
|
|
|
|
hasUnsavedChanges: boolean;
|
2026-04-09 16:33:05 +02:00
|
|
|
asinColumnIndex: number | null;
|
2026-03-27 11:34:09 +01:00
|
|
|
}
|
|
|
|
|
|
2026-04-22 16:52:59 +02:00
|
|
|
// Canonical column indices (defaults)
|
2026-03-27 11:34:09 +01:00
|
|
|
export const COLUMNS = {
|
|
|
|
|
ARTICLE_NO: 0,
|
|
|
|
|
ARTICLE_NAME: 2,
|
|
|
|
|
LINE: 7,
|
|
|
|
|
LICENSE: 8,
|
|
|
|
|
DETAILS_EN: 9,
|
|
|
|
|
DETAILS_DE: 10,
|
2026-04-22 16:52:59 +02:00
|
|
|
BARCODE: 29,
|
|
|
|
|
TARIFF_CODE: 60,
|
|
|
|
|
COUNTRY_ORIGIN: 62,
|
|
|
|
|
LONG_DE: 64,
|
|
|
|
|
LONG_EN: 65,
|
|
|
|
|
SHORT_DE: 66,
|
|
|
|
|
SHORT_EN: 67,
|
|
|
|
|
RECOMMENDED_AGE: 70,
|
2026-04-09 16:23:25 +02:00
|
|
|
CLASSIFICATION: 11,
|
2026-04-22 16:52:59 +02:00
|
|
|
ITEM_AVAILABLE: 16,
|
|
|
|
|
MOQ: 28,
|
|
|
|
|
UNITS_INNER: 32,
|
|
|
|
|
UNITS_OUTER: 33,
|
|
|
|
|
ASIN: 76,
|
|
|
|
|
INNER_W: 43,
|
|
|
|
|
INNER_L: 44,
|
|
|
|
|
INNER_H: 45,
|
|
|
|
|
OUTER_W: 48,
|
|
|
|
|
OUTER_L: 49,
|
|
|
|
|
OUTER_H: 50,
|
2026-04-20 18:46:50 +02:00
|
|
|
VERIFIED_DIMS: 100,
|
|
|
|
|
VALIDATED_CHECK: 101,
|
2026-04-21 09:24:02 +02:00
|
|
|
VALIDATED_NOTE: 102,
|
2026-04-23 12:58:51 +02:00
|
|
|
PRODUCT_TYPE: 103,
|
2026-04-23 13:02:14 +02:00
|
|
|
ITEM_TO_LOGISTIC: 104,
|
|
|
|
|
ANNA_CHECK: 105,
|
|
|
|
|
ANNA_NOTE: 106
|
2026-04-22 16:52:59 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Search patterns for dynamic detection
|
|
|
|
|
export const COLUMN_PATTERNS: Record<keyof typeof COLUMNS, string[]> = {
|
|
|
|
|
ARTICLE_NO: ['article', 'no'],
|
|
|
|
|
ARTICLE_NAME: ['article', 'name'],
|
|
|
|
|
LINE: ['line'],
|
|
|
|
|
LICENSE: ['license'],
|
|
|
|
|
DETAILS_EN: ['details', 'english'],
|
|
|
|
|
DETAILS_DE: ['details', 'german'],
|
|
|
|
|
BARCODE: ['article', 'barcode'],
|
|
|
|
|
TARIFF_CODE: ['tariff', 'code'],
|
|
|
|
|
COUNTRY_ORIGIN: ['country', 'origin'],
|
|
|
|
|
LONG_DE: ['long', 'description', 'german'],
|
|
|
|
|
LONG_EN: ['long', 'description', 'english'],
|
|
|
|
|
SHORT_DE: ['short', 'description', 'german'],
|
|
|
|
|
SHORT_EN: ['short', 'description', 'english'],
|
|
|
|
|
RECOMMENDED_AGE: ['recommended', 'age'],
|
|
|
|
|
CLASSIFICATION: ['classification'],
|
|
|
|
|
ITEM_AVAILABLE: ['item', 'available'],
|
|
|
|
|
MOQ: ['moq'],
|
|
|
|
|
UNITS_INNER: ['units', 'inner'],
|
|
|
|
|
UNITS_OUTER: ['units', 'outer'],
|
|
|
|
|
ASIN: ['asin'],
|
|
|
|
|
INNER_W: ['inner', 'w'],
|
|
|
|
|
INNER_L: ['inner', 'l'],
|
|
|
|
|
INNER_H: ['inner', 'h'],
|
|
|
|
|
OUTER_W: ['outer', 'w'],
|
|
|
|
|
OUTER_L: ['outer', 'l'],
|
|
|
|
|
OUTER_H: ['outer', 'h'],
|
2026-04-28 09:22:03 +02:00
|
|
|
VERIFIED_DIMS: ['verified', 'dims'],
|
|
|
|
|
VALIDATED_CHECK: ['validated', 'check'],
|
|
|
|
|
VALIDATED_NOTE: ['validated', 'note'],
|
|
|
|
|
PRODUCT_TYPE: ['product', 'type'],
|
|
|
|
|
ITEM_TO_LOGISTIC: ['item', 'logistic'],
|
|
|
|
|
ANNA_CHECK: ['anna', 'check'],
|
|
|
|
|
ANNA_NOTE: ['anna', 'note'],
|
2026-04-23 18:36:35 +02:00
|
|
|
// Virtual/Extra columns stay hardcoded and are NOT auto-detected from headers
|
|
|
|
|
// to prevent internal data from being shifted or overwritten by Excel column shifts.
|
2026-04-22 16:52:59 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export function resolveColumnIndices(headers: string[]): typeof COLUMNS {
|
|
|
|
|
const resolved = { ...COLUMNS };
|
|
|
|
|
const h = headers.map(val => String(val || '').toLowerCase());
|
|
|
|
|
|
|
|
|
|
Object.entries(COLUMN_PATTERNS).forEach(([key, patterns]) => {
|
|
|
|
|
const idx = h.findIndex(headerText =>
|
|
|
|
|
patterns.every(p => headerText.includes(p.toLowerCase()))
|
|
|
|
|
);
|
|
|
|
|
if (idx >= 0) {
|
|
|
|
|
resolved[key as keyof typeof COLUMNS] = idx;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return resolved;
|
|
|
|
|
}
|