---
id: STATE-ACC-TRX-011
title: Credit lifecycle
object: DOM-ACC-TRX-004
product_area: accounting
module: transactions
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
source_sha:
  services-accounting: f47cb263875bbc0c5640fba7dae6785ec32695f8
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
states:
  - name: not created
    meaning: No credit grant exists.
  - name: open
    meaning: >-
      Value remains after applications and refunds, even when settlement holds
      leave no available balance.
  - name: used
    meaning: >-
      Applications and refunds have consumed the value, without reservations
      determining this status.
  - name: void
    meaning: An unused grant has been cancelled and retained.
  - name: expired
    meaning: >-
      Expiry exists in the vocabulary without an implemented status-setting
      path.
transitions:
  - from: not created
    to: open
    trigger: grant customer value
    guard: >-
      Manual grants need customer, unit, currency, reason and accounts;
      payment-derived value cannot exceed available receipt money.
    side_effects:
      - assign the credit number
      - transfer payment-derived value from its receipt
      - append grant facts
    who: >-
      Staff with credit-create permission or settlement, cancellation and
      Commerce service coordination.
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/credits/credit-commands.ts;
      services-accounting:modules/transactions/db/credits.table.ts;
      services-accounting:modules/transactions/tests/e2e/credits.e2e.spec.js#it
      refuses a manual credit without its accounts, and a payment’s credit
      without its payment (400)
  - from: open
    to: used
    trigger: consume all available value
    guard: >-
      Applications and refunds reach the original amount; reservation alone does
      not satisfy this status condition.
    side_effects:
      - >-
        derive used from applications and refunds rather than the
        reservation-adjusted available balance
    who: Database amount maintenance.
    provenance: observed
    source: >-
      services-accounting:db/migrations/20261017174829_payments_core.sql:derive_credit_status
  - from: used
    to: open
    trigger: release previously spent value
    guard: An original applied application must be eligible for reversal.
    side_effects:
      - restore available credit
    who: Staff with credit-application create permission.
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/credits/credit-commands.ts;
      services-accounting:modules/transactions/db/credits.table.ts;
      services-accounting:modules/transactions/tests/integration/services/credits/credits.integration.spec.js#it
      marks the first reversed and gives the money back to the credit, which is
      open again
  - from: open
    to: void
    trigger: cancel the unused grant
    guard: >-
      A reason, no spending, reservations or returns and an unposted batch are
      required.
    side_effects:
      - restore source receipt money where applicable
      - append cancellation facts
    who: Staff with credit-update permission.
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/credits/credit-commands.ts;
      services-accounting:modules/transactions/db/credits.table.ts;
      services-accounting:modules/transactions/tests/integration/services/credits/credits.integration.spec.js#it
      refuses voiding a credit with money applied (credit_has_applications)
invalid:
  - from: void
    to: open
    why: A cancelled credit grant cannot be reopened.
  - from: used
    to: void
    why: 'Any applied, refunded or reserved value prevents credit cancellation.'
  - from: open
    to: expired
    why: >-
      The service has no expiry-status transition, and only direct application
      checks expiry eligibility.
concurrency: >-
  Database balance bounds and ordered credit locks coordinate competing
  applications.
invariants:
  - INV-DOM-ACC-TRX-004-03
  - INV-DOM-ACC-TRX-004-07
  - INV-DOM-ACC-TRX-004-09
evidence:
  - >-
    services-accounting at f47cb263: services/credits/credit-commands.ts;
    db/credits.table.ts, payment-vocabularies.ts (credit statuses).
---
# Credit lifecycle

## The Lifecycle

Applications and refunds determine open and used; reservations reduce availability without determining status. Expired is declared but unavailable as an implemented transition.

```mermaid
stateDiagram-v2
  direction LR
  state "not created" as s0
  state "open" as s1
  state "used" as s2
  state "void" as s3
  state "expired" as s4
  s0 --> s1 : grant customer value
  s1 --> s2 : consume all available value
  s2 --> s1 : release previously spent value
  s1 --> s3 : cancel the unused grant
```

## 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

Database balance bounds and ordered credit locks coordinate competing applications. Expiry is evaluated by direct application without a scheduled state change; settlement currently omits that check.
