---
id: ATS-ACC-PRD-015
scope: CAP-ACC-PRD-015
product_area: accounting
module: products
revision: 3
status: proposed
approved_by: null
approved_at: null
source_sha:
  services-accounting: f47cb263875bbc0c5640fba7dae6785ec32695f8
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-ACC-PRD-015-01
    title: Missing setup is explicit on reads
    level: api
    proves:
      - BR-CAP-ACC-PRD-015-01
    preconditions: A product has no accounting setup.
    steps: Read the product and request its full setup.
    expected: The summary is empty and the full setup request returns not found.
    negative: false
    data_needs: A product has no accounting setup.
    bound_to:
      - >-
        services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers accounting: null
        on the product
      - >-
        services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 404 to a read of
        its setup
      - TST-ACC-PRD-026
    provenance: test
    source: >-
      services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers accounting: null
      on the product
    category: rule
    binding_scope:
      - suite: TST-ACC-PRD-026
        assertions:
          - >-
            services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers accounting:
            null on the product
          - >-
            services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 404 to a
            read of its setup
        provenance: test
        source: >-
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers accounting:
          null on the product;
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 404 to a read
          of its setup
  - id: ATS-ACC-PRD-015-02
    title: Revenue requirements follow sellability
    level: api
    proves:
      - BR-CAP-ACC-PRD-015-02
    preconditions: 'Accounting, Donation and Legacy fixtures are available.'
    steps: Save each setup without a revenue account.
    expected: Sellable kinds fail and Legacy configuration succeeds.
    negative: true
    data_needs: 'Accounting, Donation and Legacy fixtures are available.'
    bound_to:
      - >-
        services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to an
        Accounting Product without a revenue GL account
      - >-
        services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to a
        Donation Product without a revenue GL account
      - >-
        services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#accepts a Legacy Product
        without a revenue GL account
      - TST-ACC-PRD-026
    provenance: test
    source: >-
      services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to an
      Accounting Product without a revenue GL account
    category: validation
    binding_scope:
      - suite: TST-ACC-PRD-026
        assertions:
          - >-
            services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to an
            Accounting Product without a revenue GL account
          - >-
            services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to a
            Donation Product without a revenue GL account
          - >-
            services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#accepts a Legacy
            Product without a revenue GL account
        provenance: test
        source: >-
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to an
          Accounting Product without a revenue GL account;
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to a
          Donation Product without a revenue GL account;
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#accepts a Legacy
          Product without a revenue GL account
  - id: ATS-ACC-PRD-015-03
    title: Financial references stay within the product unit
    level: unit
    proves:
      - BR-CAP-ACC-PRD-015-03
      - INV-DOM-ACC-PRD-004-02
    preconditions: 'Two units have charts, dimensions and merchant records.'
    steps: Assign foreign-unit or missing references to setup fields.
    expected: Every invalid reference fails with scope or absence details.
    negative: true
    data_needs: 'Two units have charts, dimensions and merchant records.'
    bound_to:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
        a revenue GL account of another business unit, naming both units
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
        a write-off GL account of another business unit
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
        a department of another business unit
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
        an accounting project of another business unit
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
        a merchant account of another business unit
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
        a GL account the tenant does not have
      - >-
        services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to another
        unit’s revenue GL account
      - TST-ACC-PRD-036
      - TST-ACC-PRD-026
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
      a revenue GL account of another business unit, naming both units
    category: boundary
    binding_scope:
      - suite: TST-ACC-PRD-036
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
            a revenue GL account of another business unit, naming both units
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
            a write-off GL account of another business unit
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
            a department of another business unit
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
            an accounting project of another business unit
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
            a merchant account of another business unit
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
            a GL account the tenant does not have
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          a revenue GL account of another business unit, naming both units;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          a write-off GL account of another business unit;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          a department of another business unit;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          an accounting project of another business unit;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          a merchant account of another business unit;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          a GL account the tenant does not have;
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to another
          unit’s revenue GL account
      - suite: TST-ACC-PRD-026
        assertions:
          - >-
            services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to
            another unit’s revenue GL account
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          a revenue GL account of another business unit, naming both units;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          a write-off GL account of another business unit;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          a department of another business unit;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          an accounting project of another business unit;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          a merchant account of another business unit;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          a GL account the tenant does not have;
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to another
          unit’s revenue GL account
  - id: ATS-ACC-PRD-015-04
    title: Account categories match their slots
    level: unit
    proves:
      - BR-CAP-ACC-PRD-015-04
      - INV-DOM-ACC-PRD-004-03
    preconditions: The chart contains each account category.
    steps: Assign incompatible categories to setup slots and then supply matching categories.
    expected: Mismatches fail and the correctly categorized setup succeeds.
    negative: true
    data_needs: The chart contains each account category.
    bound_to:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
        an asset account as the revenue account, naming the slot and the types it takes, and writes no setup
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
        an income account as the receivable
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
        an income account as the deferred revenue account
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
        an account of the wrong kind in the write-off, cost of goods sold and inventory slots
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#accepts
        every slot holding an account of its type (premise of the refusals)
      - >-
        services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#refuses revenue booked to
        an asset account, naming the slot and the types it takes
      - 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0118.spec.ts#ACT-ACC-0118'
      - TST-ACC-PRD-036
      - TST-ACC-PRD-066
      - TST-ACC-PRD-009
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
      an asset account as the revenue account, naming the slot and the types it takes, and writes no setup
    category: validation
    binding_scope:
      - suite: TST-ACC-PRD-036
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
            an asset account as the revenue account, naming the slot and the types it takes, and writes no
            setup
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
            an income account as the receivable
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
            an income account as the deferred revenue account
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
            an account of the wrong kind in the write-off, cost of goods sold and inventory slots
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#accepts
            every slot holding an account of its type (premise of the refusals)
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          an asset account as the revenue account, naming the slot and the types it takes, and writes no
          setup;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          an income account as the receivable;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          an income account as the deferred revenue account;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          an account of the wrong kind in the write-off, cost of goods sold and inventory slots;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#accepts
          every slot holding an account of its type (premise of the refusals);
          services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#refuses revenue booked
          to an asset account, naming the slot and the types it takes;
          react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0118.spec.ts#ACT-ACC-0118
      - suite: TST-ACC-PRD-066
        assertions:
          - >-
            services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#refuses revenue booked
            to an asset account, naming the slot and the types it takes
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          an asset account as the revenue account, naming the slot and the types it takes, and writes no
          setup;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          an income account as the receivable;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          an income account as the deferred revenue account;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          an account of the wrong kind in the write-off, cost of goods sold and inventory slots;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#accepts
          every slot holding an account of its type (premise of the refusals);
          services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#refuses revenue booked
          to an asset account, naming the slot and the types it takes;
          react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0118.spec.ts#ACT-ACC-0118
      - suite: TST-ACC-PRD-009
        assertions:
          - 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0118.spec.ts#ACT-ACC-0118'
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          an asset account as the revenue account, naming the slot and the types it takes, and writes no
          setup;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          an income account as the receivable;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          an income account as the deferred revenue account;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          an account of the wrong kind in the write-off, cost of goods sold and inventory slots;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#accepts
          every slot holding an account of its type (premise of the refusals);
          services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#refuses revenue booked
          to an asset account, naming the slot and the types it takes;
          react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0118.spec.ts#ACT-ACC-0118
  - id: ATS-ACC-PRD-015-05
    title: Held inactive references remain editable
    level: unit
    proves:
      - BR-CAP-ACC-PRD-015-05
      - INV-DOM-ACC-PRD-004-05
    preconditions: A setup retains an account later deactivated and other inactive references exist.
    steps: 'Correct notes, move the account to a new slot and newly choose inactive records.'
    expected: The notes correction retains the account and new inactive assignments fail.
    negative: true
    data_needs: A setup retains an account later deactivated and other inactive references exist.
    bound_to:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
        it newly named in another field
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#keeps
        it on an edit that changes only the notes
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
        newly assigning an inactive GL account
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
        newly assigning an inactive department
      - >-
        services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 200 at the next
        version, keeping the inactive account it already held
      - TST-ACC-PRD-036
      - TST-ACC-PRD-026
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
      it newly named in another field
    category: edge
    binding_scope:
      - suite: TST-ACC-PRD-036
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
            it newly named in another field
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#keeps
            it on an edit that changes only the notes
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
            newly assigning an inactive GL account
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
            newly assigning an inactive department
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          it newly named in another field;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#keeps
          it on an edit that changes only the notes;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          newly assigning an inactive GL account;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          newly assigning an inactive department;
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 200 at the
          next version, keeping the inactive account it already held
      - suite: TST-ACC-PRD-026
        assertions:
          - >-
            services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 200 at the
            next version, keeping the inactive account it already held
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          it newly named in another field;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#keeps
          it on an edit that changes only the notes;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          newly assigning an inactive GL account;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          newly assigning an inactive department;
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 200 at the
          next version, keeping the inactive account it already held
  - id: ATS-ACC-PRD-015-06
    title: Tax assignment respects workspace and retention
    level: api
    proves:
      - BR-CAP-ACC-PRD-015-06
    preconditions: 'Class fixtures include active, foreign and inactive choices.'
    steps: 'Choose an active class, clear it, try invalid choices and resave a held retired class.'
    expected: Eligible assignments and retained classes succeed; invalid new choices fail.
    negative: true
    data_needs: 'Class fixtures include active, foreign and inactive choices.'
    bound_to:
      - >-
        services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#keeps the class it
        already names after the class is retired
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#names
        an active tax class of the tenant, whatever the product’s business unit
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
        newly choosing an inactive tax class
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
        another tenant’s tax class as one the tenant does not have
      - >-
        services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to newly
        choosing an inactive tax class
      - TST-ACC-PRD-026
      - TST-ACC-PRD-036
    provenance: test
    source: >-
      services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#keeps the class it already
      names after the class is retired
    category: interaction
    binding_scope:
      - suite: TST-ACC-PRD-026
        assertions:
          - >-
            services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#keeps the class it
            already names after the class is retired
          - >-
            services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to newly
            choosing an inactive tax class
        provenance: test
        source: >-
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#keeps the class it
          already names after the class is retired;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#names
          an active tax class of the tenant, whatever the product’s business unit;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          newly choosing an inactive tax class;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          another tenant’s tax class as one the tenant does not have;
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to newly
          choosing an inactive tax class
      - suite: TST-ACC-PRD-036
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#names
            an active tax class of the tenant, whatever the product’s business unit
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
            newly choosing an inactive tax class
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
            another tenant’s tax class as one the tenant does not have
        provenance: test
        source: >-
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#keeps the class it
          already names after the class is retired;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#names
          an active tax class of the tenant, whatever the product’s business unit;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          newly choosing an inactive tax class;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          another tenant’s tax class as one the tenant does not have;
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to newly
          choosing an inactive tax class
    exercises:
      - CAP-ACC-PRD-015
      - CAP-ACC-PRD-018
  - id: ATS-ACC-PRD-015-07
    title: Setup replacement requires its own version
    level: api
    proves:
      - BR-CAP-ACC-PRD-015-07
    preconditions: A product initially has no setup.
    steps: 'Create its setup, then replace without a version and with an old version.'
    expected: Creation starts at one and invalid replacement versions fail.
    negative: true
    data_needs: A product initially has no setup.
    bound_to:
      - >-
        services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to a
        replacement without the version read
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
        replacing a setup without the version read
      - >-
        services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 409 to a stale
        version
      - TST-ACC-PRD-026
      - TST-ACC-PRD-036
    provenance: test
    source: >-
      services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to a
      replacement without the version read
    category: concurrency
    binding_scope:
      - suite: TST-ACC-PRD-026
        assertions:
          - >-
            services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to a
            replacement without the version read
          - >-
            services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 409 to a
            stale version
        provenance: test
        source: >-
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to a
          replacement without the version read;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          replacing a setup without the version read;
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 409 to a stale
          version
      - suite: TST-ACC-PRD-036
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
            replacing a setup without the version read
        provenance: test
        source: >-
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to a
          replacement without the version read;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          replacing a setup without the version read;
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 409 to a stale
          version
  - id: ATS-ACC-PRD-015-08
    title: Setup replacement is transactional
    level: unit
    proves:
      - BR-CAP-ACC-PRD-015-08
      - INV-DOM-ACC-PRD-004-09
    preconditions: A setup contains each supported collection.
    steps: Omit values in a valid replacement and cause validation and database failures in later attempts.
    expected: Valid omission clears values and failed attempts preserve the last complete setup.
    negative: true
    data_needs: A setup contains each supported collection.
    bound_to:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#leaves
        the previous setup and collections when a rule refuses the replacement
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#answers
        the replaced setup at version 2, its cleared fields left out and every collection replaced
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#leaves
        the previous setup and collections when the database refuses a new row after the old ones were removed
      - TST-ACC-PRD-036
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#leaves
      the previous setup and collections when a rule refuses the replacement
    category: failure
    binding_scope:
      - suite: TST-ACC-PRD-036
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#leaves
            the previous setup and collections when a rule refuses the replacement
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#answers
            the replaced setup at version 2, its cleared fields left out and every collection replaced
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#leaves
            the previous setup and collections when the database refuses a new row after the old ones were
            removed
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#leaves
          the previous setup and collections when a rule refuses the replacement;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#answers
          the replaced setup at version 2, its cleared fields left out and every collection replaced;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#leaves
          the previous setup and collections when the database refuses a new row after the old ones were
          removed
  - id: ATS-ACC-PRD-015-09
    title: Setup locks require deliberate removal
    level: unit
    proves:
      - BR-CAP-ACC-PRD-015-09
    preconditions: Setups have update and delete locks.
    steps: 'Replace without changing the update lock, clear it explicitly and delete a still delete-locked setup.'
    expected: Only the deliberate unlock replacement succeeds.
    negative: true
    data_needs: Setups have update and delete locks.
    bound_to:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#unlocks
        a setup locked against updates when the replacement states sys_locked null, then deletes it
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
        a setup locked against updates
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
        a setup locked against deletes
      - >-
        services-accounting:modules/products/tests/unit/api/products-api-mapper.spec.js#keeps an explicit null
        on an accounting setup replacement
      - TST-ACC-PRD-036
      - TST-ACC-PRD-044
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#unlocks
      a setup locked against updates when the replacement states sys_locked null, then deletes it
    category: permission
    binding_scope:
      - suite: TST-ACC-PRD-036
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#unlocks
            a setup locked against updates when the replacement states sys_locked null, then deletes it
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
            a setup locked against updates
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
            a setup locked against deletes
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#unlocks
          a setup locked against updates when the replacement states sys_locked null, then deletes it;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          a setup locked against updates;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          a setup locked against deletes;
          services-accounting:modules/products/tests/unit/api/products-api-mapper.spec.js#keeps an explicit
          null on an accounting setup replacement
      - suite: TST-ACC-PRD-044
        assertions:
          - >-
            services-accounting:modules/products/tests/unit/api/products-api-mapper.spec.js#keeps an explicit
            null on an accounting setup replacement
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#unlocks
          a setup locked against updates when the replacement states sys_locked null, then deletes it;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          a setup locked against updates;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
          a setup locked against deletes;
          services-accounting:modules/products/tests/unit/api/products-api-mapper.spec.js#keeps an explicit
          null on an accounting setup replacement
  - id: ATS-ACC-PRD-015-10
    title: Deleting setup preserves product identity
    level: api
    proves:
      - BR-CAP-ACC-PRD-015-10
    preconditions: A product has a setup.
    steps: Delete the setup and repeat deletion.
    expected: The product retains an empty summary and repeat deletion returns not found.
    negative: false
    data_needs: A product has a setup.
    bound_to:
      - >-
        services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#deletes it, leaving the
        product with accounting: null
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#leaves
        the product, its accounting summary null
      - >-
        services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 404 to deleting
        a setup that does not exist
      - TST-ACC-PRD-026
      - TST-ACC-PRD-036
    provenance: test
    source: >-
      services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#deletes it, leaving the
      product with accounting: null
    category: transition
    binding_scope:
      - suite: TST-ACC-PRD-026
        assertions:
          - >-
            services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#deletes it, leaving
            the product with accounting: null
          - >-
            services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 404 to
            deleting a setup that does not exist
        provenance: test
        source: >-
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#deletes it, leaving
          the product with accounting: null;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#leaves
          the product, its accounting summary null;
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 404 to
          deleting a setup that does not exist
      - suite: TST-ACC-PRD-036
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#leaves
            the product, its accounting summary null
        provenance: test
        source: >-
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#deletes it, leaving
          the product with accounting: null;
          services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#leaves
          the product, its accounting summary null;
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 404 to
          deleting a setup that does not exist
  - id: ATS-ACC-PRD-015-11
    title: Referenced book records cannot disappear
    level: api
    proves:
      - BR-CAP-ACC-PRD-015-11
    preconditions: 'A setup refers to accounts, dimensions, merchant configuration and a class.'
    steps: Attempt deletion of referenced book records.
    expected: Dependencies reject those removals.
    negative: true
    data_needs: 'A setup refers to accounts, dimensions, merchant configuration and a class.'
    bound_to:
      - >-
        services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 409 to deleting
        a GL account a setup still names
      - >-
        services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 409 to deleting
        a tax class a setup still names
      - >-
        services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js#refuses
        deleting a GL account a setup names as its revenue account
      - >-
        services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js#refuses
        deleting a department a setup names
      - >-
        services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js#refuses
        deleting a merchant account a setup names
      - TST-ACC-PRD-026
      - TST-ACC-PRD-031
    provenance: test
    source: >-
      services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 409 to deleting a
      GL account a setup still names
    category: invariant
    binding_scope:
      - suite: TST-ACC-PRD-026
        assertions:
          - >-
            services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 409 to
            deleting a GL account a setup still names
          - >-
            services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 409 to
            deleting a tax class a setup still names
        provenance: test
        source: >-
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 409 to
          deleting a GL account a setup still names;
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 409 to
          deleting a tax class a setup still names;
          services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js#refuses
          deleting a GL account a setup names as its revenue account;
          services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js#refuses
          deleting a department a setup names;
          services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js#refuses
          deleting a merchant account a setup names
      - suite: TST-ACC-PRD-031
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js#refuses
            deleting a GL account a setup names as its revenue account
          - >-
            services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js#refuses
            deleting a department a setup names
          - >-
            services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js#refuses
            deleting a merchant account a setup names
        provenance: test
        source: >-
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 409 to
          deleting a GL account a setup still names;
          services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 409 to
          deleting a tax class a setup still names;
          services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js#refuses
          deleting a GL account a setup names as its revenue account;
          services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js#refuses
          deleting a department a setup names;
          services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js#refuses
          deleting a merchant account a setup names
  - id: ATS-ACC-PRD-015-12
    title: Catalogue and setup authority are independent
    level: api
    proves:
      - BR-CAP-ACC-PRD-015-12
    preconditions: 'Product-only, accounting-only and reader personas exist.'
    steps: Read and mutate setups and attempt product creation under these personas.
    expected: Separate permissions determine each action without granting unrelated product creation.
    negative: true
    data_needs: 'Product-only, accounting-only and reader personas exist.'
    bound_to:
      - >-
        services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused reading a
        product’s accounting setup
      - >-
        services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused changing a
        product’s accounting setup
      - >-
        services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused deleting a
        product’s accounting setup
      - >-
        services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#changes a product’s
        accounting setup
      - >-
        services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#reads a product’s
        accounting setup
      - 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0122.spec.ts#ACT-ACC-0122'
      - TST-ACC-PRD-028
      - TST-ACC-PRD-012
    provenance: test
    source: >-
      services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused reading a
      product’s accounting setup
    category: permission
    binding_scope:
      - suite: TST-ACC-PRD-028
        assertions:
          - >-
            services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused reading a
            product’s accounting setup
          - >-
            services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused changing a
            product’s accounting setup
          - >-
            services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused deleting a
            product’s accounting setup
          - >-
            services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#changes a product’s
            accounting setup
          - >-
            services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#reads a product’s
            accounting setup
        provenance: test
        source: >-
          services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused reading a
          product’s accounting setup;
          services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused changing a
          product’s accounting setup;
          services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused deleting a
          product’s accounting setup;
          services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#changes a product’s
          accounting setup; services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#reads
          a product’s accounting setup;
          react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0122.spec.ts#ACT-ACC-0122
      - suite: TST-ACC-PRD-012
        assertions:
          - 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0122.spec.ts#ACT-ACC-0122'
        provenance: test
        source: >-
          services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused reading a
          product’s accounting setup;
          services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused changing a
          product’s accounting setup;
          services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused deleting a
          product’s accounting setup;
          services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#changes a product’s
          accounting setup; services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#reads
          a product’s accounting setup;
          react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0122.spec.ts#ACT-ACC-0122
  - id: ATS-ACC-PRD-015-13
    title: Setup ownership cannot move
    level: unit
    proves:
      - BR-CAP-ACC-PRD-015-13
    preconditions: A saved setup has a fixed product and unit.
    steps: Attempt direct changes to those ownership coordinates.
    expected: The write-once protection rejects the changes.
    negative: true
    data_needs: A saved setup has a fixed product and unit.
    bound_to:
      - >-
        services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js#refuses a
        change of product_id (RHF01)
      - TST-ACC-PRD-031
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js#refuses a
      change of product_id (RHF01)
    category: invariant
    binding_scope:
      - suite: TST-ACC-PRD-031
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js#refuses
            a change of product_id (RHF01)
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js#refuses
          a change of product_id (RHF01)
  - id: ATS-ACC-PRD-015-14
    title: Resolve setup at posting and preserve an existing entry
    level: browser
    proves:
      - BR-CAP-ACC-PRD-015-01
      - BR-CAP-ACC-PRD-015-16
      - AS-JNY-ACC-PRD-005-03
    preconditions: 'Two products lack setups, and an issued invoice remains unposted.'
    steps: >-
      Assign revenue configuration to one product, post the invoice batch, then change that setup’s revenue
      account.
    expected: >-
      The configured product posts to its assigned revenue account, the other uses the unit default, and later
      correction leaves the posted account unchanged.
    negative: false
    data_needs: A business unit with a revenue default and an alternative income account.
    bound_to:
      - 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0121.spec.ts#ACT-ACC-0121'
      - TST-ACC-PRD-011
    provenance: test
    source: 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0121.spec.ts#ACT-ACC-0121'
    category: interaction
    binding_scope:
      - suite: TST-ACC-PRD-011
        assertions:
          - 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0121.spec.ts#ACT-ACC-0121'
        provenance: test
        source: 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0121.spec.ts#ACT-ACC-0121'
    exercises:
      - CAP-ACC-PRD-015
  - id: ATS-ACC-PRD-015-15
    title: 'First setup, replacement and removal change completeness'
    category: transition
    level: api
    proves:
      - BR-CAP-ACC-PRD-015-07
      - BR-CAP-ACC-PRD-015-10
    preconditions: A product initially has no setup and valid account fixtures are available.
    steps: >-
      Create its setup, replace it at the returned setup version, delete it, and inspect the product after
      each action.
    expected: Completeness follows the setup state while the product identity remains fixed.
    negative: true
    data_needs: A product initially has no setup and valid account fixtures are available.
    bound_to: []
    provenance: proposed
    source: >-
      rhythm-v2-docs:specs/accounting/products/design/state-models/STATE-ACC-PRD-003-accounting-setup-lifecycle.md#transitions;
      services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#deletes it, leaving the
      product with accounting: null
    binding_scope: []
  - id: ATS-ACC-PRD-015-16
    title: Setup editors exercise every supported protection change
    category: transition
    level: api
    proves:
      - BR-CAP-ACC-PRD-015-09
    preconditions: A setup editor rereads its version before each replacement.
    steps: >-
      Move unlocked protection to each lock, delete-only protection to unlocked and combined, and explicitly
      reduce combined protection to each weaker setting.
    expected: >-
      The saved protection matches each supported request; replacement without explicit reduction of combined
      protection fails.
    negative: true
    data_needs: A setup editor rereads its version before each replacement.
    bound_to: []
    provenance: proposed
    source: >-
      rhythm-v2-docs:specs/accounting/products/design/state-models/STATE-ACC-PRD-002-record-lock.md#transitions;
      services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#unlocks
      a setup locked against updates when the replacement states sys_locked null, then deletes it
    binding_scope: []
  - id: ATS-ACC-PRD-015-17
    title: Setup removal restores missing-setup and kind-default reads
    category: interaction
    level: api
    proves:
      - BR-CAP-ACC-PRD-015-10
      - BR-CAP-ACC-PRD-006-05
      - BR-CAP-ACC-PRD-016-01
      - BR-CAP-ACC-PRD-017-01
      - BR-CAP-ACC-PRD-018-01
    preconditions: 'A product has a deferred setup class, a kind default and deletion protection on its setup.'
    steps: >-
      Try product deletion, deliberately remove setup protection, delete the setup, and read the product and
      missing-setup list.
    expected: >-
      Setup protection blocks product removal; setup deletion keeps the product, restores kind fallback and
      returns it to missing-setup results.
    negative: true
    data_needs: 'A product has a deferred setup class, a kind default and deletion protection on its setup.'
    bound_to: []
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#deletes it, leaving the
      product with accounting: null;
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
      a product whose accounting setup is locked against deletes, leaving the product and its setup
      (DEF-ACT-0101); services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers
      400 to deferral without a deferred revenue GL account;
      services-accounting:modules/products/tests/e2e/product-accounting-setups.e2e.spec.js#answers the active
      products with no setup, by name;
      services-accounting:modules/products/tests/e2e/products-shared-base.e2e.spec.js#lets the product’s own
      accounting setup class win over the type default
    exercises:
      - CAP-ACC-PRD-015
      - CAP-ACC-PRD-006
      - CAP-ACC-PRD-016
      - CAP-ACC-PRD-017
      - CAP-ACC-PRD-018
    binding_scope: []
