# Plan: booking_checkin — Notificación WA de Check-in 24hs antes del vuelo

## Estado actual (base sobre la que se construye)

| Componente | Estado |
|---|---|
| `SIT_BOOKING_CHECKIN` | ✅ Constante definida en stx.php |
| `SITS()[SIT_BOOKING_CHECKIN]` | ✅ Entrada en hardcode.php con `meta_template => 'booking_checkin'` |
| `AL_CHECKIN($x)` | ✅ Existe — lista plans con pasajeros en las próximas 2 semanas |
| `AL_WAO_ENQUEUE($x)` | ✅ Existe — encola mensajes en fly.wao con dedup automático |
| `fly.wao` | ✅ Tabla existente — contiene `bookingId, passengerId, wa_id, sit, meta_template, payload, context, status` |
| Template Meta `booking_checkin` | ❌ Pendiente de crear en Meta Business Manager |
| Builder `_wao_bld_booking_checkin()` | ❌ Pendiente |
| `AL_CHECKIN_ENQUEUE()` | ❌ Pendiente |
| Persistencia de respuesta del pasajero | ❌ Pendiente (campo o tabla) |
| Acción en motor.php | ❌ Pendiente |
| Handler de respuesta en webhook | ❌ Pendiente |

---

## Flujo completo

```
[Cron/n8n — diario]
        │
        ▼
AL_CHECKIN_ENQUEUE(planId o rango de fechas)
  ├── Query: plans con flightDate en próximas 24hs + pasajeros con wa_id + booking activo
  ├── Por cada pasajero → AL_WAO_ENQUEUE(eSendType: SIT_BOOKING_CHECKIN, passengerId, wa_id)
  │     └── _wao_bld_booking_checkin() → payload con 2 quick_reply buttons
  └── AL_WAO_MOTOR() lo envía vía Meta Graph API

[Pasajero recibe WA con 2 botones]
  ├── "✅ Confirmar abordaje"
  └── "❌ No viajaré"

[Pasajero presiona botón]
        │
        ▼
Webhook recibe button payload → execute: 'checkinConfirm' + reservationCode + response
        │
        ▼
Handler en motor.php actualiza fly.reservations.checkin_status
```

---

## Template Meta `booking_checkin`

**Tipo:** `template` con componente `BUTTONS` de tipo `QUICK_REPLY`

**Variables body:**
- `{{1}}` — nombre del pasajero (`userName`)
- `{{2}}` — código de reserva (`reservationCode`)
- `{{3}}` — resumen del itinerario (`itinerarySummary`) — ej: "EZE → MDZ · 19/05/2026 08:30"

**Botones:**
| Index | Texto visible | payload JSON |
|---|---|---|
| 0 | "✅ Confirmar abordaje" | `{"execute":"checkinConfirm","code":"XXXXXX","r":"ok"}` |
| 1 | "❌ No viajaré" | `{"execute":"checkinConfirm","code":"XXXXXX","r":"no"}` |

> `code` = `reservationCode` (6 chars). Mantener payload corto — Meta tiene límite de 128 chars.

---

## Tareas de desarrollo

### 1. Template Meta (Meta Business Manager)
Crear template `booking_checkin` con:
- Idioma: `es_AR`
- Category: `UTILITY`
- 3 variables body + 2 botones QUICK_REPLY con payload dinámico

### 2. `_wao_bld_booking_checkin($x)` — en airlines.php
Builder privado, igual que los existentes. Recibe `$x[summary]` y `$x[wa_id]`.
- Body: `userName`, `reservationCode`, `itinerarySummary`
- Button index 0: quick_reply payload `{"execute":"checkinConfirm","code":"{{reservationCode}}","r":"ok"}`
- Button index 1: quick_reply payload `{"execute":"checkinConfirm","code":"{{reservationCode}}","r":"no"}`
- Agregar `case SIT_BOOKING_CHECKIN:` en el switch de `AL_WAO_ENQUEUE`

