# PublishStandardCost

## Permission Scope

inventoryMaster

## Overview

publishStandardCost publishes a new standard cost generation for an item, effective immediately. On-hand stock is revalued by (new standard − previous standard) × costed on-hand quantity, recorded directly in financial-accounting as a balanced posted journal entry (inventory account against the standard cost adjustment account, source STANDARD_COST_REVISION), keeping revision effects separate from purchase price variance. The standard cost is item-global, but each company keeps its own ledger: each company holding costed on-hand revalues it in its own entry, using the accounts of the item's assigned policy in that company. Already-issued cost of goods sold is never restated.

Generations are append-only: a revision inserts a new row rather than mutating history. The first generation never revalues, since there is no prior standard to revalue against.

## Business Rules

- Unit cost must be zero or greater
- Publishing does not require the item to be cost-tracked, so a standard can be staged before the item's first movement auto-assigns its policy
- When a prior generation exists, the revaluation basis per company is its costed on-hand — the sum of the item's unconsumed CostLayer quantities. For each company with positive costed on-hand, the delta — (new − previous) × that on-hand — is recorded as a posted journal entry in that company's ledger (an open accounting period covering today must exist)
- Each company's entry uses the posting accounts of the item's assigned policy in that company; the adjustment side posts to the standard cost adjustment account
- A company with on-hand to revalue must have the item cost-tracked — its policy supplies the entry's accounts; otherwise the publication fails
- Companies where the item's assigned policy does not use STANDARD are skipped
- When a company's on-hand is zero, its delta is zero, or there is no prior generation, no journal entry is created for it
- Revaluation never restates already-issued cost of goods sold

## Process Flow

```mermaid
flowchart TD
    A[Receive standard cost publication] --> B{Unit cost >= 0?}
    B -->|No| C[Return error: INVALID_UNIT_COST]
    B -->|Yes| L[Insert standard cost generation]
    L --> M{Prior generation exists?}
    M -->|No| N[Return standard cost]
    M -->|Yes| P[Sum unconsumed cost layers per company]
    P --> Q[Per standard-cost company with on-hand > 0: create and post revaluation journal entry with its posting accounts]
    Q --> N
```

## External Dependencies

- [inventory::ItemValuation](../model/ItemValuation.md) - Determines the companies where the item is cost-tracked and each company's assigned policy
- [inventory::ValuationPolicy](../model/ValuationPolicy.md) - Posting accounts of each revalued company's entry
- [inventory::CostLayer](../model/CostLayer.md) - Costed on-hand quantity for the revaluation
- [financial-accounting::JournalEntry](../../../financial-accounting/docs/model/JournalEntry.md) - Revaluation journals are created and posted

## Error Scenarios

- **INVALID_UNIT_COST**: Unit cost is negative
- **ITEM_VALUATION_NOT_FOUND**: No valuation record exists for the specified item
- **ACCOUNTING_PERIOD_NOT_FOUND**: No accounting period covers the posting date
- **JOURNAL_ENTRY_CREATE_FAILED**: Journal entry creation failed
- **JOURNAL_ENTRY_POST_FAILED**: Journal entry posting failed

## Test Cases

- inserts a standard cost generation and creates an upward revaluation journal entry
- inserts a standard cost generation and creates a downward revaluation journal entry
- revalues each cost-tracked company's on-hand in its own ledger with its own accounts
- returns error when a company holds on-hand but the item is not cost-tracked there
- creates a balanced revaluation journal entry with STANDARD_COST_REVISION source
- skips revaluation for companies whose policy does not use standard cost
- inserts a generation without revaluation when on-hand quantity is zero
- does not revalue when publishing the first generation
- returns error when unit cost is negative
- returns error when no accounting period covers the posting date
