Skip to content

Payroll Service

Orchestrator · Remuneraciones

ServicePayrollMotor de Cálculo

PayrollService es la pieza central del dominio de remuneraciones del Orchestrator. Coordina la hidratación de datos, la ejecución del motor de cálculo y la persistencia de la liquidación. El dominio separa el cálculo puro (PayrollEngine y sus calculadoras) del acceso a datos (PayrollRepository) y de la orquestación transaccional (PayrollService).

  • Directorysrc/domain/payroll/
    • Directorycalculators/
      • BaseSalaryCalculator.ts
      • GratificationCalculator.ts
      • HealthPlanCalculator.ts
      • ProrrataCalculator.ts
      • SocialLawsCalculator.ts
      • TaxCalculator.ts
    • PayrollEngine.ts
    • PayrollInputBuilder.ts
    • PayrollRepository.ts
    • PayrollService.ts
    • pdf-template.ts
    • types.ts
    • tests /
CapaArchivoRol
ServicePayrollService.tsCapa de aplicación: valida, hidrata contexto, orquesta el cálculo, gestiona la transacción y los eventos. Extiende BaseService.
EnginePayrollEngine.tsFunción pura de cálculo, sin dependencias de base de datos. calculate(input) es determinista.
Input BuilderPayrollInputBuilder.tsConstrucción fluida y validada del PayrollInput (~30 campos).
RepositoryPayrollRepository.tsAcceso a PostgreSQL: hidratación de contexto, persistencia y consultas de router.
Calculatorscalculators/Reglas de negocio específicas, cada una aislada y testeable.
Typestypes.tsTipos compartidos del dominio: ContractType, HealthMode, GratificationMode.

PayrollEngine.calculate(input: PayrollInput) ejecuta el cálculo en este orden:

  1. Sueldo base prorrateadoBaseSalaryCalculator ajusta el sueldo base por días trabajados sobre la base de cálculo (30 por defecto), con piso en el sueldo mínimo.

  2. Horas extra — se obtiene el valor hora con el factor del Art. 32 y se aplican los recargos según el tipo de hora extra registrada.

  3. GratificaciónGratificationCalculator aplica el Art. 50 sobre el sueldo prorrateado más los bonos imponibles fijos.

  4. Total imponible — suma de haberes imponibles (sueldo, gratificación, bonos y horas extra); es la base de cotizaciones.

  5. Leyes socialesSocialLawsCalculator calcula AFP, salud, AFC y aportes patronales respetando los topes imponibles.

  6. Impuesto únicoTaxCalculator aplica la tabla del SII sobre la base tributable (imponible menos descuentos legales y APV).

  7. Haberes no imponiblesProrrataCalculator prorratea colación y movilización por días trabajados.

  8. Descuentos y líquido — se suman descuentos legales, impuesto, anticipos, préstamos y descuentos voluntarios; el líquido es el total de haberes menos el total de descuentos.

CalculadoraResponsabilidad
BaseSalaryCalculatorSueldo base prorrateado por días trabajados, con piso en el sueldo mínimo.
GratificationCalculatorGratificación legal (Art. 50): modos 25 %, abono anual, exento o sin gratificación.
SocialLawsCalculatorLeyes sociales: AFP, salud, AFC, SIS, mutual y aportes patronales, respetando topes.
TaxCalculatorImpuesto único de segunda categoría sobre la base tributable.
HealthPlanCalculatorResolución de la cotización de salud: FONASA 7 % vs. ISAPRE (mayor entre 7 % y plan pactado).
ProrrataCalculatorProrrateo mensual de montos fijos (colación, movilización) según días trabajados.
MétodoTipoDescripción
previewPayroll(ctx, contractId, period, overrides)LecturaCalcula una liquidación sin persistirla.
generatePayroll(ctx, contractId, period, options)EscrituraCalcula y persiste dentro de una transacción. Admite dryRun, force y overrides.
deletePayroll(ctx, id, force)EscrituraElimina una liquidación. Bloqueada para estados APROBADA y PAGADA salvo force.
updateFileUrl(ctx, id, url)EscrituraAsocia la URL del PDF de liquidación.
updateStatus(ctx, id, estado)EscrituraCambia el estado; al pasar a APROBADA encola el evento payroll:approved.

El Service recibe siempre un ServiceContext (tenant, usuario, base de datos) y sigue el patrón de servicio de backend: validación de parámetros, transacciones con withTransaction y resultados tipados.

El Service ajusta las tasas del seguro de cesantía (AFC) según el tipo de contrato antes de construir el PayrollInput:

Tipo de contratoTrabajadorEmpleadorIndemnización
INDEFINIDO0,6 %2,4 %
PLAZO_FIJO3,0 %
CASA_PARTICULAR3,0 %1,11 %

HealthPlanCalculator resuelve la cotización: en FONASA siempre se descuenta el 7 % de la base imponible topeada; en ISAPRE se descuenta el mayor entre ese 7 % legal y el plan pactado (UF o CLP).

AFP, salud y SIS comparten el tope de pensión; el seguro de cesantía usa un tope mayor. Los topes llegan en UF y se convierten a pesos con la UF del periodo liquidado.

generatePayroll corre dentro de una transacción: hidrata el contexto, calcula con el Engine y persiste con el Repository. La liquidación queda en estado CALCULADA.

EstadoSignificado
BORRADORLiquidación en preparación.
CALCULADAResultado generado y persistido.
APROBADALiquidación validada; emite el evento payroll:approved.
PAGADAPago registrado.
ANULADALiquidación dejada sin efecto.

savePayroll hace upsert de la cabecera —única por empleado, año y mes— y reescribe el detalle por concepto. Una liquidación APROBADA o PAGADA no se sobrescribe ni elimina salvo force.

import { PayrollService } from "@/domain/payroll/PayrollService";
const service = new PayrollService();
// Previsualización: calcula sin persistir
const preview = await service.previewPayroll(
ctx, // ServiceContext: tenant, usuario, base de datos
"contract-uuid-123",
new Date("2026-05-01"),
{ horas_extra_50: 5 }, // overrides opcionales
);
// Generación: calcula y persiste dentro de una transacción
const generated = await service.generatePayroll(
ctx,
"contract-uuid-123",
new Date("2026-05-01"),
{ dryRun: false, force: false },
);