92 lines
3.9 KiB
TypeScript
92 lines
3.9 KiB
TypeScript
import { AlertTriangle } from 'lucide-react'
|
|
import { formatPercent } from '@/lib/format'
|
|
import type { Activity } from '@/domain/types'
|
|
import type { RoiResult } from '@/domain/roi'
|
|
|
|
// Umbral de ROI a partir del cual se dispara la advertencia de verosimilitud.
|
|
// Un ROI > 1000% anual es matemáticamente posible pero comercialmente inverosímil:
|
|
// indica casi siempre un input incorrecto (frecuencia sobreestimada, costo auto subestimado
|
|
// o inversión subestimada). Documentado en METHODOLOGY_AUTOMATED_COST.md.
|
|
const ROI_HIGH_THRESHOLD = 1000
|
|
|
|
interface TransparencySectionProps {
|
|
activities: Activity[]
|
|
investment: number
|
|
roi?: RoiResult
|
|
}
|
|
|
|
export function TransparencySection({ activities, investment, roi }: TransparencySectionProps) {
|
|
const zeroCostAutomatable = activities.filter(
|
|
(a) => a.automatable && a.automatedCostFixed === 0 && a.automatedTimeMinutes === 0
|
|
)
|
|
const investmentIsZero = investment === 0
|
|
|
|
// Caso 4: ROI > 1000% finito (Infinity no aplica — ya lo cubre el caso de investment=0)
|
|
const roiIsUnusuallyHigh =
|
|
roi !== undefined &&
|
|
Number.isFinite(roi.roiAnnualPercent) &&
|
|
roi.roiAnnualPercent > ROI_HIGH_THRESHOLD
|
|
|
|
if (zeroCostAutomatable.length === 0 && !investmentIsZero && !roiIsUnusuallyHigh) return null
|
|
|
|
return (
|
|
<div className="rounded-xl border border-amber-200 bg-amber-50 p-5 space-y-3">
|
|
<div className="flex items-center gap-2">
|
|
<AlertTriangle className="h-4 w-4 text-amber-600 shrink-0" />
|
|
<h3 className="text-sm font-semibold text-amber-800">Transparencia metodológica</h3>
|
|
</div>
|
|
|
|
{zeroCostAutomatable.length > 0 && (
|
|
<div className="text-xs text-amber-700 leading-relaxed space-y-1.5">
|
|
<p className="font-medium">
|
|
{zeroCostAutomatable.length === 1
|
|
? '1 actividad automatizable sin costo configurado:'
|
|
: `${zeroCostAutomatable.length} actividades automatizables sin costo configurado:`}
|
|
</p>
|
|
<ul className="list-disc list-inside space-y-0.5 ml-1">
|
|
{zeroCostAutomatable.map((a) => (
|
|
<li key={a.id} className="font-mono">
|
|
{a.name || a.bpmnElementId}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
<p className="text-amber-600">
|
|
Estas actividades se incluyen en el escenario automatizado con costo cero, lo que puede
|
|
inflar artificialmente el ahorro calculado. Configurá sus costos en el workspace para
|
|
un análisis realista.
|
|
</p>
|
|
</div>
|
|
)}
|
|
|
|
{investmentIsZero && (
|
|
<p className="text-xs text-amber-700 leading-relaxed">
|
|
<span className="font-medium">Inversión en automatización no configurada.</span>{' '}
|
|
El payback aparece como inmediato y el ROI como infinito porque no hay inversión inicial.
|
|
Configurá la inversión total en la tab "Global" del workspace para un análisis
|
|
financiero completo.
|
|
</p>
|
|
)}
|
|
|
|
{roiIsUnusuallyHigh && roi && (
|
|
<div className="text-xs text-amber-700 leading-relaxed space-y-1.5">
|
|
<p>
|
|
<span className="font-medium">
|
|
ROI inusualmente alto detectado: {formatPercent(roi.roiAnnualPercent)}.
|
|
</span>{' '}
|
|
Un ROI superior al {formatPercent(ROI_HIGH_THRESHOLD, 0)} anual suele indicar uno de estos casos:
|
|
</p>
|
|
<ul className="list-disc list-inside space-y-0.5 ml-1">
|
|
<li>Frecuencia anual del proceso sobreestimada</li>
|
|
<li>Costo automatizado por ejecución subestimado</li>
|
|
<li>Inversión en automatización subestimada</li>
|
|
</ul>
|
|
<p className="text-amber-600">
|
|
Revisá estos inputs antes de presentar el reporte al cliente.
|
|
Ver <span className="font-mono">METHODOLOGY_AUTOMATED_COST.md</span> para guía de estimación.
|
|
</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|