README docs DINE_ORDERS_API.md

Dine Orders API — floor-plan tables with active dine-in orders

Endpoints for listing floor-plan tables and their open / done dine-in invoices. Each invoice inside dinerOrderDetail uses the same object shape and datatypes as POST /v1/invoices/sync, GET /v1/invoices/history, and GET /v1/kds-orders, defined in src/validations/invoice.validation.js (syncInvoicePayloadSchema), plus one optional UI field: order_type_icon.

Authentication: jwtAuth — valid JWT in Authorization: Bearer <token>. Tenant scope (customer_id, location_id) is taken from the token, not from query parameters.

Validation: src/validations/dineOrders.validation.js (request + response contract schemas for frontend alignment).

See also:


Routes

Method Path Handler
GET /v1/dine-orders List floor-plan tables with open/done invoices per table

Legacy / gateway paths (for migration reference):

Legacy / external Invoice service
GET /dine-orders GET /v1/dine-orders

Authentication

Authorization: Bearer <jwt>
Claim Aliases Required
customer_id customerId yes
location_id locationId yes

Missing claims → 400 Authentication must include customer_id and location_id.

All data is scoped to the token’s customer_id + location_id.


GET /v1/dine-orders

Returns a plain JSON array of table objects (no pagination wrapper). Empty array when no tables exist for the tenant location.

Implementation: dineOrdersController.getDineOrdersdineOrdersService.getDineOrdersTableRepository.getDineTables + InvoiceRepository.getDineInvoicesByTableIdsmapInvoiceToSyncPayloadShape.

Query parameters

Param Type Default Description
table_id number Filter to a single floor-plan table (tables.id)
brand_id number Filter invoices by invoices.brand_id
app_version string Client version; affects items[].qty numeric type in response
build_number number | string Used with app_version for qty typing
icon_pixel_size number 24 1–512; width/height for order_type_icon URL
icon_format string png png, jpg, jpeg, webp, gif
icon_url_format string Alias of icon_format

Invalid query values → 400 with Joi validation message.

Selection rules

Tables included when:

  • tables.customer_id + tables.location_id match JWT
  • Optional table_id query filter
  • Sorted by tables.id ascending

Invoices loaded per table when:

  • invoices.customer_id + invoices.location_id match JWT
  • invoices.table_id matches a returned table
  • invoices.status in open, done
  • Optional brand_id query filter
  • Sorted by created_at descending (newest first per table)
  • Line items: only is_deleted = 0 rows are loaded

Inclusion in dinerOrderDetail:

  • Only invoices with at least one non-deleted line item are included
  • Invoices with no items are skipped (not added to dinerOrderDetail or uuid)

dinerOrderDetail values:

Condition dinerOrderDetail
No open/done invoices for table null
Invoices exist but none have items [] (empty array)
One or more invoices with items Array of sync-shaped invoice objects

plate_number on table row: taken from the latest open/done invoice for that table (created_at DESC), not from tables.plate_number.

Example request

GET /v1/dine-orders?table_id=5935&brand_id=412&icon_pixel_size=32&icon_format=png
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Response

HTTP status: 200 OK

Body: dineOrdersListResponseSchema — array of dineTableResponseSchema.

[
  {
    "floor_id": 606,
    "id": 5935,
    "name": "Table A5",
    "customer_id": 437,
    "location_id": 907,
    "x": 72,
    "y": 49,
    "is_rounded": 0,
    "rotation": 0,
    "height": 30,
    "width": 30,
    "people_size": 0,
    "attended_by": null,
    "unavailable": 1,
    "is_plate": 1,
    "plate_number": null,
    "uuid": [
      "AA792674-95CA-4C2E-AED4-BDB68314CA83"
    ],
    "dinerOrderDetail": [
      {
        "uuid": "AA792674-95CA-4C2E-AED4-BDB68314CA83",
        "status": "open",
        "customer_id": 437,
        "location_id": 907,
        "order_no": 2,
        "customer_invoice_id": 234972,
        "table_id": 5935,
        "order_type": "dine-in",
        "order_type_icon_key": "",
        "order_type_icon": null,
        "payments": null,
        "items": [
          {
            "name": "Mocha",
            "product_id": 257508,
            "qty": 1,
            "price": 10,
            "subtotal": 10,
            "modifiers": [],
            "addons": null
          }
        ]
        // … remaining sync payload fields — see INVOICE_REQUEST.md
      }
    ]
  }
]