evidence:
  - 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0118.spec.ts'
  - 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0122.spec.ts'
  - 'services-accounting:modules/products/db/product-accounting-setups.table.ts'
  - 'services-accounting:modules/products/services/persistence/product-accounting-setups.ts'
  - 'services-accounting:modules/products/services/rules/product-rules.ts'
  - 'services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js'
  - 'services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js'
  - 'services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js'
  - >-
    services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js
  - 'services-accounting:modules/products/tests/unit/api/products-api-mapper.spec.js'
  - 'services-accounting:modules/products/tests/unit/rules/product-rules.spec.js'
  - >-
    rhythm-v2-docs:specs/accounting/products/design/workflows/WF-ACC-PRD-002-save-a-product-and-its-accounting-setup-from.md
  - >-
    rhythm-v2-docs:specs/accounting/products/design/workflows/WF-ACC-PRD-005-save-many-accounting-setups-at-once.md
coverage:
  rule: covered
  transition: covered
  validation: covered
  permission: covered
  edge: covered
  failure: covered
  boundary: covered
  concurrency: covered
  invariant: covered
  interaction: covered
coverage_notes:
  remaining_obligations:
    reason: >-
      All lock transitions, setup mutation on retired products, first-setup races and staged console
      failure/retry need execution; unchanged posted accounts have a separate browser proof. Workflow edges
      not named by a scenario remain in this finding rather than gaining a binding from shared workflow
      membership.
    provenance: unknown
    source: FND-ACC-PRD-064
  meaning:
    reason: >-
      Covered means a specification scenario exists in this category. Executable coverage and run results
      remain independent.
    provenance: documented
    source: 'rhythm-v2-docs:specs/CONVENTIONS.md#9.10 Capability Test Specification (`ATS`, under `design/tests/`)'
