Skip to content

PRD: Order split, merge & rollback

ModuleSalePRD IDPRD-ORD-002
StatusReady to devFEATORD
EpicPlaneBANA-1518
Date2026-06-15Versionv1.0
Packages@nx/saleURDORD
SurfaceSale · POS
OwnerPhát Nguyễn

TL;DR

A cashier can split a draft into new drafts (allocating items and quantities per bill, with partial-quantity line splitting), merge several drafts into one (cancelling the sources), or rollback a merge so every item returns to its exact original order - all in a single atomic transaction. Combos always move as a unit, seat/table holds travel with the items, and an append-only transfer-history lineage makes every merge reversible.

Scope note: What travels alongside the items is the order's seat/table allocation usages - cloned on split, moved on merge, cancelled on rollback. Inventory stock reservations are not separately manipulated; they stay conserved because items only relocate within the same merchant and location. Pricing differs by operation: split re-runs the pricing engine for new and retained orders; merge and rollback recompute totals from the already-locked line prices.

1. Context & Problem

A draft order (ORD) already plays both cart and committed-order roles, but a real service counter constantly reshapes drafts: two friends who sat together now want separate bills; three tabs opened by mistake should be one; a merge done in haste must be undone. The order lifecycle alone offers no way to move items between drafts - a cashier would have to cancel and re-key, losing prices, customer links, and the stock already reserved.

Without a first-class restructure path, the counter either refuses these everyday requests or rebuilds orders manually, which drops reserved inventory, mis-prices combos, and leaves no trace of what moved where. This PRD closes that gap: declarative split / merge / rollback operations that move items (and their seat/table holds) atomically, keep combos intact, and record a reversible lineage so a merge can always be walked back.

2. Goals & Non-Goals

Goals

  • Split a draft into N new drafts by allocating items and quantities - full-quantity lines move whole; partial allocations split the line.
  • Merge one or more drafts into a target draft and cancel the emptied sources.
  • Rollback a merge so every item returns to its original source order, restored to draft.
  • Keep combos atomic - a lead and all its children always move together with full quantity.
  • Stamp an append-only transfer-history lineage on every moved item so the path is auditable and reversible.
  • Carry the seat/table allocation usages with the items and re-price every affected order, all inside one transaction (inventory stock reservations are not separately moved - see the terminology note above).

Non-Goals

  • Bill splitting into independently-payable checks - that is CHK (PRD-CHK-001); this PRD reshapes orders, not payment checks.
  • Splitting or merging non-draft orders - restructure is DRAFT-only (C-02).
  • Restructuring an order that has active checks - blocked until the checks are rolled back.
  • Payment, refund, or stock-mutation logic - owned by Payment and Inventory.

3. Success Metrics

MetricTarget / signal
Reshape without re-keyA cashier splits, merges, or rolls back from one action - no cancel-and-re-enter
AtomicityA failed sub-step leaves every participating order exactly as it was
Combo integrityNo split ever orphans a combo lead or child; combo members never partially move
ReversibilityAny merge can be rolled back to the original orders using only the recorded lineage
Hold continuitySeat/table allocation usages follow the items - no double-hold, no lost hold (inventory stock reservations are conserved implicitly, not separately moved)

4. Personas & Use Cases

PersonaGoal in this feature
CashierSplit a shared tab into separate bills, or combine mistaken tabs, in one step
ManagerUndo a wrong merge cleanly, with the original orders restored intact
OwnerTrust that every reshape keeps prices, combos, and seat/table holds correct

Core scenario: a table of four opened one draft but wants two bills. The cashier splits the draft - assigning two mains and a shared starter (full quantity) to bill A and the rest to bill B - and the system creates two new drafts, moves the lines (splitting the shared-by-quantity ones), carries the seat/table holds, re-prices both, and cancels the now-empty original. Later they realise it should have been one bill, merge B back into A, and - spotting a third error - roll the merge back so B is restored exactly as it was.

5. User Stories

  • As a cashier, I split a draft into new drafts by choosing items and quantities per bill, so a shared tab becomes separate bills in one step.
  • As a cashier, I take a line's full quantity or just part of it, so I can move a whole dish or just two of five.
  • As a cashier, I merge several drafts into one, so mistaken separate tabs become a single bill and the others close.
  • As a manager, I roll a merge back, so a wrong combine is undone and every item returns to its original order.
  • As an owner, I want combos to move as a unit and seat/table holds to travel with the items, so reshaping never corrupts a bundle or its holds.

6. Functional Requirements

