---
id: TST-COM-ORD-075
title: Billing and tender
kind: api-lifecycle
product_area: commerce
module: orders
revision: 1
status: draft
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
repository: services-commerce
files:
  - modules/orders/tests/e2e/billing-and-tender.e2e.spec.js
implements:
  - ATS-COM-ORD-006-01
  - ATS-COM-ORD-006-03
  - ATS-COM-ORD-006-10
  - ATS-COM-ORD-007-01
  - ATS-COM-ORD-007-02
  - ATS-COM-ORD-007-03
  - ATS-COM-ORD-007-04
  - ATS-COM-ORD-007-05
  - ATS-COM-ORD-007-07
  - ATS-COM-ORD-007-08
  - ATS-COM-ORD-007-09
  - ATS-COM-ORD-007-10
  - ATS-COM-ORD-007-11
  - ATS-COM-ORD-008-05
  - ATS-COM-ORD-008-06
  - ATS-COM-ORD-008-07
  - ATS-COM-ORD-008-09
  - FAS-COM-ORD-02-01
  - FAS-COM-ORD-02-02
  - FAS-COM-ORD-02-03
environment: local
implementation_state: implemented
latest_result: not-run
latest_run_at: null
latest_run_ref: null
conformance: not-verified
estimated_minutes: 2
isolation: The suite creates its own test workspace records and removes them using the fixture cleanup.
evidence:
  - provenance: test
    source: 'services-commerce:modules/orders/tests/e2e/billing-and-tender.e2e.spec.js'
    test_cases:
      - 'commerce:order:{id}:bill:1:issue'
      - >-
        billed the order at placement: billed, placed, one pro forma sale invoice linked under the first bill
        key, the line carrying its invoice line
      - >-
        answers 200: the attempt succeeded with Accounting’s payment, the order accepted, the pro forma
        converted by that first money
      - >-
        never stores the card: the attempt keeps a reference of the merchant account and the token’s last four
        only
      - 'mirrors Accounting’s position: invoiced and paid in full, nothing due'
      - >-
        tells the story on the history: placed, billed, the tender recorded, submitted and resolved, the
        transition to accepted
      - 'refuses a second tender of the accepted order, 409 order_not_tenderable'
      - >-
        answers 200 declined with the processor’s code, the order still placed with its pro forma, the attempt
        declined
      - 'accepts the order on the next attempt, under the next sequence and key'
      - 'accepts the order on the leg that completes the total (08 row 14), the first leg captured'
      - pay later converts the pro forma to a real invoice and accepts the order on terms
      - >-
        store credit settles the order through Accounting’s settlement, the credit applied and the order
        accepted
      - 'answers uncertain, the order tender_uncertain, the attempt uncertain naming Accounting’s intent'
      - >-
        resumes the same attempt on a retry, whatever card the retry names, and moves nothing while the intent
        is processing
      - 'accepts the order once Accounting holds the payment, with one charge and the payment on the attempt'
      - >-
        bills a real invoice at placement and accepts the order on terms, the obligation waiting on the
        invoice
      - >-
        opens the gate of the console order when it is billed: the invoice is unpaid and the line is no longer
        waiting
      - leaves a console order waiting when the product’s own policy requires payment first
      - 'leaves the portal order on terms waiting on its invoice, as before'
      - leaves the order placed and pending with one attempt; the buyer’s tender bills it first and proceeds
      - 'refuses the tender 409 order_not_billed when billing it now gets no answer either, charging nothing'
      - deletes the pro forma in Accounting and records it on the history
      - captured both legs and left the order placed before the void
      - 'records order.void_refund_planned with each leg, its amount and how it goes back'
      - >-
        ran the plan through the adjustment worker: the card leg refunded under the void’s key, then the memo
        of the sale invoice
      - >-
        tells the story on the history: the pro forma not deleted for its money, the plan, each step, the
        adjustment completed
      - >-
        refunds nothing twice: a second void is 409, a re-run of the plan sends nothing and a replayed request
        answers the same plan
      - refunds a card leg alone to its card when staff void the order
      - leaves an adjustment_failed exception for a person when Accounting refuses the refund
      - >-
        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)
      - >-
        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)
      - 'refuses a card tender without its token, 400, and a body with an unknown field, 400'
      - >-
        refuses another member’s order 403 not_your_party, a reader without commerce.orders.tender 403
        permission_missing, and another tenant’s order 404
      - 'lets staff record an offline check, accepting the order'
      - >-
        lets staff record a money order and a cashier’s check as split payments, each under its Accounting
        method
      - 'refuses a member a second payment, 409 split_tender_not_allowed naming the policy'
      - 'lets staff record cash for the rest although the policy lists no offline method, accepting the order'
      - 'still refuses a member an offline tender under that policy, 409 tender_kind_not_allowed'
      - >-
        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
      - >-
        shows the order’s frozen card rule on the order read, so the console can say the policy refuses a card
        for this total (COMM-M1 review E6)
      - >-
        refuses a card outside the profile’s acceptance range on an order placed under it, 409
        tender_kind_not_allowed naming the range, from the order’s snapshot
      - 'creates the pro forma and issues it at placement, in that order, under the bill key and its issue key'
      - 'answers the placed order billed against an issued pro forma: open, in the PF series'
      - 'takes the card for the whole order after the issue replays: 200 succeeded, the order accepted'
      - 'leaves the invoice converted by that money, paid, and the mirror paid in full'
      - >-
        refuses the card 409 merchant_account_not_eligible under a real processor, naming
        merchant_account_not_connected, nothing recorded
      - takes the card under ACCOUNTING_PAYMENT_PROCESSOR=dummy and pays the order in full
