# GenerateVarianceReport

## Permission Scope

accounting

## Overview

generateVarianceReport creates a variance report in DRAFT status for a specific cost object and accounting period. The command collects actual amounts from posted journal entries in finance-ledger, retrieves planned amounts from budget line items, calculates variance per cost element, categorizes variance direction (FAVORABLE or UNFAVORABLE based on account type), and computes variance percentages. Division by zero is handled gracefully when the planned amount is zero.

## Business Rules

- Requires a valid `companyId` referencing an ACTIVE company
- Requires a valid `accountingPeriodId` referencing an existing accounting period
- Requires a valid cost object reference (cost center, profit center, or internal order)
- Report is created in DRAFT status
- Actual amounts are sourced exclusively from POSTED journal entries in finance-ledger (DRAFT entries are excluded)
- Actual amounts are aggregated by cost element, cost object, and accounting period
- Planned amounts are sourced from budget line items, matched by cost element
- Variance amount per cost element is calculated as actual minus planned
- Variance percentage is calculated as (actual - planned) / planned * 100
- When planned amount is zero and actual is non-zero, variance percentage is handled gracefully (not division by zero)
- For cost/expense elements: FAVORABLE when actual < planned, UNFAVORABLE when actual > planned
- For revenue elements: FAVORABLE when actual > planned, UNFAVORABLE when actual < planned
- When actual equals planned, variance is zero and direction is FAVORABLE
- A VarianceReportLine is created for each cost element with either a planned or actual amount (or both)
- A cost element with actual postings but no budget line item generates a line with zero planned amount
- Summary totals (total planned, total actual, total variance) are computed from the sum of detail lines
- Budget line items must exist for the specified cost object and period
- Regenerating for the same cost object and period replaces an existing DRAFT report
- A FINAL report is not overwritten; a new DRAFT is created alongside it
- Emits an audit event recording the report generation and acting user

## Process Flow

```mermaid
flowchart TD
    A[Receive generate variance report request] --> B{Company exists and is ACTIVE?}
    B -->|No| C[Return error: COMPANY_NOT_FOUND]
    B -->|Yes| D{Accounting period exists?}
    D -->|No| E[Return error: ACCOUNTING_PERIOD_NOT_FOUND]
    D -->|Yes| F{Cost object exists?}
    F -->|No| G[Return error: COST_OBJECT_NOT_FOUND]
    F -->|Yes| H{Budget line items exist for cost object and period?}
    H -->|No| I[Return error: NO_BUDGET_DATA]
    H -->|Yes| J[Collect actual amounts from POSTED journal entries]
    J --> K[Collect planned amounts from budget line items]
    K --> L[Calculate variance per cost element: actual - planned]
    L --> M[Calculate variance percentage per cost element]
    M --> N[Categorize direction: FAVORABLE or UNFAVORABLE]
    N --> O[Create VarianceReportLine per cost element]
    O --> P[Compute summary totals from detail lines]
    P --> Q[Create VarianceReport in DRAFT status]
    Q --> R[Emit audit event]
    R --> S[Return generated variance report]
```

## External Dependencies

- [organization::getCompany](../../../organization/docs/queries/GetCompany.md) — Validates that the referenced company exists and is ACTIVE
- [finance-ledger::getAccountingPeriod](../../../finance-ledger/docs/queries/GetAccountingPeriod.md) — Validates that the referenced accounting period exists

## Error Scenarios

- **COMPANY_NOT_FOUND**: Referenced company does not exist or is not in ACTIVE status
- **ACCOUNTING_PERIOD_NOT_FOUND**: Referenced accounting period does not exist
- **COST_OBJECT_NOT_FOUND**: Referenced cost object (cost center, profit center, or internal order) does not exist
- **NO_BUDGET_DATA**: No budget line items exist for the specified cost object and period

## Test Cases

- returns error when company does not exist
- returns error when company is not ACTIVE
- returns error when accounting period does not exist
- returns error when cost object does not exist
- returns error when no budget line items exist for the cost object and period
- generates a variance report in DRAFT status for a cost center
- calculates variance as actual minus planned per cost element
- handles division by zero when planned amount is zero
- sets variance direction to FAVORABLE when actual equals planned
- categorizes cost/expense variance as FAVORABLE when actual is less than planned
- categorizes revenue variance as FAVORABLE when actual is greater than planned
- creates a line for actual postings without a matching budget line item
- computes summary totals from the sum of detail lines
- replaces existing DRAFT report when regenerating for same cost object and period
- does not overwrite a FINAL report when regenerating
- emits audit event recording the report generation and acting user
