---
id: ATS-ACC-PRD-005
scope: CAP-ACC-PRD-005
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-005-01
    title: Withdrawal and return advance catalogue status
    level: browser
    proves:
      - BR-CAP-ACC-PRD-005-01
    preconditions: An active product is available in the grid.
    steps: Confirm Deactivate followed by Activate.
    expected: Each change advances the version and produces the selected status.
    negative: false
    data_needs: An active product is available in the grid.
    bound_to:
      - 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0107.spec.ts#ACT-ACC-0107'
      - TST-ACC-PRD-003
    provenance: test
    source: 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0107.spec.ts#ACT-ACC-0107'
    category: transition
    binding_scope:
      - suite: TST-ACC-PRD-003
        assertions:
          - 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0107.spec.ts#ACT-ACC-0107'
        provenance: test
        source: 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0107.spec.ts#ACT-ACC-0107'
  - id: ATS-ACC-PRD-005-02
    title: Retirement changes status once
    level: unit
    proves:
      - BR-CAP-ACC-PRD-005-02
    preconditions: An active product is available.
    steps: Retire it and repeat retirement.
    expected: The first action changes status at the next version; the repeat is refused.
    negative: true
    data_needs: An active product is available.
    bound_to:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#retires
        the product at version 2, changing nothing else
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        retiring a retired product
      - 'services-accounting:modules/products/tests/e2e/products.e2e.spec.js#answers 409 to retiring it again'
      - TST-ACC-PRD-040
      - TST-ACC-PRD-030
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#retires
      the product at version 2, changing nothing else
    category: transition
    binding_scope:
      - suite: TST-ACC-PRD-040
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#retires
            the product at version 2, changing nothing else
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
            retiring a retired product
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#retires
          the product at version 2, changing nothing else;
          services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
          retiring a retired product;
          services-accounting:modules/products/tests/e2e/products.e2e.spec.js#answers 409 to retiring it again
      - suite: TST-ACC-PRD-030
        assertions:
          - >-
            services-accounting:modules/products/tests/e2e/products.e2e.spec.js#answers 409 to retiring it
            again
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#retires
          the product at version 2, changing nothing else;
          services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
          retiring a retired product;
          services-accounting:modules/products/tests/e2e/products.e2e.spec.js#answers 409 to retiring it again
  - id: ATS-ACC-PRD-005-03
    title: Reactivation supports both withdrawn states
    level: unit
    proves:
      - BR-CAP-ACC-PRD-005-03
    preconditions: One product is inactive and another retired.
    steps: Reactivate both and also attempt reactivation of an active product.
    expected: Withdrawn products become active; the active-product attempt fails.
    negative: true
    data_needs: One product is inactive and another retired.
    bound_to:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#reactivates
        an inactive product
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#reactivates
        the retired product at version 3
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        reactivating an active product
      - TST-ACC-PRD-040
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#reactivates
      an inactive product
    category: transition
    binding_scope:
      - suite: TST-ACC-PRD-040
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#reactivates
            an inactive product
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#reactivates
            the retired product at version 3
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
            reactivating an active product
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#reactivates
          an inactive product;
          services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#reactivates
          the retired product at version 3;
          services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
          reactivating an active product
  - id: ATS-ACC-PRD-005-04
    title: Lifecycle writes require the read version
    level: api
    proves:
      - BR-CAP-ACC-PRD-005-04
    preconditions: A product is at version two.
    steps: Request retirement without a version and with version one.
    expected: Both requests fail.
    negative: true
    data_needs: A product is at version two.
    bound_to:
      - >-
        services-accounting:modules/products/tests/e2e/products.e2e.spec.js#answers 400 to a lifecycle request
        without the version read
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        retiring at a version the product has moved on from
      - TST-ACC-PRD-030
      - TST-ACC-PRD-040
    provenance: test
    source: >-
      services-accounting:modules/products/tests/e2e/products.e2e.spec.js#answers 400 to a lifecycle request
      without the version read
    category: validation
    binding_scope:
      - suite: TST-ACC-PRD-030
        assertions:
          - >-
            services-accounting:modules/products/tests/e2e/products.e2e.spec.js#answers 400 to a lifecycle
            request without the version read
        provenance: test
        source: >-
          services-accounting:modules/products/tests/e2e/products.e2e.spec.js#answers 400 to a lifecycle
          request without the version read;
          services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
          retiring at a version the product has moved on from
      - suite: TST-ACC-PRD-040
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
            retiring at a version the product has moved on from
        provenance: test
        source: >-
          services-accounting:modules/products/tests/e2e/products.e2e.spec.js#answers 400 to a lifecycle
          request without the version read;
          services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
          retiring at a version the product has moved on from
  - id: ATS-ACC-PRD-005-05
    title: Update locks stop lifecycle changes
    level: unit
    proves:
      - BR-CAP-ACC-PRD-005-05
    preconditions: A product is locked against updates.
    steps: Attempt retirement.
    expected: The refusal identifies the lock.
    negative: true
    data_needs: A product is locked against updates.
    bound_to:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#names
        the lock when a locked product is retired
      - >-
        services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#refuses a retire of a
        record locked against updates, naming the lock
      - TST-ACC-PRD-040
      - TST-ACC-PRD-066
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#names
      the lock when a locked product is retired
    category: permission
    binding_scope:
      - suite: TST-ACC-PRD-040
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#names
            the lock when a locked product is retired
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#names
          the lock when a locked product is retired;
          services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#refuses a retire of a
          record locked against updates, naming the lock
      - suite: TST-ACC-PRD-066
        assertions:
          - >-
            services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#refuses a retire of a
            record locked against updates, naming the lock
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#names
          the lock when a locked product is retired;
          services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#refuses a retire of a
          record locked against updates, naming the lock
  - id: ATS-ACC-PRD-005-06
    title: Retirement needs update authority
    level: api
    proves:
      - BR-CAP-ACC-PRD-005-06
    preconditions: A product reader is available.
    steps: Request retirement.
    expected: The caller is denied.
    negative: true
    data_needs: A product reader is available.
    bound_to:
      - >-
        services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused retiring a
        product
      - TST-ACC-PRD-028
    provenance: test
    source: >-
      services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused retiring a
      product
    category: permission
    binding_scope:
      - suite: TST-ACC-PRD-028
        assertions:
          - >-
            services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused retiring a
            product
        provenance: test
        source: >-
          services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused retiring a
          product
  - id: ATS-ACC-PRD-005-07
    title: Inactive retirement and locked restoration are checked
    category: edge
    level: api
    proves:
      - BR-CAP-ACC-PRD-005-02
      - BR-CAP-ACC-PRD-005-03
      - BR-CAP-ACC-PRD-005-05
    preconditions: One product is inactive and another retired product has combined protection.
    steps: 'Retire the inactive product, then try to reactivate the protected retired product.'
    expected: Retirement succeeds without replacing configuration; restoration refuses the protected record.
    negative: true
    data_needs: One product is inactive and another retired product has combined protection.
    bound_to: []
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#retires
      the product at version 2, changing nothing else;
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#reactivates
      an inactive product;
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#names
      the lock when a locked product is retired
    binding_scope: []
  - id: ATS-ACC-PRD-005-08
    title: Restoration requires update authority
    category: permission
    level: api
    proves:
      - BR-CAP-ACC-PRD-005-06
    preconditions: A retired product exists and the caller can read products but cannot update them.
    steps: Request reactivation and read the product with an authorized reader.
    expected: Access is refused and retirement remains unchanged.
    negative: true
    data_needs: A retired product exists and the caller can read products but cannot update them.
    bound_to: []
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused retiring a
      product
    binding_scope: []
  - id: ATS-ACC-PRD-005-09
    title: Retiring a held component changes admission without removing the relationship
    category: interaction
    level: api
    proves:
      - BR-CAP-ACC-PRD-005-02
      - BR-CAP-ACC-PRD-004-04
      - BR-CAP-ACC-PRD-011-03
      - BR-CAP-ACC-PRD-006-01
    preconditions: A bundle holds one active component and a second active product is not included.
    steps: >-
      Retire both products; try ordinary correction, resave the held component, add the newly retired product,
      and delete the held component.
    expected: >-
      Ordinary correction and new inclusion fail; retained inclusion succeeds and its deletion remains
      blocked.
    negative: true
    data_needs: A bundle holds one active component and a second active product is not included.
    bound_to: []
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#retires
      the product at version 2, changing nothing else;
      services-accounting:modules/products/tests/e2e/products.e2e.spec.js#answers 409 to replacing a retired
      product;
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#keeps
      a retired component the bundle already holds when a replacement resends it, and refuses a new retired
      one;
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
      deleting a product another product bundles, 409, and keeps it
    exercises:
      - CAP-ACC-PRD-005
      - CAP-ACC-PRD-004
      - CAP-ACC-PRD-011
      - CAP-ACC-PRD-006
    binding_scope: []
