diff --git a/dashboard-COPY b/dashboard-COPY new file mode 160000 index 0000000..1200d26 --- /dev/null +++ b/dashboard-COPY @@ -0,0 +1 @@ +Subproject commit 1200d268665ae1effbbd67511f13a0fd4d99d851 diff --git a/inventory/src/components/products/ProductFilters.tsx b/inventory/src/components/products/ProductFilters.tsx index e76a0ac..2a6788c 100644 --- a/inventory/src/components/products/ProductFilters.tsx +++ b/inventory/src/components/products/ProductFilters.tsx @@ -74,10 +74,12 @@ const BASE_FILTER_OPTIONS: FilterOption[] = [ { id: 'isReplenishable', label: 'Replenishable', type: 'boolean', group: 'Basic Info', operators: BOOLEAN_OPERATORS }, { id: 'abcClass', label: 'ABC Class', type: 'select', group: 'Basic Info', operators: SELECT_OPERATORS, options: [] }, { id: 'status', label: 'Status', type: 'select', group: 'Basic Info', operators: SELECT_OPERATORS, options: [ - { value: 'in_stock', label: 'In Stock' }, - { value: 'low_stock', label: 'Low Stock' }, - { value: 'out_of_stock', label: 'Out of Stock' }, - { value: 'discontinued', label: 'Discontinued' }, + { value: 'Critical', label: 'Critical' }, + { value: 'At Risk', label: 'At Risk' }, + { value: 'Reorder', label: 'Reorder' }, + { value: 'Overstocked', label: 'Overstocked' }, + { value: 'Healthy', label: 'Healthy' }, + { value: 'New', label: 'New' }, ]}, { id: 'dateCreated', label: 'Created Date', type: 'date', group: 'Basic Info', operators: DATE_OPERATORS }, @@ -91,6 +93,9 @@ const BASE_FILTER_OPTIONS: FilterOption[] = [ // Physical Properties group { id: 'weight', label: 'Weight', type: 'number', group: 'Physical', operators: NUMBER_OPERATORS }, + { id: 'length', label: 'Length', type: 'number', group: 'Physical', operators: NUMBER_OPERATORS }, + { id: 'width', label: 'Width', type: 'number', group: 'Physical', operators: NUMBER_OPERATORS }, + { id: 'height', label: 'Height', type: 'number', group: 'Physical', operators: NUMBER_OPERATORS }, { id: 'dimensions', label: 'Dimensions', type: 'text', group: 'Physical', operators: STRING_OPERATORS }, // Customer Engagement group @@ -99,18 +104,24 @@ const BASE_FILTER_OPTIONS: FilterOption[] = [ { id: 'baskets', label: 'Basket Adds', type: 'number', group: 'Customer', operators: NUMBER_OPERATORS }, { id: 'notifies', label: 'Stock Alerts', type: 'number', group: 'Customer', operators: NUMBER_OPERATORS }, - // Stock group - { id: 'currentStock', label: 'Current Stock', type: 'number', group: 'Stock', operators: NUMBER_OPERATORS }, - { id: 'preorderCount', label: 'Preorders', type: 'number', group: 'Stock', operators: NUMBER_OPERATORS }, - { id: 'notionsInvCount', label: 'Notions Inventory', type: 'number', group: 'Stock', operators: NUMBER_OPERATORS }, - { id: 'onOrderQty', label: 'On Order', type: 'number', group: 'Stock', operators: NUMBER_OPERATORS }, - { id: 'configSafetyStock', label: 'Safety Stock', type: 'number', group: 'Stock', operators: NUMBER_OPERATORS }, - { id: 'replenishmentUnits', label: 'Replenish Qty', type: 'number', group: 'Stock', operators: NUMBER_OPERATORS }, - { id: 'toOrderUnits', label: 'To Order', type: 'number', group: 'Stock', operators: NUMBER_OPERATORS }, - { id: 'stockCoverInDays', label: 'Stock Cover (Days)', type: 'number', group: 'Stock', operators: NUMBER_OPERATORS }, - { id: 'sellsOutInDays', label: 'Sells Out In (Days)', type: 'number', group: 'Stock', operators: NUMBER_OPERATORS }, - { id: 'isOldStock', label: 'Old Stock', type: 'boolean', group: 'Stock', operators: BOOLEAN_OPERATORS }, - { id: 'overstockedUnits', label: 'Overstock Qty', type: 'number', group: 'Stock', operators: NUMBER_OPERATORS }, + // Inventory & Stock group + { id: 'currentStock', label: 'Current Stock', type: 'number', group: 'Inventory', operators: NUMBER_OPERATORS }, + { id: 'preorderCount', label: 'Preorders', type: 'number', group: 'Inventory', operators: NUMBER_OPERATORS }, + { id: 'notionsInvCount', label: 'Notions Inventory', type: 'number', group: 'Inventory', operators: NUMBER_OPERATORS }, + { id: 'onOrderQty', label: 'On Order', type: 'number', group: 'Inventory', operators: NUMBER_OPERATORS }, + { id: 'configSafetyStock', label: 'Safety Stock', type: 'number', group: 'Inventory', operators: NUMBER_OPERATORS }, + { id: 'replenishmentUnits', label: 'Replenish Qty', type: 'number', group: 'Inventory', operators: NUMBER_OPERATORS }, + { id: 'toOrderUnits', label: 'To Order', type: 'number', group: 'Inventory', operators: NUMBER_OPERATORS }, + { id: 'stockCoverInDays', label: 'Stock Cover (Days)', type: 'number', group: 'Inventory', operators: NUMBER_OPERATORS }, + { id: 'sellsOutInDays', label: 'Sells Out In (Days)', type: 'number', group: 'Inventory', operators: NUMBER_OPERATORS }, + { id: 'isOldStock', label: 'Old Stock', type: 'boolean', group: 'Inventory', operators: BOOLEAN_OPERATORS }, + { id: 'overstockedUnits', label: 'Overstock Qty', type: 'number', group: 'Inventory', operators: NUMBER_OPERATORS }, + { id: 'stockoutDays30d', label: 'Stockout Days (30d)', type: 'number', group: 'Inventory', operators: NUMBER_OPERATORS }, + { id: 'stockoutRate30d', label: 'Stockout Rate %', type: 'number', group: 'Inventory', operators: NUMBER_OPERATORS }, + { id: 'avgStockUnits30d', label: 'Avg Stock Units (30d)', type: 'number', group: 'Inventory', operators: NUMBER_OPERATORS }, + { id: 'receivedQty30d', label: 'Received Qty (30d)', type: 'number', group: 'Inventory', operators: NUMBER_OPERATORS }, + { id: 'poCoverInDays', label: 'PO Cover (Days)', type: 'number', group: 'Inventory', operators: NUMBER_OPERATORS }, + { id: 'earliestExpectedDate', label: 'Expected Date', type: 'date', group: 'Inventory', operators: DATE_OPERATORS }, // Pricing Group { id: "currentPrice", label: "Current Price", type: "number", group: "Pricing", operators: ["=", ">", ">=", "<", "<=", "between"] }, @@ -119,6 +130,9 @@ const BASE_FILTER_OPTIONS: FilterOption[] = [ { id: "currentLandingCostPrice", label: "Landing Cost", type: "number", group: "Pricing", operators: ["=", ">", ">=", "<", "<=", "between"] }, // Valuation Group + { id: "currentStockCost", label: "Current Stock Cost", type: "number", group: "Valuation", operators: ["=", ">", ">=", "<", "<=", "between"] }, + { id: "currentStockRetail", label: "Current Stock Retail", type: "number", group: "Valuation", operators: ["=", ">", ">=", "<", "<=", "between"] }, + { id: "currentStockGross", label: "Current Stock Gross", type: "number", group: "Valuation", operators: ["=", ">", ">=", "<", "<=", "between"] }, { id: "avgStockCost30d", label: "Avg Stock Cost (30d)", type: "number", group: "Valuation", operators: ["=", ">", ">=", "<", "<=", "between"] }, { id: "avgStockRetail30d", label: "Avg Stock Retail (30d)", type: "number", group: "Valuation", operators: ["=", ">", ">=", "<", "<=", "between"] }, { id: "avgStockGross30d", label: "Avg Stock Gross (30d)", type: "number", group: "Valuation", operators: ["=", ">", ">=", "<", "<=", "between"] }, @@ -132,6 +146,8 @@ const BASE_FILTER_OPTIONS: FilterOption[] = [ { id: "overstockedRetail", label: "Overstock Retail", type: "number", group: "Valuation", operators: ["=", ">", ">=", "<", "<=", "between"] }, // Sales Metrics Group + { id: "salesVelocityDaily", label: "Daily Velocity", type: "number", group: "Sales Metrics", operators: ["=", ">", ">=", "<", "<=", "between"] }, + { id: "yesterdaySales", label: "Yesterday Sales", type: "number", group: "Sales Metrics", operators: ["=", ">", ">=", "<", "<=", "between"] }, { id: "sales7d", label: "Sales (7d)", type: "number", group: "Sales Metrics", operators: ["=", ">", ">=", "<", "<=", "between"] }, { id: "revenue7d", label: "Revenue (7d)", type: "number", group: "Sales Metrics", operators: ["=", ">", ">=", "<", "<=", "between"] }, { id: "sales14d", label: "Sales (14d)", type: "number", group: "Sales Metrics", operators: ["=", ">", ">=", "<", "<=", "between"] }, @@ -140,9 +156,7 @@ const BASE_FILTER_OPTIONS: FilterOption[] = [ { id: "revenue30d", label: "Revenue (30d)", type: "number", group: "Sales Metrics", operators: ["=", ">", ">=", "<", "<=", "between"] }, { id: "sales365d", label: "Sales (365d)", type: "number", group: "Sales Metrics", operators: ["=", ">", ">=", "<", "<=", "between"] }, { id: "revenue365d", label: "Revenue (365d)", type: "number", group: "Sales Metrics", operators: ["=", ">", ">=", "<", "<=", "between"] }, - { id: "salesVelocityDaily", label: "Daily Velocity", type: "number", group: "Sales Metrics", operators: ["=", ">", ">=", "<", "<=", "between"] }, { id: "dateLastSold", label: "Date Last Sold", type: "date", group: "Sales Metrics", operators: ["=", ">", ">=", "<", "<=", "between"] }, - { id: "yesterdaySales", label: "Sales (Yesterday)", type: "number", group: "Sales Metrics", operators: ["=", ">", ">=", "<", "<=", "between"] }, { id: "avgSalesPerDay30d", label: "Avg Sales/Day (30d)", type: "number", group: "Sales Metrics", operators: ["=", ">", ">=", "<", "<=", "between"] }, { id: "avgSalesPerMonth30d", label: "Avg Sales/Month (30d)", type: "number", group: "Sales Metrics", operators: ["=", ">", ">=", "<", "<=", "between"] }, { id: "returnsUnits30d", label: "Returns Units (30d)", type: "number", group: "Sales Metrics", operators: ["=", ">", ">=", "<", "<=", "between"] }, @@ -188,20 +202,45 @@ const BASE_FILTER_OPTIONS: FilterOption[] = [ { id: "replenishmentNeededRaw", label: "Replenishment Needed Raw", type: "number", group: "Forecasting", operators: ["=", ">", ">=", "<", "<=", "between"] }, { id: "forecastLostSalesUnits", label: "Forecast Lost Sales Units", type: "number", group: "Forecasting", operators: ["=", ">", ">=", "<", "<=", "between"] }, { id: "forecastLostRevenue", label: "Forecast Lost Revenue", type: "number", group: "Forecasting", operators: ["=", ">", ">=", "<", "<=", "between"] }, - { id: "stockoutDays30d", label: "Stockout Days (30d)", type: "number", group: "Stock", operators: ["=", ">", ">=", "<", "<=", "between"] }, - { id: "stockoutRate30d", label: "Stockout Rate %", type: "number", group: "Stock", operators: ["=", ">", ">=", "<", "<=", "between"] }, - { id: "avgStockUnits30d", label: "Avg Stock Units (30d)", type: "number", group: "Stock", operators: ["=", ">", ">=", "<", "<=", "between"] }, - { id: "receivedQty30d", label: "Received Qty (30d)", type: "number", group: "Stock", operators: ["=", ">", ">=", "<", "<=", "between"] }, - { id: "poCoverInDays", label: "PO Cover (Days)", type: "number", group: "Stock", operators: ["=", ">", ">=", "<", "<=", "between"] }, + + // Dates & Timing Group + { id: "dateFirstReceived", label: "First Received", type: "date", group: "Dates", operators: ["=", ">", ">=", "<", "<=", "between"] }, + { id: "dateLastReceived", label: "Last Received", type: "date", group: "Dates", operators: ["=", ">", ">=", "<", "<=", "between"] }, + { id: "dateFirstSold", label: "First Sold", type: "date", group: "Dates", operators: ["=", ">", ">=", "<", "<=", "between"] }, + { id: "ageDays", label: "Age (Days)", type: "number", group: "Dates", operators: ["=", ">", ">=", "<", "<=", "between"] }, + { id: "avgLeadTimeDays", label: "Avg Lead Time", type: "number", group: "Dates", operators: ["=", ">", ">=", "<", "<=", "between"] }, + { id: "replenishDate", label: "Replenish Date", type: "date", group: "Dates", operators: ["=", ">", ">=", "<", "<=", "between"] }, + { id: "planningPeriodDays", label: "Planning Period (Days)", type: "number", group: "Dates", operators: ["=", ">", ">=", "<", "<=", "between"] }, // Lead Time & Replenishment { id: "configLeadTime", label: "Config Lead Time", type: "number", group: "Lead Time", operators: ["=", ">", ">=", "<", "<=", "between"] }, { id: "configDaysOfStock", label: "Config Days of Stock", type: "number", group: "Lead Time", operators: ["=", ">", ">=", "<", "<=", "between"] }, - { id: "avgLeadTimeDays", label: "Avg Lead Time", type: "number", group: "Lead Time", operators: ["=", ">", ">=", "<", "<=", "between"] }, - { id: "earliestExpectedDate", label: "Next Arrival Date", type: "date", group: "Lead Time", operators: ["=", ">", ">=", "<", "<=", "between"] }, - { id: "dateLastReceived", label: "Date Last Received", type: "date", group: "Lead Time", operators: ["=", ">", ">=", "<", "<=", "between"] }, - { id: "dateFirstReceived", label: "First Received", type: "date", group: "Dates", operators: ["=", ">", ">=", "<", "<=", "between"] }, - { id: "dateFirstSold", label: "First Sold", type: "date", group: "Dates", operators: ["=", ">", ">=", "<", "<=", "between"] }, + + // Growth Analysis Group + { id: "salesGrowth30dVsPrev", label: "Sales Growth % (30d vs Prev)", type: "number", group: "Growth Analysis", operators: ["=", ">", ">=", "<", "<=", "between"] }, + { id: "revenueGrowth30dVsPrev", label: "Revenue Growth % (30d vs Prev)", type: "number", group: "Growth Analysis", operators: ["=", ">", ">=", "<", "<=", "between"] }, + { id: "salesGrowthYoy", label: "Sales Growth % YoY", type: "number", group: "Growth Analysis", operators: ["=", ">", ">=", "<", "<=", "between"] }, + { id: "revenueGrowthYoy", label: "Revenue Growth % YoY", type: "number", group: "Growth Analysis", operators: ["=", ">", ">=", "<", "<=", "between"] }, + + // Demand Variability Group + { id: "salesVariance30d", label: "Sales Variance (30d)", type: "number", group: "Demand Variability", operators: ["=", ">", ">=", "<", "<=", "between"] }, + { id: "salesStdDev30d", label: "Sales Std Dev (30d)", type: "number", group: "Demand Variability", operators: ["=", ">", ">=", "<", "<=", "between"] }, + { id: "salesCv30d", label: "Sales CV % (30d)", type: "number", group: "Demand Variability", operators: ["=", ">", ">=", "<", "<=", "between"] }, + { id: "demandPattern", label: "Demand Pattern", type: "text", group: "Demand Variability", operators: STRING_OPERATORS }, + + // Service Level Group + { id: "fillRate30d", label: "Fill Rate % (30d)", type: "number", group: "Service Level", operators: ["=", ">", ">=", "<", "<=", "between"] }, + { id: "stockoutIncidents30d", label: "Stockout Incidents (30d)", type: "number", group: "Service Level", operators: ["=", ">", ">=", "<", "<=", "between"] }, + { id: "serviceLevel30d", label: "Service Level % (30d)", type: "number", group: "Service Level", operators: ["=", ">", ">=", "<", "<=", "between"] }, + { id: "lostSalesIncidents30d", label: "Lost Sales Incidents (30d)", type: "number", group: "Service Level", operators: ["=", ">", ">=", "<", "<=", "between"] }, + + // Seasonality Group + { id: "seasonalityIndex", label: "Seasonality Index", type: "number", group: "Seasonality", operators: ["=", ">", ">=", "<", "<=", "between"] }, + { id: "seasonalPattern", label: "Seasonal Pattern", type: "text", group: "Seasonality", operators: STRING_OPERATORS }, + { id: "peakSeason", label: "Peak Season", type: "text", group: "Seasonality", operators: STRING_OPERATORS }, + + // Data Quality Group + { id: "lifetimeRevenueQuality", label: "Lifetime Revenue Quality", type: "text", group: "Data Quality", operators: STRING_OPERATORS }, ]; interface ProductFiltersProps { diff --git a/inventory/src/components/products/ProductTable.tsx b/inventory/src/components/products/ProductTable.tsx index 2906504..9fd7b83 100644 --- a/inventory/src/components/products/ProductTable.tsx +++ b/inventory/src/components/products/ProductTable.tsx @@ -26,7 +26,7 @@ import { useSortable, } from "@dnd-kit/sortable"; import { CSS } from "@dnd-kit/utilities"; -import { ProductMetric, ProductMetricColumnKey } from "@/types/products"; +import { ProductMetric, ProductMetricColumnKey, ProductStatus } from "@/types/products"; import { Skeleton } from "@/components/ui/skeleton"; import { getStatusBadge } from "@/utils/productUtils"; @@ -166,19 +166,21 @@ export function ProductTable({ } }; - const formatColumnValue = (product: ProductMetric, columnKey: ProductMetricColumnKey) => { - const columnDef = columnDefs.find(def => def.key === columnKey); + const formatColumnValue = (product: ProductMetric, columnKey: ProductMetricColumnKey): React.ReactNode => { const value = product[columnKey as keyof ProductMetric]; - - if (columnKey === 'status') { - return
; - } - + const columnDef = columnDefs.find(col => col.key === columnKey); + + // Use the format function from column definition if available if (columnDef?.format) { return columnDef.format(value, product); } - - // Default formatting for common types if no formatter provided + + // Special handling for status + if (columnKey === 'status') { + return
; + } + + // Special handling for boolean values if (typeof value === 'boolean') { return value ? 'Yes' : 'No'; } @@ -308,4 +310,4 @@ export function ProductTable({
); -} \ No newline at end of file +} diff --git a/inventory/src/pages/Products.tsx b/inventory/src/pages/Products.tsx index 69fae9c..ae26a06 100644 --- a/inventory/src/pages/Products.tsx +++ b/inventory/src/pages/Products.tsx @@ -39,7 +39,7 @@ interface ColumnDef { group: string; noLabel?: boolean; width?: string; - format?: (value: any) => string; + format?: (value: any, product?: ProductMetric) => React.ReactNode; } // Define available columns with their groups @@ -70,7 +70,19 @@ const AVAILABLE_COLUMNS: ColumnDef[] = [ // Physical Properties { key: 'weight', label: 'Weight', group: 'Physical', format: (v) => v === 0 ? '0' : v ? v.toFixed(2) : '-' }, - { key: 'dimensions', label: 'Dimensions', group: 'Physical', format: (v) => v ? `${v.length}×${v.width}×${v.height}` : '-' }, + { key: 'length', label: 'Length', group: 'Physical', format: (v) => v === 0 ? '0' : v ? v.toFixed(2) : '-' }, + { key: 'width', label: 'Width', group: 'Physical', format: (v) => v === 0 ? '0' : v ? v.toFixed(2) : '-' }, + { key: 'height', label: 'Height', group: 'Physical', format: (v) => v === 0 ? '0' : v ? v.toFixed(2) : '-' }, + { key: 'dimensions', label: 'Dimensions', group: 'Physical', format: (v, product) => { + // Handle dimensions as separate length, width, height fields + const length = product?.length; + const width = product?.width; + const height = product?.height; + if (length && width && height) { + return `${length}×${width}×${height}`; + } + return '-'; + }}, // Customer Engagement { key: 'rating', label: 'Rating', group: 'Customer', format: (v) => v === 0 ? '0' : v ? v.toFixed(1) : '-' }, @@ -530,6 +542,16 @@ export function Products() { console.log('revenue30d:', transformedProducts[0].revenue30d); console.log('margin30d:', transformedProducts[0].margin30d); console.log('markup30d:', transformedProducts[0].markup30d); + + // Debug specific fields with issues + console.log('configSafetyStock:', transformedProducts[0].configSafetyStock); + console.log('length:', transformedProducts[0].length); + console.log('width:', transformedProducts[0].width); + console.log('height:', transformedProducts[0].height); + console.log('first7DaysSales:', transformedProducts[0].first7DaysSales); + console.log('first30DaysSales:', transformedProducts[0].first30DaysSales); + console.log('first7DaysRevenue:', transformedProducts[0].first7DaysRevenue); + console.log('first30DaysRevenue:', transformedProducts[0].first30DaysRevenue); } // Transform the metrics response to match our expected format diff --git a/inventory/src/types/products.ts b/inventory/src/types/products.ts index 6f32e5f..9fee899 100644 --- a/inventory/src/types/products.ts +++ b/inventory/src/types/products.ts @@ -112,6 +112,10 @@ export interface ProductMetric { width: number | null; height: number | null; } | null; + // Individual dimension fields for backend compatibility + length: number | null; + width: number | null; + height: number | null; countryOfOrigin: string | null; location: string | null; baskets: number | null; // Number of times added to basket @@ -280,6 +284,9 @@ export type ProductMetricColumnKey = | 'location' | 'moq' | 'weight' + | 'length' + | 'width' + | 'height' | 'dimensions' | 'rating' | 'reviews' @@ -308,9 +315,13 @@ export type ProductMetricColumnKey = | 'stockCoverInDays' | 'sellsOutInDays' | 'onOrderQty' + | 'onOrderCost' + | 'onOrderRetail' | 'earliestExpectedDate' | 'isOldStock' | 'overstockedUnits' + | 'overstockedCost' + | 'overstockedRetail' | 'stockoutDays30d' | 'stockoutRate30d' | 'avgStockUnits30d' @@ -331,10 +342,6 @@ export type ProductMetricColumnKey = | 'replenishmentCost' | 'replenishmentRetail' | 'replenishmentProfit' - | 'onOrderCost' - | 'onOrderRetail' - | 'overstockedCost' - | 'overstockedRetail' | 'sales7d' | 'revenue7d' | 'sales14d' @@ -354,24 +361,13 @@ export type ProductMetricColumnKey = | 'roas30d' | 'adSpend30d' | 'gmroi30d' - | 'first7DaysSales' - | 'first7DaysRevenue' - | 'first30DaysSales' - | 'first30DaysRevenue' - | 'first60DaysSales' - | 'first60DaysRevenue' - | 'first90DaysSales' - | 'first90DaysRevenue' - | 'lifetimeSales' - | 'lifetimeRevenue' - | 'lifetimeAvgPrice' - | 'forecastSalesUnits' - | 'forecastSalesValue' - | 'forecastStockCover' - | 'forecastedOutOfStockDate' - | 'salesVelocity' + | 'stockturn30d' + | 'sellThrough30d' + | 'returnRate30d' + | 'discountRate30d' + | 'markdown30d' + | 'markdownRate30d' | 'salesVelocityDaily' - | 'dateLastSold' | 'yesterdaySales' | 'avgSalesPerDay30d' | 'avgSalesPerMonth30d' @@ -383,13 +379,22 @@ export type ProductMetricColumnKey = | 'asp30d' | 'acp30d' | 'avgRos30d' - | 'markup30d' - | 'stockturn30d' - | 'sellThrough30d' - | 'returnRate30d' - | 'discountRate30d' - | 'markdown30d' - | 'markdownRate30d' + | 'lifetimeSales' + | 'lifetimeRevenue' + | 'lifetimeRevenueQuality' + | 'first7DaysSales' + | 'first7DaysRevenue' + | 'first30DaysSales' + | 'first30DaysRevenue' + | 'first60DaysSales' + | 'first60DaysRevenue' + | 'first90DaysSales' + | 'first90DaysRevenue' + | 'dateFirstReceived' + | 'dateLastReceived' + | 'dateFirstSold' + | 'dateLastSold' + | 'avgLeadTimeDays' | 'leadTimeForecastUnits' | 'daysOfStockForecastUnits' | 'planningPeriodForecastUnits' @@ -398,12 +403,6 @@ export type ProductMetricColumnKey = | 'replenishmentNeededRaw' | 'forecastLostSalesUnits' | 'forecastLostRevenue' - | 'avgLeadTimeDays' - | 'dateLastReceived' - | 'dateFirstReceived' - | 'dateFirstSold' - | 'imageUrl' - // New metrics from P3-P5 implementation | 'salesGrowth30dVsPrev' | 'revenueGrowth30dVsPrev' | 'salesGrowthYoy' @@ -419,7 +418,7 @@ export type ProductMetricColumnKey = | 'seasonalityIndex' | 'seasonalPattern' | 'peakSeason' - | 'lifetimeRevenueQuality'; + | 'imageUrl'; // Mapping frontend keys to backend query param keys export const FRONTEND_TO_BACKEND_KEY_MAP: Record = {