---
id: CAP-ACC-PRD-015
title: Assign a product’s accounting treatment
feature: FEAT-ACC-PRD-04
product_area: accounting
module: products
revision: 3
status: draft
product_intent: proposed
implementation_evidence: observed
supersedes:
  - react-console acceptance inventory CAP-ACC-PRD-014
  - react-console acceptance inventory CAP-ACC-PRD-020 (the editor's accounting stage)
  - react-console acceptance inventory RUL-ACC-PRD-032
  - react-console acceptance inventory RUL-ACC-PRD-037
  - react-console acceptance inventory RUL-ACC-PRD-038
  - react-console acceptance inventory RUL-ACC-PRD-039
  - react-console acceptance inventory RUL-ACC-PRD-044
  - react-console acceptance inventory RUL-ACC-PRD-045
source_sha:
  services-accounting: f47cb263875bbc0c5640fba7dae6785ec32695f8
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
  - 'services-accounting:docs/milestones/ACCT-M1-books-and-invoices.md#D3'
  - 'services-accounting:docs/milestones/ACCT-M1-books-and-invoices.md#D11'
  - 'services-accounting:docs/milestones/ACCT-M1-books-and-invoices.md#D12'
  - 'services-accounting:docs/milestones/ACCT-M1-books-and-invoices.md#R21'
  - 'services-accounting:docs/migrations/accounting-modernization/products-shared/README.md#D-7'
purpose: A finance specialist assigns accounts and dimensions to a product.
outcomes:
  - Accounts and dimensions describe the product’s financial treatment.
concepts:
  - CON-ACC-PRD-004
actors:
  - ACT-ACC-006
  - ACT-ACC-008
  - ACT-ACC-007
surfaces:
  - console
  - api
permissions:
  - key: accounting.product-accounting.read
    where_checked: api
    scope: tenant
  - key: accounting.product-accounting.update
    where_checked: api
    scope: tenant
  - key: accounting.product-accounting.delete
    where_checked: api
    scope: tenant
rules:
  - id: BR-CAP-ACC-PRD-015-01
    proved_by: [ATS-ACC-PRD-015-01, ATS-ACC-PRD-015-14, TST-ACC-PRD-011, TST-ACC-PRD-026]
    statement: >-
      A product may lack an accounting setup, in which case its summary is empty and recorded posting policy
      uses unit defaults.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers accounting: null
      on the product;
      react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0121.spec.ts#ACT-ACC-0121
    origin: 'services-accounting:docs/milestones/ACCT-M1-books-and-invoices.md#D3'
  - id: BR-CAP-ACC-PRD-015-02
    proved_by: [ATS-ACC-PRD-015-02, TST-ACC-PRD-026]
    statement: 'Sellable products require a revenue account in their setup, while Legacy Products may omit it.'
    kind: validation
    enforced_at:
      - service
    must_prove: true
    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
    origin: 'services-accounting:docs/milestones/ACCT-M1-books-and-invoices.md#D3'
  - id: BR-CAP-ACC-PRD-015-03
    proved_by: [ATS-ACC-PRD-015-03, TST-ACC-PRD-026, TST-ACC-PRD-036]
    statement: >-
      Setup accounts and dimensions belong to the product’s unit, except tax classes belong to the workspace
      as a whole.
    kind: validation
    enforced_at:
      - service
      - database
    must_prove: true
    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
    origin: none
  - id: BR-CAP-ACC-PRD-015-04
    proved_by: [ATS-ACC-PRD-015-04, TST-ACC-PRD-009, TST-ACC-PRD-036, TST-ACC-PRD-066]
    statement: >-
      Receivable and inventory slots require asset accounts, revenue requires income, deferred revenue
      requires liability, and write-off and cost of goods sold require expense.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    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
    origin: none
  - id: BR-CAP-ACC-PRD-015-05
    proved_by: [ATS-ACC-PRD-015-05, TST-ACC-PRD-026, TST-ACC-PRD-036]
    statement: >-
      New setup references require active records; an inactive record retained in the same field remains
      acceptable.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/product-accounting-setups.integration.spec.js#refuses
      it newly named in another field
    origin: none
  - id: BR-CAP-ACC-PRD-015-06
    proved_by: [ATS-ACC-PRD-015-06, TST-ACC-PRD-026, TST-ACC-PRD-036]
    statement: >-
      A setup tax class overrides its kind default, and an already held class remains acceptable after
      retirement.
    kind: policy
    enforced_at:
      - service
      - database
    must_prove: true
    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
    origin: 'services-accounting:docs/migrations/accounting-modernization/products-shared/README.md#D-7'
  - id: BR-CAP-ACC-PRD-015-07
    proved_by: [ATS-ACC-PRD-004-11, ATS-ACC-PRD-015-07, ATS-ACC-PRD-015-15, TST-ACC-PRD-026, TST-ACC-PRD-036]
    statement: >-
      A first setup needs no read version, but existing setups require their read version and reject stale
      replacement.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers 400 to a
      replacement without the version read
    origin: none
  - id: BR-CAP-ACC-PRD-015-08
    proved_by: [ATS-ACC-PRD-015-08, ATS-ACC-PRD-017-07, TST-ACC-PRD-036]
    statement: >-
      Setup replacement clears omitted values and replaces all child collections transactionally, preserving
      previous data if it fails.
    kind: invariant
    enforced_at:
      - service
    must_prove: true
    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
    origin: 'services-accounting:docs/milestones/ACCT-M1-books-and-invoices.md#D12'
  - id: BR-CAP-ACC-PRD-015-09
    proved_by: [ATS-ACC-PRD-006-11, ATS-ACC-PRD-015-09, ATS-ACC-PRD-015-16, TST-ACC-PRD-036, TST-ACC-PRD-044]
    statement: >-
      Update-locked setups require explicit lock removal for replacement, either lock blocks deletion, and
      authorized setup editors may remove locks.
    kind: permission
    enforced_at:
      - service
    must_prove: true
    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
    origin: 'services-accounting:docs/milestones/ACCT-M1-books-and-invoices.md#D11'
  - id: BR-CAP-ACC-PRD-015-10
    proved_by: [ATS-ACC-PRD-003-05, ATS-ACC-PRD-015-10, ATS-ACC-PRD-015-15, ATS-ACC-PRD-015-17, TST-ACC-PRD-026, TST-ACC-PRD-036]
    statement: Deleting an accounting setup leaves its product intact with an empty accounting summary.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#deletes it, leaving the
      product with accounting: null
    origin: none
  - id: BR-CAP-ACC-PRD-015-11
    proved_by: [ATS-ACC-PRD-015-11, TST-ACC-PRD-026, TST-ACC-PRD-031]
    statement: >-
      Accounts, dimensions, merchant accounts and tax classes referenced by setups cannot be deleted while
      referenced.
    kind: invariant
    enforced_at:
      - database
    must_prove: true
    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
    origin: none
  - id: BR-CAP-ACC-PRD-015-12
    proved_by: [ATS-ACC-PRD-015-12, TST-ACC-PRD-012, TST-ACC-PRD-028]
    statement: >-
      Setup reads, replacement and deletion require separate product-accounting permissions, independent of
      product permissions.
    kind: permission
    enforced_at:
      - api
    must_prove: true
    provenance: test
    source: >-
      services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused reading a
      product’s accounting setup
    origin: 'services-accounting:docs/milestones/ACCT-M1-books-and-invoices.md#D3'
  - id: BR-CAP-ACC-PRD-015-13
    proved_by: [ATS-ACC-PRD-015-13, TST-ACC-PRD-031]
    statement: A setup’s product and business unit are fixed at creation and cannot change.
    kind: invariant
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js#refuses a
      change of product_id (RHF01)
    origin: none
  - id: BR-CAP-ACC-PRD-015-14
    proved_by: []
    statement: >-
      The console groups accounting into five cards, saves it separately after the product, and requires a
      receivable account beyond backend requirements.
    kind: policy
    enforced_at:
      - console
    must_prove: false
    provenance: observed
    source: 'react-console:components/accounting-config/products/product-editor.tsx:useProductEditorState'
    origin: 'services-accounting:docs/milestones/ACCT-M1-books-and-invoices.md#R21'
  - id: BR-CAP-ACC-PRD-015-15
    proved_by: []
    statement: Accounting permits creation and replacement of setups on retired products.
    kind: policy
    enforced_at:
      - service
    must_prove: false
    provenance: observed
    source: 'services-accounting:modules/products/services/persistence/products.ts:lockProductForAccounting'
    origin: none
  - id: BR-CAP-ACC-PRD-015-16
    proved_by: [ATS-ACC-PRD-015-14, TST-ACC-PRD-011]
    statement: >-
      Changing an accounting setup after posting leaves the account recorded on the existing posted entry
      unchanged.
    kind: invariant
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0121.spec.ts#ACT-ACC-0121'
    origin: none
scenarios:
  - id: SC-CAP-ACC-PRD-015-01
    given: A workshop has no accounting setup.
    when: 'Finance supplies revenue, receivable and deferred accounts plus a department.'
    then: The setup starts at version one and the product summary identifies its revenue account.
    provenance: test
    source: >-
      services-accounting:modules/products/tests/e2e/product-accounting.e2e.spec.js#answers the summary on the
      product
edge_cases:
  - id: SC-CAP-ACC-PRD-015-02
    given: A caller has product management authority but no setup read authority.
    when: The caller requests full accounting setup.
    then: The setup read fails while product editing remains independently authorized.
    provenance: test
    source: >-
      services-accounting:modules/products/tests/e2e/products-security.e2e.spec.js#is refused reading a
      product’s accounting setup
constraints: []
depends_on:
  - CAP-ACC-PRD-002
related:
  - CAP-ACC-PRD-003
  - CAP-ACC-PRD-006
  - CAP-ACC-PRD-016
  - CAP-ACC-PRD-017
  - CAP-ACC-PRD-018
journeys:
  - JNY-ACC-PRD-001
  - JNY-ACC-PRD-005
open_questions:
  - OQ-ACC-PRD-001
evidence:
  - 'react-console:components/accounting-config/products/product-accounting-section.tsx'
  - 'react-console:components/accounting-config/products/product-editor.tsx'
  - 'react-console:components/accounting-config/products/product-gl-accounts-card.tsx'
  - 'react-console:lib/accounting-config/product-accounting-form.ts'
  - 'react-console:lib/accounting-config/product-accounting-rules.ts'
  - 'react-console:lib/authz/backend-aliases.ts'
  - 'services-accounting:aws/accounting.service.ts'
  - 'services-accounting:docs/accounting/products.md'
  - 'services-accounting:docs/migrations/accounting-modernization/products-shared/README.md'
  - 'services-accounting:docs/milestones/ACCT-M1-books-and-invoices.md'
  - 'services-accounting:modules/products/aws/api/products.routes.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/persistence/products.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/integration/services/persistence/product-accounting-setups.queries.integration.spec.js
controls: [TC-IAM-001, TC-IAM-002, TC-IAM-004, TC-IAM-005, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-005, TC-AZ-006, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-TEN-004, TC-DAT-001, TC-DAT-004, TC-LOG-001, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-PI-001, TC-PI-003, TC-PI-005]
exercised_by: [FAS-ACC-PRD-01-01, FAS-ACC-PRD-02-01, FAS-ACC-PRD-04-01, FAS-ACC-PRD-04-02, FAS-ACC-PRD-04-03, FAS-ACC-PRD-04-04, FAS-ACC-PRD-04-05]
suites: [TST-ACC-PRD-009, TST-ACC-PRD-011, TST-ACC-PRD-012, TST-ACC-PRD-026, TST-ACC-PRD-028, TST-ACC-PRD-031, TST-ACC-PRD-036, TST-ACC-PRD-044, TST-ACC-PRD-066]
---

# Assign a product’s accounting treatment

## Purpose

A finance specialist assigns accounts and dimensions to a product.

## How It Works

A finance specialist assigns accounts and dimensions to a product. Those references must belong to the appropriate workspace and business unit. New references must be active, and account slots restrict account kinds. The service creates or replaces the setup independently from the product record. A replacement carries the setup version and complete child collections. A failed setup save preserves its previous configuration. Console creation may already have committed the product when the setup fails. Staff can correct the setup and retry without creating the product again. Independent permissions support specialists who manage accounts separately from catalogue details.

## Relationships

This outcome uses create a product with a permanent identity.