evidence:
  - 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0107.spec.ts'
  - 'react-console:components/accounting-config/products/product-row-actions.tsx'
  - 'services-accounting:modules/products/services/persistence/products.ts'
  - 'services-accounting:modules/products/services/rules/product-rules.ts'
  - 'services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js'
  - 'services-accounting:modules/products/tests/e2e/products.e2e.spec.js'
  - 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - 'services-accounting:modules/products/tests/unit/rules/product-rules.spec.js'
  - >-
    rhythm-v2-docs:specs/accounting/products/design/workflows/WF-ACC-PRD-001-create-or-replace-a-product-with-its-owned-settings.md
  - >-
    rhythm-v2-docs:specs/accounting/products/design/workflows/WF-ACC-PRD-004-save-a-domain-product-inside-the-domain-s.md
coverage:
  rule: 'gap: FND-ACC-PRD-054'
  transition: covered
  validation: covered
  permission: covered
  edge: covered
  failure: 'gap: FND-ACC-PRD-054'
  boundary: 'gap: FND-ACC-PRD-054'
  concurrency: 'gap: FND-ACC-PRD-054'
  invariant: 'gap: FND-ACC-PRD-054'
  interaction: covered
coverage_notes:
  rule:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-054
  failure:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-054
  boundary:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-054
  concurrency:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-054
  invariant:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-054
  remaining_obligations:
    reason: >-
      Inactive retirement, both restoration lock states, invoice preservation and concurrent lifecycle actions
      require complete execution. 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-054
  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-054
