# Cancelled Status Refactor

## Goal
Replace the single `CANCELLED` status with 3 granular statuses that reflect what actually happened.

## New Statuses

| Status | Label | When |
|---|---|---|
| `CANCELLED_NOTPROCESSED` | Cancelled - Not Processed | Vendor was never involved (pending payment, local cancel, rebooking replacement) |
| `CANCELLED_REFUNDABLE` | Cancelled - Refundable | Vendor cancelled + refund was issued |
| `CANCELLED_NONREFUNDABLE` | Cancelled - Non Refundable | Vendor cancelled + no refund |

> Old `CANCELLED` records in DB stay as-is (backwards compatible). The `default` case in `getStatusLabel()` will still render them.

---

## Files to Update

### 1. `app/Models/ActivityBookingModel.php`
Add 3 new constants (keep `STATUS_CANCELLED` for old data):
```php
const STATUS_CANCELLED_NOTPROCESSED  = 'CANCELLED_NOTPROCESSED';
const STATUS_CANCELLED_REFUNDABLE    = 'CANCELLED_REFUNDABLE';
const STATUS_CANCELLED_NONREFUNDABLE = 'CANCELLED_NONREFUNDABLE';
```

---

### 2. `app/Http/Controllers/XeniApiController.php`
Five places where `'CANCELLED'` is assigned:

| Line | Method | New Status |
|---|---|---|
| ~8785 | `cancelBooking()` — local/custom/pending path | `CANCELLED_NOTPROCESSED` |
| ~8858 | `cancelBooking()` — vendor path | `CANCELLED_REFUNDABLE` or `CANCELLED_NONREFUNDABLE` (check `$isRefundable`, but this method doesn't call `determineRefundability` yet — needs to be added) |
| ~9133 | `cancelBookingXeni()` — already has `$isRefundable` | `CANCELLED_REFUNDABLE` or `CANCELLED_NONREFUNDABLE` |
| ~10939 | `cancelPendingBooking()` — user cancels unpaid booking | `CANCELLED_NOTPROCESSED` |
| ~12201 | Update booking flow — old booking replaced by new one | `CANCELLED_NOTPROCESSED` |

Also: `mapVendorStatus()` at ~line 3591 maps vendor-reported `CANCELLED`/`VOIDED` → keep as `CANCELLED` (this is a vendor status, not our status).

---

### 3. `app/Http/Controllers/AdminBookingController.php`
**`Rule::in()` arrays** — ~7 occurrences at lines: 49, 251, 563, 714, 851, 1019, 2022
Add all 3 new statuses alongside `CANCELLED`.

**`getStatusLabel()`** at line ~1153:
```php
'CANCELLED'              => 'Cancelled',
'CANCELLED_NOTPROCESSED' => 'Cancelled - Not Processed',
'CANCELLED_REFUNDABLE'   => 'Cancelled - Refundable',
'CANCELLED_NONREFUNDABLE'=> 'Cancelled - Non Refundable',
```

**`getStatusChangeDescription()`** at line ~2423:
```php
'CANCELLED'              => 'Booking cancelled',
'CANCELLED_NOTPROCESSED' => 'Booking cancelled (not processed by vendor)',
'CANCELLED_REFUNDABLE'   => 'Booking cancelled - refund issued',
'CANCELLED_NONREFUNDABLE'=> 'Booking cancelled - non refundable',
```

---

### 4. `app/Http/Controllers/XeniBookingsController.php`
**`getStatusLabel()`** at line ~1153 — same additions as AdminBookingController.

**`Rule::in()` array** at line ~908 — add 3 new statuses.

**Stats COUNT queries** at lines ~790 and ~876:
```sql
-- Change from:
COUNT(CASE WHEN status = 'CANCELLED' THEN 1 END) as cancelled_bookings
-- To:
COUNT(CASE WHEN status IN ('CANCELLED','CANCELLED_NOTPROCESSED','CANCELLED_REFUNDABLE','CANCELLED_NONREFUNDABLE') THEN 1 END) as cancelled_bookings
```

---

## Logic for `cancelBooking()` (~line 8741)
This method does NOT currently call `determineRefundability()`. For the vendor path, need to add:
```php
$cancellationPolicy = data_get($booking->bk_details_json, 'activity.cancellation_policy')
    ?? data_get($booking->bk_details_json, 'cancellation_policy');
$isRefundable = $this->determineRefundability($cancellationPolicy);

$booking->status = $isRefundable
    ? ActivityBookingModel::STATUS_CANCELLED_REFUNDABLE
    : ActivityBookingModel::STATUS_CANCELLED_NONREFUNDABLE;
```

---

## Status
- [x] `ActivityBookingModel.php` — add constants
- [x] `XeniApiController.php` — cancelBooking (local path) → CANCELLED_NOTPROCESSED
- [x] `XeniApiController.php` — cancelBooking (vendor path) + added determineRefundability() call
- [x] `XeniApiController.php` — cancelBookingXeni → REFUNDABLE / NONREFUNDABLE
- [x] `XeniApiController.php` — cancelPendingBooking → CANCELLED_NOTPROCESSED
- [x] `XeniApiController.php` — line ~12201 (rebooking replacement) → CANCELLED_NOTPROCESSED
- [x] `AdminBookingController.php` — Rule::in arrays (all spots)
- [x] `AdminBookingController.php` — getStatusLabel() (both instances)
- [x] `AdminBookingController.php` — getStatusChangeDescription()
- [x] `XeniBookingsController.php` — getStatusLabel()
- [x] `XeniBookingsController.php` — Rule::in array
- [x] `XeniBookingsController.php` — COUNT queries (2 spots)

## DONE ✓ — Implemented on 2026-03-11
