# ProcessInventoryHandoff

## Permission Scope

subledgerHandoff

## Overview

processInventoryHandoff receives inventory valuation events from the inventory module (goods receipts, adjustments, scrap) and creates corresponding Miscellaneous-type journal entries in the general ledger. For goods receipts, the entry debits the inventory asset account and credits the clearing account. For adjustments, it debits the adjustment expense and credits the inventory asset. For scrap, it debits the scrap expense and credits the inventory asset. The command enforces idempotency and supports multi-currency transactions.

## Business Rules

- Receives a handoff event containing the inventory valuation change data and relevant account references
- Creates a journal entry classified as Miscellaneous journal type
- For goods receipts: debits inventory asset account and credits the clearing account
- For adjustments: debits adjustment expense account and credits inventory asset account
- For scrap: debits scrap expense account and credits inventory asset account
- The journal entry must be balanced (total debits equal total credits in functional currency)
- The journal entry carries a source document reference linking to the originating inventory event
- Idempotent processing: duplicate events with the same source document reference return the original acknowledgment without re-posting
- Validates that the target accounting period is in OPEN or FUTURE_ENTERABLE status
- Validates that all referenced GL accounts are active in the Chart of Accounts
- Handles deprecated GL accounts with successor mappings by redirecting to the successor
- Supports multi-currency: foreign currency amounts are converted to base currency using the provided exchange rate
- Rejects events with zero or negative amounts
- Events are scoped to a company
- Emits an audit event recording the source module, document reference, and journal entry created

## Process Flow

```mermaid
flowchart TD
    A[Receive inventory handoff event] --> B{Idempotency check: already posted?}
    B -->|Yes| C[Return existing acknowledgment]
    B -->|No| D{Accounting period OPEN or FUTURE_ENTERABLE?}
    D -->|No| E[Return error: invalid period status]
    D -->|Yes| F{GL accounts valid and active?}
    F -->|No| G[Return error: account validation failed]
    F -->|Yes| H{Event type?}
    H -->|Goods receipt| I[Create entry: debit inventory asset, credit clearing]
    H -->|Adjustment| J[Create entry: debit adjustment expense, credit inventory asset]
    H -->|Scrap| K[Create entry: debit scrap expense, credit inventory asset]
    I --> L[Post journal entry]
    J --> L
    K --> L
    L --> M[Emit audit event]
    M --> N[Return acknowledgment]
```

## External Dependencies

- [coa-management::getAccount](../../../coa-management/docs/queries/GetAccount.md) - Validates that inventory, clearing, and expense GL accounts are active
- [primitives::getCurrency](../../../primitives/docs/queries/GetCurrency.md) - Validates currency for multi-currency transactions

## Error Scenarios

- **INVALID_PERIOD_STATUS**: Target accounting period is not in OPEN or FUTURE_ENTERABLE status
- **ACCOUNT_NOT_FOUND**: Referenced GL account does not exist
- **ACCOUNT_NOT_ACTIVE**: Referenced GL account is not in active status
- **INVALID_AMOUNT**: Handoff event contains zero or negative amounts
- **COMPANY_MISMATCH**: Handoff event company does not match the GL account company scope

## Test Cases

- returns existing entry for idempotent duplicate
- returns error when amount is zero or negative
- returns error when amount is negative
- returns error when period is not OPEN or FUTURE_ENTERABLE
- returns error when period is CLOSED
- returns error when company does not match period company
- returns error when debit account does not exist
- returns error when credit account does not exist
- returns error when debit account is not active
- returns error when credit account is not active
- creates journal entry with correct type and amounts
- handles multi-currency with exchange rate
