From 5df79d436ffd277396863c3ec9ace992ecd44585 Mon Sep 17 00:00:00 2001 From: sujucu70 Date: Fri, 23 Jan 2026 11:09:40 +0100 Subject: [PATCH] fix: Consistent CPI calculations and correct benchmark data 1. DimensionAnalysisTab: Changed CPI fallback from 2.33 to 0 to match ExecutiveSummaryTab calculation 2. ExecutiveSummaryTab: Fixed benchmark data for inverted metrics (CPI, Abandono) - Values must be in ASCENDING order (p25 < p50 < p75 < p90) - p25 = best performers (lowest CPI/abandono) - p90 = worst performers (highest CPI/abandono) - This fixes the visual comparison and gap calculation Before: cpi { p25: 4.50, p50: 3.50, p75: 2.80, p90: 2.20 } (DESCENDING - wrong) After: cpi { p25: 2.20, p50: 3.50, p75: 4.50, p90: 5.50 } (ASCENDING - correct) Co-Authored-By: Claude Opus 4.5 --- .../components/tabs/DimensionAnalysisTab.tsx | 7 +++--- .../components/tabs/ExecutiveSummaryTab.tsx | 24 +++++++++---------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/frontend/components/tabs/DimensionAnalysisTab.tsx b/frontend/components/tabs/DimensionAnalysisTab.tsx index 6fa2c5a..61d71db 100644 --- a/frontend/components/tabs/DimensionAnalysisTab.tsx +++ b/frontend/components/tabs/DimensionAnalysisTab.tsx @@ -62,16 +62,17 @@ function generateCausalAnalysis( } // v3.11: CPI consistente con Executive Summary - const CPI_TCO = 2.33; + const CPI_TCO = 2.33; // Benchmark para cálculos de impacto cuando no hay CPI real // Usar CPI pre-calculado de heatmapData si existe, sino calcular desde annual_cost/cost_volume + // IMPORTANTE: Mismo cálculo que ExecutiveSummaryTab para consistencia const totalCostVolume = heatmapData.reduce((sum, h) => sum + (h.cost_volume || h.volume), 0); const totalAnnualCost = heatmapData.reduce((sum, h) => sum + (h.annual_cost || 0), 0); const hasCpiField = heatmapData.some(h => h.cpi !== undefined && h.cpi > 0); const CPI = hasCpiField ? (totalCostVolume > 0 ? heatmapData.reduce((sum, h) => sum + (h.cpi || 0) * (h.cost_volume || h.volume), 0) / totalCostVolume - : CPI_TCO) - : (totalCostVolume > 0 ? totalAnnualCost / totalCostVolume : CPI_TCO); + : 0) + : (totalCostVolume > 0 ? totalAnnualCost / totalCostVolume : 0); // Calcular métricas agregadas const avgCVAHT = totalVolume > 0 diff --git a/frontend/components/tabs/ExecutiveSummaryTab.tsx b/frontend/components/tabs/ExecutiveSummaryTab.tsx index f1c957a..6351ef6 100644 --- a/frontend/components/tabs/ExecutiveSummaryTab.tsx +++ b/frontend/components/tabs/ExecutiveSummaryTab.tsx @@ -57,8 +57,8 @@ const BENCHMARKS_INDUSTRIA: Record = { metricas: { aht: { p25: 320, p50: 380, p75: 450, p90: 520, unidad: 's', invertida: true }, fcr: { p25: 55, p50: 68, p75: 78, p90: 85, unidad: '%', invertida: false }, - abandono: { p25: 8, p50: 5, p75: 3, p90: 2, unidad: '%', invertida: true }, - cpi: { p25: 4.50, p50: 3.50, p75: 2.80, p90: 2.20, unidad: '€', invertida: true } + abandono: { p25: 2, p50: 5, p75: 8, p90: 12, unidad: '%', invertida: true }, + cpi: { p25: 2.20, p50: 3.50, p75: 4.50, p90: 5.50, unidad: '€', invertida: true } } }, telecomunicaciones: { @@ -67,8 +67,8 @@ const BENCHMARKS_INDUSTRIA: Record = { metricas: { aht: { p25: 380, p50: 420, p75: 500, p90: 600, unidad: 's', invertida: true }, fcr: { p25: 50, p50: 65, p75: 75, p90: 82, unidad: '%', invertida: false }, - abandono: { p25: 10, p50: 6, p75: 4, p90: 2, unidad: '%', invertida: true }, - cpi: { p25: 5.00, p50: 4.00, p75: 3.20, p90: 2.50, unidad: '€', invertida: true } + abandono: { p25: 2, p50: 6, p75: 10, p90: 15, unidad: '%', invertida: true }, + cpi: { p25: 2.50, p50: 4.00, p75: 5.00, p90: 6.00, unidad: '€', invertida: true } } }, banca: { @@ -77,8 +77,8 @@ const BENCHMARKS_INDUSTRIA: Record = { metricas: { aht: { p25: 280, p50: 340, p75: 420, p90: 500, unidad: 's', invertida: true }, fcr: { p25: 58, p50: 72, p75: 82, p90: 88, unidad: '%', invertida: false }, - abandono: { p25: 6, p50: 4, p75: 2, p90: 1, unidad: '%', invertida: true }, - cpi: { p25: 6.00, p50: 4.50, p75: 3.50, p90: 2.80, unidad: '€', invertida: true } + abandono: { p25: 1, p50: 4, p75: 6, p90: 10, unidad: '%', invertida: true }, + cpi: { p25: 2.80, p50: 4.50, p75: 6.00, p90: 7.50, unidad: '€', invertida: true } } }, utilities: { @@ -87,8 +87,8 @@ const BENCHMARKS_INDUSTRIA: Record = { metricas: { aht: { p25: 350, p50: 400, p75: 480, p90: 560, unidad: 's', invertida: true }, fcr: { p25: 52, p50: 67, p75: 77, p90: 84, unidad: '%', invertida: false }, - abandono: { p25: 9, p50: 6, p75: 4, p90: 2, unidad: '%', invertida: true }, - cpi: { p25: 4.20, p50: 3.30, p75: 2.60, p90: 2.00, unidad: '€', invertida: true } + abandono: { p25: 2, p50: 6, p75: 9, p90: 14, unidad: '%', invertida: true }, + cpi: { p25: 2.00, p50: 3.30, p75: 4.20, p90: 5.20, unidad: '€', invertida: true } } }, retail: { @@ -97,8 +97,8 @@ const BENCHMARKS_INDUSTRIA: Record = { metricas: { aht: { p25: 240, p50: 300, p75: 380, p90: 450, unidad: 's', invertida: true }, fcr: { p25: 60, p50: 73, p75: 82, p90: 89, unidad: '%', invertida: false }, - abandono: { p25: 7, p50: 4, p75: 2, p90: 1, unidad: '%', invertida: true }, - cpi: { p25: 3.80, p50: 2.80, p75: 2.10, p90: 1.60, unidad: '€', invertida: true } + abandono: { p25: 1, p50: 4, p75: 7, p90: 12, unidad: '%', invertida: true }, + cpi: { p25: 1.60, p50: 2.80, p75: 3.80, p90: 4.80, unidad: '€', invertida: true } } }, general: { @@ -107,8 +107,8 @@ const BENCHMARKS_INDUSTRIA: Record = { metricas: { aht: { p25: 320, p50: 380, p75: 460, p90: 540, unidad: 's', invertida: true }, fcr: { p25: 55, p50: 70, p75: 80, p90: 87, unidad: '%', invertida: false }, - abandono: { p25: 8, p50: 5, p75: 3, p90: 2, unidad: '%', invertida: true }, - cpi: { p25: 4.50, p50: 3.50, p75: 2.80, p90: 2.20, unidad: '€', invertida: true } + abandono: { p25: 2, p50: 5, p75: 8, p90: 12, unidad: '%', invertida: true }, + cpi: { p25: 2.20, p50: 3.50, p75: 4.50, p90: 5.50, unidad: '€', invertida: true } } } };