scenario_coverage:
  - scenario: ATS-COM-ORD-006-01
    test_cases:
      - >-
        billed the order at placement: billed, placed, one pro forma sale invoice linked under the first bill
        key, the line carrying its invoice line
      - 'creates the pro forma and issues it at placement, in that order, under the bill key and its issue key'
      - >-
        bills a real invoice at placement and accepts the order on terms, the obligation waiting on the
        invoice
    scope: >-
      The cited cases exercise the scenario’s listed fixture outcomes; this register makes no verified
      conformance claim.
  - scenario: ATS-COM-ORD-006-03
    test_cases:
      - leaves the order placed and pending with one attempt; the buyer’s tender bills it first and proceeds
    scope: >-
      The cited cases exercise the scenario’s listed fixture outcomes; this register makes no verified
      conformance claim.
  - scenario: ATS-COM-ORD-006-10
    test_cases:
      - >-
        opens the gate of the console order when it is billed: the invoice is unpaid and the line is no longer
        waiting
      - leaves a console order waiting when the product’s own policy requires payment first
      - 'leaves the portal order on terms waiting on its invoice, as before'
    scope: >-
      The cited cases exercise the scenario’s listed fixture outcomes; this register makes no verified
      conformance claim.
  - scenario: ATS-COM-ORD-007-01
    test_cases:
      - 'answers uncertain, the order tender_uncertain, the attempt uncertain naming Accounting’s intent'
      - >-
        resumes the same attempt on a retry, whatever card the retry names, and moves nothing while the intent
        is processing
      - 'accepts the order once Accounting holds the payment, with one charge and the payment on the attempt'
    scope: >-
      The cited cases exercise the scenario’s listed fixture outcomes; this register makes no verified
      conformance claim.
  - scenario: ATS-COM-ORD-007-02
    test_cases:
      - >-
        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)
      - 'refuses a second tender of the accepted order, 409 order_not_tenderable'
    scope: >-
      The cited cases exercise the scenario’s listed fixture outcomes; this register makes no verified
      conformance claim.
  - scenario: ATS-COM-ORD-007-03
    test_cases:
      - >-
        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)
      - 'lets staff record cash for the rest although the policy lists no offline method, accepting the order'
      - 'still refuses a member an offline tender under that policy, 409 tender_kind_not_allowed'
    scope: >-
      The cited cases exercise the scenario’s listed fixture outcomes; this register makes no verified
      conformance claim.
  - scenario: ATS-COM-ORD-007-04
    test_cases:
      - >-
        never stores the card: the attempt keeps a reference of the merchant account and the token’s last four
        only
    scope: >-
      The cited cases exercise the scenario’s listed fixture outcomes; this register makes no verified
      conformance claim.
  - scenario: ATS-COM-ORD-007-05
    test_cases:
      - >-
        answers 200 declined with the processor’s code, the order still placed with its pro forma, the attempt
        declined
      - 'accepts the order on the next attempt, under the next sequence and key'
    scope: >-
      The cited cases exercise the scenario’s listed fixture outcomes; this register makes no verified
      conformance claim.
  - scenario: ATS-COM-ORD-007-07
    test_cases:
      - 'accepts the order on the leg that completes the total (08 row 14), the first leg captured'
    scope: >-
      The cited cases exercise the scenario’s listed fixture outcomes; this register makes no verified
      conformance claim.
  - scenario: ATS-COM-ORD-007-08
    test_cases:
      - 'refuses a member a second payment, 409 split_tender_not_allowed naming the policy'
      - >-
        lets staff record a money order and a cashier’s check as split payments, each under its Accounting
        method
    scope: >-
      The cited cases exercise the scenario’s listed fixture outcomes; this register makes no verified
      conformance claim.
  - scenario: ATS-COM-ORD-007-09
    test_cases:
      - pay later converts the pro forma to a real invoice and accepts the order on terms
    scope: >-
      The cited cases exercise the scenario’s listed fixture outcomes; this register makes no verified
      conformance claim.
  - scenario: ATS-COM-ORD-007-10
    test_cases:
      - >-
        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
      - >-
        refuses a card outside the profile’s acceptance range on an order placed under it, 409
        tender_kind_not_allowed naming the range, from the order’s snapshot
    scope: >-
      The cited cases exercise the scenario’s listed fixture outcomes; this register makes no verified
      conformance claim.
  - scenario: ATS-COM-ORD-007-11
    test_cases:
      - 'refuses the tender 409 order_not_billed when billing it now gets no answer either, charging nothing'
    scope: >-
      The cited cases exercise the scenario’s listed fixture outcomes; this register makes no verified
      conformance claim.
  - scenario: ATS-COM-ORD-008-05
    test_cases:
      - deletes the pro forma in Accounting and records it on the history
    scope: >-
      The cited cases exercise the scenario’s listed fixture outcomes; this register makes no verified
      conformance claim.
  - scenario: ATS-COM-ORD-008-06
    test_cases:
      - >-
        ran the plan through the adjustment worker: the card leg refunded under the void’s key, then the memo
        of the sale invoice
    scope: >-
      The cited cases exercise the scenario’s listed fixture outcomes; this register makes no verified
      conformance claim.
  - scenario: ATS-COM-ORD-008-07
    test_cases:
      - >-
        refunds nothing twice: a second void is 409, a re-run of the plan sends nothing and a replayed request
        answers the same plan
    scope: >-
      The cited cases exercise the scenario’s listed fixture outcomes; this register makes no verified
      conformance claim.
  - scenario: ATS-COM-ORD-008-09
    test_cases:
      - deletes the pro forma in Accounting and records it on the history
      - >-
        refunds nothing twice: a second void is 409, a re-run of the plan sends nothing and a replayed request
        answers the same plan
    scope: >-
      The cited cases exercise the scenario’s listed fixture outcomes; this register makes no verified
      conformance claim.
  - scenario: FAS-COM-ORD-02-01
    test_cases:
      - >-
        billed the order at placement: billed, placed, one pro forma sale
        invoice linked under the first bill key, the line carrying its invoice
        line
      - >-
        answers 200: the attempt succeeded with Accounting’s payment, the order
        accepted, the pro forma converted by that first money
    scope: >-
      The fixture chain asserts this outcome within the suite’s declared
      dependency boundary.
  - scenario: FAS-COM-ORD-02-02
    test_cases:
      - >-
        refunds nothing twice: a second void is 409, a re-run of the plan sends
        nothing and a replayed request answers the same plan
    scope: >-
      The fixture chain asserts this outcome within the suite’s declared
      dependency boundary.
  - scenario: FAS-COM-ORD-02-03
    test_cases:
      - >-
        answers 200 declined with the processor’s code, the order still placed
        with its pro forma, the attempt declined
      - 'accepts the order on the next attempt, under the next sequence and key'
    scope: >-
      The fixture chain asserts this outcome within the suite’s declared
      dependency boundary.
dependency_evidence:
  provenance: test
  source: 'services-commerce:modules/orders/tests/e2e/billing-and-tender.e2e.spec.js'
  declared_by_test: >-
    the composed handler, the routes, the placement, the billing and tender workflows, the stub participant,
    the persistence services, P4's register and exceptions, PostgreSQL (the stand-in view). Doubled: the
    signing key pair, the other services' tables (local stand-ins), Accounting (the fixture, with the
    contracts package's schema).
---

# Billing and tender

## Verification Boundary

The suite drives the composed local API dispatcher and its registered routes.

## What This Suite Proves

The registered cases check billing and tender with their fixture records and assertions. Scenario bindings name only the examples those cases exercise.

## What It Does Not Prove

A registered file supplies no run result or verified conformance by itself. Local fixtures do not establish deployed cross-service behavior or complete browser journeys.

## Real Dependencies and Test Doubles

PostgreSQL and the exercised Commerce persistence or workflow code are real. Remote service records, clocks and transports follow the suite’s fixtures.

## Must Not Be Doubled

The database constraints, role restrictions, locks and transactions exercised by this suite must use PostgreSQL.
