# US-HR-003: Costeo de Mano de Obra por Obra **Epic:** MAI-007 - RRHH, Asistencias y Nómina **RF:** RF-HR-003 **ET:** ET-HR-003 **Tipo:** Historia de Usuario **Prioridad:** Alta **Story Points:** 10 **Sprint:** 10 **Estado:** 📋 Pendiente **Última actualización:** 2025-11-17 --- ## 📖 Historia de Usuario **Como** Director de Constructora o Ingeniero Residente **Quiero** un sistema automático que calcule y registre el costo real de mano de obra por obra usando el FSR **Para** comparar presupuesto vs real, detectar desviaciones temprano y proyectar el costo final al 100% de avance --- ## 🎯 Criterios de Aceptación ### CA-1: Configuración del FSR (Factor de Salario Real) ⚙️ **Dado que** soy Director de Constructora **Cuando** accedo a "Configuración" > "RRHH" > "Factor de Salario Real" **Entonces** puedo: 1. **Ver FSR Actual:** - Ver tarjeta con FSR total: **1.58** - Ver desglose de componentes: - IMSS: 23.00% - INFONAVIT: 5.00% - Aguinaldo: 4.17% - Vacaciones: 1.67% - Prima Vacacional: 0.42% - Domingos: 14.28% - Días Festivos: 2.19% - Ausentismo: 5.00% - Otros: 3.00% - **Total: 58%** → FSR = 1 + 0.58 = **1.58** 2. **Editar Componentes:** - Poder modificar cada porcentaje individualmente - Ver actualización automática del FSR total - Ejemplo: Si cambio IMSS a 25%, FSR se recalcula a 1.60 - Validación: Cada componente debe ser ≥ 0% y ≤ 50% - Validación: FSR total debe ser entre 1.0 y 3.0 3. **Guardar Configuración:** - Al guardar, se registra fecha de cambio - FSR aplica a **nuevos** cálculos (no retroactivo) - Mensaje: "FSR actualizado a 1.60. Aplicará a registros posteriores al 2025-11-17" - Log de auditoría: quién cambió, cuándo y valores anteriores vs nuevos **Y** solo el rol Director puede modificar el FSR ### CA-2: Cálculo Automático de Costo al Aprobar Asistencia 🤖 **Dado que** se aprueba un registro de asistencia **Cuando** el evento `attendance.approved` se dispara **Entonces** el sistema debe automáticamente: 1. **Obtener Datos del Empleado:** - Empleado: Juan Pérez García - Salario diario base: $450.00 - Obra asignada: Casa Modelo Norte - Salario específico de obra (si existe): $500.00 - **Usar:** $500.00 (prioridad a salario específico) 2. **Obtener FSR de la Constructora:** - Buscar FSR configurado: 1.58 - Fecha efectiva: 2025-11-15 3. **Calcular Días Trabajados:** - Basado en check-in y check-out: - Check-in: 07:15 AM - Check-out: 05:30 PM - Horas trabajadas: 10h 15min - **Si ≥ 8 horas:** 1.0 día - **Si 4-8 horas:** 0.5 días - **Si < 4 horas:** 0.25 días - En este caso: **1.0 día** 4. **Calcular Costo Real:** ``` Costo Real = Salario Diario × Días Trabajados × FSR Costo Real = $500.00 × 1.0 × 1.58 = $790.00 ``` 5. **Determinar Partida Presupuestal:** - Buscar si el empleado pertenece a una cuadrilla - Buscar si la cuadrilla está asignada a una partida presupuestal en esa obra - Cuadrilla: Albañilería A - Partida asignada: "03.02 - Muro de Block" - Si no hay asignación: marcar como "Indirecto" 6. **Guardar Registro de Costo:** ```json { "attendanceId": "uuid-attendance", "employeeId": "uuid-employee", "workId": "uuid-work", "budgetItemId": "uuid-budget-item", // o null "workDate": "2025-11-17", "daysWorked": 1.0, "dailySalary": 500.00, "fsr": 1.58, "realCost": 790.00 // Calculado automáticamente por BD } ``` **Y** este proceso debe ocurrir en segundo plano sin intervención del usuario ### CA-3: Dashboard de Costeo por Obra 📊 **Dado que** soy Director, Ingeniero o Residente **Cuando** accedo a una obra > "Costeo de Mano de Obra" **Entonces** veo un dashboard con: 1. **Resumen en Tarjetas:** ``` ┌─────────────────────┐ ┌─────────────────────┐ │ Presupuesto MO │ │ Real Gastado │ │ $1,250,000 │ │ $875,342 │ └─────────────────────┘ └─────────────────────┘ ┌─────────────────────┐ ┌─────────────────────┐ │ Proyección 100% │ │ Desviación │ │ $1,312,500 │ │ +5.0% [AMARILLO] │ └─────────────────────┘ └─────────────────────┘ ``` 2. **Indicadores de Color:** - **Verde:** Desviación < 10% (dentro de presupuesto) - **Amarillo:** Desviación 10-20% (advertencia) - **Rojo:** Desviación > 20% (crítico) 3. **Avance Físico:** - Porcentaje de avance de la obra: 66.7% - Integrado desde módulo de Control de Obra - Proyección calculada como: `Real Gastado / Avance Físico × 100` - Ejemplo: `$875,342 / 0.667 × 100 = $1,312,500` 4. **Fórmula de Desviación:** ``` Desviación = (Proyección - Presupuesto) / Presupuesto × 100 Desviación = ($1,312,500 - $1,250,000) / $1,250,000 × 100 = +5.0% ``` ### CA-4: Detalle por Partida Presupuestal 📋 **Dado que** veo el dashboard de costeo **Cuando** bajo a la sección "Costo por Partida" **Entonces** veo una tabla con: | Partida | Presupuestado | Real Gastado | Días-Hombre | Desviación | Estado | |---------|---------------|--------------|-------------|------------|--------| | 02.01 - Excavación | $85,000 | $82,500 | 165 | -2.9% | 🟢 | | 03.02 - Muro de Block | $320,000 | $285,000 | 570 | -10.9% | 🟢 | | 04.01 - Castillos | $180,000 | $195,000 | 390 | +8.3% | 🟡 | | 05.03 - Losa | $425,000 | $312,842 | 625 | (proyección) | 🟢 | | **Indirecto** | $240,000 | $0 | 0 | - | - | | **TOTAL** | **$1,250,000** | **$875,342** | **1,750** | **+5.0%** | **🟡** | **Características de la tabla:** - Ordenable por cualquier columna - Filtrable por estado (verde, amarillo, rojo) - Exportable a Excel - Clic en partida: ver detalle de empleados **Y** la fila "Indirecto" agrupa costos sin partida asignada (supervisión, logística, etc.) ### CA-5: Detalle de Empleados por Partida 👷 **Dado que** hago clic en una partida (ej: "03.02 - Muro de Block") **Cuando** se abre el modal de detalle **Entonces** veo: 1. **Header:** - Partida: 03.02 - Muro de Block - Presupuestado: $320,000 - Real gastado: $285,000 - Días-hombre: 570 2. **Lista de Empleados:** | Empleado | Cuadrilla | Días Trabajados | Costo Total | |----------|-----------|-----------------|-------------| | Juan Pérez | Albañilería A | 45 | $35,550 | | María López | Albañilería A | 43 | $34,002 | | Carlos Ruiz | Albañilería B | 38 | $30,020 | | ... | ... | ... | ... | 3. **Gráfica de Tendencia:** - Gráfica de línea mostrando costo acumulado por semana - Comparación con curva de presupuesto - Detectar si hay aceleración o desaceleración de gasto ### CA-6: Asignación de Cuadrillas a Partidas 🔧 **Dado que** soy Ingeniero o Residente **Cuando** accedo a "Cuadrillas" en una obra **Entonces** puedo: 1. **Ver Cuadrillas de la Obra:** - Lista de cuadrillas activas - Por cada cuadrilla: nombre, tipo, supervisor, # miembros 2. **Asignar a Partida:** - Hacer clic en "Asignar a Partida" - Seleccionar partida del presupuesto (dropdown) - Seleccionar fecha de inicio: 2025-11-10 - Fecha de fin: opcional (abierta si es indefinido) - Guardar asignación 3. **Registro de Asignación:** ```json { "crewId": "uuid-crew", "workId": "uuid-work", "budgetItemId": "uuid-budget-item", "startDate": "2025-11-10", "endDate": null, // Abierta "isActive": true } ``` 4. **Validación:** - Una cuadrilla puede estar asignada a múltiples partidas en diferentes periodos - No puede estar en dos partidas **simultáneamente** (fechas traslapadas) - Si se intenta: error "La cuadrilla ya está asignada a '04.01 - Castillos' desde el 2025-11-08" 5. **Historial de Asignaciones:** - Ver tabla con todas las asignaciones pasadas y presentes - Filtrar por cuadrilla, partida, fecha **Y** a partir de la fecha de asignación, todos los costos de esa cuadrilla se imputan a la partida correspondiente ### CA-7: Alertas de Desviación 🚨 **Dado que** el sistema calcula costos diariamente **Cuando** detecta una desviación significativa **Entonces** debe: 1. **Generar Alerta Automática:** - **Condición:** Desviación de una partida > 15% - Crear notificación para: - Ingeniero Residente de la obra - Director de Constructora - Contenido de notificación: ``` ⚠️ Alerta de Desviación de Costo Obra: Casa Modelo Norte Partida: 04.01 - Castillos Desviación: +18.5% Real: $195,000 vs Presupuesto: $164,620 (a la fecha) Acción recomendada: Revisar rendimientos y asignación de personal ``` 2. **Dashboard de Alertas:** - Sección en home del usuario - Lista de alertas activas - Filtros: por obra, por criticidad (amarillo, rojo) - Acción: "Marcar como revisado" 3. **Email Semanal:** - Cada lunes a las 8 AM - Resumen de alertas de la semana anterior - Top 3 partidas con mayor desviación - Solo si hay alertas activas ### CA-8: Comparación Histórica de Obras 📈 **Dado que** soy Director **Cuando** accedo a "Reportes" > "Análisis Comparativo de Obras" **Entonces** puedo: 1. **Seleccionar Obras:** - Seleccionar hasta 5 obras para comparar - Filtrar por: estado (activa, terminada), año, tipo de obra 2. **Ver Tabla Comparativa:** | Obra | Presup. MO | Real MO | Desv. | m² | Costo/m² | Eficiencia | |------|------------|---------|-------|-----|----------|------------| | Casa Norte | $1.25M | $1.31M | +5% | 250 | $5,240 | 95% | | Casa Sur | $980K | $920K | -6% | 200 | $4,600 | 106% | | Edificio A | $3.5M | $3.8M | +8% | 800 | $4,750 | 92% | 3. **Fórmulas:** - Costo/m² = Real MO / Metros cuadrados - Eficiencia = (Presupuesto / Real) × 100 - Benchmark: Identificar obra con mejor costo/m² 4. **Gráfica de Dispersión:** - Eje X: Metros cuadrados - Eje Y: Costo/m² - Cada punto: una obra - Detectar outliers **Y** poder exportar el análisis a PDF para presentaciones ### CA-9: Proyección y Escenarios 🔮 **Dado que** veo el dashboard de una obra en progreso **Cuando** accedo a "Proyecciones" **Entonces** puedo: 1. **Ver Proyección Base:** - Basada en % de avance físico actual - Costo final proyectado: $1,312,500 - Desviación proyectada: +5.0% 2. **Simular Escenarios:** - **Escenario Optimista:** Si mejoramos rendimiento 10% - Costo proyectado: $1,181,250 (-5.5%) - **Escenario Pesimista:** Si rendimiento empeora 10% - Costo proyectado: $1,443,750 (+15.5%) - **Escenario Realista:** Con tendencia actual - Mantiene proyección base 3. **Ajuste de Variables:** - Slider de % de mejora/empeoramiento: -20% a +20% - Cambio de FSR futuro (si se espera cambio legal) - Cambio de salario promedio (aumentos programados) - Ver impacto en tiempo real 4. **Exportar Escenario:** - Guardar escenario con nombre - Ejemplo: "Escenario Post-Aumento Salarial Diciembre" - Compartir con equipo vía link ### CA-10: Permisos por Rol 🔐 **Roles y Permisos:** | Acción | Director | Engineer | Resident | HR | Finance | |--------|----------|----------|----------|-----|---------| | Ver dashboard costeo | ✅ | ✅ | ✅ | ❌ | ✅ | | Configurar FSR | ✅ | ❌ | ❌ | ❌ | ❌ | | Asignar cuadrillas a partidas | ✅ | ✅ | ✅ | ❌ | ❌ | | Ver detalle de empleados | ✅ | ✅ | ✅ | ✅ | ✅ | | Ver salarios individuales | ✅ | ❌ | ❌ | ✅ | ✅ | | Exportar reportes | ✅ | ✅ | ✅ | ❌ | ✅ | | Crear proyecciones | ✅ | ✅ | ❌ | ❌ | ❌ | --- ## 🔧 Detalles Técnicos ### Arquitectura Event-Driven ```typescript // labor-costs.service.ts import { Injectable } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; @Injectable() export class LaborCostsService { /** * Event listener que se ejecuta cuando se aprueba asistencia */ @OnEvent('attendance.approved') async handleAttendanceApproved(attendance: AttendanceRecord) { // 1. Obtener empleado y salario const employee = await this.getEmployeeWithSalary(attendance.employeeId); // 2. Obtener FSR de la constructora const fsrConfig = await this.getFSRConfig(employee.constructoraId); // 3. Calcular días trabajados const daysWorked = await this.calculateDaysWorked(attendance); // 4. Determinar partida presupuestal const budgetItemId = await this.determineBudgetItem( attendance.employeeId, attendance.workId, attendance.workDate ); // 5. Crear registro de costo const laborCost = this.laborCostRepo.create({ attendanceId: attendance.id, employeeId: attendance.employeeId, workId: attendance.workId, budgetItemId, workDate: attendance.workDate, daysWorked, dailySalary: employee.workSpecificSalary || employee.currentSalary, fsr: fsrConfig.totalFsr, // realCost se calcula automáticamente en BD con GENERATED column }); await this.laborCostRepo.save(laborCost); // 6. Verificar desviaciones y emitir alertas si es necesario await this.checkDeviations(attendance.workId); } } ``` ### Columna Calculada en PostgreSQL ```sql -- labor_costs table CREATE TABLE hr.labor_costs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), attendance_id UUID UNIQUE NOT NULL REFERENCES hr.attendance_records(id), employee_id UUID NOT NULL, work_id UUID NOT NULL, budget_item_id UUID REFERENCES budgets.budget_items(id), work_date DATE NOT NULL, days_worked DECIMAL(3,2) NOT NULL CHECK(days_worked > 0 AND days_worked <= 1), daily_salary DECIMAL(10,2) NOT NULL, fsr DECIMAL(4,2) NOT NULL, -- Columna generada automáticamente real_cost DECIMAL(10,2) GENERATED ALWAYS AS (daily_salary * days_worked * fsr) STORED, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX idx_labor_costs_work ON hr.labor_costs(work_id, work_date); CREATE INDEX idx_labor_costs_budget_item ON hr.labor_costs(budget_item_id); ``` ### Query de Dashboard ```typescript // Obtener resumen de costeo por obra async getCostSummary(workId: string) { // 1. Total presupuestado de MO const budgetedLabor = await this.db.query(` SELECT SUM(labor_cost) as total FROM budgets.budget_items WHERE work_id = $1 `, [workId]); // 2. Total real gastado const realLabor = await this.db.query(` SELECT SUM(real_cost) as total, COUNT(*) as total_records, SUM(days_worked) as total_days FROM hr.labor_costs WHERE work_id = $1 `, [workId]); // 3. Avance físico (de control de obra) const physicalProgress = await this.getPhysicalProgress(workId); // 4. Proyección const projected = physicalProgress > 10 ? (realLabor.total / physicalProgress) * 100 : null; // 5. Desviación const deviation = projected ? ((projected - budgetedLabor.total) / budgetedLabor.total) * 100 : null; return { budgeted: budgetedLabor.total, real: realLabor.total, totalDays: realLabor.total_days, physicalProgress, projected, deviation, status: this.getDeviationStatus(deviation), }; } ``` ### Componente React del Dashboard ```typescript // CostDashboard.tsx import { useQuery } from '@tanstack/react-query'; import { Card } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; export function CostDashboard({ workId }: { workId: string }) { const { data, isLoading } = useQuery({ queryKey: ['labor-costs', 'summary', workId], queryFn: () => apiService.get(`/hr/labor-costs/summary/${workId}`), refetchInterval: 60000, // Actualizar cada minuto }); if (isLoading) return ; const statusColors = { green: 'bg-green-500', yellow: 'bg-yellow-500', red: 'bg-red-500', }; return (
{/* Tarjetas de resumen */}

