---
id: TST-ACC-TRX-001
title: Receivables aging 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/ar-aging.e2e.spec.js
implements:
  - ATS-ACC-TRX-018-03
  - ATS-ACC-TRX-018-06
  - ATS-ACC-TRX-018-07
implements_parts:
  - scenario: ATS-ACC-TRX-018-03
    assertion: >-
      it answers every item once, in kind and id order, each with its bucket and
      balance
    provenance: test
    source: >-
      services-accounting:modules/transactions/tests/e2e/ar-aging.e2e.spec.js#it
      answers every item once, in kind and id order, each with its bucket and
      balance
  - scenario: ATS-ACC-TRX-018-06
    assertion: >-
      it still answers the published version 1 while version 2 waits to be
      admitted
    provenance: test
    source: >-
      services-accounting:modules/transactions/tests/e2e/ar-aging.e2e.spec.js#it
      still answers the published version 1 while version 2 waits to be admitted
  - scenario: ATS-ACC-TRX-018-06
    assertion: >-
      it refuses the first version’s cursor with 409 version_changed, rather
      than continuing in the second version
    provenance: test
    source: >-
      services-accounting:modules/transactions/tests/e2e/ar-aging.e2e.spec.js#it
      refuses the first version’s cursor with 409 version_changed, rather than
      continuing in the second version
  - scenario: ATS-ACC-TRX-018-06
    assertion: it answers 404 not_available naming not_planned for a month with no run
    provenance: test
    source: >-
      services-accounting:modules/transactions/tests/e2e/ar-aging.e2e.spec.js#it
      answers 404 not_available naming not_planned for a month with no run
  - scenario: ATS-ACC-TRX-018-07
    assertion: >-
      it refuses a principal holding only the application’s access with 403
      permission_missing
    provenance: test
    source: >-
      services-accounting:modules/transactions/tests/e2e/ar-aging.e2e.spec.js#it
      refuses a principal holding only the application’s access with 403
      permission_missing
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/ar-aging.e2e.spec.js'
evidence:
  - provenance: test
    source: 'services-accounting:modules/transactions/tests/e2e/ar-aging.e2e.spec.js'
    assertion_titles:
      - the A/R aging route (end to end)
      - a published month
      - >-
        answers 200 with the captured version 1, as known at September’s end,
        and its publication
      - >-
        answers the totals by business unit, currency and bucket in report
        order, and no items without detail
      - answers the same for the month’s last date as for its label
      - 'answers one business unit’s totals, none for a unit with no item'
      - 'the items, a page at a time'
      - answers two items and a cursor on the first page
      - 'answers the last two on the second, and no cursor after them'
      - >-
        answers every item once, in kind and id order, each with its bucket and
        balance
      - answers each item’s document and customer as captured
      - published data only
      - >-
        still answers the published version 1 while version 2 waits to be
        admitted
      - a newer version published between pages
      - >-
        refuses the first version’s cursor with 409 version_changed, rather than
        continuing in the second version
      - answers the new version from the first page
      - a month with no published version
      - answers 404 not_available naming not_planned for a month with no run
      - 'answers the status of the month’s only run, planned, while it waits'
      - 'answers tenant B, which has no run, exactly as a month with none'
      - refusals
      - refuses a period that is neither a month nor a date with 400
      - refuses a date that is not its month’s last with 400
      - refuses a cursor without detail with 400
      - >-
        refuses a principal holding only the application’s access with 403
        permission_missing
      - answers a principal holding accounting.ar-aging.read
    imports:
      - const chai = require('chai');
      - >-
        const { parseBody, proxyEvent } =
        require('@rhythmsoftware/macroservice-testing/signed-context');
      - 'const { stage } = require(''@rhythmsoftware/macroservice-testing/stage'');'
      - >-
        const { planSnapshotRuns } =
        require('@rhythmsoftware/macroservice-snapshots/snapshot-planner');
      - >-
        const { resetJobEngineChannelDepsForTests } =
        require('@rhythmsoftware/macroservice-jobs/engine/job-engine');
      - 'const { integrationDatabaseUrl } = require(''../../../../db/config'');'
      - >-
        const { registerLocalTenant } =
        require('../../../../db/test-support/platform-tables');
      - >-
        const { accountingApi, accountingGrant } =
        require('../../../books/tests/e2e/e2e-security');
      - >-
        const { listSnapshotTenants } =
        require('../../../maintenance/services/persistence/tenants');
      - >-
        const { SNAPSHOT_STORE, requestSnapshotRun } =
        require('../../services/persistence/snapshot-runs');
      - 'const { arAgingSnapshot } = require(''../../services/types/ar-aging'');'
      - '} = require(''../integration/ar-aging-fixtures'');'
      - "\t\t\tctx: ctx ?? session.require().administrator,"
      - "\t\t\tconst { status, body } = totals.require();"
      - "\t\t\tconst { body } = totals.require();"
      - "\t\t\texpect([byDate.status, byDate.body.run_id]).to.deep.equal([200, totals.require().body.run_id]);"
      - "\t\t\tconst { first } = pages.require();"
      - "\t\t\tconst { second } = pages.require();"
      - "\t\t\tconst { first, second } = pages.require();"
      - "\t\t\tconst { world } = session.require();"
      - "\t\t\tconst item = pages.require().first.body.items[0];"
      - "\t\tsession.require();"
      - "\t\t\tconst { status, body } = rerun.require();"
      - "\t\t\trerun.require();"
      - "\t\t\tconst { first, next } = republished.require();"
      - "\t\t\tconst { fresh } = republished.require();"
      - "\t\t\texpect(refusal(await get({ period_end: '2026-09' }, { ctx: session.require().applicationOnly }))).to.deep.equal({"
      - "\t\t\texpect((await get({ period_end: '2026-09' }, { ctx: session.require().agingReader })).status).to.equal(200);"
    test_double_declarations:
      - >-
        const { resetJobEngineChannelDepsForTests } =
        require('@rhythmsoftware/macroservice-jobs/engine/job-engine');
      - "\tafter(() => resetJobEngineChannelDepsForTests());"
---

# Receivables aging 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 published items reconcile with grouped totals; pagination cannot mix publications; aging access also isolates workspaces. 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.
