---
id: STATE-COM-ORD-004
title: Order lifecycle
object: DOM-COM-ORD-002
product_area: commerce
module: orders
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
states:
  - name: placed
    meaning: 'The recorded sale awaits its payment requirement, with a deadline for pay-now purchases.'
  - name: tender_uncertain
    meaning: 'Accounting has not resolved a payment, preventing an independent attempt.'
  - name: accepted
    meaning: The payment or terms requirement is satisfied and delivery may proceed.
  - name: voided
    meaning: The unaccepted sale ended through release and financial reversal.
  - name: cancelled
    meaning: No item quantity remains after cancellation of the accepted sale.
  - name: closed
    meaning: 'The lifecycle declares closure, but no current caller performs it.'
transitions:
  - from: placed
    to: accepted
    trigger: 'Billing permits terms or no-payment acceptance, or successful payment covers the required amount.'
    guard: Billing exists and the applicable total or deposit requirement is met.
    side_effects:
      - record acceptance time with its history event
      - reevaluate purchased-line delivery gates
      - derive and persist the latest financial projection
      - attempt progression of the originating amendment
      - ensure the future payment arrangement after deposit acceptance
    who: System after billing or a payment attempt
    provenance: test
    source: >-
      services-commerce:modules/orders/tests/e2e/billing-and-tender.e2e.spec.js#answers 200: the attempt
      succeeded with Accounting’s payment, the order accepted, the pro forma converted by that first money
  - from: placed
    to: tender_uncertain
    trigger: Accounting cannot give a final payment result.
    guard: The sale remains placed.
    side_effects:
      - retain unresolved attempt status and any remote intent reference
    who: System within a payment attempt
    provenance: test
    source: >-
      services-commerce:modules/orders/tests/e2e/billing-and-tender.e2e.spec.js#answers uncertain, the order
      tender_uncertain, the attempt uncertain naming Accounting’s intent
  - from: tender_uncertain
    to: accepted
    trigger: Recovery confirms enough captured payment to accept.
    guard: The resumed attempt resolves successfully.
    side_effects:
      - perform the common post-acceptance processing
    who: 'Buyer or staff retrying, or the uncertain-payment sweep'
    provenance: test
    source: >-
      services-commerce:modules/orders/tests/e2e/billing-and-tender.e2e.spec.js#accepts the order once
      Accounting holds the payment, with one charge and the payment on the attempt
  - from: tender_uncertain
    to: placed
    trigger: Recovery ends without enough payment or finds no remaining open attempt.
    guard: Unresolved attempt processing has ended.
    side_effects:
      - 'record whether recovery found no capture, partial payment or no open attempt'
    who: 'Buyer, staff or the uncertain-payment sweep'
    provenance: observed
    source: 'services-commerce:modules/orders/services/tender/tender-order.ts'
  - from: placed
    to: voided
    trigger: A staff void or elapsed-deadline pass ends the sale.
    guard: 'Status remains placed, excluding accepted and uncertain.'
    side_effects:
      - return purchased resources and offer uses and stop waiting delivery
      - create settlement steps for previously captured legs
      - request provisional-invoice removal outside the domain transaction
      - end the originating amendment and reinstate its original line
      - retain the reasoned void intervention record
    who: 'Staff with the void permission, or the system'
    provenance: test
    source: >-
      services-commerce:modules/checkout/tests/e2e/order-void.e2e.spec.js#answers 200 with the order voided,
      carrying the reason, its lines and the history
  - from: accepted
    to: cancelled
    trigger: Completed cancellation leaves no item quantity standing.
    guard: Settlement permits cancellation and all item lines are cancelled.
    side_effects:
      - append cancellation-linked status history
    who: System (cancellation settlement)
    provenance: test
    source: >-
      services-commerce:modules/orders/tests/e2e/cancellations.e2e.spec.js#lists the order’s cancellations and
      reads one; cancelling the mug too closes the order cancelled (B5)
  - from: accepted
    to: closed
    trigger: The lifecycle offers closure without a current producer.
    guard: No implemented closure condition is defined.
    side_effects: []
    who: Nobody today
    provenance: observed
    source: 'services-commerce:modules/orders/services/persistence/orders.ts:ORDER_TRANSITIONS'
invalid:
  - from: tender_uncertain
    to: voided
    why: Unresolved capture must be resolved before resources and money can safely be voided.
  - from: accepted
    to: voided
    why: Accepted purchases use after-sale cancellation and settlement.
  - from: voided
    to: placed
    why: 'Voided, cancelled and closed statuses have no service exits.'
  - from: placed
    to: cancelled
    why: Placed purchases use void rather than cancellation documents.
concurrency: >-
  The order lock serializes status writes, but remote Accounting requests run outside it. The payment deadline
  begins at placement. Post-acceptance failures leave acceptance standing; register and mirror passes recover
  some follow-ups, while the amendment hand-off lacks recovery.
invariants:
  - INV-DOM-COM-ORD-002-04
  - INV-DOM-COM-ORD-002-09
evidence:
  - >-
    services-commerce at c8b66a98: modules/orders/services/persistence/orders.ts (ORDER_TRANSITIONS,
    transitionOrder); services/orders/accept-order.ts, void-order.ts, tender-window-sweeper.ts;
    services/tender/tender-order.ts; services/cancellations/cancellation-settlement.ts.
---

# Order lifecycle

## The Lifecycle

```mermaid
stateDiagram-v2
  [*] --> placed: placement
  placed --> accepted: paid, on terms or nothing to pay
  placed --> tender_uncertain: payment answer lost
  tender_uncertain --> accepted: payment found
  tender_uncertain --> placed: declined or partial
  placed --> voided: staff void or window passed
  accepted --> cancelled: last item line cancelled
  accepted --> closed: declared, unused
  voided --> [*]
  cancelled --> [*]
  closed --> [*]
```

## Transitions Explained

A sale begins placed. Billing can accept terms and zero-payment purchases; successful attempts accept purchases once their required amount is covered. Unresolved payments pause the sale as uncertain, while void ends an unaccepted purchase and full cancellation ends an accepted one.

## What Cannot Happen

The lifecycle excludes voiding an accepted or uncertain sale. Terminal states do not reopen. Closed remains a declared destination without an implementation that enters it.

## Concurrency and Timing

The order lock serializes status writes, but remote Accounting requests run outside it. The payment deadline begins at placement. Post-acceptance failures leave acceptance standing; register and mirror passes recover some follow-ups, while the amendment hand-off lacks recovery.
