Sistema NEXUS v3.4 migrado con: Estructura principal: - core/orchestration: Sistema SIMCO + CAPVED (27 directivas, 28 perfiles) - core/catalog: Catalogo de funcionalidades reutilizables - shared/knowledge-base: Base de conocimiento compartida - devtools/scripts: Herramientas de desarrollo - control-plane/registries: Control de servicios y CI/CD - orchestration/: Configuracion de orquestacion de agentes Proyectos incluidos (11): - gamilit (submodule -> GitHub) - trading-platform (OrbiquanTIA) - erp-suite con 5 verticales: - erp-core, construccion, vidrio-templado - mecanicas-diesel, retail, clinicas - betting-analytics - inmobiliaria-analytics - platform_marketing_content - pos-micro, erp-basico Configuracion: - .gitignore completo para Node.js/Python/Docker - gamilit como submodule (git@github.com:rckrdmrd/gamilit-workspace.git) - Sistema de puertos estandarizado (3005-3199) Generated with NEXUS v3.4 Migration System EPIC-010: Configuracion Git y Repositorios
26 KiB
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:
-
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
-
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
-
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:
-
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)
-
Obtener FSR de la Constructora:
- Buscar FSR configurado: 1.58
- Fecha efectiva: 2025-11-15
-
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
- Basado en check-in y check-out:
-
Calcular Costo Real:
Costo Real = Salario Diario × Días Trabajados × FSR Costo Real = $500.00 × 1.0 × 1.58 = $790.00 -
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"
-
Guardar Registro de Costo:
{ "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:
-
Resumen en Tarjetas:
┌─────────────────────┐ ┌─────────────────────┐ │ Presupuesto MO │ │ Real Gastado │ │ $1,250,000 │ │ $875,342 │ └─────────────────────┘ └─────────────────────┘ ┌─────────────────────┐ ┌─────────────────────┐ │ Proyección 100% │ │ Desviación │ │ $1,312,500 │ │ +5.0% [AMARILLO] │ └─────────────────────┘ └─────────────────────┘ -
Indicadores de Color:
- Verde: Desviación < 10% (dentro de presupuesto)
- Amarillo: Desviación 10-20% (advertencia)
- Rojo: Desviación > 20% (crítico)
-
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
-
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:
-
Header:
- Partida: 03.02 - Muro de Block
- Presupuestado: $320,000
- Real gastado: $285,000
- Días-hombre: 570
-
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 ... ... ... ... -
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:
-
Ver Cuadrillas de la Obra:
- Lista de cuadrillas activas
- Por cada cuadrilla: nombre, tipo, supervisor, # miembros
-
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
-
Registro de Asignación:
{ "crewId": "uuid-crew", "workId": "uuid-work", "budgetItemId": "uuid-budget-item", "startDate": "2025-11-10", "endDate": null, // Abierta "isActive": true } -
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"
-
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:
-
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
-
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"
-
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:
-
Seleccionar Obras:
- Seleccionar hasta 5 obras para comparar
- Filtrar por: estado (activa, terminada), año, tipo de obra
-
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% -
Fórmulas:
- Costo/m² = Real MO / Metros cuadrados
- Eficiencia = (Presupuesto / Real) × 100
- Benchmark: Identificar obra con mejor costo/m²
-
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:
-
Ver Proyección Base:
- Basada en % de avance físico actual
- Costo final proyectado: $1,312,500
- Desviación proyectada: +5.0%
-
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
- Escenario Optimista: Si mejoramos rendimiento 10%
-
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
-
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
// 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
-- 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
// 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
// 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 <Skeleton />;
const statusColors = {
green: 'bg-green-500',
yellow: 'bg-yellow-500',
red: 'bg-red-500',
};
return (
<div className="space-y-6">
{/* Tarjetas de resumen */}
<div className="grid grid-cols-4 gap-4">
<Card className="p-6">
<p className="text-sm text-muted-foreground">Presupuesto MO</p>
<p className="text-3xl font-bold">
${data.budgeted.toLocaleString('es-MX')}
</p>
</Card>
<Card className="p-6">
<p className="text-sm text-muted-foreground">Real Gastado</p>
<p className="text-3xl font-bold">
${data.real.toLocaleString('es-MX')}
</p>
<p className="text-xs text-muted-foreground mt-1">
{data.totalDays} días-hombre
</p>
</Card>
<Card className="p-6">
<p className="text-sm text-muted-foreground">Proyección 100%</p>
<p className="text-3xl font-bold">
${data.projected?.toLocaleString('es-MX') || 'N/A'}
</p>
<p className="text-xs text-muted-foreground mt-1">
Avance: {data.physicalProgress}%
</p>
</Card>
<Card className="p-6">
<p className="text-sm text-muted-foreground">Desviación</p>
<div className="flex items-center gap-3">
<p className="text-3xl font-bold">
{data.deviation > 0 ? '+' : ''}
{data.deviation?.toFixed(1)}%
</p>
<Badge className={statusColors[data.status]}>
{data.status.toUpperCase()}
</Badge>
</div>
</Card>
</div>
{/* Tabla de partidas */}
<BudgetItemsTable workId={workId} />
{/* Gráfica de tendencia */}
<CostTrendChart workId={workId} />
</div>
);
}
🧪 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:
- Aprobar asistencia del empleado
- Event
attendance.approvedse dispara - Sistema calcula costo automáticamente
Resultado esperado:
- Registro en
hr.labor_costscreado:dailySalary: 500.00daysWorked: 1.0fsr: 1.58realCost: 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:
- Registrar asistencia del empleado
- 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:
- 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:
- Ir a "Configuración" > "FSR"
- Cambiar IMSS de 23% a 25%
- Ver actualización automática: FSR = 1.60
- 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:
- Ir a obra > "Costeo de Mano de Obra"
- 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:
- Registrar más asistencias que aumentan el costo
- Desviación supera 15%
- 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:
- Ir a Cuadrillas de la obra
- Seleccionar "Albañilería A"
- Clic en "Asignar a Partida"
- Seleccionar "03.02 - Muro de Block"
- Fecha inicio: 2025-11-10
- Guardar
Resultado esperado:
- Registro creado en
crew_budget_assignments startDate: 2025-11-10endDate: 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:
- Intentar asignar la misma cuadrilla a "04.01 - Castillos"
- 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:
- Ir a "Proyecciones"
- 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:
- Ir a "Reportes" > "Análisis Comparativo"
- Seleccionar 3 obras
- 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
{
"@nestjs/event-emitter": "^2.0.3",
"decimal.js": "^10.4.3"
}
Librerías Frontend
{
"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_costscon columna generada - Crear tabla
hr.fsr_configuration - Crear tabla
hr.crew_budget_assignments - Implementar
LaborCostsServicecon 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
CostTrendChartcon 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