# Phase 5: Cart & Checkout (Filament + Manager API + Customer Pre-order)

## Objective
Deliver the complete dine-in ordering and checkout flow for restaurant managers, customer pre-ordering with prepayment, and Filament order management — all in one phase. Follows the exact same cart/payment patterns as the Shop Manager module.

---

## Filament Admin

### 5.1 OrdersRelationManager (Restaurant Context)

**File:** `app/Filament/Resources/RestaurantResource/RelationManagers/OrdersRelationManager.php`

Shows orders linked to this restaurant (via `restaurant_id` on Order model).

**Table Columns:**
- Order ID (public_id), Customer name, Items count, Total, Tip, Payment provider (badge), Status (badge), Table(s), created_at

**Filters:**
- Status, Payment provider, Date range

**Actions:**
- View order detail (modal)
- Download invoice PDF
- Resend invoice

### 5.2 Restaurant Order Detail View

In the order view modal or page:
- Customer info
- Table(s) assigned
- Line items with menu item names, quantities, prices
- Subtotal, Tip, Total
- Payment details (provider, receipt photo for POS, cash amounts for CASH)
- Invoice link

---

## API Endpoints (Restaurant Manager — Cart)

### 5.3 List Carts

**Controller:** `app/Http/Controllers/Api/Employee/RestaurantManager/ListCartsController.php`

- `GET /v1/places/{place}/restaurants/{restaurant}/carts`
- Returns all orders with status=WAITING_PAYMENT, restaurant_id=this restaurant, employee_id=current user
- Each cart includes: customer info, items, table(s), subtotal

### 5.4 Create Cart

**Controller:** `app/Http/Controllers/Api/Employee/RestaurantManager/CreateCartController.php`

- `POST /v1/places/{place}/restaurants/{restaurant}/carts`
- Body:
```json
{
  "customer_id": "user_public_id",
  "table_ids": ["table_public_id_1"]
}
```
- `customer_id` is optional (walk-in without customer)
- `table_ids` is optional (can assign later)
- Creates Order with:
  - status = WAITING_PAYMENT
  - restaurant_id = restaurant.id
  - employee_id = authenticated employee.id
  - place_id = place.id
- If tables provided, sets table status to OCCUPIED

### 5.5 Show Cart

**Controller:** `app/Http/Controllers/Api/Employee/RestaurantManager/ShowCartController.php`

- `GET /v1/places/{place}/restaurants/{restaurant}/carts/{order}`
- Returns full cart with items, customer, tables, totals

### 5.6 Update Cart (Full Replace)

**Controller:** `app/Http/Controllers/Api/Employee/RestaurantManager/UpdateCartController.php`

- `PUT /v1/places/{place}/restaurants/{restaurant}/carts/{order}`
- Replaces entire item list

### 5.7 Delete Cart

**Controller:** `app/Http/Controllers/Api/Employee/RestaurantManager/DeleteCartController.php`

- `DELETE /v1/places/{place}/restaurants/{restaurant}/carts/{order}`
- Frees assigned tables (status → AVAILABLE)
- Deletes order and items

### 5.8 Add Item to Cart

**Controller:** `app/Http/Controllers/Api/Employee/RestaurantManager/AddCartItemController.php`

- `POST /v1/places/{place}/restaurants/{restaurant}/carts/{order}/items`
- Body: `{ menu_item_id: "public_id", quantity: 2 }`
- Creates OrderItem with:
  - orderable_type = restaurant_menu_item
  - orderable_id = menu_item.id
  - metadata = { quantity }
  - money_price computed from RestaurantMenuItem::orderableMoneyPrice()

### 5.9 Update Item Quantity

**Controller:** `app/Http/Controllers/Api/Employee/RestaurantManager/UpdateCartItemQuantityController.php`

- `PATCH /v1/places/{place}/restaurants/{restaurant}/carts/{order}/items/{item}`
- Body: `{ quantity: 3 }`
- Updates metadata.quantity and recalculates price

### 5.10 Remove Item

**Controller:** `app/Http/Controllers/Api/Employee/RestaurantManager/RemoveCartItemController.php`

- `DELETE /v1/places/{place}/restaurants/{restaurant}/carts/{order}/items/{item}`

### 5.11 Change Cart Customer