coverage_findings:
  - FND-ACC-PRD-064
related_capabilities:
  - CAP-ACC-PRD-003
  - CAP-ACC-PRD-006
  - CAP-ACC-PRD-016
  - CAP-ACC-PRD-017
  - CAP-ACC-PRD-018
workflows:
  - WF-ACC-PRD-002
  - WF-ACC-PRD-005
rule_coverage:
  - rule: BR-CAP-ACC-PRD-015-01
    scenarios:
      - ATS-ACC-PRD-015-01
      - ATS-ACC-PRD-015-14
  - rule: BR-CAP-ACC-PRD-015-02
    scenarios:
      - ATS-ACC-PRD-015-02
  - rule: BR-CAP-ACC-PRD-015-03
    scenarios:
      - ATS-ACC-PRD-015-03
  - rule: BR-CAP-ACC-PRD-015-04
    scenarios:
      - ATS-ACC-PRD-015-04
  - rule: BR-CAP-ACC-PRD-015-05
    scenarios:
      - ATS-ACC-PRD-015-05
  - rule: BR-CAP-ACC-PRD-015-06
    scenarios:
      - ATS-ACC-PRD-015-06
  - rule: BR-CAP-ACC-PRD-015-07
    scenarios:
      - ATS-ACC-PRD-015-07
      - ATS-ACC-PRD-015-15
  - rule: BR-CAP-ACC-PRD-015-08
    scenarios:
      - ATS-ACC-PRD-015-08
  - rule: BR-CAP-ACC-PRD-015-09
    scenarios:
      - ATS-ACC-PRD-015-09
      - ATS-ACC-PRD-015-16
  - rule: BR-CAP-ACC-PRD-015-10
    scenarios:
      - ATS-ACC-PRD-015-10
      - ATS-ACC-PRD-015-15
      - ATS-ACC-PRD-015-17
  - rule: BR-CAP-ACC-PRD-015-11
    scenarios:
      - ATS-ACC-PRD-015-11
  - rule: BR-CAP-ACC-PRD-015-12
    scenarios:
      - ATS-ACC-PRD-015-12
  - rule: BR-CAP-ACC-PRD-015-13
    scenarios:
      - ATS-ACC-PRD-015-13
  - rule: BR-CAP-ACC-PRD-015-16
    scenarios:
      - ATS-ACC-PRD-015-14