related_capabilities:
  - CAP-ACC-PRD-004
  - CAP-ACC-PRD-006
  - CAP-ACC-PRD-011
workflows:
  - WF-ACC-PRD-001
  - WF-ACC-PRD-004
rule_coverage:
  - rule: BR-CAP-ACC-PRD-005-01
    scenarios:
      - ATS-ACC-PRD-005-01
  - rule: BR-CAP-ACC-PRD-005-02
    scenarios:
      - ATS-ACC-PRD-005-02
      - ATS-ACC-PRD-005-07
      - ATS-ACC-PRD-005-09
  - rule: BR-CAP-ACC-PRD-005-03
    scenarios:
      - ATS-ACC-PRD-005-03
      - ATS-ACC-PRD-005-07
  - rule: BR-CAP-ACC-PRD-005-04
    scenarios:
      - ATS-ACC-PRD-005-04
  - rule: BR-CAP-ACC-PRD-005-05
    scenarios:
      - ATS-ACC-PRD-005-05
      - ATS-ACC-PRD-005-07
  - rule: BR-CAP-ACC-PRD-005-06
    scenarios:
      - ATS-ACC-PRD-005-06
      - ATS-ACC-PRD-005-08
interaction_coverage:
  - scenario: ATS-ACC-PRD-005-09
    exercises:
      - CAP-ACC-PRD-005
      - CAP-ACC-PRD-004
      - CAP-ACC-PRD-011
      - CAP-ACC-PRD-006
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#retires
      the product at version 2, changing nothing else;
      services-accounting:modules/products/tests/e2e/products.e2e.spec.js#answers 409 to replacing a retired
      product;
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#keeps
      a retired component the bundle already holds when a replacement resends it, and refuses a new retired
      one;
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
      deleting a product another product bundles, 409, and keeps it
state_coverage:
  - model: STATE-ACC-PRD-001
    from: active
    to: inactive
    scenarios:
      - ATS-ACC-PRD-005-01
    finding: null
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#answers
      the replaced record at version 2, the cleared fields left out and both collections replaced
  - model: STATE-ACC-PRD-001
    from: inactive
    to: active
    scenarios:
      - ATS-ACC-PRD-005-01
      - ATS-ACC-PRD-005-03
    finding: null
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#reactivates
      an inactive product
  - model: STATE-ACC-PRD-001
    from: active
    to: retired
    scenarios:
      - ATS-ACC-PRD-005-02
    finding: null
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#retires
      the product at version 2, changing nothing else
  - model: STATE-ACC-PRD-001
    from: inactive
    to: retired
    scenarios:
      - ATS-ACC-PRD-005-07
    finding: null
    provenance: proposed
    source: 'services-accounting:modules/products/services/rules/product-rules.ts:retireProblem'
  - model: STATE-ACC-PRD-001
    from: retired
    to: active
    scenarios:
      - ATS-ACC-PRD-005-03
    finding: null
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#reactivates
      the retired product at version 3
  - model: STATE-ACC-PRD-001
    from: active
    to: deleted
    scenarios: []
    finding: FND-ACC-PRD-054
    provenance: unknown
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#takes
      its prices, components, accounting setup and the setup’s collections with it
  - model: STATE-ACC-PRD-001
    from: inactive
    to: deleted
    scenarios: []
    finding: FND-ACC-PRD-054
    provenance: unknown
    source: 'services-accounting:modules/products/services/persistence/products.ts:deleteProduct'
  - model: STATE-ACC-PRD-001
    from: retired
    to: deleted
    scenarios: []
    finding: FND-ACC-PRD-054
    provenance: unknown
    source: 'services-accounting:modules/products/services/persistence/products.ts:deleteProduct'
permission_coverage:
  - key: accounting.products.update
    where_checked: api
    scope: tenant
    scenarios:
      - ATS-ACC-PRD-005-05
      - ATS-ACC-PRD-005-06
      - ATS-ACC-PRD-005-08
    finding: null
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#names
      the lock when a locked product is retired;
      services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused retiring a
      product
invariant_coverage:
  - invariant: INV-DOM-ACC-PRD-001-06
    scenarios:
      - ATS-ACC-PRD-005-02
    finding: FND-ACC-PRD-054
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
      replacing a retired product
    note: >-
      The mapped scenario exercises the related behavior; the complete invariant statement still needs
      dedicated proof.
---

# Withdraw a product from sale and restore it: 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. Inactive retirement, both restoration lock states, invoice preservation and concurrent lifecycle actions require complete execution. Workflow edges not named by a scenario remain in this finding rather than gaining a binding from shared workflow membership.

## Interactions With Related Capabilities

Retiring a held component changes admission without removing the relationship. A bundle holds one active component and a second active product is not included. Retire both products; try ordinary correction, resave the held component, add the newly retired product, and delete the held component. Ordinary correction and new inclusion fail; retained inclusion succeeds and its deletion remains blocked.
