# Phase 5: Cart & Checkout (Dine-in ordering, payments, tips, pre-orders) — DONE

**Completed:** 2026-03-13

## What was delivered

### Actions (3)

- `app/Actions/RestaurantManager/CreateRestaurantCartAction.php` — Creates Order with WAITING_PAYMENT status, restaurant context, optional table assignment (sets OCCUPIED)
- `app/Actions/RestaurantManager/AddMenuItemToCartAction.php` — Adds menu item to cart or increments quantity if already present, uses OrderItem::makeFor() with restaurant mode metadata
- `app/Actions/RestaurantManager/CompleteRestaurantOrderAction.php` — Post-payment side effects: frees assigned restaurant tables (status → AVAILABLE)

### Form Requests (12)

- `app/Http/Requests/RestaurantManager/CreateCartRequest.php` — customer_id nullable, table_ids nullable array
- `app/Http/Requests/RestaurantManager/AddCartItemRequest.php` — menu_item_id required, quantity optional (default 1)
- `app/Http/Requests/RestaurantManager/UpdateCartRequest.php` — items array with menu_item_id + quantity
- `app/Http/Requests/RestaurantManager/UpdateCartItemQuantityRequest.php` — quantity required min:0
- `app/Http/Requests/RestaurantManager/ChangeCartCustomerRequest.php` — customer_id required
- `app/Http/Requests/RestaurantManager/AssignCartTablesRequest.php` — table_ids required array min:1
- `app/Http/Requests/RestaurantManager/AddTipRequest.php` — amount numeric min:0, currency size:3
- `app/Http/Requests/RestaurantManager/CashPaymentRequest.php` — amount_received, amount_returned, currency, cash_photo
- `app/Http/Requests/RestaurantManager/PosPaymentRequest.php` — receipt_photo, terminal_id nullable
- `app/Http/Requests/RestaurantManager/SendInvoiceRequest.php` — email required
- `app/Http/Requests/Restaurant/CreatePreorderRequest.php` — items array with menu_item_id + quantity
- `app/Http/Requests/Restaurant/PayPreorderRequest.php` — payment_method in:wallet,stripe

### API Resources (6)

- `app/Http/Resources/RestaurantManager/CartResource.php` — Order as cart: customer, items_count, table_ids, total, tip
- `app/Http/Resources/RestaurantManager/CartItemResource.php` — OrderItem with menu_item details, quantity, unit_price, total_price
- `app/Http/Resources/RestaurantManager/RestaurantOrderResource.php` — Order list: tip, table_ids, payment_provider
- `app/Http/Resources/RestaurantManager/RestaurantOrderDetailResource.php` — Full detail: items, tip, payment_details, has_invoice
- `app/Http/Resources/RestaurantManager/PaymentDetailsResource.php` — Payment confirmation: receipt_url, cash_photo_url, tip
- `app/Http/Resources/Restaurant/CustomerPreorderResource.php` — Pre-order customer view: items, total, status

### API Controllers — Restaurant Manager (22)

**Cart Management (10):**
- `ListCartsController` — GET paginated carts for restaurant
- `CreateCartController` — POST with optional customer + table assignment
- `ShowCartController` — GET cart detail with items
- `UpdateCartController` — PUT replace all items
- `DeleteCartController` — DELETE cart and free tables
- `AddCartItemController` — POST add menu item to cart
- `UpdateCartItemQuantityController` — PATCH item quantity
- `RemoveCartItemController` — DELETE item from cart
- `ChangeCartCustomerController` — PATCH change cart customer
- `AssignCartTablesController` — POST assign tables to cart

**Payment & Tips (6):**
- `AddTipController` — POST add/update tip (tip_amount + tip_currency)
- `WalletPayCartController` — POST wallet payment → markAsPaid + CompleteRestaurantOrderAction
- `CashPayOrderController` — POST cash payment via ProcessCashPaymentAction + CompleteRestaurantOrderAction
- `PosPayOrderController` — POST POS payment via ProcessPosPaymentAction + CompleteRestaurantOrderAction
- `StripePayCartController` — POST creates Stripe Checkout Session
- `CryptoPayCartController` — POST creates NOWPayments invoice

**Orders & Invoices (4):**
- `ListOrdersController` — GET paginated PAID orders
- `ShowOrderController` — GET order detail with employee ownership check
- `DownloadInvoiceController` — GET invoice PDF download
- `SendInvoiceController` — POST send invoice to email

**Customer Management (2):**
- `SearchCustomersController` — GET search by name/email
- `CreateCustomerController` — POST quick customer creation via CreateQuickCustomerAction

### API Controllers — Customer (3)

- `CreatePreorderController` — POST pre-order linked to reservation (validates ownership, accepts_preorders, status)
- `ShowPreorderController` — GET view own pre-order for reservation
- `PayPreorderController` — POST pay pre-order via wallet or stripe

### Filament Admin (1)

- `app/Filament/Resources/RestaurantResource/RelationManagers/OrdersRelationManager.php`
  - Shows PAID orders with columns: public_id, customer, items count, total, tip, payment provider badge, status badge, table IDs, date
  - Filters by status and payment provider
  - View action with modal for full order detail

### Routes (28)

- 22 Restaurant Manager routes under `v1/places/{place}/restaurants/{restaurant}/`:
  - Cart: GET/POST carts, GET/PUT/DELETE carts/{order}, POST carts/{order}/items, PATCH/DELETE carts/{order}/items/{item}, PATCH carts/{order}/customer, POST carts/{order}/tables
  - Payment: POST carts/{order}/tip, POST carts/{order}/pay/wallet, POST carts/{order}/pay/cash, POST carts/{order}/pay/pos, POST carts/{order}/pay/stripe, POST carts/{order}/pay/crypto
  - Orders: GET orders, GET orders/{order}, GET orders/{order}/invoice/download, POST orders/{order}/invoice/send
  - Customers: GET customers/search, POST customers
- 3 Customer routes under `v1/places/{place}/restaurants/{restaurant}/reservations/{reservation}/`:
  - POST preorder, GET preorder, POST preorder/pay

### Modified Files

- `app/Filament/Resources/RestaurantResource.php` — Added OrdersRelationManager to getRelations()
- `routes/api.php` — Added Phase 5 routes (manager + customer)

### Tests

- `tests/Feature/Controllers/RestaurantManager/CartCheckoutTest.php` — 15 test cases covering:
  - Create cart with table assignment (OCCUPIED check)
  - Create walk-in cart (no customer)
  - Add menu item to cart
  - Update item quantity
  - Remove item from cart
  - Assign tables to cart (OCCUPIED check)
  - Delete cart frees tables (AVAILABLE check)
  - Add tip to order
  - List paid restaurant orders
  - Customer pre-order linked to reservation
  - Pre-order denied when accepts_preorders=false
  - Pre-order denied for other user's reservation
  - Inactive menu items skipped in pre-order
  - Non-authorized users get 403
  - All endpoints return public_id, never internal id

## Quality Checks

- `vendor/bin/pint` — PASS (50 files, 1 auto-fixed style issue)
- `vendor/bin/phpstan --level=7` — PASS (0 errors after fixing 6 initial issues)

## Files Summary

| Type | Count |
|---|---|
| Actions | 3 |
| FormRequests | 12 |
| API Resources | 6 |
| API Controllers (Manager) | 22 |
| API Controllers (Customer) | 3 |
| Filament RelationManagers | 1 |
| Tests | 1 (15 test cases) |
| Modified files | 2 (RestaurantResource.php, routes/api.php) |
| **Total new files** | **48** |
