# POS Flow (spec §127 "Critical Business Test")

This is the exact sequence executed live against the seeded database while
building this system.

1. **Login as cashier** → `POST /api/auth/login` with
   `cashier@petzy.example` / `Admin@123`.
2. **Select outlet** → outlet `1` ("PetZY Hotel & Restaurant"), from the
   user's assigned outlets.
3. **Open POS, select Dine-In, Table 1.**
4. **Add items** — Paneer Tikka × 2, Coffee (Medium variation) × 1:

   ```http
   POST /api/pos
   { "outlet_id": 1, "order_type": "dine_in", "table_id": 1, "guests": 2,
     "items": [{ "item_id": 1, "quantity": 2 }, { "item_id": 9, "variation_id": 2, "quantity": 1 }] }
   ```

   Server response (abridged) — subtotal `680.00`, tax `73.20`
   (CGST 6% + SGST 6% = 12% on the ₹560 starter line, CGST 2.5% + SGST 2.5%
   = 5% on the ₹120 coffee line — GST is always charged as both components
   together, never just one), grand total `753.20`,
   `order_number: "INV-PTZ01-2026-000001"`. Table 1 flips to `occupied` with
   `current_order_id` set.

5. **Submit KOT** → `POST /api/pos/1/kot`. Creates `kot`/`kot_items`,
   routes items to their kitchen stations (Tandoor for Paneer Tikka,
   Beverage for Coffee), deducts recipe stock for any recipe-linked item
   (none in this order), and emits `kot:new` to the `kitchen:1` Socket.IO
   room. Order status → `placed`.
6. **Kitchen accepts → starts → marks ready** →
   `PATCH /api/kitchen/kot/1/status` with `accepted`, then `preparing`,
   then `ready`. Each transition is validated against the KOT's current
   status and re-emits `kot:updated` to both the kitchen and outlet rooms.
7. **Return to POS, generate bill** — the order's live totals are already
   authoritative (computed at creation).
8. **Split payment** — cash ₹500 + UPI ₹253.20:

   ```http
   POST /api/payments
   { "order_id": 1, "payments": [
       { "method": "cash", "amount": 500 },
       { "method": "upi", "amount": 253.20, "reference_number": "UPI-TEST-1" } ] }
   ```

   Result: `paid_amount: 753.20`, `balance_amount: 0`, `status: "closed"`,
   `closed_at` set, and — because it's a dine-in order fully paid — Table 1
   is freed back to `available`.
9. **Verify inventory deduction** — `GET /api/inventory/transactions`
   (recipe-linked items only deduct stock; Paneer Tikka/Coffee aren't
   recipe-linked in the seed data, so no deduction occurred for this
   particular order — see a recipe-linked example below).
10. **Verify sales / payment reports** — `GET /api/reports/sales` and
    `GET /api/reports/payments` for the date range include this order once
    its status is `paid`/`closed`.

## Recipe-based inventory deduction

Selling **Paneer Butter Masala** (item `3`, which has a seeded recipe) would
deduct, per unit sold: Paneer 250g, Tomato 150g, Butter 30g, Cream 50ml,
Spices 10g — each recorded as an `inventory_transactions` row with
`type: "consumption"` and a negative quantity, inside the same database
transaction as the KOT submission (so a failure rolls back the whole KOT).

## RBAC verified live

- Cashier → `GET /api/users` → `403 Missing required permission: users.manage`.
- Cashier → `GET /api/pos?outlet_id=1` (their assigned outlet) → `200`.
- Cashier → `GET /api/orders?outlet_id=999` (not assigned) → `403 You do not have access to this outlet`.
