Plataforma técnica · Orchestrator
Employee Service
Remuneraciones Empleados Maestro
EmployeeService administra el maestro central de trabajadores. Expone CRUD con validaciones de identidad, sanitización antes de persistir y dos modos de consulta diferenciados: cuando hay filtros, lee desde una vista enriquecida con contrato/cargo/departamento/AFP/isapre; cuando no hay filtros, hace fallback a la tabla base con LIMIT 1000.
No calcula remuneraciones ni resuelve condiciones contractuales. Su responsabilidad es mantener la entidad empleado consistente para que ContractService, AttendanceService, VacationService, PayrollService y FiniquitoService operen sobre una base estable.
Ubicación
Section titled “Ubicación”Directoryorchestrator/src/domain/employees/
- EmployeeService.ts
- EmployeeRepository.ts
Tabla principal: remuneraciones.empleados. Vista enriquecida: remuneraciones.v_empleados_activos (incluye datos del contrato vigente, cargo, departamento, AFP e isapre).
API pública
Section titled “API pública”| Método | Firma | Resultado |
|---|---|---|
getEmployeeById | (ctx, id) => Promise<Employee | null> | Empleado completo o null si no existe. |
getEmployees | (ctx, filter: EmployeeFilter) => Promise<EmployeeListResult | Employee[]> | Con filtros → { rows, total } desde vista; sin filtros → array desde tabla base. |
createEmployee | (ctx, data: EmployeeInput) => Promise<ServiceResult<void>> | Persiste empleado sanitizado. Falla con Error si faltan obligatorios o formato inválido. |
updateEmployee | (ctx, id, data: EmployeeInput) => Promise<ServiceResult<boolean>> | Update parcial. true si afectó filas. |
deleteEmployee | (ctx, id) => Promise<ServiceResult<boolean>> | DELETE físico. Sin restricción FK → puede fallar si hay contratos vigentes. |
ServiceContext provee tenantDb y userId; el service usa this.getPool(tenantDb) para obtener el pool del tenant.
interface EmployeeFilter { q?: string; // búsqueda libre: nombre, RUT, cargo, departamento estado?: string; // ACTIVO | INACTIVO | VACACIONES | LICENCIA | FINIQUITADO scope?: string; // 'activos' fuerza uso de la vista limit?: number; // default 50, clamp [1, 1000] offset?: number; // default 0}
interface EmployeeInput { rut?: string; nombres?: string; apellidos?: string; fecha_nacimiento?: string | Date; sexo?: string; // M | F estado_civil?: string; // SOLTERO | CASADO | VIUDO | DIVORCIADO | SEPARADO nacionalidad?: string; // default CHILENA email?: string | null; telefono?: string | null; celular?: string | null; direccion?: string | null; comuna?: string | null; region?: string | null; codigo_postal?: string | null; fecha_ingreso?: string | Date; fecha_egreso?: string | Date | null; estado_empleado?: string; // default ACTIVO banco?: string | null; tipo_cuenta?: string | null; // CUENTA_CORRIENTE | CUENTA_VISTA | CUENTA_AHORRO numero_cuenta?: string | null; afp_id?: string | null; isapre_id?: string | null; foto_url?: string | null; observaciones?: string | null; asignacion_familiar?: boolean | string | number | null; hijos?: number | string | null;}Estrategia de consulta
Section titled “Estrategia de consulta”getEmployees decide qué fuente leer según el filtro recibido. La lógica activa la vista cuando el caller necesita datos contractuales o cuando paginará.
// Trigger: filter.scope === 'activos' | filter.q | filter.estado | filter.limit !== 1000return EmployeeRepository.findActiveWithFilters(pool, filter);// → { rows: EmployeeActiveRow[], total: number }Lee remuneraciones.v_empleados_activos con count + data paralelos. Cada fila incluye contrato vigente, cargo, departamento, AFP, isapre, antigüedad y edad calculadas.
return EmployeeRepository.findAllFallback(pool);// → Employee[] con LIMIT 1000Lee directo de remuneraciones.empleados. No incluye datos contractuales. Útil para selectores y dumps; el LIMIT 1000 evita explotar memoria.
Validaciones
Section titled “Validaciones”createEmployee exige campos obligatorios y formato:
| Campo | Regla |
|---|---|
rut, nombres, apellidos, fecha_nacimiento, fecha_ingreso, sexo | Obligatorios. Falta → Error("Faltan campos obligatorios"). |
rut | Regex ^[0-9]+-[0-9kK]$ (formato 12345678-9). |
sexo | Trim + uppercase ∈ ["M", "F"]. |
estado_civil | Uppercase ∈ ["SOLTERO", "CASADO", "VIUDO", "DIVORCIADO", "SEPARADO"]. |
estado_empleado | Uppercase ∈ ["ACTIVO", "INACTIVO", "VACACIONES", "LICENCIA", "FINIQUITADO"]. |
tipo_cuenta (si se envía) | Uppercase ∈ ["CUENTA_CORRIENTE", "CUENTA_VISTA", "CUENTA_AHORRO"]. |
updateEmployee valida sólo los campos enviados (parcial): rut, sexo, estado_civil si están presentes.
Sanitización
Section titled “Sanitización”Antes de persistir, sanitizeData aplica reglas consistentes:
| Operación | Campos |
|---|---|
trim() + uppercase | sexo, estado_civil, estado_empleado, nacionalidad, tipo_cuenta. |
trim() o null si vacío | strings opcionales (email, telefono, celular, direccion, etc.). |
| Coerción booleana flexible | asignacion_familiar acepta "true", "1", "on", "sí", "si", "y", "yes". |
parseInt con piso 0 | hijos. |
| Defaults | estado_civil = "SOLTERO", nacionalidad = "CHILENA", estado_empleado = "ACTIVO". |
Errores
Section titled “Errores”| Origen | Mensaje | Cuándo |
|---|---|---|
| Validación previa | "Faltan campos obligatorios" | Crear sin alguno de los 6 obligatorios. |
| Validación RUT | "Formato de RUT inválido. Debe ser: 12345678-9" | Crear/actualizar con RUT que no calza con el regex. |
| Validación sexo | "Sexo debe ser 'M' o 'F'" | Crear/actualizar con sexo fuera del catálogo. |
| Validación enum | "<Campo> debe ser uno de: A, B, C" | Estado civil, estado empleado o tipo cuenta fuera del catálogo. |
| Base de datos | unique_violation (Postgres 23505) | RUT duplicado a nivel de constraint. |
| Base de datos | foreign_key_violation (Postgres 23503) | delete con contratos vigentes que lo referencian. |
Flujo de escritura
Section titled “Flujo de escritura”-
Endpoint HTTP llama a
EmployeeService.createEmployee(ctx, data). -
validateEmployeeData(data)confirma obligatorios y formato. -
sanitizeData(data)normaliza strings, enums y booleans. -
EmployeeRepository.create(pool, cleanData, ctx.userId)persiste mediantebuildInsertconcreated_by/updated_by. -
Retorna
ServiceResult<void>. La UI recarga estado leyendo la lista actualizada.
Dependencias
Section titled “Dependencias”| Recurso | Uso |
|---|---|
BaseService | Hereda getPool, log, validateRequired, success. |
sqlBuilders (buildInsert, buildUpdate, buildWhere) | Genera SQL parametrizado para evitar inyección. |
remuneraciones.empleados | Tabla del tenant. |
remuneraciones.v_empleados_activos | Vista para consultas filtradas con joins precalculados. |
Consumidores
Section titled “Consumidores”| Service | Cómo usa al empleado |
|---|---|
ContractService | empleado_id obligatorio al crear contrato; valida que exista. |
AttendanceService | Vincula marcas, ausencias y horas extra al empleado. |
VacationService | Calcula saldo desde fecha_ingreso del empleado. |
PayrollService | Hidrata contexto con datos personales, AFP, isapre y asignacion_familiar. |
FiniquitoService | Marca al empleado como FINIQUITADO con fecha_egreso al cierre del vínculo. |