Open orders reference
On this page
An open order is an order that stays editable while a customer keeps adding to it, then is paid at the end of the visit. Hospitality businesses describe it as a tab or a table order. This topic covers how one is stored and what each stage does to the records, for anyone building an integration, a report, or a custom POS layout around the feature.
For the operator procedure, see Start an open order. For enabling the feature, see Configure open orders.
Requirements
| Requirement | Value |
|---|---|
| Package version | 21.3.0 or later (21.2.0 adds s_c__Memo__c, 21.3.0 adds the order item cancellation fields) |
| Store variable | pos.open_orders.enabled set to true |
| Optional store variable | pos.memo.label to rename the memo label shown to staff |
How an open order is stored
An open order is an ordinary Order record with two things that distinguish it: a type stamp and a live link to a cart.
| Record | Field | Meaning |
|---|---|---|
| Order | s_c__POS_Order_Type__c |
Set to OPEN while the order is open. The same field carries other POS order types, such as Layby. |
| Order | s_c__Memo__c |
The staff-facing identifier, Text(80), for example a table number or a customer name. |
| Cart | s_c__Order_Id__c |
Links the working cart to the open order. Resuming an order finds its cart through this lookup. |
| Order Item | s_c__Cancelled_At__c |
When a submitted line was canceled. |
| Order Item | s_c__Cancelled_By_User_Id__c |
The user who canceled it. |
The cart is the working surface and the order is the committed record. Items exist on the cart as soon as staff add them, and reach the order only when they are submitted. Query s_c__POS_Order_Type__c = 'OPEN' to list the orders currently running in a venue.
An open order is created as a shell: no payments, no fulfillments, and no finalization. It is not put through the checkout pipeline until it is paid.
What submit does
Submitting sends the whole cart to the linked order, not a narrow patch of the changes. That matters when building anything that reads the result.
- Idempotent by line. The server upserts each line by its
sc_id, so resubmitting an unchanged order changes nothing. - Repricing. Every line is repriced on submit, because a customer change can move prices across the whole order. Once a payment has been recorded against the order, repricing is skipped so a settled total cannot drift away from what was paid.
- Quantity splitting. A line with a quantity above 1 is split into individual single-unit lines on both the cart and the order, so each unit is tracked, prepared, and canceled independently. A unit discount carries across unchanged and a line-level transaction discount is distributed across the split lines, leaving the total unchanged.
- Fulfillment fan-out. Each submit creates fulfillments only for lines that route to a fulfillment station and do not have one yet, grouped by fulfillment type, stock location, and fulfillment station. Lines with no station get their fulfillments at checkout, so in a store without station routing a submit creates no fulfillments. Successive submits therefore produce separate fulfillments, which is what makes each round its own kitchen ticket. Lines with a
deliveryfulfillment type are left for the checkout shipping flow. - Cancellation. A line submitted with a quantity of 0 is stamped canceled on the server. Restoring the quantity clears the stamp.
- Commit only. Submitting does not clear the cart. The POS cart’s Submit button pairs the submit with
cart:newto free the register.
Lifecycle actions
The actions below drive the feature and can be placed on POS action items or called from custom JavaScript through scAction. Parameters for each are documented in the POS actions reference.
| Stage | Action |
|---|---|
| Create against a fresh cart | cart:new:open_order |
| Convert the active cart | cart:update:open_order |
| Edit the memo in place | open_order:update |
| Commit the cart to the order | open_order:submit |
| Resume for another round | order:resume |
| Cancel a single submitted line | cart:item:cancel |
| Cancel the order | order:cancel |
Taking payment
An open order is paid by resuming its cart and checking out, not by an order-level payment. Calling checkout:start with the order_sc_id of an open order is declined with This order is still open. Resume it to take payment. Resume it with order:resume and start checkout from the resulting cart instead.
Offline behavior
Creating, updating, submitting, and canceling all work offline. Each change is queued through the unsaved-changes engine on the device and syncs when the register reconnects.
Resuming is the exception. An order the register does not already hold locally has to be fetched, so order:resume fails while offline with Can't continue this order while offline.
Cross-register contention only warns. When a second register resumes an order’s cart that another register already has open, the cart shows a banner, This cart is currently open on another register (<register name>)., but editing and submitting are not blocked, so the last submit wins. A workflow that expects exclusive access needs to enforce that itself.
Was this article helpful?
Thanks for your feedback! It helps us improve our docs.