# Procesos y Eventos

El plugin mantiene pocos procesos activos y concentra las reglas críticas en eventos de modelo.

## Procesos activos

<table id="bkmrk-procesousogenerateap" 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;">Proceso</th><th style="border:1px solid #d8dee9;padding:12px;background:#eef2f7;text-align:left;">Uso</th></tr></thead><tbody><tr><td style="border:1px solid #d8dee9;padding:12px;">`GenerateAppointmentSlots`</td><td style="border:1px solid #d8dee9;padding:12px;">Genera registros `CDS_AppointmentSlot` para el empleado, servicio y fecha seleccionados. Puede resolver valores desde la cita actual cuando se ejecuta desde la ventana.</td></tr><tr><td style="border:1px solid #d8dee9;padding:12px;">`ReopenAppointment`</td><td style="border:1px solid #d8dee9;padding:12px;">Reabre una cita procesada cambiándola a pendiente y limpiando `Processed` mediante un contexto controlado.</td></tr></tbody></table>

## Proceso `GenerateAppointmentSlots`

Este proceso se usa para crear horarios disponibles persistentes que luego pueden consultarse desde la ventana iDempiere o desde la API leyendo la tabla `CDS_AppointmentSlot`.

<table id="bkmrk-par%C3%A1metrorequeridous" 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;">Parámetro</th><th style="border:1px solid #d8dee9;padding:12px;background:#eef2f7;text-align:left;">Requerido</th><th style="border:1px solid #d8dee9;padding:12px;background:#eef2f7;text-align:left;">Uso</th></tr></thead><tbody><tr><td style="border:1px solid #d8dee9;padding:12px;">`AD_Org_ID`</td><td style="border:1px solid #d8dee9;padding:12px;">Sí, directo o resuelto desde la cita</td><td style="border:1px solid #d8dee9;padding:12px;">Organización para cargar configuración y validar disponibilidad.</td></tr><tr><td style="border:1px solid #d8dee9;padding:12px;">`CDS_AppointmentEmployee_ID`</td><td style="border:1px solid #d8dee9;padding:12px;">Sí</td><td style="border:1px solid #d8dee9;padding:12px;">Empleado para el cual se generan slots.</td></tr><tr><td style="border:1px solid #d8dee9;padding:12px;">`CDS_AppointmentService_ID`</td><td style="border:1px solid #d8dee9;padding:12px;">Sí</td><td style="border:1px solid #d8dee9;padding:12px;">Servicio que define duración, precio e intervalo del slot.</td></tr><tr><td style="border:1px solid #d8dee9;padding:12px;">`AppointmentDate`</td><td style="border:1px solid #d8dee9;padding:12px;">Sí</td><td style="border:1px solid #d8dee9;padding:12px;">Fecha para la cual se generan horarios disponibles.</td></tr><tr><td style="border:1px solid #d8dee9;padding:12px;">`CDS_Appointment_ID`</td><td style="border:1px solid #d8dee9;padding:12px;">Opcional</td><td style="border:1px solid #d8dee9;padding:12px;">Si se ejecuta desde una cita, permite resolver organización, empleado, servicio y fecha desde el registro actual.</td></tr></tbody></table>

Antes de generar nuevos slots, el proceso desactiva slots previos activos del usuario actual. Si hay una cita, desactiva los slots asociados a esa cita. Si no hay cita, desactiva slots del mismo usuario, empleado, servicio y fecha.

<p class="callout info">**Uso recomendado:** desde la ventana de cita se selecciona empleado, servicio y fecha; luego se ejecuta `GenerateAppointmentSlots`; finalmente se selecciona un registro de `CDS_AppointmentSlot`.</p>

## Proceso `ReopenAppointment`

Este proceso reabre una cita procesada para permitir correcciones administrativas controladas.

<table id="bkmrk-par%C3%A1metrorequeridous-1" 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;">Parámetro</th><th style="border:1px solid #d8dee9;padding:12px;background:#eef2f7;text-align:left;">Requerido</th><th style="border:1px solid #d8dee9;padding:12px;background:#eef2f7;text-align:left;">Uso</th></tr></thead><tbody><tr><td style="border:1px solid #d8dee9;padding:12px;">`CDS_Appointment_ID`</td><td style="border:1px solid #d8dee9;padding:12px;">Sí, directo o resuelto desde el registro actual</td><td style="border:1px solid #d8dee9;padding:12px;">Cita procesada que se desea reabrir.</td></tr></tbody></table>

Si la cita ya está abierta, el proceso informa que no requiere reapertura. Si está procesada, activa un contexto temporal `#CDS_ReopenAppointment`, coloca `Processed=N` y cambia el estado a `Pending`.

## Validación por evento actual

