Skip to content

CAP-ACC-REC-001Record processor payouts without duplicate entry

Markdown

CAP-ACC-REC-001

Record processor payouts without duplicate entry

Markdown
  • DocumentDraft
  • Product intentConfirmed
  • ImplementationObserved

KindCapabilityProduct areaAccountingModuleReconciliationRevision2

Read atservices-accounting f47cb263react-console baf6dae3

The Formal Contract

The narrative above explains; the sections below are authoritative — the rules, scenarios and tests this document binds.

Outcomes
Each merchant deposit or debit has one retained payout record.Look-alike entry requires an explicit recorded acknowledgement.Creation retry preserves the original record.
Surfaces
consoleapi
Preconditions
The merchant belongs to the selected unit and remains active.
Postconditions
The created payout retains manual origin with verification and reconciliation pending.
Intent sources
services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D10 (§2 payouts: manual entry and duplicate rules)services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D6 (architecture §3.4 U1, U9)services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D8 (processor import out)

Controls

22 controls apply, from the corpus control catalogue.

TC-IAM-001 TC-IAM-002 TC-IAM-004 TC-IAM-005 TC-AZ-001 TC-AZ-002 TC-AZ-003 TC-AZ-004 TC-AZ-006 TC-TEN-001 TC-TEN-002 TC-TEN-003 TC-TEN-004 TC-DAT-001 TC-LOG-002 TC-LOG-003 TC-LOG-004 TC-LOG-005 TC-PI-001 TC-PI-002 TC-PI-003 TC-PI-005

Permissions

KeyChecked atScope
accounting.payouts.createapitenant
accounting.payouts.readapitenant
accounting.payouts.createconsoletenant

Business Rules

12 rules, 11 to be proved before approval. A rule's product intent is derived from its origin: 12 confirmed by a product decision, the rest inheriting this capability's confirmed.

IdRuleKindEnforced atProvenance
01must prove
Confirmed
Staff enter a merchant account, an integer minor-unit net amount and a reported deposit day; zero and negative amounts are valid, and the merchant’s settlement bank is used when no bank is supplied.
✓ A Payrix debit of -15.00 for fees is recorded as a payout of -1500.✗ A deposit with no reported deposit date is refused, naming the field.
origin: services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D6 (architecture §3.4 U9: negative and zero payouts allowed)
validationapi, servicetest
02must prove
Confirmed
The merchant determines the payout’s unit, currency and processor permanently; inactive merchants and banks, or banks in another unit or currency, cannot be used.
origin: services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D10 (§4: the architecture §6 invariants hold; INV-02)
invariantapi, service, databasetest
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
03must prove
Confirmed
A merchant’s nonvoided payouts cannot share a processor reference; voiding the earlier payout releases that reference.
✓ PX-1083 a second time is refused.✗ PX-1083 on another merchant account is accepted.
origin: services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D10 (plan approved 2026-10-22 10:40 ET; §2 scope); §3: a second deposit with the same reference is refused
policyservice, databasetest
services-accounting:modules/reconciliation/tests/integration/services/persistence/payouts.integration.spec.js#refuses a reference a live payout of the merchant account has with duplicate-reference; 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; react-console:acceptance/accounting/playwright/journeys/reconciliation-close/ACT-ACC-0591.spec.ts#ACT-ACC-0591
04must prove
Confirmed
An equal amount within two business days either side in the merchant’s bank calendar requires acknowledgement of every possible duplicate, and Rhythm retains and audits those acknowledgements.
origin: services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D10 (§3: the same amount and date warns and needs an acknowledgement)
policyservicetest
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/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/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; react-console:acceptance/accounting/playwright/journeys/reconciliation-close/ACT-ACC-0591.spec.ts#ACT-ACC-0591
05must prove
Confirmed
Voided payouts reserve no processor reference and do not participate in possible-duplicate detection.
origin: services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D10 (plan approved 2026-10-22 10:40 ET; §2 scope)
policyservice, databasetest
services-accounting:modules/reconciliation/tests/integration/services/persistence/payouts.integration.spec.js#does not count a voided payout as a possible duplicate; 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; 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
06must prove
Confirmed
Creation requires a request key scoped to its caller: identical retries return the existing payout, a changed body fails, and another caller’s key starts a separate request.
origin: services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D10 (§2: idempotency of every money command)
validationapi, servicetest
07must prove
Confirmed
Payout numbering advances within the workspace without collisions between simultaneous creates, and the number is searchable with or without its payout prefix.
calculationservice, databasetest
08must prove
Confirmed
Failed payout creation rolls back the payout, request-key record and audit event together.
invariantservicetest
09must prove
Confirmed
A created payout starts as manual, bank-unverified and unreconciled, with its keyed creation event committed alongside it.
origin: services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D6 (architecture §3.4 U1: source is how it was entered; verification only by evidence)
lifecycleservice, databasetest
10must prove
Confirmed
The duplicate preview returns hard-reference and possible-duplicate results without creating a payout.
origin: services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D10 (plan approved 2026-10-22 10:40 ET; §2 scope)
calculationapi, servicetest
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 a reference 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
11must prove
Confirmed
The create permission governs payout recording, the read permission governs duplicate preview, and the console disables creation when create is absent.
origin: services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D10 (§2: permissions (preparer and approver policies))
permissionapi, consoletest
services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#refuses a principal without accounting.payouts.create with 403
12
Confirmed
Console payout creation has no duplicate-acknowledgement payload, so acknowledging a look-alike currently requires the API.
policyconsoleobserved

Scenarios

IdGivenWhenThenProvenance
01The Payrix merchant in the sample unit has a reported deposit of $9,725.00 on October 10.Enter the processor deposit.A manual unverified payout stores 972500 minor units with that accounting day.test
services-accounting:modules/reconciliation/tests/e2e/reconciliation-scenario.e2e.spec.js#step 3: enters PX-1083 as a manual, unverified payout of 972500 dated 2026-10-10
02The sample processor reference already belongs to a live payout.Attempt another payout with that reference.Creation fails for a hard-reference duplicate.test
services-accounting:modules/reconciliation/tests/e2e/reconciliation-scenario.e2e.spec.js#step 3: refuses a second entry of PX-1083 as a duplicate reference
03A live payout has the same reported day and $9,725.00 amount.Enter another deposit without its own reference.Possible-duplicate refusal identifies the existing payout.test
services-accounting:modules/reconciliation/tests/e2e/reconciliation-scenario.e2e.spec.js#step 3: answers an entry with no reference, the same amount and date, possible-duplicate naming PX-1083

Edge Cases

IdGivenWhenThenProvenance
04An equal amount is reported three business days earlier.Preview duplicates for the new deposit.That earlier payout is outside possible-duplicate eligibility.test
services-accounting:modules/reconciliation/tests/e2e/payouts.e2e.spec.js#answers none when the payout of the amount was reported three business days before
05Processor charges produce a debit rather than a deposit.Record a negative-fifteen-dollar payout.The bank debit is retained as a signed payout.test

The Markdown files under specs/ in rhythmsoftware/rhythm-v2-docs are the canonical source of truth. This reader is a generated, read-only projection of them.