---
id: ATS-ACC-REC-001
scope: CAP-ACC-REC-001
product_area: accounting
module: reconciliation
revision: 3
status: proposed
approved_by: null
approved_at: null
source_sha:
  services-accounting: f47cb263875bbc0c5640fba7dae6785ec32695f8
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-ACC-REC-001-01
    title: Required payout facts and signed money
    level: api
    proves:
      - BR-CAP-ACC-REC-001-01
    preconditions: A configured merchant has a default settlement bank.
    steps: 'Submit missing-date, fractional, zero and negative-fifteen-dollar payout requests.'
    expected: Invalid requests identify their field; zero and negative payouts are recorded.
    negative: true
    data_needs: Use the isolated reconciliation fixture unit.
    bound_to:
      - >-
        services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#refuses a body without its
        reported deposit date with 400 naming the field
      - >-
        services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#refuses an amount that is not
        a whole number of minor units with 400
      - >-
        services-accounting:modules/reconciliation/tests/integration/db/payouts.table.integration.spec.js#stores
        a zero payout
      - >-
        services-accounting:modules/reconciliation/tests/integration/db/payouts.table.integration.spec.js#stores
        a negative payout, a debit of the bank account
      - TST-ACC-REC-025
      - TST-ACC-REC-033
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#refuses a body without its
      reported deposit date with 400 naming the field
    category: validation
  - id: ATS-ACC-REC-001-02
    title: Merchant and bank compatibility
    level: api
    proves:
      - BR-CAP-ACC-REC-001-02
    preconditions: Two units include a euro merchant and an inactive bank.
    steps: 'Try an inactive merchant and banks with a wrong unit, wrong currency or inactive status.'
    expected: Each invalid selection fails; a valid payout uses the merchant’s currency and processor.
    negative: true
    data_needs: Provide Two units and their accounts for this case.
    bound_to:
      - >-
        services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#answers 200 with the payout,
        its currency, processor and bank account the merchant account’s
      - >-
        services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#refuses an inactive merchant
        account with 400
      - >-
        services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#refuses a bank account of
        another business unit with 400
      - >-
        services-accounting:modules/reconciliation/tests/integration/services/persistence/payouts.integration.spec.js#refuses
        a bank account in another currency than the merchant account’s
      - >-
        services-accounting:modules/reconciliation/tests/integration/services/persistence/payouts.integration.spec.js#refuses
        an inactive bank account
      - >-
        services-accounting:modules/reconciliation/tests/integration/db/payouts.table.integration.spec.js#refuses
        a merchant account in another currency
      - TST-ACC-REC-025
      - TST-ACC-REC-057
      - TST-ACC-REC-033
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#answers 200 with the payout,
      its currency, processor and bank account the merchant account’s
    category: invariant
  - id: ATS-ACC-REC-001-03
    title: Live reference reservation
    level: api
    proves:
      - BR-CAP-ACC-REC-001-03
      - BR-CAP-ACC-REC-001-05
    preconditions: A live payout holds the sample processor reference.
    steps: 'Repeat that reference, use it on another merchant, then void the original and reuse it.'
    expected: 'Same-merchant duplication fails until void, while another merchant can use the reference.'
    negative: true
    data_needs: Provide One merchant account per unit plus a second account for this case.
    bound_to:
      - >-
        services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#refuses a processor reference
        a live payout of the merchant account has with 409 duplicate-reference
      - >-
        services-accounting:modules/reconciliation/tests/integration/db/payouts.table.integration.spec.js#allows
        the same reference on another merchant account
      - >-
        services-accounting:modules/reconciliation/tests/integration/db/payouts.table.integration.spec.js#allows
        the reference again once the payout holding it is voided
      - >-
        services-accounting:modules/reconciliation/tests/integration/services/persistence/payouts.integration.spec.js#records
        a reference again once the payout that had it is voided
      - TST-ACC-REC-025
      - TST-ACC-REC-033
      - TST-ACC-REC-057
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#refuses a processor reference a
      live payout of the merchant account has with 409 duplicate-reference
    category: edge
  - id: ATS-ACC-REC-001-04
    title: All duplicate candidates acknowledged
    level: api
    proves:
      - BR-CAP-ACC-REC-001-04
      - BR-CAP-ACC-REC-001-05
    preconditions: A five-hundred-dollar payout is reported on Wednesday.
    steps: >-
      Enter the same amount the following business day with no, incomplete and complete acknowledgement, then
      retry after void.
    expected: >-
      Only complete acknowledgement allows the live look-alike and records its audit; voided payouts are
      excluded.
    negative: true
    data_needs: Provide merchant account with a bank calendar for this case.
    bound_to:
      - >-
        services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#refuses a payout of the same
        amount reported a business day apart with 409 possible-duplicate and its candidates
      - >-
        services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#records the possible
        duplicate once every candidate is acknowledged, storing the acknowledgement
      - >-
        services-accounting:modules/reconciliation/tests/integration/services/persistence/payouts.integration.spec.js#refuses
        an acknowledgement that leaves a candidate out
      - >-
        services-accounting:modules/reconciliation/tests/integration/services/persistence/payouts.integration.spec.js#records
        the payout once every candidate is acknowledged, storing them and auditing the acknowledgement
      - >-
        services-accounting:modules/reconciliation/tests/integration/services/persistence/payouts.integration.spec.js#does
        not count a voided payout as a possible duplicate
      - TST-ACC-REC-025
      - TST-ACC-REC-057
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#refuses a payout of the same
      amount reported a business day apart with 409 possible-duplicate and its candidates
    category: boundary
  - id: ATS-ACC-REC-001-05
    title: Caller-scoped creation replay
    level: api
    proves:
      - BR-CAP-ACC-REC-001-06
    preconditions: A payout already exists under a caller’s key.
    steps: 'Retry unchanged, change the body, switch caller and omit the key.'
    expected: >-
      Unchanged retry returns that payout, changed or missing-key requests fail, and the other caller starts a
      new request.
    negative: true
    data_needs: Provide Two people with the create permission for this case.
    bound_to:
      - >-
        services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#answers the same payout for
        the same key and body, recording it once
      - >-
        services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#refuses the same key with
        another body with 409
      - >-
        services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#refuses a create without an
        Idempotency-Key with 400
      - >-
        services-accounting:modules/reconciliation/tests/integration/services/persistence/payouts.integration.spec.js#treats
        another caller’s use of the key as another request
      - >-
        services-accounting:modules/reconciliation/tests/integration/services/persistence/payouts.integration.spec.js#refuses
        another request under a key already used with idempotency-key-reused
      - TST-ACC-REC-025
      - TST-ACC-REC-057
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#answers the same payout for the
      same key and body, recording it once
    category: validation
  - id: ATS-ACC-REC-001-06
    title: Unique sequential payout numbers
    level: api
    proves:
      - BR-CAP-ACC-REC-001-07
    preconditions: Existing payouts establish the workspace’s current number.
    steps: Create two concurrently and search their numbers with and without the payout prefix.
    expected: Numbers advance distinctly and both search forms find the intended record.
    negative: false
    data_needs: The existing isolated fixture is sufficient.
    bound_to:
      - >-
        services-accounting:modules/reconciliation/tests/integration/services/persistence/payouts.integration.spec.js#numbers
        the tenant’s next payout one after its last
      - >-
        services-accounting:modules/reconciliation/tests/integration/services/persistence/payouts.integration.spec.js#gives
        two payouts recorded at once two numbers
      - >-
        services-accounting:modules/reconciliation/tests/integration/services/persistence/payouts.queries.integration.spec.js#searches
        by the payout’s number written PO-n
      - TST-ACC-REC-057
      - TST-ACC-REC-058
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/integration/services/persistence/payouts.integration.spec.js#numbers
      the tenant’s next payout one after its last
    category: concurrency
  - id: ATS-ACC-REC-001-07
    title: Creation and rollback history
    level: api
    proves:
      - BR-CAP-ACC-REC-001-08
      - BR-CAP-ACC-REC-001-09
    preconditions: A merchant account is available for creation.
    steps: Create a valid payout and submit another request that must be refused.
    expected: 'The successful payout and keyed event commit together; refusal leaves no payout, key or event.'
    negative: false
    data_needs: No additional fixture beyond the case setup.
    bound_to:
      - >-
        services-accounting:modules/reconciliation/tests/integration/services/persistence/payouts.integration.spec.js#records
        the payout from the merchant account’s facts and answers it whole
      - >-
        services-accounting:modules/reconciliation/tests/integration/services/persistence/payouts.integration.spec.js#records
        the payout’s audit event in its transaction, with its key
      - >-
        services-accounting:modules/reconciliation/tests/integration/services/persistence/payouts.integration.spec.js#writes
        nothing when it refuses: no payout, no key, no event
      - TST-ACC-REC-057
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/integration/services/persistence/payouts.integration.spec.js#records
      the payout from the merchant account’s facts and answers it whole
    category: failure
  - id: ATS-ACC-REC-001-08
    title: Duplicate preview without writes
    level: api
    proves:
      - BR-CAP-ACC-REC-001-10
    preconditions: 'Saved payouts provide known reference, amount and date cases.'
    steps: 'Preview a hard-reference duplicate, a nearby equal amount and an unused amount.'
    expected: 'The preview reports reference, possible and no duplicate respectively without creation.'
    negative: false
    data_needs: No additional fixture beyond the case setup.
    bound_to:
      - 'services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#answers a reference duplicate'
      - >-
        services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#answers a payout of the
        amount reported two business days before as a possible duplicate
      - >-
        services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#answers none for an amount no
        payout has
      - >-
        services-accounting:modules/reconciliation/tests/integration/services/persistence/payouts.queries.integration.spec.js#answers
        the live payouts of the amount within two business days of the date, by number, Columbus Day skipped
      - TST-ACC-REC-025
      - TST-ACC-REC-058
    provenance: test
    source: 'services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#answers a reference duplicate'
    category: rule
  - id: ATS-ACC-REC-001-09
    title: Creation requires its permission
    level: api
    proves:
      - BR-CAP-ACC-REC-001-11
    preconditions: A reader lacks payout create.
    steps: Attempt to record a deposit as that reader.
    expected: Creation is denied with a forbidden response.
    negative: true
    data_needs: Use a caller whose role grants inspection only.
    bound_to:
      - >-
        services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#refuses a principal without
        accounting.payouts.create with 403
      - TST-ACC-REC-025
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#refuses a principal without
      accounting.payouts.create with 403
    category: permission
  - id: ATS-ACC-REC-001-10
    title: Console opens the created workspace
    level: browser
    proves:
      - AS-JNY-ACC-REC-002-01
    preconditions: Mock mode supplies a selected unit.
    steps: Create a payout and inspect the request and resulting reconciliation heading.
    expected: 'The request sends minor-unit money and a header key, then opens the new payout’s workspace.'
    negative: false
    data_needs: Use the reconciliation mock route responses.
    bound_to:
      - >-
        react-console:e2e/mock/accounting-reconciliation.mock.spec.ts#Add Payout is a command: the new payout
        is on the list when it is read again
      - TST-ACC-REC-022
    provenance: test
    source: >-
      react-console:e2e/mock/accounting-reconciliation.mock.spec.ts#Add Payout is a command: the new payout is
      on the list when it is read again
    category: interaction
  - id: ATS-ACC-REC-001-11
    title: Duplicate and retry controls together
    level: api
    proves:
      - BR-CAP-ACC-REC-001-03
      - BR-CAP-ACC-REC-001-04
      - BR-CAP-ACC-REC-001-06
    preconditions: The isolated reconciliation fixture is configured.
    steps: 'Create a deposit, repeat its reference, try a look-alike and retry or alter keyed requests.'
    expected: >-
      Reference and unacknowledged duplicates fail, while keys replay unchanged requests and reject changed
      ones.
    negative: true
    data_needs: Use the isolated reconciliation fixture unit.
    bound_to:
      - >-
        react-console:acceptance/accounting/playwright/journeys/reconciliation-close/ACT-ACC-0591.spec.ts#ACT-ACC-0591
      - TST-ACC-REC-002
    provenance: test
    source: >-
      react-console:acceptance/accounting/playwright/journeys/reconciliation-close/ACT-ACC-0591.spec.ts#ACT-ACC-0591
    category: interaction
  - id: ATS-ACC-REC-001-12
    title: Voiding frees a reference for replacement
    category: interaction
    level: api
    proves:
      - BR-CAP-ACC-REC-001-03
      - BR-CAP-ACC-REC-001-05
      - BR-CAP-ACC-REC-002-06
      - BR-CAP-ACC-REC-002-07
    interacts_with:
      - CAP-ACC-REC-002
    relies_on:
      - ATS-ACC-REC-001-03
      - ATS-ACC-REC-002-04
    preconditions: Use one isolated workspace with the financial records and caller roles required by the relied-on cases.
    steps:
      - do: 'Record a referenced payout, void it and record a replacement using the same reference.'
        expect: The replacement is a distinct live payout and the cancelled entry remains reviewable.
        provenance: proposed
        source:
          - >-
            specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-001-record-a-processor-deposit-exactly-once.md
          - >-
            specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-002-correct-document-or-void-a-deposit-until-it-is-reconciled.md
    expected: The replacement is a distinct live payout and the cancelled entry remains reviewable.
    negative: false
    data_needs: >-
      Local merchant and bank accounts, an open operational batch and distinct preparation and approval
      callers.
    bound_to: []
    provenance: proposed
    source:
      - >-
        specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-001-record-a-processor-deposit-exactly-once.md
      - >-
        specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-002-correct-document-or-void-a-deposit-until-it-is-reconciled.md
  - id: ATS-ACC-REC-001-13
    title: Recorded numbers identify separate payouts
    category: interaction
    level: api
    proves:
      - BR-CAP-ACC-REC-001-07
      - BR-CAP-ACC-REC-004-03
      - BR-CAP-ACC-REC-004-05
    interacts_with:
      - CAP-ACC-REC-004
    relies_on:
      - ATS-ACC-REC-001-06
      - ATS-ACC-REC-004-02
    preconditions: Use one isolated workspace with the financial records and caller roles required by the relied-on cases.
    steps:
      - do: Record two deposits concurrently and find each by its assigned number.
        expect: Each search identifies its corresponding saved deposit.
        provenance: proposed
        source:
          - >-
            specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-001-record-a-processor-deposit-exactly-once.md
          - >-
            specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-004-find-deposits-and-see-where-each-one-stands.md
    expected: Each search identifies its corresponding saved deposit.
    negative: false
    data_needs: >-
      Local merchant and bank accounts, an open operational batch and distinct preparation and approval
      callers.
    bound_to: []
    provenance: proposed
    source:
      - >-
        specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-001-record-a-processor-deposit-exactly-once.md
      - >-
        specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-004-find-deposits-and-see-where-each-one-stands.md
  - id: ATS-ACC-REC-001-14
    title: Creation replay retains one record and activity
    category: interaction
    level: api
    proves:
      - BR-CAP-ACC-REC-001-06
      - BR-CAP-ACC-REC-020-05
    interacts_with:
      - CAP-ACC-REC-020
    relies_on:
      - ATS-ACC-REC-001-05
      - ATS-ACC-REC-020-05
    preconditions: Use one isolated workspace with the financial records and caller roles required by the relied-on cases.
    steps:
      - do: 'Record a keyed payout, replay it and inspect its activity as a reader.'
        expect: Replay returns the original payout and its committed creation history remains readable.
        provenance: proposed
        source:
          - >-
            specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-001-record-a-processor-deposit-exactly-once.md
          - >-
            specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-020-keep-preparing-apart-from-approving-and-leave-a-trail-of.md
    expected: Replay returns the original payout and its committed creation history remains readable.
    negative: false
    data_needs: >-
      Local merchant and bank accounts, an open operational batch and distinct preparation and approval
      callers.
    bound_to: []
    provenance: proposed
    source:
      - >-
        specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-001-record-a-processor-deposit-exactly-once.md
      - >-
        specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-020-keep-preparing-apart-from-approving-and-leave-a-trail-of.md
