---
id: ATS-COM-CAT-004
scope: CAP-COM-CAT-004
product_area: commerce
module: catalog
revision: 1
status: proposed
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-COM-CAT-004-01
    title: Tax-zone validation reports invalid configuration
    level: api
    proves:
      - BR-CAP-COM-CAT-004-01
      - BR-CAP-COM-CAT-004-02
    preconditions: A tax-zone request can be submitted
    steps: >-
      Use an unassigned country, excessive rate, missing rate name and reversed
      rate interval
    expected: Validation identifies each issue without saving the zone
    negative: true
    data_needs: none
    bound_to:
      - >-
        services-commerce:modules/configuration/tests/e2e/tax-zones.e2e.spec.js#answers
        400 to a country code that is not two upper-case letters, naming the
        field
      - >-
        services-commerce:modules/configuration/tests/e2e/tax-zones.e2e.spec.js#answers
        400 to a rate past the ceiling and to a rate without a name, naming the
        field
      - >-
        services-commerce:modules/configuration/tests/e2e/tax-zones.e2e.spec.js#answers
        400 to a rate whose effective_from follows its effective_to, naming the
        field, not the database rule, and saves nothing (DEF-COM-0866)
    provenance: test
    source: >-
      services-commerce:modules/configuration/tests/e2e/tax-zones.e2e.spec.js#answers
      400 to a country code that is not two upper-case letters, naming the field
  - id: ATS-COM-CAT-004-02
    title: Tax-prefix clearing requires explicit null
    level: unit
    proves:
      - BR-CAP-COM-CAT-004-03
    preconditions: A saved zone carries H2X
    steps: Replace its prefix with spaces and then null
    expected: Spaces fail validation; null removes the prefix
    negative: true
    data_needs: none
    bound_to:
      - >-
        services-commerce:modules/configuration/tests/unit/api/blank-tax-zone-values.spec.js#refuses
        a whitespace-only postal_code_prefix on a replacement 400 naming the
        field, instead of clearing H2X
      - >-
        services-commerce:modules/configuration/tests/unit/api/blank-tax-zone-values.spec.js#clears
        postal_code_prefix on an explicit null, the one way to clear it
    provenance: test
    source: >-
      services-commerce:modules/configuration/tests/unit/api/blank-tax-zone-values.spec.js#refuses
      a whitespace-only postal_code_prefix on a replacement 400 naming the
      field, instead of clearing H2X
  - id: ATS-COM-CAT-004-03
    title: Tax applicability follows product-type selection
    level: unit
    proves:
      - BR-CAP-COM-CAT-004-04
    preconditions: Rates include unrestricted and selected-type configurations
    steps: Calculate tax for several product types and submit a list of 101 types
    expected: 'Only matching rates contribute, and the oversized list fails'
    negative: false
    data_needs: none
    bound_to:
      - >-
        services-commerce:modules/pricing/tests/unit/tax/zone-tax-calculation.spec.js#applies
        to every product type when it names none, and to the named ones alone
        otherwise
      - >-
        services-commerce:modules/configuration/tests/unit/api/blank-tax-zone-values.spec.js#refuses
        101 product types, one past the limit, naming product_type_ids
    provenance: test
    source: >-
      services-commerce:modules/pricing/tests/unit/tax/zone-tax-calculation.spec.js#applies
      to every product type when it names none, and to the named ones alone
      otherwise
  - id: ATS-COM-CAT-004-04
    title: Specificity selects the rate components to round
    level: unit
    proves:
      - BR-CAP-COM-CAT-004-05
      - BR-CAP-COM-CAT-004-06
    preconditions: 'Country, region and prefix zones match the address'
    steps: Calculate tax for an address matching the prefix zone
    expected: >-
      That zone supplies individually rounded components whose sum is the line
      tax
    negative: false
    data_needs: none
    bound_to:
      - >-
        services-commerce:modules/pricing/tests/unit/tax/zone-tax-calculation.spec.js#scores
        a prefix over a region over a country alone
      - >-
        services-commerce:modules/pricing/tests/unit/tax/zone-tax-calculation.spec.js#sums
        every applicable rate per line, each rounded on its own, and names each
        component
      - >-
        services-commerce:modules/pricing/tests/unit/tax/zone-tax-calculation.spec.js#rounds
        half away from zero to a whole minor unit
    provenance: test
    source: >-
      services-commerce:modules/pricing/tests/unit/tax/zone-tax-calculation.spec.js#scores
      a prefix over a region over a country alone
  - id: ATS-COM-CAT-004-05
    title: Address requirements differ between checkout and display
    level: unit
    proves:
      - BR-CAP-COM-CAT-004-07
    preconditions: A zone can tax every product type
    steps: Request checkout and display calculations without an address
    expected: Checkout refuses the taxable line; display returns zero tax with a warning
    negative: true
    data_needs: none
    bound_to:
      - >-
        services-commerce:modules/pricing/tests/unit/tax/zone-table-tax.spec.js#refuses
        a line a zone’s rate for every product type could tax, naming the line
        and its product
      - >-
        services-commerce:modules/pricing/tests/unit/tax/zone-table-tax.spec.js#answers
        zero with the no-address warning, not a refusal, reading nothing
    provenance: test
    source: >-
      services-commerce:modules/pricing/tests/unit/tax/zone-table-tax.spec.js#refuses
      a line a zone’s rate for every product type could tax, naming the line and
      its product
  - id: ATS-COM-CAT-004-06
    title: Tax reads do not grant tax writes
    level: api
    proves:
      - BR-CAP-COM-CAT-004-10
    preconditions: The caller is a read-only tax user
    steps: Inspect and attempt to change zones
    expected: Inspection succeeds and changes fail permission checks
    negative: true
    data_needs: Read-exclusively persona
    bound_to:
      - >-
        services-commerce:modules/configuration/tests/e2e/configuration-security.e2e.spec.js#lists
        and reads the tax zones
      - >-
        services-commerce:modules/configuration/tests/e2e/configuration-security.e2e.spec.js#is
        refused the creates, 403 permission_missing
    provenance: test
    source: >-
      services-commerce:modules/configuration/tests/e2e/configuration-security.e2e.spec.js#lists
      and reads the tax zones
evidence:
  - 'Pinned service inputs: test sources in scenario bindings'
  - 'Pinned console inputs: console sources in scenario bindings'
---

# Calculate tax from buyer geography: Acceptance Test Set

## Coverage

| Rule | Proof Scenario or Gap |
|---|---|
| `BR-CAP-COM-CAT-004-01` | `ATS-COM-CAT-004-01` |
| `BR-CAP-COM-CAT-004-02` | `ATS-COM-CAT-004-01` |
| `BR-CAP-COM-CAT-004-03` | `ATS-COM-CAT-004-02` |
| `BR-CAP-COM-CAT-004-04` | `ATS-COM-CAT-004-03` |
| `BR-CAP-COM-CAT-004-05` | `ATS-COM-CAT-004-04` |
| `BR-CAP-COM-CAT-004-06` | `ATS-COM-CAT-004-04` |
| `BR-CAP-COM-CAT-004-07` | `ATS-COM-CAT-004-05` |
| `BR-CAP-COM-CAT-004-10` | `ATS-COM-CAT-004-06` |