`AppointmentModelValidator` se ejecuta antes de crear o cambiar una cita. Para citas pendientes o aprobadas valida los datos mínimos y la disponibilidad real.

- Cliente requerido.
- Empleado requerido.
- Servicio requerido.
- Fecha de cita requerida.
- Hora inicial y final requeridas.
- Hora inicial menor que hora final.
- Fecha de cita igual al día de la hora inicial.
- Duración mayor que cero.
- Precio no negativo.
- Empleado habilitado para prestar el servicio.
- Slot consistente con empleado, servicio, horas, duración y precio.
- Sin bloqueo por día libre de organización o empleado.
- Horario cubierto por agenda del empleado.
- Sin conflicto con otra cita activa pendiente o aprobada.

## Estados y procesamiento actual

- Si el estado viene vacío, se asigna `Draft`.
- Los estados finales marcan `Processed = true`.
- Los estados no finales limpian `Processed`.
- Una cita procesada no se puede modificar salvo mediante reapertura controlada.

## Roadmap de validaciones en eventos

Las siguientes reglas deben agregarse al evento para que el comportamiento sea consistente desde ventanas iDempiere y desde REST/API.

<table id="bkmrk-validaci%C3%B3n-pendiente" 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;">Validación pendiente</th><th style="border:1px solid #d8dee9;padding:12px;background:#eef2f7;text-align:left;">Momento sugerido</th><th style="border:1px solid #d8dee9;padding:12px;background:#eef2f7;text-align:left;">Regla esperada</th></tr></thead><tbody><tr><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Resolver configuración desde servicio</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">`BeforeNew` y `BeforeChange`</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">El servicio debe indicar qué configuración de agenda aplica. La cita usa esa configuración para anticipación, horario macro y aprobación.</td></tr><tr><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Servicio con una sola configuración</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Al guardar servicio o relación configuración-servicio</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Un servicio no debe estar asociado a más de una configuración activa.</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;">`BeforeNew` y generación de slots</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Si `StartDateTime` está antes de ahora + `MinAdvanceHours`, la cita o slot debe bloquearse.</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;">`BeforeNew` y generación de slots</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Si `StartDateTime` supera hoy + `MaxAdvanceDays`, la cita o slot debe bloquearse.</td></tr><tr><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Horario macro de configuración</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">`BeforeNew`, `BeforeChange` y generación de slots</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">El horario de agenda general debe contener el rango solicitado antes de evaluar el horario del empleado.</td></tr><tr><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Forzar aprobación</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">`BeforeNew`</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Si la configuración tiene `ForceApproval=Y`, la cita debe quedar pendiente aunque el servicio permita aprobación automática.</td></tr><tr><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Autoaprobar si el servicio lo permite</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">`BeforeNew`</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Si `AutoApproveIfServiceAllows=Y` y el servicio no requiere aprobación, la cita puede quedar `Approved`.</td></tr></tbody></table>

## Roadmap de workflows y correos

Además de las validaciones, falta definir workflows y plantillas de correo para notificar al cliente cuando cambie el estado de una cita.

<table id="bkmrk-flujo-pendientedispa" 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;">Flujo pendiente</th><th style="border:1px solid #d8dee9;padding:12px;background:#eef2f7;text-align:left;">Disparo sugerido</th><th style="border:1px solid #d8dee9;padding:12px;background:#eef2f7;text-align:left;">Resultado esperado</th></tr></thead><tbody><tr><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Notificar cita aprobada</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Cambio de estado a `Approved`.</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Enviar correo al cliente con fecha, hora, servicio y empleado.</td></tr><tr><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Notificar cita cancelada</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Cambio de estado a `Cancelled`.</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Enviar correo al cliente con el motivo de cancelación cuando exista.</td></tr><tr><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Notificar reprogramación</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Cambio de fecha, hora o empleado.</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Enviar correo con el nuevo horario confirmado.</td></tr><tr><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Recordatorio de cita</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Proceso programado antes de `StartDateTime`.</td><td style="border:1px solid #d8dee9;padding:12px;vertical-align:top;">Enviar recordatorio al cliente según configuración.</td></tr></tbody></table>

También falta crear las plantillas de correo, definir destinatarios, configurar remitente, parametrizar cuándo enviar cada notificación y evitar reenvíos duplicados con campos de control si aplica.

## Orden recomendado de validación

1. Resolver servicio, empleado y organización.
2. Resolver configuración de agenda desde el servicio.
3. Aplicar reglas de anticipación mínima y máxima.
4. Validar horario macro de configuración.
5. Validar días libres de organización vinculados a la configuración.
6. Validar relación empleado-servicio.
7. Validar horario y días libres del empleado.
8. Validar slot seleccionado.
9. Validar conflictos con citas existentes.
10. Resolver estado de aprobación: pendiente o aprobada.