**Controller:** `app/Http/Controllers/Api/Employee/RestaurantManager/ChangeCartCustomerController.php`

- `POST /v1/places/{place}/restaurants/{restaurant}/carts/{order}/customer`
- Body: `{ customer_id: "user_public_id" }`

### 5.12 Assign Tables to Cart

**Controller:** `app/Http/Controllers/Api/Employee/RestaurantManager/AssignCartTablesController.php`

- `POST /v1/places/{place}/restaurants/{restaurant}/carts/{order}/tables`
- Body: `{ table_ids: ["table_public_id_1", "table_public_id_2"] }`
- Updates `restaurant_table_ids` JSON on order
- Sets table status to OCCUPIED

---

## API Endpoints (Restaurant Manager — Payment & Tips)

### 5.13 Add Tip

**Controller:** `app/Http/Controllers/Api/Employee/RestaurantManager/AddTipController.php`

- `POST /v1/places/{place}/restaurants/{restaurant}/carts/{order}/tip`
- Body: `{ amount: 500, currency: "EUR" }`
- Stores in `tip_amount` + `tip_currency` on Order
- Can be called before or after payment (updates if already set)

### 5.14–5.18 Payment Endpoints

Same pattern as Shop Manager. 5 controllers:

**Wallet:** `POST /carts/{order}/pay/wallet`
**Stripe:** `POST /carts/{order}/pay/stripe`
**Crypto:** `POST /carts/{order}/pay/crypto`
**POS:** `POST /carts/{order}/pay/pos` (+ receipt photo, terminal_id)
**Cash:** `POST /carts/{order}/pay/cash` (+ amounts, cash_photo)

All use existing Shop Manager payment actions (ProcessPosPaymentAction, ProcessCashPaymentAction) or create restaurant-specific wrappers if needed.

On payment success:
1. Order status → PAID
2. OrderPaid event fires
3. Invoice generated (queued job)
4. Assigned tables → status AVAILABLE (dine-in complete)

### 5.19–5.20 Orders & Invoices

**List Orders:** `GET /orders` — PAID orders for this restaurant
**Show Order:** `GET /orders/{order}` — full detail
**Download Invoice:** `GET /orders/{order}/invoice` — PDF
**Send Invoice:** `POST /orders/{order}/invoice/send` — email

Same pattern as Shop Manager controllers.

---

## API Endpoints (Restaurant Manager — Customer Management)

### 5.21 Search Customers

**Controller:** `app/Http/Controllers/Api/Employee/RestaurantManager/SearchCustomersController.php`

- `GET /v1/places/{place}/restaurants/{restaurant}/customers?q=...`
- Reuse Shop Manager's customer search logic

### 5.22 Create Customer

**Controller:** `app/Http/Controllers/Api/Employee/RestaurantManager/CreateCustomerController.php`

- `POST /v1/places/{place}/restaurants/{restaurant}/customers`
- Body: `{ firstname, lastname, email?, phone? }`
- Reuse `CreateQuickCustomerAction` from Shop Manager

---

## API Endpoints (Customer — Pre-order)

### 5.23 Create Pre-order

**Controller:** `app/Http/Controllers/Api/Restaurant/CreatePreorderController.php`

- `POST /v1/places/{place}/restaurants/{restaurant}/reservations/{reservation}/preorder`
- Body:
```json
{
  "items": [
    { "menu_item_id": "public_id_1", "quantity": 2 },
    { "menu_item_id": "public_id_2", "quantity": 1 }
  ]
}
```
- Creates Order with:
  - status = WAITING_PAYMENT
  - user_id = authenticated customer
  - restaurant_id = restaurant.id
  - place_id = place.id
  - employee_id = null (customer-initiated)
- Links order to reservation via `preorder_order_id`
- Only allowed if:
  - Reservation belongs to user
  - Reservation status is PENDING or CONFIRMED
  - Restaurant `accepts_preorders` is true
  - Menu items are active and available for reservation's date/service period

### 5.24 View Pre-order

**Controller:** `app/Http/Controllers/Api/Restaurant/ShowPreorderController.php`

- `GET /v1/places/{place}/restaurants/{restaurant}/reservations/{reservation}/preorder`
- Returns pre-order items, totals, payment status

### 5.25 Pay Pre-order