interaction_coverage:
  - scenario: ATS-ACC-PRD-015-06
    exercises:
      - CAP-ACC-PRD-015
      - CAP-ACC-PRD-018
    provenance: test
    source: >-
      services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#keeps the class it already
      names after the class is retired
  - scenario: ATS-ACC-PRD-015-14
    exercises:
      - CAP-ACC-PRD-015
    provenance: test
    source: 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0121.spec.ts#ACT-ACC-0121'
  - scenario: ATS-ACC-PRD-015-17
    exercises:
      - CAP-ACC-PRD-015
      - CAP-ACC-PRD-006
      - CAP-ACC-PRD-016
      - CAP-ACC-PRD-017
      - CAP-ACC-PRD-018
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#deletes it, leaving the
      product with accounting: null;
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
      a product whose accounting setup is locked against deletes, leaving the product and its setup
      (DEF-ACT-0101); services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers
      400 to deferral without a deferred revenue GL account;
      services-accounting:modules/products/tests/e2e/product-accounting-setups.e2e.spec.js#answers the active
      products with no setup, by name;
      services-accounting:modules/products/tests/e2e/products-shared-base.e2e.spec.js#lets the product’s own
      accounting setup class win over the type default
state_coverage:
  - model: STATE-ACC-PRD-002
    from: unlocked
    to: delete-locked
    scenarios:
      - ATS-ACC-PRD-015-16
    finding: null
    provenance: proposed
    source: 'services-accounting:modules/products/aws/api/products-api-mapper.ts:toInput'
  - model: STATE-ACC-PRD-002
    from: unlocked
    to: update-and-delete-locked
    scenarios:
      - ATS-ACC-PRD-015-16
    finding: null
    provenance: proposed
    source: 'services-accounting:modules/products/aws/api/products-api-mapper.ts:toInput'
  - model: STATE-ACC-PRD-002
    from: delete-locked
    to: unlocked
    scenarios:
      - ATS-ACC-PRD-015-16
    finding: null
    provenance: proposed
    source: 'services-accounting:modules/products/services/rules/product-rules.ts:lockedReplaceProblem'
  - model: STATE-ACC-PRD-002
    from: delete-locked
    to: update-and-delete-locked
    scenarios:
      - ATS-ACC-PRD-015-16
    finding: null
    provenance: proposed
    source: 'services-accounting:modules/products/services/rules/product-rules.ts:lockedReplaceProblem'
  - model: STATE-ACC-PRD-002
    from: update-and-delete-locked
    to: unlocked
    scenarios:
      - ATS-ACC-PRD-015-16
    finding: null
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#unlocks
      a locked product replaced with sys_locked null, then edits and deletes it
  - model: STATE-ACC-PRD-002
    from: update-and-delete-locked
    to: delete-locked
    scenarios:
      - ATS-ACC-PRD-015-16
    finding: null
    provenance: proposed
    source: 'services-accounting:modules/products/services/rules/product-rules.ts:lockedReplaceProblem'
  - model: STATE-ACC-PRD-003
    from: not set up
    to: set up
    scenarios:
      - ATS-ACC-PRD-015-07
      - ATS-ACC-PRD-015-15
    finding: null
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#gives
      the product its accounting summary
  - model: STATE-ACC-PRD-003
    from: set up
    to: set up
    scenarios:
      - ATS-ACC-PRD-015-07
      - ATS-ACC-PRD-015-08
    finding: null
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#answers
      the replaced setup at version 2, its cleared fields left out and every collection replaced
  - model: STATE-ACC-PRD-003
    from: set up
    to: not set up
    scenarios:
      - ATS-ACC-PRD-015-10
    finding: null
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#unlocks
      a setup locked against updates when the replacement states sys_locked null, then deletes it
