# Journal Entry Management

## Overview

Journal Entry Management is the core transactional capability of the financial-accounting module, implementing double-entry bookkeeping for all financial postings. A journal entry consists of a header record (JournalEntry) carrying the entry date, status, posting period, description, and optional structured source document reference, along with one or more JournalLine records that each specify a GL account (from coa-management), debit or credit amount, and line-level description. Every journal entry must satisfy the fundamental accounting constraint: total debits must equal total credits before it can be posted. Posting transitions the header to POSTED; the JournalLine rows under POSTED entries are the general-ledger surface for balances, reporting, and traceability.

Journal entries follow a lifecycle of DRAFT to either CANCELLED or POSTED, with posted entries eligible for reversal via a separate posted mirror entry that references the original. Cancelling a draft preserves the attempted accounting document without creating ledger effect. The original posted entry remains POSTED so its ledger effect stays traceable and nets against the reversal entry. Business origin is represented by the optional source document type and source document ID rather than a journal type classification. Amounts are recorded in the company's base currency; multi-currency conversion is outside the current scope.

## Business Purpose

Organizations need a rigorous, traceable journal entry system to record financial transactions and maintain the integrity of their general ledger:

- **Double-entry enforcement**: Every journal entry must balance total debits against total credits, preventing one-sided postings that would corrupt the trial balance and financial reports
- **Lifecycle gating**: The DRAFT to POSTED progression ensures entries can be reviewed and corrected before they affect account balances. Only JournalLine rows under POSTED JournalEntry headers contribute to the general ledger and financial reports
- **Draft cancellation traceability**: Draft journal entries that are abandoned transition to CANCELLED rather than being hard-deleted, preserving what was prepared and why it never reached the ledger
- **Immutable posted entries**: Once posted, a journal entry cannot be modified or deleted — only reversed. This preserves the traceability required by GAAP, IFRS, and local accounting regulations
- **Reversal via mirror entry**: Reversing a posted entry creates a new journal entry with inverted debit/credit lines rather than deleting the original, maintaining a complete history of all postings and corrections
- **Period-aware posting**: Journal entries reference an accounting period and can only be posted to periods that are in OPEN status, enforcing the period lifecycle managed by the accounting-period-management feature
- **Source document traceability**: Optional source document type and source document ID link journal entries back to their originating business transactions, supporting review inquiries and reconciliation
- **GL account reference validation**: Journal lines must reference existing GL accounts from coa-management. Account lifecycle and replacement policy remain owned by coa-management

## Process Flow

```mermaid
stateDiagram-v2
    [*] --> Draft: createJournalEntry
    Draft --> Draft: updateJournalEntry
    Draft --> Cancelled: cancelJournalEntry
    Draft --> Posted: postJournalEntry
```

```mermaid
flowchart TD
    A[Identify transaction to record] --> B[Create JournalEntry header in DRAFT]
    B --> C[Provide prepared JournalLine records with debit/credit amounts]
    C --> G{Debits = Credits?}
    G -- No --> C
    G -- Yes --> H{GL accounts exist?}
    H -- No --> I[Resolve account issues]
    I --> C
    H -- Yes --> J{Target period OPEN?}
    J -- No --> K[Select valid posting period]
    K --> J
    J -- Yes --> L[Post journal entry]
    L --> N[Posted journal lines update account balances]
```

```mermaid
flowchart TD
    A[Select posted journal entry to reverse] --> B[Create mirror entry with inverted debits/credits]
    B --> C{Reversal period OPEN?}
    C -- No --> D[Select valid reversal period]
    D --> C
    C -- Yes --> E[Post reversal entry]
    E --> F[Original entry remains POSTED]
    F --> G[Original and reversal balances net to zero]
```

## Scenario Patterns

