---
id: ATS-COM-CAT-016
scope: CAP-COM-CAT-016
product_area: commerce
module: catalog
revision: 1
status: proposed
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-COM-CAT-016-01
    title: Alternative pricing matches the decision’s examples
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-01
      - BR-CAP-COM-CAT-016-02
      - AS-JNY-COM-CAT-005-01
    preconditions: >-
      Standard, Member and Student prices are one hundred, eighty and sixty
      dollars
    steps: Assess combining and noncombining twenty-five-percent benefits
    expected: >-
      Results are sixty, seventy-five and sixty dollars, with the ineffective
      code unused and explained
    negative: false
    data_needs: none
    bound_to:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#1.
        combine = yes, member: $80.00 less 25 % is $60.00 (tax 8 % is $4.80)
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#2.
        combine = no, member: audience pricing $80.00 against $100.00 less 25 %
        = $75.00; the promotional price wins
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#3.
        combine = no, student at $60.00: audience pricing wins, EARLY25 consumes
        no use, and the buyer is told why
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#is
        the same answer for the same input
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#1.
      combine = yes, member: $80.00 less 25 % is $60.00 (tax 8 % is $4.80)
  - id: ATS-COM-CAT-016-02
    title: Bounded combination search handles extra promotions
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-03
    preconditions: Five promotions cannot combine with audience prices
    steps: Evaluate the candidate set
    expected: >-
      At most sixteen base alternatives are explored; later entries are retained
      only when they improve the total
    negative: false
    data_needs: none
    bound_to:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#takes
        one of two when the other loses on its own line: A a better price on the
        guide, B a worse one on the mug
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#tries
        the fifth and later one at a time in entry order
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#leaves
        the fifth unused when it does not lower the total
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#asks
        for at most sixteen distinct alternatives when four promotions stay off
        audience prices
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#takes
      one of two when the other loses on its own line: A a better price on the
      guide, B a worse one on the mug
  - id: ATS-COM-CAT-016-03
    title: Sequential line benefits precede order benefits
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-04
    preconditions: >-
      A hundred-dollar line supports ten-percent and twenty-dollar order
      benefits
    steps: Evaluate their application
    expected: The result is seventy dollars and subsequent benefits use the prior result
    negative: false
    data_needs: none
    bound_to:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#Q2:
        line-level before order-level: 10 % and $20 off the order on $100.00 is
        $70.00, not $72.00
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/stacking.spec.js#puts
        automatic promotions first by priority, then the codes in the order
        entered
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/stacking.spec.js#J16:
        an automatic 10% stackable then a 15% stackable code on 20000 give 2000
        then 2700, net 15300
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#Q2:
      line-level before order-level: 10 % and $20 off the order on $100.00 is
      $70.00, not $72.00
  - id: ATS-COM-CAT-016-04
    title: Exclusive codes compete against automatic benefits
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-05
    preconditions: Automatic Fall pricing and two exclusive VIP benefits exist
    steps: Assess the weaker VIP alone and both VIP codes in either order
    expected: >-
      The weak code loses to automatic pricing; the better exclusive wins
      consistently and conflicts identify the holder
    negative: false
    data_needs: none
    bound_to:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#5.
        exclusive code against the automatic outcome: VIP5 (5 %) would give
        $76.00, Fall 10 % gives $72.00; VIP5 is dropped and consumes no use
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#Q5:
        every combination of the exclusive codes: the better of two exclusive
        codes wins whatever the order entered
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#Q5:
        the exclusive code that loses to another is refused, naming the one that
        holds the line
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/stacking.spec.js#refuses
        any promotion on a line an exclusive one holds
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#5.
      exclusive code against the automatic outcome: VIP5 (5 %) would give
      $76.00, Fall 10 % gives $72.00; VIP5 is dropped and consumes no use
  - id: ATS-COM-CAT-016-05
    title: Comparison bases and ties preserve audience pricing
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-06
    preconditions: Alternatives tie and another cart has a minimum threshold
    steps: Assess the alternatives and qualifying subtotal
    expected: >-
      The tie retains audience pricing without usage, and minimum qualification
      uses post-line-discount amounts
    negative: false
    data_needs: none
    bound_to:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#Q4:
        a tie goes to audience pricing, and the tied code is not used up
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#Q7:
        the comparison is the order total before tax and shipping
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#Q3:
        the minimum order is measured on the qualifying lines after the
        line-level promotions
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#Q4:
      a tie goes to audience pricing, and the tied code is not used up
  - id: ATS-COM-CAT-016-06
    title: Discount arithmetic preserves rounded allocations
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-08
      - BR-CAP-COM-CAT-016-09
    preconditions: Amounts support percentage and proportional examples
    steps: >-
      Calculate fifteen percent of 3333 and allocate fixed discounts across
      unequal and equal lines
    expected: 'Results are 500, allocations 1714/857/429 and 834/833/833'
    negative: false
    data_needs: none
    bound_to:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/benefits.spec.js#takes
        15% off 3333 as 500 (499.95 rounded half up)
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/allocation.spec.js#shares
        3000 over 10000, 5000 and 2500 as 1714, 857, 429: the largest fraction
        gets the unit
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/allocation.spec.js#shares
        2500 over three 10000 lines as 834, 833, 833: the tie goes to the first
        line
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/allocation.spec.js#sums
        to the amount exactly, every part its floor or one more and never above
        its basis, ties to the earlier line
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/benefits.spec.js#takes
      15% off 3333 as 500 (499.95 rounded half up)
  - id: ATS-COM-CAT-016-07
    title: Item exclusions and shipping caps remain distinct
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-10
    preconditions: The cart includes pass-through and promotion-excluded lines
    steps: Apply an item percentage and a shipping benefit
    expected: >-
      Only qualifying item lines receive the percentage and shipping reduction
      stops at zero
    negative: false
    data_needs: none
    bound_to:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/apply-promotions.spec.js#never
        touches a tax, shipping or fee line, nor a product excluded from
        promotions
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/shipping-offers.spec.js#caps
        amount_off_shipping at the charge and never takes it below zero
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/parts.spec.js#leaves
        a line excluded from promotions out of every part, whatever the provider
        says
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/apply-promotions.spec.js#never
      touches a tax, shipping or fee line, nor a product excluded from
      promotions
  - id: ATS-COM-CAT-016-08
    title: Refusal order returns private-information-safe messages
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-11
      - BR-CAP-COM-CAT-016-13
    preconditions: Codes independently fail qualification checks
    steps: 'Validate each code, including uncertain and anonymous eligibility'
    expected: >-
      The first applicable reason wins, private values remain hidden,
      uncertainty refuses and restricted visitors are asked to sign in
    negative: true
    data_needs: none
    bound_to:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/validation.spec.js#answers
        the first refusal in the order of 10.3: an inactive code before an
        exhausted one
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/validation.spec.js#keeps
        the limit, the owner and the rule out of every customer message
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/validation.spec.js#fails
        closed on an indeterminate verdict, for must_match and for
        must_not_match alike
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/validation.spec.js#asks
        an anonymous purchaser to sign in for an eligibility rule (J15), before
        refusing it as ineligible
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/validation.spec.js#answers
      the first refusal in the order of 10.3: an inactive code before an
      exhausted one
  - id: ATS-COM-CAT-016-09
    title: Ineffective codes produce no applied benefit
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-12
      - AS-JNY-COM-CAT-005-02
    preconditions: 'Codes have zero benefit, wrong business unit or no qualifying item'
    steps: Assess each against the cart
    expected: No discount or use is applied and the reason remains reported
    negative: false
    data_needs: none
    bound_to:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/apply-promotions.spec.js#refuses
        a promotion whose benefit is zero on every qualifying line (an amount
        off a line already free)
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/apply-promotions.spec.js#J14:
        refuses a promotion of another business unit with the staff reason
        business unit
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#records
        as applied only the promotions that gave a discount; a code that gave
        nothing is rejected and not applied
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/apply-promotions.spec.js#refuses
      a promotion whose benefit is zero on every qualifying line (an amount off
      a line already free)
  - id: ATS-COM-CAT-016-10
    title: Alternative explanations identify why a code loses or wins
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-14
    preconditions: Codes compete with audience and automatic prices
    steps: Render the comparison messages
    expected: Messages explain the outcome using both totals where applicable
    negative: false
    data_needs: none
    bound_to:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/reason-codes.spec.js#says
        in the customer’s words that the audience price was better, with both
        totals
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/reason-codes.spec.js#says,
        the reverse, that the promotional price was lower than the audience
        price
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/reason-codes.spec.js#says
        that the automatic promotions were better
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/reason-codes.spec.js#says
      in the customer’s words that the audience price was better, with both
      totals
  - id: ATS-COM-CAT-016-11
    title: Selling-area timeout distinguishes preview from placement
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-15
    preconditions: A part provider cannot answer within its timeout
    steps: Preview the cart and attempt placement
    expected: Preview omits the unavailable parts; placement returns the retry refusal
    negative: true
    data_needs: Fake slow provider
    bound_to:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/parts.spec.js#refuses
        a code promotion_check_unavailable when a part is listed unavailable,
        and discounts nothing
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/parts.spec.js#simply
        does not apply an automatic promotion with an unavailable part, and
        reports nothing
      - >-
        services-commerce:modules/promotions/tests/unit/areas/area-registry.spec.js#cuts
        a slow provider at the timeout and makes its parts unavailable
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/parts.spec.js#refuses
      a code promotion_check_unavailable when a part is listed unavailable, and
      discounts nothing
  - id: ATS-COM-CAT-016-12
    title: Concurrent usage respects finite capacity
    level: api
    proves:
      - BR-CAP-COM-CAT-016-16
    preconditions: A code permits one hundred uses
    steps: Run two hundred competing placements
    expected: 'One hundred succeed, one hundred fail and usage totals remain one hundred'
    negative: true
    data_needs: Concurrency harness
    bound_to:
      - >-
        services-commerce:modules/promotions/tests/integration/services/persistence/redemption-concurrency.integration.spec.js#applies
        exactly 100 and answers the other 100 code_exhausted
      - >-
        services-commerce:modules/promotions/tests/integration/services/persistence/redemption-concurrency.integration.spec.js#counts
        100 uses on the code
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/integration/services/persistence/redemption-concurrency.integration.spec.js#applies
      exactly 100 and answers the other 100 code_exhausted