permission_coverage:
  - key: accounting.product-accounting.read
    where_checked: api
    scope: tenant
    scenarios:
      - ATS-ACC-PRD-015-09
      - ATS-ACC-PRD-015-12
    finding: null
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#unlocks
      a setup locked against updates when the replacement states sys_locked null, then deletes it;
      services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused reading a
      product’s accounting setup
  - key: accounting.product-accounting.update
    where_checked: api
    scope: tenant
    scenarios:
      - ATS-ACC-PRD-015-09
      - ATS-ACC-PRD-015-12
    finding: null
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#unlocks
      a setup locked against updates when the replacement states sys_locked null, then deletes it;
      services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused reading a
      product’s accounting setup
  - key: accounting.product-accounting.delete
    where_checked: api
    scope: tenant
    scenarios:
      - ATS-ACC-PRD-015-09
      - ATS-ACC-PRD-015-12
    finding: null
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#unlocks
      a setup locked against updates when the replacement states sys_locked null, then deletes it;
      services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused reading a
      product’s accounting setup
invariant_coverage:
  - invariant: INV-DOM-ACC-PRD-004-01
    scenarios:
      - ATS-ACC-PRD-015-13
    finding: FND-ACC-PRD-064
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js#refuses a
      second setup of the product
    note: >-
      The mapped scenario exercises the related behavior; the complete invariant statement still needs
      dedicated proof.
  - invariant: INV-DOM-ACC-PRD-004-02
    scenarios:
      - ATS-ACC-PRD-015-03
    finding: null
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
      a revenue GL account of another business unit, naming both units
  - invariant: INV-DOM-ACC-PRD-004-03
    scenarios:
      - ATS-ACC-PRD-015-04
    finding: null
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
      an asset account as the revenue account, naming the slot and the types it takes, and writes no setup
  - invariant: INV-DOM-ACC-PRD-004-04
    scenarios:
      - ATS-ACC-PRD-015-02
    finding: FND-ACC-PRD-064
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
      a Donation Product’s setup without a revenue GL account
    note: >-
      The mapped scenario exercises the related behavior; the complete invariant statement still needs
      dedicated proof.
  - invariant: INV-DOM-ACC-PRD-004-05
    scenarios:
      - ATS-ACC-PRD-015-05
    finding: null
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
      newly assigning an inactive GL account
  - invariant: INV-DOM-ACC-PRD-004-09
    scenarios:
      - ATS-ACC-PRD-015-08
    finding: null
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#leaves
      the previous setup and collections when the database refuses a new row after the old ones were removed
  - invariant: INV-DOM-ACC-PRD-004-10
    scenarios:
      - ATS-ACC-PRD-015-11
    finding: FND-ACC-PRD-064
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
      deleting a tax class a default names, as one a setup names
    note: >-
      The mapped scenario exercises the related behavior; the complete invariant statement still needs
      dedicated proof.
  - invariant: INV-DOM-ACC-PRD-004-13
    scenarios:
      - ATS-ACC-PRD-015-14
    finding: FND-ACC-PRD-064
    provenance: proposed
    source: >-
      services-accounting:docs/architecture/accounting-2.0/06-integrity-model.md#The accounting is resolved
      and frozen at posting
    note: >-
      The mapped scenario exercises the related behavior; the complete invariant statement still needs
      dedicated proof.
---

# Assign a product’s accounting treatment: Capability Test Specification

## Coverage

The frontmatter lists a proof scenario or finding for every required rule and records each applicable category. Scenario coverage describes what to check; bindings identify the assertions that already exist, and execution results remain unverified. All lock transitions, setup mutation on retired products, first-setup races and staged console failure/retry need execution; unchanged posted accounts have a separate browser proof. Workflow edges not named by a scenario remain in this finding rather than gaining a binding from shared workflow membership.

## Interactions With Related Capabilities

Setup removal restores missing-setup and kind-default reads. A product has a deferred setup class, a kind default and deletion protection on its setup. Try product deletion, deliberately remove setup protection, delete the setup, and read the product and missing-setup list. Setup protection blocks product removal; setup deletion keeps the product, restores kind fallback and returns it to missing-setup results.
