# PostJournalEntry

## Overview

postJournalEntry transitions a journal entry from DRAFT to POSTED status, making it an immutable part of the general ledger. Posting validates the fundamental accounting constraint (total debits must equal total credits in the functional currency), verifies that the target accounting period is in OPEN or FUTURE_ENTERABLE status, confirms all referenced GL accounts are active, and ensures the entry has at least two journal lines. When a GL account has a successor mapping (deprecated account), the posting is redirected to the successor account.

## Business Rules

- Journal entry must exist and be in DRAFT status
- Entry must have at least two journal lines
- Total debits must equal total credits in the functional currency (balance validation)
- An unbalanced entry cannot be posted
- The target accounting period must be in OPEN or FUTURE_ENTERABLE status
- Posting to a NEVER_OPENED, CLOSED, or PERMANENTLY_CLOSED period is rejected
- All referenced GL accounts must be from an ACTIVE Chart of Accounts
- Journal lines referencing an inactive or draft GL account are rejected at posting time
- Journal lines referencing a deprecated GL account with a successor mapping are redirected to the successor account
- If the successor account is itself inactive or deprecated without a further successor, the posting is rejected
- Successor account redirect is recorded in the audit trail
- Once posted, the entry is immutable (no field updates, no line additions or removals)
- Posted entries cannot be deleted; only reversal is permitted
- Emits an audit event recording the status transition from DRAFT to POSTED and the posting user

## Process Flow

```mermaid
flowchart TD
    A[Receive post journal entry request] --> B{Journal entry exists?}
    B -->|No| C[Return error: journal entry not found]
    B -->|Yes| D{Entry status is DRAFT?}
    D -->|No| E[Return error: invalid status for posting]
    D -->|Yes| F{At least 2 journal lines?}
    F -->|No| G[Return error: minimum lines not met]
    F -->|Yes| H{All GL accounts active?}
    H -->|No| I{Successor account available?}
    I -->|No| J[Return error: inactive account]
    I -->|Yes| K[Redirect to successor account]
    K --> H
    H -->|Yes| L{Period OPEN or FUTURE_ENTERABLE?}
    L -->|No| M[Return error: invalid period status]
    L -->|Yes| N{Debits equal credits in functional currency?}
    N -->|No| O[Return error: unbalanced entry]
    N -->|Yes| P[Transition entry to POSTED]
    P --> Q[Emit audit event]
    Q --> R[Return posted journal entry]
```

## External Dependencies

- [coa-management::getAccount](../../../coa-management/docs/queries/GetAccount.md) - Validates that all referenced GL accounts are active and resolves successor account mappings

## Error Scenarios

- **JOURNAL_ENTRY_NOT_FOUND**: Referenced journal entry does not exist
- **INVALID_STATUS_FOR_POSTING**: Journal entry is not in DRAFT status; only DRAFT entries can be posted
- **MINIMUM_LINES_NOT_MET**: Journal entry has fewer than two journal lines
- **UNBALANCED_ENTRY**: Total debits do not equal total credits in the functional currency
- **INVALID_PERIOD_STATUS**: Target accounting period is not in OPEN or FUTURE_ENTERABLE status
- **INACTIVE_ACCOUNT**: A referenced GL account is inactive or in draft status with no successor mapping
- **SUCCESSOR_ACCOUNT_INVALID**: A successor account is itself inactive or deprecated without a further successor

## Test Cases

- returns error when journal entry does not exist
- returns error when journal entry is already POSTED
- returns error when journal entry is REVERSED
- returns error when entry has fewer than two journal lines
- returns error when entry has only one line (debit only or credit only)
- returns error when total debits do not equal total credits in functional currency
- returns error when target period is in NEVER_OPENED status
- returns error when target period is in CLOSED status
- returns error when target period is in PERMANENTLY_CLOSED status
- returns error when a GL account is inactive
- returns error when a GL account is in draft status
- returns error when successor account is itself inactive without further successor
- posts balanced DRAFT entry to OPEN period
- posts balanced DRAFT entry to FUTURE_ENTERABLE period
- redirects deprecated GL account to successor account at posting time
- records successor account redirect in audit trail
- entry becomes immutable after posting
- emits audit event recording status transition from DRAFT to POSTED and posting user
