Skip to content

Plataforma técnica · Orchestrator

Attendance Service

Remuneraciones Asistencia

AttendanceService mantiene los marcajes de asistencia del empleado y expone dos vistas del periodo: la grilla mensual día por día (para la UI) y el resumen mensual con totales agregados (días trabajados, ausencias, horas extra) que PayrollEngine consume al armar el contexto de la liquidación.

El servicio expone tanto métodos de instancia (vía ServiceContext) como métodos estáticos legacy preservados para callers antiguos que reciben el Pool directamente. Los estáticos están marcados como TODO: remove after migration.

  • Directoryorchestrator/src/domain/attendance/
    • AttendanceService.ts
    • AttendanceRepository.ts

Tabla: remuneraciones.asistencia_mensual (1 fila por empleado por día). Vistas usadas: getMonthlyGrid y getMonthlySummary consultan agregaciones derivadas.

MétodoFirmaResultado
getMonthlyGrid(ctx, employeeId, monthDate) => Promise<GridRow[]>Una fila por día del mes con marcas, horas trabajadas, atrasos, ausencias.
getMonthlySummary(ctx, employeeId, monthDate) => Promise<MonthlySummary>Totales agregados listos para liquidar.
findById(ctx, id) => Promise<AttendanceRow | null>Marcaje individual.
findAll(ctx, filter: AttendanceListFilter) => Promise<AttendanceRow[]>Listado con filtros.
MétodoFirmaComportamiento
saveMonthlyAttendance(ctx, employeeId, records: AttendanceRecord[]) => Promise<ServiceResult<number>>Upsert batch transaccional. Devuelve cantidad de filas procesadas.
saveDailyAttendance(ctx, employeeId, record) => Promise<ServiceResult<void>>Upsert único usando el mismo batch helper.
delete(ctx, id) => Promise<ServiceResult<boolean>>Borra una fila por id.
MétodoEquivalente de instancia
AttendanceService.getMonthlyGrid(db, employeeId, monthDate)service.getMonthlyGrid(ctx, employeeId, monthDate)
AttendanceService.getMonthlySummary(db, employeeId, monthDate)service.getMonthlySummary(ctx, employeeId, monthDate)

Existen para llamadores que ya tienen Pool (típicamente otros services que entran con PoolClient dentro de una transacción). Se eliminarán cuando todos los callers migren al patrón ServiceContext.

// Input para upsert batch
interface AttendanceRecord {
fecha: string; // YYYY-MM-DD
hora_entrada?: string | null;
hora_salida?: string | null;
horas_trabajadas?: number;
horas_extra_50?: number;
horas_extra_100?: number;
ausencia?: boolean;
tipo_ausencia?: string | null;
observacion?: string | null;
}
interface AttendanceListFilter {
empleado_id?: string;
fecha_desde?: string;
fecha_hasta?: string;
limit?: number;
offset?: number;
}

saveMonthlyAttendance envuelve la operación en withTransaction(ctx, async (client) => {...}) heredado de BaseService. Si cualquier upsert falla, rollback de todo el lote — no quedan días “a medias”. AttendanceRepository.upsertAttendanceBatch itera sobre los records y aplica INSERT ... ON CONFLICT (empleado_id, fecha) DO UPDATE.

saveDailyAttendance no abre transacción propia; invoca el mismo upsertAttendanceBatch con un array de un único record, lo que garantiza la misma semántica de upsert.

OperaciónValidación
saveMonthlyAttendancevalidateRequired({ employeeId, records }, ["employeeId", "records"]). El service no valida los records uno por uno — confía en el repo y constraint DB.
saveDailyAttendancevalidateRequired({ employeeId, record }, ["employeeId", "record"]).
deletevalidateRequired({ id }, ["id"]).

Las reglas de coherencia (hora_salida > hora_entrada, horas_trabajadas dentro del límite de la jornada) se aplican aguas arriba en la UI o en PayrollEngine al momento de calcular; este service solo persiste lo que recibe.

ReglaDetalle
Resumen cerrado antes de liquidarPayrollService rechaza calcular liquidaciones definitivas si el resumen del periodo no está aprobado. La aprobación se materializa en una tabla separada (asistencia_cierre_mensual) que no administra este service.
Contexto de jornadaLa grilla esperada se calcula con la jornada_id del contrato vigente; este service no la duplica.
Vacaciones/permisosCuando una solicitud de VacationService o PermissionService se aprueba, marca los días correspondientes en la grilla con tipo_ausencia y el resumen los suma a la categoría adecuada.
ServiceCómo consume
PayrollService (vía PayrollInputBuilder)Lee getMonthlySummary para obtener días trabajados, ausencias por tipo y horas extra.
VacationService / PermissionServiceEscriben filas con tipo_ausencia cuando una solicitud se aprueba para el periodo.
Sevastopol island attendance-view-islandLee getMonthlyGrid para mostrar el calendario editable.