evidence:
  - 'Pinned service inputs: test sources in scenario bindings'
  - 'Pinned console inputs: console sources in scenario bindings'
---

# Choose the best permitted promotional result: Acceptance Test Set

## Coverage

| Rule | Proof Scenario or Gap |
|---|---|
| `BR-CAP-COM-CAT-016-01` | `ATS-COM-CAT-016-01` |
| `BR-CAP-COM-CAT-016-02` | `ATS-COM-CAT-016-01` |
| `BR-CAP-COM-CAT-016-03` | `ATS-COM-CAT-016-02` |
| `BR-CAP-COM-CAT-016-04` | `ATS-COM-CAT-016-03` |
| `BR-CAP-COM-CAT-016-05` | `ATS-COM-CAT-016-04` |
| `BR-CAP-COM-CAT-016-06` | `ATS-COM-CAT-016-05` |
| `BR-CAP-COM-CAT-016-08` | `ATS-COM-CAT-016-06` |
| `BR-CAP-COM-CAT-016-09` | `ATS-COM-CAT-016-06` |
| `BR-CAP-COM-CAT-016-10` | `ATS-COM-CAT-016-07` |
| `BR-CAP-COM-CAT-016-11` | `ATS-COM-CAT-016-08` |
| `BR-CAP-COM-CAT-016-12` | `ATS-COM-CAT-016-09` |
| `BR-CAP-COM-CAT-016-13` | `ATS-COM-CAT-016-08` |
| `BR-CAP-COM-CAT-016-14` | `ATS-COM-CAT-016-10` |
| `BR-CAP-COM-CAT-016-15` | `ATS-COM-CAT-016-11` |
| `BR-CAP-COM-CAT-016-16` | `ATS-COM-CAT-016-12` |
