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.
Ubicación
Section titled “Ubicación”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.
API pública
Section titled “API pública”Lecturas
Section titled “Lecturas”| Método | Firma | Resultado |
|---|---|---|
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. |
Escrituras
Section titled “Escrituras”| Método | Firma | Comportamiento |
|---|---|---|
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étodos estáticos legacy
Section titled “Métodos estáticos legacy”| Método | Equivalente 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 batchinterface 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;}Transaccionalidad
Section titled “Transaccionalidad”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.
Validaciones
Section titled “Validaciones”| Operación | Validación |
|---|---|
saveMonthlyAttendance | validateRequired({ employeeId, records }, ["employeeId", "records"]). El service no valida los records uno por uno — confía en el repo y constraint DB. |
saveDailyAttendance | validateRequired({ employeeId, record }, ["employeeId", "record"]). |
delete | validateRequired({ 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.
Reglas críticas para payroll
Section titled “Reglas críticas para payroll”| Regla | Detalle |
|---|---|
| Resumen cerrado antes de liquidar | PayrollService 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 jornada | La grilla esperada se calcula con la jornada_id del contrato vigente; este service no la duplica. |
| Vacaciones/permisos | Cuando 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. |
Consumidores
Section titled “Consumidores”| Service | Cómo consume |
|---|---|
PayrollService (vía PayrollInputBuilder) | Lee getMonthlySummary para obtener días trabajados, ausencias por tipo y horas extra. |
VacationService / PermissionService | Escriben filas con tipo_ausencia cuando una solicitud se aprueba para el periodo. |
Sevastopol island attendance-view-island | Lee getMonthlyGrid para mostrar el calendario editable. |