# Manual On-Arrival Reservation + WhatsApp Notification

## Date
2026-06-29

## Goal
Change the owner/employee on-arrival reservation flow so that:

1. OTP is **only** required when a *new* `PendingCustomer` is created.
2. Reservation approval is **not** gated by OTP for registered customers or existing pending customers.
3. After a manual on-arrival reservation is confirmed, a WhatsApp message is sent to the customer with the reservation details.
4. The existing `PendingReservation` infrastructure is left in place and continues to be used to hold dates during validation.

## Background

The current flow is:

1. `POST /api/v1/reservations/on-arrival/prepare` — resolves or creates a customer; does not send OTP.
2. `POST /api/v1/reservations/on-arrival/validate` — creates a `PendingReservation`, holds dates, and sends an OTP to **every** customer.
3. `POST /api/v1/reservations/on-arrival/verify` — verifies the OTP and converts the pending reservation into a real `Reservation`.

This design sends OTP for registered customers and existing pending customers as well, which is unnecessary for a manual reservation made by an owner/employee. It also never notifies the customer that a reservation has been made.

## Clarifications from product owner

- `PendingCustomer.is_verified` is **not** set by OTP. It is set when a pending customer later registers as a normal `Customer`. OTP verification must therefore be tracked separately.
- OTP still confirms the reservation for new pending customers, just like the current logic.
- `PendingReservation` should be kept because it is useful for holding dates. It must not be removed from migrations or other parts of the system.

## Proposed flow

### Registered customer

1. `prepareOnArrival(phone)` → returns registered `customer`.
2. `validateOnArrival(...)` → creates a `PendingReservation`, immediately confirms it to a real `Reservation`, and sends a WhatsApp notification.

### Existing pending customer (phone already OTP-verified)

1. `prepareOnArrival(phone)` → returns existing `pending_customer`.
2. `validateOnArrival(...)` → creates a `PendingReservation`, immediately confirms it, and sends a WhatsApp notification.

### New pending customer

1. `prepareOnArrival(phone, name, whatsapp_number)` → creates `PendingCustomer` with `phone_verified_at = null`, returns `pending_customer`.
2. `validateOnArrival(...)` → creates a `PendingReservation`, sends an OTP, and returns the pending reservation.
3. `verifyOtp(phone, otp)` → verifies the OTP, sets `phone_verified_at`, confirms the pending reservation, and sends a WhatsApp notification.

## Architecture

### Database change

Add a nullable `phone_verified_at` timestamp to the `pending_customers` table:

- `null` = the pending customer's phone number has not been OTP-verified yet.
- Filled = the phone number has been OTP-verified; future manual reservations skip OTP.

Existing pending customers in production should be backfilled to their `created_at` value (or otherwise marked verified) so they are not blocked from future reservations.

### Component changes

| Component | Change |
|-----------|--------|
| `ReservationController::prepareOnArrival` | Stop sending OTP. Only resolve/create the customer and return the appropriate resource. |
| `ReservationController::validateOnArrival` | Branch based on customer type and `phone_verified_at`. Verified customers: create pending hold, confirm immediately, send WhatsApp. Unverified pending customers: create pending hold, send OTP, return pending reservation. |
| `PendingCustomerController::verifyOtp` | Keep reservation confirmation. After OTP is valid, set `phone_verified_at` on the pending customer, confirm the pending reservation, and send WhatsApp. |
| `ReservationService::persistFromPendingReservation` | Remove the `PendingCustomer.is_verified = true` update. Dispatch the new `ReservationCreated` notification after the real reservation is created. |
| `App\Notifications\ReservationCreated` (new) | Uses existing `WhatsAppChannel` + `AppDatabaseChannel` to notify the customer that a reservation has been made. |

### Notification content

The WhatsApp message should include the reservation details the customer needs:

- Reservation number
- Building / unit name
- Check-in and check-out dates
- Total price
- A short greeting/confirmation line

The exact message text is left to implementation; it should be concise and use the data available on the confirmed `Reservation` model.

### Error handling

- Dates unavailable during validation: cancel the pending hold and return `422` (existing behavior preserved).
- Unverified pending customer used in `verifyOtp` without a pending reservation: return `422` (existing behavior preserved).
- Invalid OTP: return `422` (existing behavior preserved).
- WhatsApp send failure: logged, not fatal. The reservation must still be confirmed.

## Testing updates

Update `tests/Feature/PendingCustomerFlowTest.php` to reflect the new behavior:

1. Registered customer flow: no OTP, reservation confirmed directly, WhatsApp dispatched.
2. Existing pending customer flow: no OTP, reservation confirmed directly, WhatsApp dispatched.
3. New pending customer flow: prepare → validate (OTP sent) → verify (reservation confirmed), WhatsApp dispatched after verify.
4. Assert that `phone_verified_at` is set after OTP verification.
5. Assert that `is_verified` is no longer changed by the OTP/reservation flow.

## Scope exclusions

- The `PendingReservation` model and table are not removed or altered beyond the existing fields.
- The online customer self-booking flow (`ReservationController::store`) is unchanged.
- No changes to owner/admin verification or registration flows.
