Ir al contenido

Reservas y Pre-Tickets de Clínica

Una reserva es una cita agendada para una fecha futura en una clínica. A diferencia de la atención directa (ver Atender cliente), una reserva no crea ticket ni comisión hasta que el paciente llega. Sirve como “pre-ticket”: aparta la cita, valida que la suscripción estará vigente ese día y, al llegar, se convierte en un ticket real.

EstadoSignificado
scheduledAgendada, a la espera de la llegada.
consumedEl paciente llegó; se convirtió en un ticket (consumed_visit_id).
cancelledCancelada por la recepción (con nota opcional).
expiredVenció sin llegada (3 h después de la hora reservada).

Campos relevantes: reserved_for (fecha/hora de la cita), consumed_visit_id (ticket resultante), consumed_at, cancelled_at, cancel_note y expiry_notified_at (sello que evita notificar dos veces).

Método y rutaAcción
POST /reservationsCrear una reserva.
GET /reservationsListar reservas agendadas.
GET /reservations/checkValidar la suscripción a la fecha futura sin agendar.
GET /reservations/summaryConteos para el tablero (hoy / próximas).
POST /reservations/:id/cancelCancelar una reserva agendada.
POST /reservations/:id/arriveRegistrar la llegada y abrir el ticket.

Al crear o verificar una reserva, el sistema no valida la suscripción de hoy sino la de la fecha reservada. Para ello busca la suscripción que cubre esa fecha (starts_at ≤ fecha ≤ valid_until y estado activo); si ninguna la cubre, toma la más reciente para clasificarla (no iniciada, vencida o inactiva). Así una reserva para la próxima semana se acepta si la suscripción seguirá vigente entonces, aunque hoy esté por renovar.

La llegada es atómica: todo ocurre en una sola transacción y, si algo falla, se revierte por completo.

graph TD
    A[POST /reservations/:id/arrive] --> B[Cargar la reserva]
    B --> C{Re-verificar la<br/>suscripción HOY}
    C -->|No activa / sin acceso| R[Rechazo: no se abre ticket]
    C -->|Activa| D[Marcar reserva consumed<br/>solo si scheduled o expired]
    D --> E[Abrir ticket de clínica]
    E --> F[Enlazar consumed_visit_id<br/>al ticket creado]

Nótese que la suscripción se vuelve a verificar al momento de la llegada, no en el de la reserva: si la cobertura caducó entre el agendamiento y la cita, la llegada se rechaza. Una reserva ya expired todavía puede consumirse si el paciente llega y la suscripción sigue activa.

El detector de alertas de clínica (cada 5 minutos) marca como vencidas las reservas no atendidas:

  • Umbral: reserved_for venció hace más de 3 horas y la reserva sigue scheduled.
  • Operación atómica: una sola sentencia pasa el estado a expired y estampa expiry_notified_at, devolviendo las filas afectadas. El filtro expiry_notified_at IS NULL evita notificar dos veces si el trabajo se reinicia.
  • Notifica a quien creó la reserva (recepción) y a los administradores de la cuenta del miembro.
  • Deduplicación: una sola alerta reservation_expired sin resolver por clínica, más una notificación por reserva.

El resumen expone dos indicadores, calculados con el día calendario de Panamá: reservas de hoy y reservas próximas (agendadas a futuro). Solo cuentan las reservas en estado scheduled.

  • Una reserva no crea ticket ni comisión hasta la llegada.
  • Una reserva para una fecha futura se acepta si la suscripción estará vigente ese día.
  • Si la cobertura caduca antes de la cita, la llegada se rechaza.
  • Una reserva no atendida pasa a expired 3 horas después y notifica una sola vez.
  • Una reserva expired aún puede consumirse si el paciente llega con suscripción activa.