Skip to content

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.

  • 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).

MétodoFirmaResultado
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;
}

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 !== 1000
return 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.

createEmployee exige campos obligatorios y formato:

CampoRegla
rut, nombres, apellidos, fecha_nacimiento, fecha_ingreso, sexoObligatorios. Falta → Error("Faltan campos obligatorios").
rutRegex ^[0-9]+-[0-9kK]$ (formato 12345678-9).
sexoTrim + uppercase ∈ ["M", "F"].
estado_civilUppercase ∈ ["SOLTERO", "CASADO", "VIUDO", "DIVORCIADO", "SEPARADO"].
estado_empleadoUppercase ∈ ["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.

Antes de persistir, sanitizeData aplica reglas consistentes:

OperaciónCampos
trim() + uppercasesexo, estado_civil, estado_empleado, nacionalidad, tipo_cuenta.
trim() o null si vacíostrings opcionales (email, telefono, celular, direccion, etc.).
Coerción booleana flexibleasignacion_familiar acepta "true", "1", "on", "sí", "si", "y", "yes".
parseInt con piso 0hijos.
Defaultsestado_civil = "SOLTERO", nacionalidad = "CHILENA", estado_empleado = "ACTIVO".
OrigenMensajeCuá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 datosunique_violation (Postgres 23505)RUT duplicado a nivel de constraint.
Base de datosforeign_key_violation (Postgres 23503)delete con contratos vigentes que lo referencian.
  1. Endpoint HTTP llama a EmployeeService.createEmployee(ctx, data).

  2. validateEmployeeData(data) confirma obligatorios y formato.

  3. sanitizeData(data) normaliza strings, enums y booleans.

  4. EmployeeRepository.create(pool, cleanData, ctx.userId) persiste mediante buildInsert con created_by/updated_by.

  5. Retorna ServiceResult<void>. La UI recarga estado leyendo la lista actualizada.

RecursoUso
BaseServiceHereda getPool, log, validateRequired, success.
sqlBuilders (buildInsert, buildUpdate, buildWhere)Genera SQL parametrizado para evitar inyección.
remuneraciones.empleadosTabla del tenant.
remuneraciones.v_empleados_activosVista para consultas filtradas con joins precalculados.
ServiceCómo usa al empleado
ContractServiceempleado_id obligatorio al crear contrato; valida que exista.
AttendanceServiceVincula marcas, ausencias y horas extra al empleado.
VacationServiceCalcula saldo desde fecha_ingreso del empleado.
PayrollServiceHidrata contexto con datos personales, AFP, isapre y asignacion_familiar.
FiniquitoServiceMarca al empleado como FINIQUITADO con fecha_egreso al cierre del vínculo.