# Motor de Disponibilidad

`AppointmentAvailabilityEngine` concentra la lógica que decide si una cita o un slot es válido para un empleado, servicio y fecha determinados.

## Responsabilidades actuales

- Cargar una configuración activa por organización con fallback a organización `0`.
- Leer duración, precio e intervalo del servicio.
- Aplicar overrides de precio y duración por empleado-servicio.
- Validar que el empleado pueda prestar el servicio.
- Validar días libres de la organización.
- Validar días libres del empleado.
- Validar cobertura del horario semanal del empleado.
- Detectar conflictos con citas existentes pendientes o aprobadas.
- Aplicar límites diarios por empleado cuando correspondan.
- Crear slots persistentes para la UI de iDempiere.

## Regla de conflicto

Una cita se considera en conflicto cuando otra cita activa del mismo empleado se cruza con el rango nuevo y tiene estado pendiente o aprobado.

```
existing.StartDateTime < newEnd
AND existing.EndDateTime > newStart
AND existing.Status IN ('PE', 'AP')
AND existing.IsActive = 'Y'
```

## Generación de slots

La generación actual es específica por empleado. El proceso no genera para todos los empleados ni autoasigna el recurso; parte de una selección explícita de empleado, servicio y fecha.

<p class="callout info">**Nota:** esta decisión hace que el flujo de UI sea más claro: primero se elige quién atiende, luego qué servicio presta, después se generan horarios disponibles.</p>

## Reglas actuales vs reglas esperadas

<table id="bkmrk-reglaestado-actualco" style="width:100%;border-collapse:collapse;margin:12px 0 20px 0;"><thead><tr><th style="border:1px solid #d8dee9;padding:12px;background:#eef2f7;text-align:left;">Regla</th><th style="border:1px solid #d8dee9;padding:12px;background:#eef2f7;text-align:left;">Estado actual</th><th style="border:1px solid #d8dee9;padding:12px;background:#eef2f7;text-align:left;">Comportamiento esperado</th></tr></thead><tbody><tr><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Empleado presta servicio</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Implementado con `CDS_EmployeeService`.</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Se mantiene como regla obligatoria.</td></tr><tr><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Día libre de organización</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Implementado por organización. Aunque `CDS_OrgDayOff` tiene `CDS_AppointmentConfig_ID`, el motor actual no filtra por configuración.</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Debe filtrar por configuración cuando el servicio resuelva una configuración específica.</td></tr><tr><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Día libre de empleado</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Implementado con `CDS_EmployeeDayOff`.</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Se mantiene como bloqueo específico del empleado.</td></tr><tr><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Horario del empleado</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Implementado con `CDS_EmployeeScheduleLine`.</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Debe validarse después del horario macro de la configuración.</td></tr><tr><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Horario macro de agenda</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Pendiente. No existe aún una tabla equivalente a horario de configuración.</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Debe definir los días y rangos generales permitidos, por encima del horario del empleado.</td></tr><tr><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Anticipación mínima</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Pendiente. Existe `MinAdvanceHours`, pero no se valida todavía.</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Debe bloquear citas creadas con menos horas de anticipación que las configuradas.</td></tr><tr><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Anticipación máxima</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Pendiente. Existe `MaxAdvanceDays`, pero no se valida todavía.</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Debe bloquear citas demasiado futuras.</td></tr><tr><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Conflictos con citas existentes</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Implementado para estados `Pending` y `Approved`.</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Se mantiene como validación obligatoria.</td></tr><tr><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Aprobación automática o forzada</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Pendiente. Existen campos de configuración y servicio, pero no se aplican en el evento.</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Debe resolverse en `BeforeNew` usando configuración y servicio.</td></tr></tbody></table>

## Roadmap del motor

- Resolver la configuración desde el servicio seleccionado, no solo desde la organización.
- Agregar validación de horario macro de configuración antes del horario del empleado.
- Aplicar `MinAdvanceHours` y `MaxAdvanceDays` al generar slots y al guardar citas.
- Filtrar días libres de organización por configuración cuando exista relación.
- Aplicar reglas de aprobación en el evento antes de validar el estado final de la cita.