Plataforma técnica · Orchestrator
Isapre Service
Remuneraciones Isapre Fonasa
IsapreService cumple dos roles: mantiene el catálogo de instituciones de salud (Fonasa, Banmédica, Cruz Blanca, etc.) y administra los contratos de salud por trabajador, que sí versionan plan UF y vigencia. La distinción es importante: el catálogo es referencia estable; los contratos son donde vive la información que PayrollService consume para calcular el descuento de salud.
A diferencia de AFP (que es un catálogo simple), Isapre requiere contrato porque cada trabajador puede pactar un plan UF distinto y porque ese plan cambia en el tiempo.
Ubicación
Section titled “Ubicación”Directoryorchestrator/src/domain/isapre/
- IsapreService.ts
- IsapreRepository.ts
- types.ts
Tablas: remuneraciones.isapre (catálogo) y remuneraciones.contrato_isapre (contratos de salud). Vista enriquecida: remuneraciones.v_contrato_isapre.
API pública
Section titled “API pública”Catálogo
Section titled “Catálogo”| Método | Firma |
|---|---|
findAll | (ctx) => Promise<Isapre[]> |
findById | (ctx, id) => Promise<Isapre | null> |
Contratos de salud
Section titled “Contratos de salud”| Método | Firma | Uso |
|---|---|---|
findContractsByContrato | (ctx, contratoId) => Promise<IsapreContractRow[]> | Historial de planes pactados para un contrato laboral. |
findContractById | (ctx, id) => Promise<IsapreContractRow | null> | Detalle individual del contrato de salud. |
findContractVigente | (ctx, contratoId, year?, month?) => Promise<IsapreContractVigenteRow | null> | Plan vigente al periodo. Default: año/mes actual en zona America/Santiago. |
listContracts | (ctx, limit=50, activeOnly=false) => Promise<IsapreContractRow[]> | Listado paginado, clamp [1, 200]. |
createContract | (ctx, data: IsapreContract) => Promise<ServiceResult<IsapreContractRow>> | Crea contrato de salud. |
updateContract | (ctx, id, data: Partial<IsapreContract>) => Promise<ServiceResult<IsapreContractRow>> | Update parcial. Falla con Error("No encontrado") si no existe. |
deleteContract | (ctx, id) => Promise<ServiceResult<boolean>> | Borra el contrato de salud. Falla con Error("No encontrado") si 0 filas. |
interface Isapre { id: string; codigo: string; nombre: string; razon_social?: string; activa?: boolean;}
interface IsapreContract { id?: string; contrato_id: string; // FK a remuneraciones.contratos isapre_id: string; // FK a remuneraciones.isapre numero_contrato?: string; // número del contrato Isapre del trabajador plan_codigo?: string; plan_nombre?: string; moneda?: string; // típicamente "UF" plan_uf: number; // valor pactado ges_uf?: number; // GES por separado adicionales_uf?: number; descuentos_uf?: number; num_cargas?: number; vigente_desde: string; // obligatorio vigente_hasta?: string;}Resolución del plan vigente
Section titled “Resolución del plan vigente”findContractVigente es el método más usado por payroll. Resuelve qué plan aplica al periodo del cálculo:
async findContractVigente(ctx, contratoId, year?, month?) { const { y, m } = currentYearMonthInChile(); const periodStr = `${year ?? y}-${String(month ?? m).padStart(2, "0")}-01`; return IsapreRepository.findContractVigenteByContrato(pool, contratoId, periodStr);}| Detalle | Implementación |
|---|---|
| Zona horaria | Intl.DateTimeFormat("en-CA", { timeZone: "America/Santiago", ... }). Evita off-by-one cerca de fin de mes en servidores UTC. |
| Formato del periodo | YYYY-MM-01 (primer día del mes). |
| Comparación en SQL | El repository compara contra vigente_desde <= periodo y (vigente_hasta IS NULL OR vigente_hasta >= periodo). |
| Sin plan | Si no hay contrato vigente, devuelve null → payroll asume Fonasa o falla según política. |
Validaciones de createContract
Section titled “Validaciones de createContract”| Campo | Regla |
|---|---|
contrato_id, isapre_id, vigente_desde | Obligatorios — validateRequired. |
plan_uf | Debe ser >= 0. Number(data.plan_uf) se coacciona; valor inválido → Error("plan_uf inválido"). |
updateContract valida existencia previa con findContractById.
Vista v_contrato_isapre
Section titled “Vista v_contrato_isapre”findContractsByContrato, findContractById y listContracts consultan la vista enriquecida que devuelve campos adicionales sobre la tabla base:
| Campo derivado | Origen |
|---|---|
empleado_nombre, empleado_rut | Join con remuneraciones.contratos → remuneraciones.empleados. |
isapre_nombre | Join con remuneraciones.isapre. |
cotizacion_total_uf | Suma de plan + ges + adicionales − descuentos. |
findContractVigenteByContrato usa un tipo distinto (IsapreContractVigenteRow) que además expone isapre_codigo, empleado_id y la vigencia como rango desde/hasta.
Errores
Section titled “Errores”| Origen | Mensaje | Cuándo |
|---|---|---|
validateRequired | "<campo> es requerido" | Falta contrato_id, isapre_id o vigente_desde al crear. |
| Service | "plan_uf inválido" | plan_uf no es número o es negativo. |
| Service | "No encontrado" | updateContract o deleteContract con id inexistente. |
Consumidores
Section titled “Consumidores”| Service | Cómo consume |
|---|---|
ContractService | getEmployeeData hace LEFT JOIN remuneraciones.isapre para incluir isapre_nombre en el PDF. |
PayrollService | Llama a findContractVigente(contratoId, anio, mes) para obtener plan_uf y calcular la diferencia adicional de salud. |
PrevisionsService | Agrupa montos calculados por isapre_id para la planilla Previred. |