Presupuesto MO

${data.budgeted.toLocaleString('es-MX')}

Real Gastado

${data.real.toLocaleString('es-MX')}

{data.totalDays} días-hombre

Proyección 100%

${data.projected?.toLocaleString('es-MX') || 'N/A'}

Avance: {data.physicalProgress}%

Desviación

{data.deviation > 0 ? '+' : ''} {data.deviation?.toFixed(1)}%

{data.status.toUpperCase()}
{/* Tabla de partidas */} {/* Gráfica de tendencia */}
); } ``` --- ## 🧪 Casos de Prueba ### TC-COST-001: Cálculo Automático de Costo ✅ **Precondiciones:** - Empleado: Juan Pérez, salario $500/día - FSR configurado: 1.58 - Asistencia: 1.0 día trabajado **Pasos:** 1. Aprobar asistencia del empleado 2. Event `attendance.approved` se dispara 3. Sistema calcula costo automáticamente **Resultado esperado:** - Registro en `hr.labor_costs` creado: - `dailySalary`: 500.00 - `daysWorked`: 1.0 - `fsr`: 1.58 - `realCost`: 790.00 (calculado automáticamente) - Cálculo: 500 × 1.0 × 1.58 = 790.00 - Proceso completado en < 500ms ### TC-COST-002: Asignación a Partida Presupuestal ✅ **Precondiciones:** - Empleado pertenece a Cuadrilla "Albañilería A" - Cuadrilla asignada a partida "03.02 - Muro de Block" desde 2025-11-10 - Fecha de trabajo: 2025-11-17 **Pasos:** 1. Registrar asistencia del empleado 2. Sistema determina partida automáticamente **Resultado esperado:** - `budgetItemId` = UUID de "03.02 - Muro de Block" - Costo se imputa a esa partida - Visible en dashboard bajo "Muro de Block" ### TC-COST-003: Empleado Sin Partida Asignada (Indirecto) ✅ **Precondiciones:** - Empleado NO pertenece a ninguna cuadrilla - O cuadrilla sin asignación a partida **Pasos:** 1. Registrar asistencia **Resultado esperado:** - `budgetItemId` = null - Costo clasificado como "Indirecto" - Visible en fila "Indirecto" en dashboard ### TC-COST-004: Configuración de FSR ⚙️ **Precondiciones:** - Usuario con rol Director - FSR actual: 1.58 **Pasos:** 1. Ir a "Configuración" > "FSR" 2. Cambiar IMSS de 23% a 25% 3. Ver actualización automática: FSR = 1.60 4. Guardar cambios **Resultado esperado:** - FSR guardado como 1.60 - Fecha efectiva: 2025-11-17 - Log de auditoría registrado: - Usuario: Director - Cambio: IMSS 23% → 25%, FSR 1.58 → 1.60 - Nuevos cálculos usan 1.60 - Cálculos anteriores mantienen 1.58 ### TC-COST-005: Dashboard de Costeo ✅ **Precondiciones:** - Obra con presupuesto MO: $1,250,000 - Real gastado: $875,342 - Avance físico: 66.7% **Pasos:** 1. Ir a obra > "Costeo de Mano de Obra" 2. Ver dashboard **Resultado esperado:** - Presupuesto: $1,250,000 - Real: $875,342 - Proyección: $1,312,500 (calculado: 875342 / 0.667) - Desviación: +5.0% (calculado: (1312500-1250000)/1250000×100) - Badge amarillo (10% < desv. < 20%) ### TC-COST-006: Alerta de Desviación 🚨 **Precondiciones:** - Partida "04.01 - Castillos" - Presupuesto: $180,000 - Real gastado: $195,000 - Desviación: +8.3% → cambia a +16.5% **Pasos:** 1. Registrar más asistencias que aumentan el costo 2. Desviación supera 15% 3. Sistema detecta automáticamente **Resultado esperado:** - Notificación creada para Ingeniero Residente y Director - Contenido: ``` ⚠️ Alerta de Desviación Partida: 04.01 - Castillos Desviación: +16.5% Real: $209,700 vs Presupuesto: $180,000 ``` - Email enviado si está configurado - Dashboard de alertas muestra 1 nueva alerta ### TC-COST-007: Asignación de Cuadrilla a Partida ✅ **Precondiciones:** - Cuadrilla "Albañilería A" creada - Obra con presupuesto que incluye "03.02 - Muro de Block" **Pasos:** 1. Ir a Cuadrillas de la obra 2. Seleccionar "Albañilería A" 3. Clic en "Asignar a Partida" 4. Seleccionar "03.02 - Muro de Block" 5. Fecha inicio: 2025-11-10 6. Guardar **Resultado esperado:** - Registro creado en `crew_budget_assignments` - `startDate`: 2025-11-10 - `endDate`: null (abierta) - `isActive`: true - A partir del 2025-11-10, todos los costos de esa cuadrilla se imputan a esa partida ### TC-COST-008: Evitar Traslape de Asignaciones ❌ **Precondiciones:** - Cuadrilla ya asignada a "03.02 - Muro" desde 2025-11-10 (sin fecha fin) **Pasos:** 1. Intentar asignar la misma cuadrilla a "04.01 - Castillos" 2. Fecha inicio: 2025-11-15 **Resultado esperado:** - Error: "La cuadrilla ya está asignada a '03.02 - Muro de Block' desde 2025-11-10" - Sugerencia: "Cierra la asignación anterior o usa otra cuadrilla" - No se permite guardar ### TC-COST-009: Proyección de Escenarios 🔮 **Precondiciones:** - Obra con costo real $875,342 - Proyección base: $1,312,500 **Pasos:** 1. Ir a "Proyecciones" 2. Mover slider a "Mejora del 10%" **Resultado esperado:** - Proyección actualizada en tiempo real - Nuevo valor: $1,181,250 (1312500 × 0.9) - Desviación: -5.5% - Badge verde - Gráfica se actualiza mostrando nueva línea de proyección ### TC-COST-010: Comparación Histórica de Obras 📈 **Precondiciones:** - 3 obras completadas con datos de costeo **Pasos:** 1. Ir a "Reportes" > "Análisis Comparativo" 2. Seleccionar 3 obras 3. Ver tabla y gráfica **Resultado esperado:** - Tabla muestra: - Casa Norte: $5,240/m², Eficiencia 95% - Casa Sur: $4,600/m², Eficiencia 106% ⭐ Mejor - Edificio A: $4,750/m², Eficiencia 92% - Gráfica de dispersión muestra 3 puntos - Casa Sur identificada como benchmark - Opción de exportar a PDF visible --- ## 📦 Dependencias ### Dependencias de Otros US - ✅ **US-FUND-004:** Infraestructura (event emitters, TypeORM) - ✅ **US-HR-001:** Empleados y cuadrillas - ⏳ **US-HR-002:** Asistencias (genera evento attendance.approved) - ⏳ **US-BUD-001:** Presupuestos (partidas presupuestales) - ⏳ **US-PROJ-003:** Control de Obra (% de avance físico) ### Librerías Backend ```json { "@nestjs/event-emitter": "^2.0.3", "decimal.js": "^10.4.3" } ``` ### Librerías Frontend ```json { "recharts": "^2.10.3", "date-fns": "^3.0.1", "jspdf": "^2.5.1" } ``` --- ## ⚠️ Riesgos ### R-1: Cambios Retroactivos de FSR **Descripción:** Si se cambia el FSR, usuarios pueden esperar recálculo retroactivo **Impacto:** Medio **Probabilidad:** Media **Mitigación:** - FSR NO es retroactivo por diseño - Mensaje claro al guardar: "Aplicará solo a registros futuros" - Opción de "Recálculo Masivo" solo para Director (con auditoría) ### R-2: Precisión de Proyección con Bajo Avance **Descripción:** Proyección al 100% es imprecisa si avance < 10% **Impacto:** Medio **Probabilidad:** Alta **Mitigación:** - No mostrar proyección si avance < 10% - Mensaje: "Proyección disponible cuando avance > 10%" - Usar promedio de obras similares como referencia inicial ### R-3: Desvinculación de Empleado de Cuadrilla **Descripción:** Si empleado sale de cuadrilla, costos pasados pueden quedar "huérfanos" **Impacto:** Bajo **Probabilidad:** Media **Mitigación:** - Los costos históricos NO se modifican - Solo costos **futuros** usan la nueva asignación - Historial de asignaciones mantiene trazabilidad --- ## 📊 Métricas de Éxito **Métricas de Negocio:** - ✅ 90% de obras con desviación < 15% - ✅ Detección de desviaciones 2 semanas antes vs método manual - ✅ Reducción de 50% en sobrecostos por mejor control **Métricas Técnicas:** - ✅ Cálculo de costo < 500ms después de aprobar asistencia - ✅ Dashboard carga en < 2 segundos - ✅ 100% de costos con partida asignada o clasificados como indirecto **Métricas de Usuario:** - ✅ 95% de Ingenieros revisan dashboard semanalmente - ✅ 0 quejas de cálculos incorrectos en primer mes - ✅ Satisfacción > 4.5/5 --- ## 📋 Checklist de Implementación ### Backend - [ ] Crear tabla `hr.labor_costs` con columna generada - [ ] Crear tabla `hr.fsr_configuration` - [ ] Crear tabla `hr.crew_budget_assignments` - [ ] Implementar `LaborCostsService` con event listener - [ ] Implementar `FSRConfigurationService` - [ ] Implementar cálculo de días trabajados - [ ] Implementar determinación de partida presupuestal - [ ] Crear endpoints de dashboard - [ ] Crear endpoint de configuración FSR - [ ] Implementar sistema de alertas - [ ] Crear queries de comparación histórica - [ ] Crear seeds de FSR por defecto ### Frontend - [ ] Crear página `CostDashboard` - [ ] Crear componente `FSRConfiguration` - [ ] Crear componente `BudgetItemsTable` - [ ] Crear componente `CostTrendChart` con Recharts - [ ] Crear componente `CrewBudgetAssignment` - [ ] Crear componente `DeviationAlerts` - [ ] Crear página `HistoricalComparison` - [ ] Crear componente `ProjectionScenarios` - [ ] Implementar exportación a PDF - [ ] Implementar permisos por rol ### Testing - [ ] Tests de cálculo de costo real - [ ] Tests de event listener - [ ] Tests de validación de FSR (1.0 - 3.0) - [ ] Tests de detección de desviaciones - [ ] Tests de asignación de cuadrillas - [ ] Tests de traslape de fechas - [ ] Tests de proyecciones - [ ] Tests E2E de flujo completo --- **Fecha de creación:** 2025-11-17 **Versión:** 1.0 **Autor:** Equipo de Desarrollo **Revisado por:** Product Owner