- **Manual Entry**: An accountant creates a journal entry that does not originate from another business document. The entry is created in DRAFT with prepared journal lines, the balance is verified, and the entry is posted to the current open period
- **Sales Invoice Posting**: The sales module generates a journal entry with a debit to Accounts Receivable and a credit to Revenue, referencing the customer invoice as the source document. The entry is posted automatically upon invoice confirmation
- **Purchase Bill Recording**: A purchase bill triggers a journal entry with a debit to the relevant expense or inventory account and a credit to Accounts Payable. The source document fields link back to the purchase bill for reconciliation
- **Opening Balance Entry**: During initial system setup or at the start of a new fiscal year, a journal entry is created to establish beginning balances for all balance sheet accounts. This entry typically carries a posting date matching the first day of the new fiscal period
- **Error Correction via Reversal**: A posted journal entry is discovered to contain an incorrect account assignment. The accountant reverses the original entry (creating a mirror posting that offsets all amounts) and then creates a new corrective entry with the correct accounts. The original entry, its reversal, and the correction all remain in the ledger for full traceability
- **Cash Receipt Recording**: A cash payment received from a customer is recorded as a journal entry with source type `INCOMING_PAYMENT`, debiting the bank/cash account and crediting Accounts Receivable. The source document fields link to the customer payment record
- **Bank Transaction Entry**: A bank fee or interest charge is recorded as a journal entry, debiting bank charges expense and crediting the bank account, referencing the bank statement line as the source document when one exists
- **Future-Dated Journal Preparation**: An entry that belongs to a future accounting period can be prepared as a draft. It is posted only after the target accounting period is OPEN

## Test Cases

- Journal entry lifecycle follows DRAFT -> POSTED state machine; reversal is represented by a separate posted reversal entry
- Journal entry can only be created in DRAFT status
- Journal entry requires a valid entry date
- Journal entry must reference a valid companyId
- Journal entry must reference a valid accounting period; the period must be in OPEN status for posting
- Journal entry description is optional and can be updated while in DRAFT status
- Source document type and source document ID are optional and can be set on creation or update in DRAFT status
- A journal entry must have at least two journal lines before it can be posted
- Each journal line must reference an existing GL account
- Each journal line must specify either a debit amount or a credit amount (not both, and not zero for both)
- Debit and credit amounts must be positive values
- Total debits must equal total credits for posting to succeed
- An unbalanced journal entry cannot be posted
- Posting a balanced DRAFT journal entry transitions its status to POSTED
- Posting an already POSTED journal entry fails with an invalid status transition error
- Posted journal entries cannot be modified (no field updates, no line additions or removals)
- Posted journal entries cannot be deleted; only reversal is permitted
- DRAFT journal entries can be cancelled; cancellation preserves the header and prepared lines
- CANCELLED journal entries cannot be updated, posted, reversed, or deleted
- Journal lines are required on journal entry creation and can be incrementally added, updated in place, or removed through updateJournalEntry while the parent is DRAFT
- Journal lines cannot be added to, updated on, or removed from a POSTED journal entry
- Updating a journal line (account, amount, description) is only permitted through the parent journal entry while the parent entry is in DRAFT status
- Reversing a posted entry creates a new journal entry with all debit/credit amounts inverted
- The reversal entry references the original entry and is automatically posted
- The original entry remains POSTED after successful reversal
- Reversing an entry that already has a reversal entry fails
- Reversing a DRAFT entry fails with an invalid status transition error
- The reversal entry must target a period that is in OPEN status
- Posting a journal entry to a CLOSED or PERMANENTLY_CLOSED period is rejected
- Posting a journal entry to a NEVER_OPENED period is rejected
- Journal entries are scoped to a company; entries from different companies are fully isolated
- Only users with appropriate permissions (from user-management) can create, post, or reverse journal entries
- Unauthorized users receive a permission denied error when attempting journal entry operations
- A journal entry with a single line (only debit or only credit) cannot be posted
- The entry date cannot be changed after the entry is posted

## Reference Links

- [Odoo Journal Entries and Journal Types](https://www.odoo.com/documentation/19.0/applications/finance/accounting/get_started/cheat_sheet.html)
- [SAP S/4HANA Journal Entry Processing](https://help.sap.com/docs/SAP_S4HANA_ON-PREMISE/ee3509643e954b3da2e0ebfa846c02e1/4cae4cc1ecaa7286e10000000a42189b.html)
- [Oracle Fusion General Ledger Journal Entries](https://docs.oracle.com/en/cloud/saas/financials/24d/oafcf/journal-entries.html)
- [NetSuite Journal Entry Overview](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_N3444641.html)
- [Sage Intacct Journal Entries](https://www.sage.com/en-us/blog/what-is-a-journal-entry-in-accounting/)
