# CreateJournalEntry

## Permission Scope

journalEntry

## Overview

createJournalEntry establishes a new journal entry in DRAFT status within the general ledger. Header fields travel under `header` and new lines travel under `lines` (a plain array -- `ADD` operations do not exist at creation time). The command requires prepared journal lines so callers create the draft accounting document as one unit. The command returns the created document root (header); callers read lines separately.

## Business Rules

- Journal entry is always created in DRAFT status
- Requires a valid `companyId` referencing a company from the organization module
- Requires a valid `accountingPeriodId` referencing an existing accounting period in the same company
- Requires a valid entry date
- Description is optional and can be set on creation
- Source document type and source document ID are optional and can be set on creation
- At least two initial journal lines are required and are created under the new DRAFT journal entry
- Each initial line must reference an existing ACTIVE GL account
- Each initial line must specify either a debit amount or a credit amount, not both
- Journal line amounts are recorded in the company's base currency; multi-currency conversion is outside the current scope
- Journal entries are scoped to a company; entries from different companies are fully isolated

## Process Flow

```mermaid
flowchart TD
    A[Receive create journal entry request] --> B{Company exists?}
    B -->|No| C[Return error: company not found]
    B -->|Yes| D{Accounting period exists in same company?}
    D -->|No| E[Return error: period not found]
    D -->|Yes| J{Valid entry date?}
    J -->|No| K[Return error: invalid entry date]
    J -->|Yes| L{Initial lines valid?}
    L -->|No| M[Return line validation error]
    L -->|Yes| N[Create journal entry in DRAFT status]
    N --> O[Create initial journal lines]
    O --> P[Return created journal entry]
```

## External Dependencies

- [coa-management::ListAccounts](../../../coa-management/docs/query/ListAccounts.md) - Validates that all referenced GL accounts exist and are ACTIVE

## Error Scenarios

- **COMPANY_NOT_FOUND**: Referenced company does not exist
- **ACCOUNTING_PERIOD_NOT_FOUND**: Referenced accounting period does not exist
- **ACCOUNTING_PERIOD_COMPANY_MISMATCH**: Accounting period belongs to a different company
- **INVALID_ENTRY_DATE**: Entry date is not a valid date
- **MINIMUM_LINES_NOT_MET**: Journal entry has fewer than two journal lines
- **ACCOUNT_NOT_FOUND**: Referenced GL account does not exist
- **ACCOUNT_INACTIVE**: Referenced GL account is not ACTIVE
- **INVALID_DEBIT_CREDIT**: Debit/credit values violate constraints

## Test Cases

- returns error when company does not exist
- returns error when accounting period does not exist
- returns error when accounting period belongs to a different company
- returns error when entry date is invalid
- returns error when initial lines are missing
- creates journal entry in DRAFT status with required fields and lines
- creates journal entry with optional description
- creates journal entry with optional source document
- passes custom header and line fields through to inserts
- returns error when an initial line account does not exist
- returns error when an initial line account is inactive
- returns error when an initial line has invalid debit and credit values
