Skip to content

CAP-COM-ORD-007Collect payment without duplicate charges

Markdown

CAP-COM-ORD-007

Collect payment without duplicate charges

Markdown
  • DocumentDraft
  • Product intentConfirmed
  • ImplementationObserved

KindCapabilityProduct areaCommerceModuleCustomer purchases, purchased benefits and vendor stockRevision1

Read atservices-commerce c8b66a98react-console baf6dae3

The Formal Contract

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

Outcomes
A declined card leaves time to pay the existing order another way.Retries preserve one charge for the same unresolved attempt.
Surfaces
consoleapijob
Intent sources
services-commerce:docs/milestones/plans/COMM-M2-plan.md#A2services-commerce:docs/milestones/plans/COMM-M2-plan.md#A11services-commerce:docs/milestones/plans/COMM-M2-plan.md#D4services-commerce:docs/milestones/plans/COMM-M2-plan.md#9. Acceptance scenariosservices-commerce:docs/milestones/plans/COMM-M2-plan.md#2. Scope

Controls

31 controls apply, from the corpus control catalogue.

TC-IAM-006 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-CRY-001 TC-DAT-001 TC-DAT-002 TC-DAT-003 TC-DAT-004 TC-LOG-004 TC-LOG-005 TC-AVL-004 TC-MON-001 TC-MON-002 TC-MON-004 TC-PI-001 TC-PI-002 TC-PI-003 TC-PI-004 TC-PI-005 TC-VEN-001 TC-VEN-002 TC-VEN-003 TC-PRV-001 TC-PRV-002

Permissions

KeyChecked atScope
commerce.orders.tenderapitenant
commerce.orders.readconsoletenant

Business Rules

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

IdRuleKindEnforced atProvenance
01must prove
Confirmed
An unresolved payment attempt is resumed with its existing Accounting key despite changed retry inputs, preventing a second charge for that attempt.
no proof recorded yet
invariantapi, servicetest
services-commerce:modules/orders/tests/e2e/billing-and-tender.e2e.spec.js#resumes the same attempt on a retry, whatever card the retry names, and moves nothing while the intent is processing
02must prove
Confirmed
The normal payment action requires a placed or payment-uncertain order within its tender window and refuses accepted orders and attempts after that window.
no proof recorded yet
validationservicetest
services-commerce:modules/orders/tests/e2e/billing-and-tender.e2e.spec.js#refuses a tender after the window 409 tender_window_expired and gives the sentence plain in the details, without the error class prefix (COMM-M2 R2-5)
03must prove
Confirmed
The frozen policy determines processor, store-credit and terms choices; console staff can record supported offline methods even without listed offline choices, while portal buyers cannot record them.
no proof recorded yet
policyservicetest
services-commerce:modules/orders/tests/e2e/billing-and-tender.e2e.spec.js#refuses an offline tender by a member, 403 tender_kind_staff_only, and a kind the profile does not allow, 409, read from the ORDER’s snapshot: the order placed before the change still allows it (22 §9)
04must prove
Confirmed
Commerce accepts a payment token and stores a merchant-account reference with the token’s final four characters, keeping the full token out of the returned attempt.
no proof recorded yet
invariantservicetest
services-commerce:modules/orders/tests/e2e/billing-and-tender.e2e.spec.js#never stores the card: the attempt keeps a reference of the merchant account and the token’s last four only
05must prove
Confirmed
A card decline preserves the placed order and pro forma, allowing a later attempt within the window under a new sequence and key.
no proof recorded yet
lifecycleservicetest
services-commerce:modules/orders/tests/e2e/billing-and-tender.e2e.spec.js#answers 200 declined with the processor’s code, the order still placed with its pro forma, the attempt declined
06must prove
Confirmed
A lost payment response leaves the order uncertain until the minute sweep resolves the existing attempt, and uncertainty lasting fifteen minutes raises an exception.
no proof recorded yet
lifecycleservicetest
services-commerce:modules/orders/tests/integration/services/orders/financial-sweeps.integration.spec.js#raises tender_uncertain on an attempt still uncertain past fifteen minutes
07must prove
Confirmed
Successful payment legs count toward acceptance, with store credit counted at the amount actually applied and a zero-application leg declined.
no proof recorded yet
calculationservicetest
services-commerce:modules/orders/tests/unit/tender/tender-rules.spec.js#leaves a credit leg that applied less than it asked at what it applied, so the order still owes the rest
08must prove
Confirmed
A single-payment policy prevents a portal buyer’s second payment, with a policy explanation, while staff can split the payment.
no proof recorded yet
policyservicetest
services-commerce:modules/orders/tests/e2e/billing-and-tender.e2e.spec.js#refuses a member a second payment, 409 split_tender_not_allowed naming the policy
09must prove
Confirmed
A terms payment choice accepts the order without a charge, converts its provisional invoice and can retain the customer’s purchase-order reference.
no proof recorded yet
lifecycleservicetest
services-commerce:modules/orders/tests/e2e/billing-and-tender.e2e.spec.js#pay later converts the pro forma to a real invoice and accepts the order on terms
10must prove
Confirmed
Accounting checks the requested or frozen merchant account against the order’s business unit, currency and method before recording a card attempt, and the frozen policy rejects amounts outside its card range.
no proof recorded yet
validationservicetest
services-commerce:modules/orders/tests/e2e/billing-and-tender.e2e.spec.js#asks Accounting whether the merchant account may settle the tender: the order’s frozen default refused when ineligible, 409 merchant_account_not_eligible, a request naming an eligible account accepted
11must prove
Confirmed
Payment first tries to bill an unbilled order and refuses the charge if billing still cannot obtain an answer.
no proof recorded yet
validationservicetest
services-commerce:modules/orders/tests/e2e/billing-and-tender.e2e.spec.js#refuses the tender 409 order_not_billed when billing it now gets no answer either, charging nothing
12must prove
Confirmed
The documented Accounting rule identifies the cardholder as payer and refuses application of their payment to another customer’s invoice.
no proof recorded yet
policyservicedocumented
13must prove
Confirmed
The composer retains the same order after card decline or an unpaid card-window close, records check references or terms purchase-order references and offers only permitted methods.
no proof recorded yet
policyconsoletest
react-console:components/order-composer/__tests__/live-composer.test.tsx#places the order, then takes a card: declined first, approved on the same order
14must prove
Confirmed
Order 360 selects pay-now payment and void actions or the terms invoice’s Accounting payment link according to order state and permissions, hiding these actions on paid orders.
no proof recorded yet
permissionconsoletest
react-console:components/console/order/__tests__/order-360-live-cards.test.tsx#shows Take Payment and Void Order on an unpaid pay-now order inside its window

Scenarios

IdGivenWhenThenProvenance
01Jane’s two-hundred-thirteen-dollar order already exists.Staff try a declining card and then an approving card.The decline leaves the order awaiting payment, and the replacement attempt accepts it with one successful charge.documented

Edge Cases

IdGivenWhenThenProvenance
02A final-second payment and expiry processing compete on the same order.The payment completes while a void attempt runs.The intended outcome preserves either the paid order or a void without retained money; this race remains unverified.unknown

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.