#RequirementURD ref
FR-1Split a DRAFT order into N new DRAFT orders, each allocated specific items and quantities, with an optional name and customer per new orderURD-ORD-012 · URD-ORD-017
FR-2A line whose full quantity is assigned moves whole; a partial assignment splits the line, leaving the remaining quantity on the sourceURD-ORD-017
FR-3A combo's lead and all its children must move together, at full quantity, into the same target; partial or orphaning combo moves are refusedURD-ORD-018
FR-4A fully-emptied source is cancelled (marked as a full split); a partially-split source is retained and re-pricedURD-ORD-017
FR-5Split refuses a non-positive quantity, an unknown item, or an over-allocation (assignments exceeding the line's available quantity)URD-ORD-017
FR-6Merge moves every item of one or more DRAFT source orders into one DRAFT target and cancels the sources (marked merged into the target)URD-ORD-013 · URD-ORD-019
FR-7Only orders of the same merchant and sale channel may mergeURD-ORD-019
FR-8Every transferred item appends a transfer-history entry (source, target, time, quantity) forming the split / merge lineageURD-ORD-020
FR-9A merge can be rolled back while the target is still DRAFT and was merged; items return to their original sources via the lineage, and each source is restored to DRAFTURD-ORD-021
FR-10On rollback, quantity added to a line after the merge stays on the target; only the originally-transferred quantity returns to the sourceURD-ORD-021
FR-11Split, merge and rollback are atomic; the seat/table allocation usages are cloned (split) / moved (merge) / cancelled (rollback) in lock-step and affected orders are re-priced (split via the pricing engine; merge/rollback recompute summaries from locked line prices)URD-ORD-022
FR-12An order with active checks cannot be split, merged, or rolled backURD-ORD-023

Full requirement text and acceptance criteria live in the Sale URD - ORD. This PRD references them rather than restating them.

7. Non-Functional Requirements

AreaRequirement
AtomicityEach operation is one all-or-nothing transaction - any failed sub-step (item move, source cancel, reprice) rolls the whole reshape back
ConcurrencyParticipating orders and their items are locked for the duration so two cashiers cannot reshape the same draft at once
AuditabilityThe transfer-history lineage is append-only - a move adds an entry, a rollback removes only the last one; corrections are new state, never edited history
Hold continuitySeat/table allocation usages travel with the items - cloned on split, moved on merge, cancelled on rollback - so holds are never lost or duplicated; inventory stock reservations are not separately manipulated (conserved because items stay within the same merchant/location)
PricingEvery order whose items changed has its totals recomputed; split re-runs the pricing engine for both the new orders and a retained partial source, while merge and rollback recompute order summaries from the already-locked line prices
Tenancy & authzAll operations confined to the user's own merchant and gated by split / merge / rollback permissions
i18nUser-facing labels and rejection reasons are bilingual (EN + VI)

8. UX & Flows

Split a draft

Merge then roll back

The cashier surface offers a split panel (assign items and quantities to one or more new bills, name each, optionally set a customer), a merge action (pick sources and a target), and a rollback action on a merged draft.

9. Data & Domain

EntityRole in reshape
OrderThe draft being reshaped; carries the markers stamped by each operation (split / merge timestamps, cancellation reason, origin link)
Order line itemThe line that moves between orders; a full move relocates it, a partial move splits it into a new line
Transfer-history entryOne append-only step of a line's lineage - source order, target order, time, and quantity moved; the last entry tells rollback where to return the line

Conceptual only - full schema and invariants live in the sale domain model. Order-to-order relations are tracked by the system, not enforced as hard links; integrity is upheld by the split / merge logic.

10. Dependencies & Assumptions

Depends on

  • Sale order lifecycle (ORD) - restructure operates only on DRAFT orders and reuses checkout / cancel transitions.
  • Combo fan-out (URD-ORD-005) - the lead / child structure that the atomicity guard protects.
  • Bill splitting (CHK) - an order with active checks is blocked from reshape until the checks are rolled back.
  • Seat/table allocation usages - cloned / moved / cancelled in step with the items (inventory stock reservations are not separately handled here).
  • The platform core - the order and line-item definitions, status helpers, and the transfer-history structure.

Assumptions

  • A cashier reshapes only their own merchant's and channel's drafts.
  • The source order's seat/table allocation usages are the holds that travel with the items.

11. Risks & Open Questions

Risk / questionMitigation / status
A partial failure leaves orders half-reshapedEach operation is one all-or-nothing transaction with locks - any failure rolls the whole reshape back
A split orphans a combo lead or childUp-front atomicity guard - combo members must all move together at full quantity, else refused
Rollback can't tell where an item came fromThe append-only transfer-history lineage records each move; rollback reads the last entry per line
Quantity changed after a merge, then rolled backSurplus added after the merge stays on the target; only the originally-transferred quantity returns
Two cashiers reshape the same draft at onceParticipating orders and items are locked for the operation's duration
Seat/table hold lost or double-countedAllocation usages are cloned on split, moved on merge, cancelled on rollback - in lock-step with the items; inventory stock reservations are conserved implicitly (items stay within one merchant/location)

12. Release Plan & Launch Criteria

AspectPlan
PhaseP2 - ORD reshape capability in the URD feature catalog
RolloutAll merchants; no feature flag
MigrationNone - reshape runs on the existing draft order and item models; transfer-history is an additive field
Launch criteriaSplit allocates items / quantities into new drafts (full and partial moves) and cancels or re-prices the source; merge folds sources into a target and cancels them; rollback restores sources from the lineage; combos move atomically; active-check orders are blocked; every operation is atomic with seat/table holds following the items
MonitoringReshape error rate by reason (over-allocation, orphaned combo, active checks, not-merged), rollback success rate, seat/table hold consistency after reshape

13. FAQ

How is this different from check splitting? Check splitting (CHK) divides one order into independently-payable checks for the same bill. This reshapes the orders themselves - moving items between separate drafts. See PRD-CHK-001.

Can I split or merge an order that's past draft? No - reshape is DRAFT-only (C-02). Once an order checks out, its items are locked.

What happens to a combo when I split? It moves as one unit. The lead and all its children must go to the same new bill at full quantity; assigning only part of a combo is refused before anything saves.

If I take only some of a line's quantity, what happens to the rest? The line splits - the taken quantity becomes a line on the new order, the remainder stays on the source, and both are re-priced.

Can every merge be undone? Yes, while the target is still draft and has no active checks. Rollback uses each line's transfer-history lineage to return it to the exact order it came from; quantity added after the merge stays on the target.

Do the table/seat holds survive a reshape? Yes - the seat/table allocation usages are cloned on split, moved on merge, and cancelled on rollback, in lock-step with the items, so holds are never lost or duplicated. Inventory stock reservations are not separately moved; they stay conserved because items only relocate between orders of the same merchant and location.

References

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.