**Controller:** `app/Http/Controllers/Api/Restaurant/PayPreorderController.php`

- `POST /v1/places/{place}/restaurants/{restaurant}/reservations/{reservation}/preorder/pay`
- Body: `{ payment_method: "wallet|stripe" }`
- Only wallet and Stripe for customer pre-orders (no POS/Cash)
- On success: order status → PAID, customer notified

---

## Actions

### 5.26 CreateRestaurantCartAction

**File:** `app/Actions/RestaurantManager/CreateRestaurantCartAction.php`

Creates Order with restaurant context, assigns tables if provided.

### 5.27 AddMenuItemToCartAction

**File:** `app/Actions/RestaurantManager/AddMenuItemToCartAction.php`

Creates OrderItem from RestaurantMenuItem, computes pricing.

### 5.28 CompleteRestaurantOrderAction

**File:** `app/Actions/RestaurantManager/CompleteRestaurantOrderAction.php`

Handles post-payment side effects specific to restaurant:
- Free assigned tables
- Link to reservation if applicable

---

## Resources (API Serialization)

- `RestaurantCartResource` — order as cart with items, tables
- `RestaurantCartItemResource` — order item with menu item details
- `RestaurantOrderResource` — paid order summary
- `RestaurantOrderDetailResource` — full order with items, payment, tip, invoice
- `RestaurantPaymentResource` — payment confirmation
- `CustomerPreorderResource` — pre-order for customer view

---

## Tests

**File:** `tests/Feature/Controllers/RestaurantManager/CartCheckoutTest.php`

- [ ] Create cart with table assignment works
- [ ] Create cart without customer works (walk-in)
- [ ] Add menu item to cart creates correct OrderItem
- [ ] Update item quantity recalculates price
- [ ] Remove item from cart works
- [ ] Assign tables to cart sets tables to OCCUPIED
- [ ] Delete cart frees tables
- [ ] Add tip stores amount on order
- [ ] Pay via wallet: deducts balance, marks PAID, frees tables
- [ ] Pay via POS: stores receipt photo, marks PAID
- [ ] Pay via cash: validates change, stores photo, marks PAID
- [ ] Pay via Stripe: creates payment intent
- [ ] Invoice generated after payment
- [ ] List orders returns PAID restaurant orders
- [ ] Order detail includes tip and table info
- [ ] Customer: create pre-order links to reservation
- [ ] Customer: pre-order only if accepts_preorders=true
- [ ] Customer: pay pre-order via wallet works
- [ ] Customer: cannot pre-order for other user's reservation
- [ ] Customer: cannot pre-order inactive menu items
- [ ] Filament: orders visible in RestaurantResource
- [ ] All endpoints return public_id, never id
- [ ] Non-authorized users get 403

---

## Files Created/Modified

| Action | File |
|---|---|
| Create | `app/Filament/Resources/RestaurantResource/RelationManagers/OrdersRelationManager.php` |
| Create | Controllers: ~22 API controllers (cart 9 + payment 6 + orders 4 + customer 2 + preorder 3) |
| Create | Actions: 3 |
| Create | Resources: 6 API resources |
| Create | Requests: ~8 form requests |
| Create | `tests/Feature/Controllers/RestaurantManager/CartCheckoutTest.php` |
| Modify | `routes/api.php` — add cart, payment, order, preorder routes |
| Modify | `app/Listeners/` — handle OrderPaid for restaurant context (free tables) |

---

## Acceptance Criteria

- [ ] Filament: Restaurant orders visible and manageable
- [ ] Manager API: Full cart lifecycle (create → add items → assign tables → pay → invoice)
- [ ] All 5 payment methods work identically to Shop Manager
- [ ] Tips stored separately from order total, included in invoice
- [ ] Tables freed on payment completion or cart deletion
- [ ] Customer pre-order: create, view, pay linked to reservation
- [ ] Pre-order respects restaurant settings (accepts_preorders)
- [ ] Invoice generated as queued job after payment
- [ ] Customer search and creation reuses Shop Manager patterns
- [ ] Swagger annotations on all controllers
- [ ] All tests pass
- [ ] `vendor/bin/pint` passes on all new/modified files
- [ ] `vendor/bin/phpstan --level=7` passes on all new/modified files