evidence:
  - >-
    Bindings identify existing tests at the pinned revisions; proposed cases remain unbound and describe the
    proof still needed.
coverage:
  rule: covered
  validation: covered
  permission: covered
  edge: covered
  failure: covered
  boundary: covered
  concurrency: covered
  invariant: covered
  interaction: covered
  transition: 'gap: FND-ACC-REC-046'
coverage_notes:
  design_completeness: >-
    Covered categories count specified cases, including proposed cases. Exhaustive state-transition,
    permission-key and domain-invariant traceability remains a separate proof gap.
---

# Record processor payouts without duplicate entry: Capability Test Specification

## Coverage

| Rule | Proved by |
|---|---|
| `BR-CAP-ACC-REC-001-01` | `ATS-ACC-REC-001-01` |
| `BR-CAP-ACC-REC-001-02` | `ATS-ACC-REC-001-02` |
| `BR-CAP-ACC-REC-001-03` | `ATS-ACC-REC-001-03`, `ATS-ACC-REC-001-11` |
| `BR-CAP-ACC-REC-001-04` | `ATS-ACC-REC-001-04`, `ATS-ACC-REC-001-11` |
| `BR-CAP-ACC-REC-001-05` | `ATS-ACC-REC-001-03`, `ATS-ACC-REC-001-04` |
| `BR-CAP-ACC-REC-001-06` | `ATS-ACC-REC-001-05`, `ATS-ACC-REC-001-11` |
| `BR-CAP-ACC-REC-001-07` | `ATS-ACC-REC-001-06` |
| `BR-CAP-ACC-REC-001-08` | `ATS-ACC-REC-001-07` |
| `BR-CAP-ACC-REC-001-09` | `ATS-ACC-REC-001-07` |
| `BR-CAP-ACC-REC-001-10` | `ATS-ACC-REC-001-08` |
| `BR-CAP-ACC-REC-001-11` | `ATS-ACC-REC-001-09` |

## Interactions With Related Capabilities

Console opens the created workspace. Duplicate and retry controls together. Voiding frees a reference for replacement. Recorded numbers identify separate payouts. Creation replay retains one record and activity. Proposed interaction cases require executable proof.