### 3. Migración — `fly.reservations.checkin_status` — en autoconfig.php
```sql
ALTER TABLE fly.reservations ADD COLUMN checkin_status TINYINT DEFAULT 0;
-- 0 = sin acción  1 = confirmado  2 = no-show anunciado
```

### 4. `AL_CHECKIN_ENQUEUE($x)` — en airlines.php
Query sobre `fly.plans + fly.reservations + fly.booking + fly.passengers + fly.users`:
- Filtro: `plans.flightDate` entre `now()` y `now() + INTERVAL 25 HOUR`
  (ventana de 25hs para tolerar corridas del cron con desfasaje)
- Condición: `bookingStatus & BOOKING_NEGATIVE_CONDITION = 0`
- Destinatario por pasajero:
  - Si `passengers.wa_id > 0` → `wa_id = passengers.wa_id`, `userName = passengers.pax_name`
  - Si no → `wa_id = users.wa_id` (comprador), `userName = passengers.pax_name` (igual — el aviso es del pasajero)
  - Si tampoco el comprador tiene wa_id → omitir ese pasajero
- Por cada pasajero → `AL_WAO_ENQUEUE` con `passengerId` explícito
- La dedup ya la hace `AL_WAO_ENQUEUE` (chequea `fly.wao` por `bookingId+wa_id+sit+status=0`)
- Retorna `{enqueued, skipped, keyErr[]}`

### 5. Acción `checkinEnqueue` en motor.php
Punto de entrada para el cron. Recibe opcionalmente `planId` (para forzar un plan específico).
Sin `planId` → llama `AL_CHECKIN_ENQUEUE` con rango de fechas automático.

### 6. Handler `checkinConfirm` en motor.php
Recibe payload del botón WA (vía webhook n8n → motor.php):
```
POST motor.php  { execute: "checkinConfirm", code: "ABCDEF", r: "ok"|"no" }
```
- Busca `reservationId` por `reservationCode = code`
- Actualiza `fly.reservations.checkin_status` → 1 (ok) o 2 (no)
- Retorna `{status, reservationId}`

> El webhook n8n existente (`P4KkTvbO26SoFJGy`) necesita un nodo adicional que detecte
> `button_reply` con `execute == "checkinConfirm"` y lo ruteé a motor.php.

---

## Decisiones de arquitectura

| Decisión | Alternativa descartada | Motivo |
|---|---|---|
| "No viajaré" = solo informativo (`checkin_status=2`) | generar tarea/orden automática | El equipo resuelve el caso manualmente; no requiere automatización |
| Destinatario primario = `fly.passengers.wa_id` | solo comprador | Checkin es personal; el equipo necesita la confirmación del pasajero |
| Fallback si pasajero sin wa_id → comprador (`fly.users.wa_id`) con nombre del pasajero | ignorar al pasajero sin número | Evita perder la notificación; `userName` = nombre del pasajero igual |
| Ventana 24–25hs (no exacto) | 24hs exactas | Tolera desfasaje del cron sin duplicar (dedup de wao lo cubre) |
| `checkin_status` en fly.reservations | tabla separada fly.checkins | Menor complejidad; la reserva es la unidad correcta |
| payload corto `code + r` | payload con bookingId + passengerId | Límite 128 chars de Meta; `reservationCode` identifica unívocamente |

---

## Orden de implementación sugerido

1. Template Meta (sin esto nada funciona en producción)
2. Migración `checkin_status`
3. Builder + case en WAO_ENQUEUE
4. `AL_CHECKIN_ENQUEUE`
5. Acción `checkinEnqueue` en motor.php
6. Handler `checkinConfirm` en motor.php
7. Nodo en n8n para rutear respuestas

---

## Preguntas abiertas

- ¿El cron lo dispara n8n (como los otros procesos) o un cron job propio del servidor?