---
id: TST-ACC-TRX-004
title: Credits suite
kind: api-lifecycle
product_area: accounting
module: transactions
revision: 1
status: draft
source_sha:
  services-accounting: f47cb263875bbc0c5640fba7dae6785ec32695f8
repository: services-accounting
files:
  - modules/transactions/tests/e2e/credits.e2e.spec.js
implements:
  - ATS-ACC-TRX-011-01
  - ATS-ACC-TRX-011-09
implements_parts:
  - scenario: ATS-ACC-TRX-011-01
    assertion: >-
      it refuses a manual credit without its accounts, and a payment’s credit
      without its payment (400)
    provenance: test
    source: >-
      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)
  - scenario: ATS-ACC-TRX-011-09
    assertion: it is refused the credit routes without their permissions (403)
    provenance: test
    source: >-
      services-accounting:modules/transactions/tests/e2e/credits.e2e.spec.js#it
      is refused the credit routes without their permissions (403)
  - scenario: ATS-ACC-TRX-011-09
    assertion: it is refused the application routes without their permissions (403)
    provenance: test
    source: >-
      services-accounting:modules/transactions/tests/e2e/credits.e2e.spec.js#it
      is refused the application routes without their permissions (403)
environment: local
implementation_state: implemented
latest_result: not-run
latest_run_at: null
latest_run_ref: null
conformance: not-verified
estimated_minutes: 3
isolation: >-
  Suite-marked records in the prepared local test database; fixture teardown
  removes owned records.
provenance: test
source: 'services-accounting:modules/transactions/tests/e2e/credits.e2e.spec.js'
evidence:
  - provenance: test
    source: 'services-accounting:modules/transactions/tests/e2e/credits.e2e.spec.js'
    assertion_titles:
      - the credit routes (end to end)
      - a caller without the route’s permission
      - is refused the credit routes without their permissions (403)
      - is refused the application routes without their permissions (403)
      - tenancy
      - answers another tenant’s credit 404 exactly as one that does not exist
      - refuses a path naming a tenant the signed context does not carry (403)
      - a body the contract refuses
      - >-
        refuses a manual credit without its accounts, and a payment’s credit
        without its payment (400)
      - refuses an application with no target (400)
      - 'the create, apply, reverse and void flow'
      - >-
        created the credit: 1,000,000, open, with its whole balance; a replay
        answers the same credit
      - 'applied 4000: the application applied, the credit left with 1000'
      - lists the credit’s applications and reads one
      - >-
        lists no void action while money is applied (reassign batch alone), then
        reverses through POST .../reverse and voids through the action
      - refuses applying the void credit 409 credit_not_open
      - the open credits read
      - 'lists Ada’s open credits in alpha USD, oldest first'
      - >-
        refuses a customer type that is neither contact nor organization (400),
        before any read
    imports:
      - >-
        const { parseBody, proxyEvent } =
        require('@rhythmsoftware/macroservice-testing/signed-context');
      - 'const { stage } = require(''@rhythmsoftware/macroservice-testing/stage'');'
      - >-
        const { accountingApi, accountingGrant } =
        require('../../../books/tests/e2e/e2e-security');
      - >-
        const { PERMISSION_MISSING, accessRefusalOf, requireOk } =
        require('../../../books/tests/e2e/configuration-e2e-support');
      - '} = require(''../integration/payments-fixtures'');'
      - "\t\t\tctx: ctx ?? session.require().administrator,"
      - "\t\tsession.require();"
      - "\t\tconst outsider = () => session.require().outsider;"
      - "\t\t\tconst { credit } = created.require();"
      - "\t\t\tconst reader = session.require().reader;"
      - "\t\t\tconst { credit } = created.require();"
      - "\t\t\tconst reader = session.require().reader;"
      - "\t\t\tconst { foreign } = created.require();"
      - "\t\t\tconst answer = await call('GET', CREDIT, { tenant: OTHER, id: created.require().foreign.id, ctx: session.require().reader });"
      - "\t\t\t\t(await call('POST', APPLICATIONS, { body: { credit_id: created.require().credit.id, allocations: [] }, key: 'e2e-empty' })).status,"
      - "\t\t\tconst { credit } = created.require();"
      - "\t\t\tconst { invoice } = session.require();"
      - "\t\t\tconst { credit } = created.require();"
      - "\t\t\tconst application = applied.require();"
      - "\t\t\texpect(requireOk(await call('GET', CREDIT, { id: created.require().credit.id }), 'reading').balance).to.deep.equal(usd(1000));"
      - "\t\t\tconst application = applied.require();"
      - "\t\t\tconst page = requireOk(await call('GET', APPLICATIONS, { query: { credit_id: created.require().credit.id } }), 'listing');"
      - "\t\t\tconst { credit } = created.require();"
      - "\t\t\tconst application = applied.require();"
      - "\t\t\tconst { invoice } = session.require();"
      - "\t\t\t\tbody: { credit_id: created.require().credit.id, allocations: [{ invoice_id: invoice.id }], batch_id: ALPHA_BATCH },"
    test_double_declarations: []
---

# Credits suite

## Verification Boundary

The suite exercises transaction commands and database protections in the local prepared test environment. Registration records the existing executable file; it does not report a run or establish product approval.

## What This Suite Proves

Its cited assertions contribute evidence for manual credit requires compatible accounts; reading credit does not authorize spending. The structured assertion bindings identify which parts of combined scenarios it executes.

## What It Does Not Prove

Local commands and route invocations do not establish deployed routing, live processor guarantees or the complete staff browser experience. An unbound feature chain remains proposed, and this registration carries no execution result.

## Real Dependencies and Test Doubles

The suite uses the imported commands, route handlers or persistence code against the local test database. Fixture helpers supply accounting context; any stepped clock, dummy processor or substituted external client is retained in the evidence declarations.

## Must Not Be Doubled

The command or persistence behavior under assertion and its relevant database protections must remain real. Substituting the final financial result removes evidence of transactional effects.
