---
id: STATE-ACC-TRX-004
title: Billing reversal operation
object: DOM-ACC-TRX-001
product_area: accounting
module: transactions
revision: 1
status: draft
design_intent: confirmed
origin: >-
  services-accounting:docs/architecture/accounting-2.0/02-decisions.md#D-06
  (Accounting owns the reversal operation; Andrew, 2026-10-17, restated
  2026-10-22)
implementation_evidence: observed
source_sha:
  services-accounting: f47cb263875bbc0c5640fba7dae6785ec32695f8
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
states:
  - name: not created
    meaning: The cancellation operation has not been recorded.
  - name: pending
    meaning: Preparation is committed and a processor return remains unresolved.
  - name: completed
    meaning: All planned cancellation steps have reached their final outcomes.
  - name: completed with exception
    meaning: >-
      Preparation is retained but a return failed or requires offline payment by
      staff.
  - name: failed
    meaning: >-
      The shared vocabulary declares failure, but refused preparation leaves no
      operation record.
transitions:
  - from: not created
    to: completed
    trigger: cancel billing without a processor return
    guard: >-
      Selected value must belong to an issued real invoice and fit its remaining
      value in an open period.
    side_effects:
      - create the reduction memo and release receipt money
      - create fee-related documents when requested
      - create remainder credit for credit treatment
    who: Staff with reversal-create permission or the Commerce reversals function.
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/reversals/reversal-commands.ts;
      services-accounting:modules/transactions/services/refunds/refund-commands.ts;
      services-accounting:modules/transactions/db/reversals.table.ts;
      services-accounting:modules/transactions/tests/integration/services/reversals/reversals.integration.spec.js#it
      wrote the credit memo of 4000 on the line, which freed the line’s 4000
      back onto the check (W-05)
  - from: not created
    to: pending
    trigger: cancel billing with an electronic return
    guard: >-
      Eligible freed money must come from a processor receipt and use refund
      treatment.
    side_effects:
      - create refund requests
      - start processor refunds after preparation commits
    who: Staff with reversal-create permission or the Commerce reversals function.
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/reversals/reversal-commands.ts;
      services-accounting:modules/transactions/services/refunds/refund-commands.ts;
      services-accounting:modules/transactions/db/reversals.table.ts;
      services-accounting:modules/transactions/tests/integration/services/reversals/reversal-two-payments.integration.spec.js#it
      requests one refund per payment, 7000 and 3000, each from its own payment
  - from: not created
    to: completed with exception
    trigger: cancel billing with a manual return
    guard: Refund treatment must draw on an offline receipt.
    side_effects:
      - retain requested refunds for staff payment
      - record the outstanding manual-return exception
    who: Authorized staff or the Commerce reversals function.
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/reversals/reversal-commands.ts;
      services-accounting:modules/transactions/services/refunds/refund-commands.ts;
      services-accounting:modules/transactions/db/reversals.table.ts;
      services-accounting:modules/transactions/tests/integration/services/reversals/reversal-refund-status.integration.spec.js#it
      turns succeeded and completed when the signed event settles the refund
  - from: pending
    to: completed
    trigger: finish the electronic return
    guard: 'A call, event or lookup must confirm the refund outcome.'
    side_effects:
      - save refund completion
      - finish the cancellation operation
    who: Processor outcome handling or scheduled recovery.
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/reversals/reversal-commands.ts;
      services-accounting:modules/transactions/services/refunds/refund-commands.ts;
      services-accounting:modules/transactions/db/reversals.table.ts;
      services-accounting:modules/transactions/tests/integration/services/reversals/reversal-refund-status.integration.spec.js#it
      turns succeeded and completed when the signed event settles the refund
  - from: pending
    to: completed with exception
    trigger: record an unsuccessful return
    guard: The processor or human resolution must establish failure.
    side_effects:
      - restore the refund's released lines
      - identify the failed refund in the operation
    who: 'Processor outcome handling, scheduled recovery or authorized staff.'
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/reversals/reversal-commands.ts:settleReversalOfRefund
invalid:
  - from: completed
    to: pending
    why: Additional cancellation requires a separate operation after completion.
  - from: not created
    to: failed
    why: >-
      Refused preparation rolls back instead of leaving a failed operation and
      permits retry.
concurrency: >-
  One keyed preparation transaction creates the component documents using
  derived keys. Processor work follows commit and uses the individual refund
  identity for deduplication.
invariants:
  - INV-DOM-ACC-TRX-001-18
evidence:
  - >-
    services-accounting at f47cb263: services/reversals/reversal-commands.ts;
    db/reversals.table.ts, payment-vocabularies.ts (operation statuses, reversal
    steps); docs/architecture/accounting-2.0/05-lifecycles.md §6.
---
# Billing reversal operation

## The Lifecycle

Billing reversal is a coordinator over financial documents. Preparation can finish immediately, require processor recovery or leave a manual-refund exception.

```mermaid
stateDiagram-v2
  direction LR
  state "not created" as s0
  state "pending" as s1
  state "completed" as s2
  state "completed with exception" as s3
  state "failed" as s4
  s0 --> s2 : cancel billing without a processor return
  s0 --> s1 : cancel billing with an electronic return
  s0 --> s3 : cancel billing with a manual return
  s1 --> s2 : finish the electronic return
  s1 --> s3 : record an unsuccessful return
```

## Transitions Explained

The transition rows identify the initiating action, eligibility checks, resulting records and responsible caller. They retain the pinned evidence for each path.

## What Cannot Happen

The invalid-transition rows describe final-state protection and unsupported paths; command eligibility remains distinct from the declared state vocabulary.

## Concurrency and Timing

One keyed preparation transaction creates the component documents using derived keys. Processor work follows commit and uses the individual refund identity for deduplication. Only the return stage crosses an asynchronous boundary; preparation remains atomic.
