# Restaurant POS: Table Management API Specifications

Base URL for all routes: `/api/tables`

**Headers Required (All Routes):**
`Authorization: Bearer <your_jwt_token>`

---

## 1. Zones & Tables Configuration

### `GET /api/tables`
Fetches all tables across all zones, including their current status and active timer start.
**Response:**
```json
{
  "success": true,
  "data": [
    {
      "id": 1,
      "table_number": "T-01",
      "zone_id": 1,
      "status": "Blank",       // "Blank" | "Running" | "Printed" | "Paid" | "RunningKOT"
      "is_virtual_split": false,
      "split_divisor": 1,
      "current_order_started_at": null
    }
  ]
}
```

### `POST /api/tables`
Creates a new physical table.
**Request Body:**
```json
{
  "table_number": "T-02",
  "zone_id": 1
}
```

### `PUT /api/tables/:table_id`
Updates a table's number or zone assignment.
**Request Body:**
```json
{
  "table_number": "T-02-Updated",
  "zone_id": 2
}
```

### `DELETE /api/tables/:table_id`
Deletes a table (Soft delete). Cannot delete a table if it has active orders.
**Response:**
```json
{
  "success": true,
  "message": "Table deleted successfully."
}
```

---

## 2. Table Lifecycle & Metadata

### `PATCH /api/tables/:table_id/status`
Updates the table's state.
**Request Body:**
```json
{
  "status": "Running"
}
```
**Response:**
```json
{
  "success": true,
  "message": "Status updated successfully.",
  "data": {
    "id": 1,
    "table_number": "T-01",
    "status": "Running",
    "current_order_started_at": "2026-04-22T17:00:00.000Z"
  }
}
```

`current_order_started_at` is set by MySQL when a table first moves to `Running` or `RunningKOT`, preserved while the table remains active, and reset to `null` when the table returns to `Blank`.

Allowed table statuses: `Blank`, `Running`, `Printed`, `Paid`, `RunningKOT`.

### `PUT /api/tables/:table_id/metadata`
Associates customers and staff with a table.
**Request Body:**
```json
{
  "customer_name": "John Doe",
  "customer_phone": "9876543210",
  "waiter_id": "W-04",
  "pax": 4,
  "comments": "Allergic to peanuts"
}
```

### `POST /api/tables/:table_id/split`
Handles "Virtual Table Generation". Creates temporary tables and **clones the active KOT items** to each.
**Request Body:**
```json
{
  "split_count": 3
}
```
**Response:** (Returns the newly generated virtual tables)
```json
{
  "success": true,
  "data": [
    { "id": 101, "table_number": "T-01-A", "status": "Printed", "split_divisor": 3, "items_cloned": 5 },
    { "id": 102, "table_number": "T-01-B", "status": "Printed", "split_divisor": 3, "items_cloned": 5 },
    { "id": 103, "table_number": "T-01-C", "status": "Printed", "split_divisor": 3, "items_cloned": 5 }
  ]
}
```

---

## 3. Order Management & Cart (KOT)

### `GET /api/tables/:table_id/orders`
Fetches the active cart/KOT for a table.
**Response:**
```json
{
  "success": true,
  "data": {
    "items": [
      {
        "cart_item_id": "uuid-1234",
        "menu_id": 42,
        "name": "Spicy Chicken Burger",
        "quantity": 2,
        "base_price": 12.00,
        "selected_modifiers": [
          { "group_name": "Add-ons", "option_name": "Extra Cheese", "price": 1.50 }
        ],
        "is_complimentary": false,
        "item_discount": 0.00
      }
    ],
    "global_discount": { "type": "percent", "value": 10 }
  }
}
```

### `POST /api/tables/:table_id/orders/items`
Adds an item to the table's cart. (Called when generating a KOT).

### `PATCH /api/tables/:table_id/orders/items/:cart_item_id`
Updates item properties (quantity, or advanced POS rules like Complimentary/Discount).

### `DELETE /api/tables/:table_id/orders/items/:cart_item_id`
Removes an item from the KOT.

---

## 4. Discounts & Calculations

### `PATCH /api/tables/:table_id/orders/discount`
Applies a global bill-level offer.
**Request Body:**
```json
{
  "type": "flat",       // "flat" | "percent" | "coupon"
  "value": 50.00,
  "coupon_code": null
}
```

---

## 5. Settlement & Payment

### `POST /api/tables/:table_id/settle`
Finalizes the table's transaction. Moving the temporary state into permanent server records (generating a billing receipt entry) and marks the table as `Paid`.

**Request Body:**
```json
{
  "primary_payment_method": "UPI",  // "Cash" | "Card" | "UPI" | "Due" | "Other" | "Part"
  "settlement_amount": 1400.00,
  
  // Conditionally required
  "upi_app": "PhonePe",             // if UPI
  "due_customer": {
    "name": "Jane", 
    "phone": "123"
  },                                // if Due
  "other_method_name": "Zomato",    // if Other
  
  // If Part payment
  "part_payments": [
    { "method": "Cash", "amount": 400 },
    { "method": "Card", "amount": 1000 }
  ],
  
  "waiter_tip": 50,
  "is_paid": true,
  "save_bill": true,                 // Optional (default: true). If false, table is cleared but NO DB record is saved (ghost receipt).
  "receipt_config_id": 1            // Optional
}
```
**Response:**
```json
{
  "success": true,
  "message": "Bill settled successfully.",
  "data": {
    "receipt_id": 8904,              // Will be 0 if save_bill was false
    "ticket_number": "TKT-T1-20260414225530",
    "total_amount": 1450.00,
    "payment_method": "UPI-PhonePe"
  }
}
```

### `POST /api/tables/:table_id/clear`
Wipes the table completely clean and marks the status as "Blank" for the next customer. If called on a virtual split table (e.g. `1-A`), it deletes the virtual table record entirely.