Table-level response fields

Field Type Description
floor_id number | null Floor plan reference (tables.floor_id)
id number Table primary key
name string | null Table display name
customer_id number Tenant customer
location_id number Tenant location
x, y number | null Floor-plan coordinates
is_rounded 0 | 1 | null Rounded table shape flag
rotation number | null Rotation in degrees
height, width number | null Table dimensions on floor plan
people_size number | null Configured people size
attended_by string | null Attendant identifier / name
unavailable 0 | 1 | null Table unavailable flag
is_plate 0 | 1 | null Plate-order table flag
plate_number string | null From latest open/done invoice on this table
uuid string[] Invoice UUIDs included in dinerOrderDetail
dinerOrderDetail array | null Sync-shaped invoices (see below)

Prod tables columns such as x_pos, y_pos, guest_name, current_status, capacity, and qr_code_link are not returned by this endpoint (legacy-compatible subset only).

Invoice objects in dinerOrderDetail

Each element is syncInvoicePayloadSchema plus optional order_type_icon — identical rules to KDS_API.md:

Concern Rule
Timestamps (created_at, updated_at, paid_at, done_at, item timestamps) Unix seconds (number)
Boolean flags on invoice/items 0 / 1 numbers
payments Array of { payment_method, amount, tip_amount } or null
items Parent lines only; addons nested; modifiers flat array
notes String array parsed from DB order_notes (legacy iOS / invoiceSyncV3 key)
order_type_icon Raster URL string or null (from order_type_icon_key + icon query params)

Full field list: INVOICE_REQUEST.md.


Database tables used

Table Role
tables Floor-plan table layout and metadata
invoices Open/done orders linked via table_id
invoice_items Line items (non-deleted only)
payments Payment rows joined by invoice uuid

floors is not joined; only tables.floor_id is returned on each table object.


Validation schemas (frontend contract)

Exported from src/validations/dineOrders.validation.js:

Export Purpose
getDineOrders Request validator for GET /v1/dine-orders query
dineOrdersListResponseSchema Full list response body
dineTableResponseSchema Single table wrapper object
dineOrderInvoiceSchema Single invoice inside dinerOrderDetail (syncInvoicePayloadSchema + order_type_icon)

Base invoice read shape: syncInvoicePayloadSchema in src/validations/invoice.validation.js.


Related code

Piece Path
Routes src/routes/v1/dineOrders.route.js
Controller src/controllers/dineOrders.controller.js
Service src/services/dineOrders.service.js
Table repository src/data/repositories/TableRepository.js
Invoice repository src/data/repositories/InvoiceRepository.jsgetDineInvoicesByTableIds
Payment repository src/data/repositories/PaymentRepository.jsgetPaymentsByUuids
Models src/models/sequelize/Table.js, src/models/sequelize/Floor.js
Response mapper src/utils/invoice-sync-response-mapper.jsmapInvoiceToSyncPayloadShape
Icon / qty helpers src/utils/kdsResponseHelpers.js
Validation src/validations/dineOrders.validation.js

Errors

Case HTTP Body
Invalid / missing JWT 401 Standard auth error
Missing customer_id / location_id in token 400 Authentication must include customer_id and location_id
Invalid query (Joi) 400 Validation message from error handler
Success — no tables 200 []
Success — tables found 200 Array of table objects

Differences from legacy GET /dine-orders

The table wrapper shape matches the legacy POS endpoint. Invoice objects inside dinerOrderDetail intentionally use the invoiceSync read shape (same as KDS/history), not the legacy v3 format:

Legacy v3 This service
order_items items
payment_method: [{ "cash": 50 }] payments: [{ payment_method, amount, tip_amount }]
modifier (string/JSON) modifiers (flat array)
Flat addons / combo JSON subquery Nested addons; combo via is_combo / combo_item_id
notes (parsed from order_notes) notes (string array)
Product image, type on each item Not included (sync shape)