Skip to main content

Mixed Postpaid and Prepaid Lines

A table session may carry both waiter-entered postpaid lines and customer-submitted prepaid lines on the same POS check. Lines added by the waiter before the customer scans appear in the initial snapshot. Lines added by the waiter after the scan arrive as TableOrderSnapshotChanged(POS_LINE_ADDED) alongside any customer-submitted prepaid items, until ORDER_CLOSED.

Two composition variants built from the existing table, prepaid, and postpaid-bill messages cover the design space. The POS does not branch on which variant the app follows; both are valid concurrent paths against the same open table session.

Whole-table settlement

This variant applies when the customer's checkout intent is "pay everything now, including the waiter-added lines". It produces one OpenApp payment and one POS-facing payment record.

  1. OpenApp sends OrderSubmissionRequested(orderContext=TABLE, items=[customer-added]) without payment. The customer-added items are submitted postpaid and join the open check alongside the waiter lines.
  2. OpenApp sends BillPreparationRequested(orderContext=TABLE, checkpoint) with no items subset. The POS returns a full bill covering both the customer-added and waiter-added lines.
  3. OpenApp executes the customer payment for the full total.
  4. OpenApp sends BillPaymentCompleted(posBillId, payment). The POS records the payment and pushes TableOrderSnapshotChanged(ORDER_CLOSED) per Postpaid Bill Payment.

Customer-item prepayment with separate residual settlement

This variant applies when the customer's intent is "prepay what I added now" - either standalone, with the remaining lines left for the waiter.

  1. OpenApp sends OrderSubmissionRequested(orderContext=TABLE, items=[customer-added], payment) with the prepaid customer payment for the customer-added items. The POS accepts the items and returns the receipt inline. The prepaid submission mechanics are described in Prepaid Ordering.
  2. In the optional or deferred manual residual step, OpenApp sends BillPreparationRequested(orderContext=TABLE, items=[waiter-line-refs]) for the residual subset, then BillPaymentCompleted(posBillId, payment) after the customer pays the residual. If this step is skipped, the waiter handles the residual physically.

If the residual step fails after the prepaid step succeeded, OpenApp refunds only the residual portion; the customer-added items remain paid and attached to the check.