# Subledger Integration

## Overview

Subledger Integration provides the standardized event-driven framework through which upstream operational modules — purchase (accounts payable), sales (accounts receivable), inventory (valuation), and manufacturing (cost settlement) — post journal entries into the general ledger. Each upstream module emits a domain event containing the financial impact of a business transaction (e.g., a validated purchase bill, an issued sales invoice, an inventory valuation change, or a manufacturing cost settlement). The finance-ledger module subscribes to these events, validates the handoff payload against its own constraints (accounting period status, account validity, debit/credit balance), creates the corresponding journal entry with appropriate journal type classification, and acknowledges successful posting back to the originating module. This event-driven architecture decouples operational transaction processing from accounting, allowing each module to evolve independently while maintaining GL completeness.

The handoff contract for each subledger type defines the required payload fields, the expected account references (sourced from coa-management), the journal type assignment, and the acknowledgment pattern. Purchase and sales handoffs reference specific GL accounts for payable/receivable recognition and revenue/expense classification. Inventory handoffs carry valuation change amounts with asset and contra-account references. Manufacturing handoffs include WIP, absorption, and variance account references along with cost settlement data. All handoff contracts enforce idempotency — duplicate event delivery results in acknowledgment without re-posting — and require the originating module to have validated the target accounting period status before emitting the event. The finance-ledger module performs its own period status check as a secondary gate, rejecting events that target periods not in OPEN or FUTURE_ENTERABLE status.

## Business Purpose

Organizations need a disciplined, auditable mechanism for subledger-to-GL integration to ensure financial completeness and operational consistency:

- **GL completeness**: Every financial transaction originating in an operational module must ultimately be reflected in the general ledger. Without standardized integration contracts, transactions can be lost between modules, leading to incomplete financial statements and failed audits
- **Separation of concerns**: Operational modules own business logic (purchase matching, invoice issuance, inventory valuation, cost settlement) while the finance-ledger owns accounting logic (double-entry enforcement, period control, account validation). The handoff contract is the boundary — upstream modules produce financial events, the GL consumes them
- **Event-driven decoupling**: By using domain events rather than direct API calls, subledger modules do not need runtime knowledge of GL internals. This follows the pattern used by Oracle Subledger Accounting (SLA) and SAP's document-posting architecture, where operational documents trigger accounting events that the GL processes independently
- **Idempotent processing**: Network failures, retries, and at-least-once delivery guarantees mean the GL may receive the same event multiple times. Idempotency keyed on source document reference ensures exactly-once posting semantics without requiring distributed transactions
- **Period validation at the boundary**: Upstream modules query accounting period status before emitting handoff events (first gate), and the finance-ledger re-validates period status upon receipt (second gate). This defense-in-depth approach prevents posting to closed or permanently closed periods even if the upstream module's status cache is stale
- **Acknowledgment contracts**: Each subledger type receives a typed acknowledgment upon successful posting (e.g., `PurchaseBillPostingAcknowledgment`, `ManufacturingCostSettlementAcknowledgment`). This enables upstream modules to track GL posting status, detect failures, and implement compensating actions
- **Journal type classification**: Handoff contracts assign the correct journal type (Sales, Purchase, Miscellaneous) to each generated journal entry, ensuring proper categorization in trial balances and financial statements
- **Audit traceability**: Every subledger-originated journal entry carries a source document reference (e.g., purchase bill ID, sales invoice number, inventory event ID, manufacturing settlement ID) linking the GL entry back to the originating business transaction for audit trail continuity

## Process Flow

The generic subledger-to-GL posting flow applies to all upstream module types:

```mermaid
flowchart TD
    A[Upstream module completes business transaction] --> B[Upstream module queries AccountingPeriod status]
    B --> C{Period OPEN or FUTURE_ENTERABLE?}
    C -- No --> D[Upstream module rejects or defers posting]
    C -- Yes --> E[Upstream module emits subledger handoff event]
    E --> F[finance-ledger receives handoff event]
    F --> G{Idempotency check: already posted?}
    G -- Yes --> H[Return existing acknowledgment]
    G -- No --> I[Validate accounting period status]
    I --> J{Period still OPEN or FUTURE_ENTERABLE?}
    J -- No --> K[Reject event with period status error]
    J -- Yes --> L[Validate GL account references via coa-management]
    L --> M{All accounts valid and active?}
    M -- No --> N[Reject event with account validation error]
    M -- Yes --> O[Create journal entry with balanced debit/credit lines]
    O --> P[Post journal entry]
    P --> Q[Emit typed acknowledgment to upstream module]
    Q --> R[Upstream module records GL posting confirmation]
```

Each subledger type maps to specific account structures and journal types:

```mermaid
flowchart LR
    subgraph Purchase
        P1[PurchaseBill validated] --> P2[Debit: Expense/Asset account]
        P2 --> P3[Credit: Accounts Payable]
        P3 --> P4[Journal Type: Purchase]
    end

    subgraph Sales
        S1[SalesInvoice issued] --> S2[Debit: Accounts Receivable]
        S2 --> S3[Credit: Revenue account]
        S3 --> S4[Journal Type: Sales]
    end

    subgraph Inventory
        I1[Valuation event emitted] --> I2[Debit/Credit: Inventory Asset]
        I2 --> I3[Credit/Debit: COGS or Adjustment]
        I3 --> I4[Journal Type: Miscellaneous]
    end

    subgraph Manufacturing
        M1[Cost settlement emitted] --> M2[Debit: Finished Goods / Variance]
        M2 --> M3[Credit: WIP account]
        M3 --> M4[Journal Type: Miscellaneous]
    end
```

## Scenario Patterns

- **Purchase Bill Payable Recognition**: A purchase module validates and matches a vendor invoice (PurchaseBill) against a purchase order and goods receipt. Upon successful three-way match, it emits a handoff event containing the bill amount, expense or asset account reference, and the accounts payable GL account. The finance-ledger creates a journal entry debiting the expense/asset account and crediting accounts payable, then returns a `PurchaseBillPostingAcknowledgment` with the generated journal entry ID

- **Sales Invoice Receivable Recognition**: The sales module issues a SalesInvoice to a customer. It emits a handoff event with the invoice total, accounts receivable GL account, and revenue account reference. The finance-ledger creates a journal entry debiting accounts receivable and crediting revenue, classified as a Sales journal type. The acknowledgment enables the sales module to mark the invoice as GL-posted

- **Sales Credit Note Reversal**: A SalesCreditNote is issued for a returned product. The sales module emits a handoff event that mirrors the original invoice posting with reversed debits and credits — debit revenue, credit accounts receivable. The finance-ledger validates the net effect and posts the reversing entry, preserving the audit link to both the original invoice and the credit note

- **Inventory Goods Receipt Valuation**: When inventory receives goods against a purchase order, the inventory module emits a valuation event with the received quantity, unit cost, inventory asset account, and goods receipt clearing account. The finance-ledger creates a journal entry debiting the inventory asset account and crediting the clearing account, capturing the cost basis of incoming stock

- **Inventory Adjustment and Scrap**: A cycle count reveals a shortfall, and the inventory module emits an adjustment event. The finance-ledger debits an inventory loss/adjustment expense account and credits the inventory asset account. For scrap events, a similar pattern posts to a scrap expense account, ensuring that inventory shrinkage is properly reflected in the GL

- **Manufacturing Cost Settlement**: At period end, the manufacturing module calculates actual production costs against standard costs and emits a cost settlement event containing WIP account references, finished goods account, and variance accounts (material price variance, labor efficiency variance, overhead variance). The finance-ledger debits finished goods and variance accounts, credits WIP, and returns a `ManufacturingCostSettlementAcknowledgment` so the manufacturing module can mark the production order as financially settled

- **Duplicate Event Delivery (Idempotency)**: A network retry causes the purchase module to emit the same PurchaseBill handoff event twice. On the second receipt, the finance-ledger detects the duplicate via the source document reference, skips journal entry creation, and returns the original acknowledgment. No duplicate posting occurs

- **Stale Period Status Rejection**: The sales module caches a period as OPEN but the period was closed by the controller between the cache read and the event emission. The finance-ledger's secondary period validation catches the mismatch and rejects the event with a period status error, prompting the sales module to defer the posting to the next open period

- **Multi-Currency Subledger Posting**: A purchase bill denominated in EUR is handed off to the finance-ledger for a company whose base currency is USD. The handoff event includes the foreign currency amount, the transaction currency code, and the exchange rate. The finance-ledger creates journal lines in both the transaction currency and the base currency, applying the exchange rate conversion per the primitives module's rate lookup

- **Cross-Subledger Period-End Verification**: During period-end close, the finance-ledger generates a subledger transfer completeness report checking that all expected handoff events from purchase, sales, inventory, and manufacturing for the closing period have been received and acknowledged. Outstanding items are flagged for the controller to investigate before closing the period

## Test Cases

- Purchase handoff event with valid PurchaseBill creates a journal entry with debit to expense/asset account and credit to accounts payable
- Purchase handoff journal entry is classified as Purchase journal type
- Purchase handoff acknowledgment includes the generated journal entry ID and posting timestamp
- Sales handoff event with valid SalesInvoice creates a journal entry with debit to accounts receivable and credit to revenue account
- Sales handoff journal entry is classified as Sales journal type
- Sales credit note handoff creates a reversing journal entry with debit to revenue and credit to accounts receivable
- Sales handoff acknowledgment includes the generated journal entry ID and posting timestamp
- Inventory goods receipt handoff creates a journal entry with debit to inventory asset and credit to clearing account
- Inventory adjustment handoff creates a journal entry with debit to adjustment expense and credit to inventory asset
- Inventory scrap handoff creates a journal entry with debit to scrap expense and credit to inventory asset
- Inventory handoff journal entries are classified as Miscellaneous journal type
- Manufacturing cost settlement handoff creates journal entries debiting finished goods and variance accounts, crediting WIP
- Manufacturing handoff returns a ManufacturingCostSettlementAcknowledgment with journal entry ID and settlement reference
- Manufacturing variance entries separately record material price variance, labor efficiency variance, and overhead variance when applicable
- All subledger-originated journal entries maintain balanced debits and credits (double-entry enforcement)
- All subledger-originated journal entries carry a source document reference linking to the originating business transaction
- Duplicate handoff events with the same source document reference are idempotent — no duplicate journal entries are created
- Duplicate handoff events return the original acknowledgment without re-posting
- Handoff events targeting an accounting period in OPEN status are accepted
- Handoff events targeting an accounting period in FUTURE_ENTERABLE status are accepted (advance postings)
- Handoff events targeting an accounting period in NEVER_OPENED status are rejected with a period status error
- Handoff events targeting an accounting period in CLOSED status are rejected with a period status error
- Handoff events targeting an accounting period in PERMANENTLY_CLOSED status are rejected with a period status error
- Handoff events referencing an invalid or non-existent GL account are rejected with an account validation error
- Handoff events referencing a GL account in DRAFT status (not yet active) are rejected with an account status error
- Handoff events referencing a deactivated GL account with a successor mapping are redirected to the successor account
- Multi-currency handoff events create journal lines in both transaction currency and base currency with correct exchange rate conversion
- Handoff events with zero or negative amounts are rejected with a validation error
- Each subledger handoff event processing emits an audit event via the audit module recording the source module, document reference, and journal entry created
- Failed handoff processing emits an audit event recording the rejection reason and source document reference
- Subledger transfer completeness check for a period reports all acknowledged and outstanding handoff events grouped by source module
- Period-end close workflow blocks closing if outstanding unacknowledged subledger events exist for the target period
- Handoff events are scoped to a company; events from one company cannot post to another company's GL accounts or periods

## Reference Links

- [Oracle Subledger Accounting (SLA) Overview](https://docs.oracle.com/en/cloud/saas/financials/24d/oafcf/subledger-accounting.html)
- [SAP FI Integration with Subledgers (AP, AR, MM)](https://help.sap.com/docs/SAP_S4HANA_ON-PREMISE/ee3509643e954b3da2e0ebfa846c02e1/4cbe15773ecd2a44e10000000a42189b.html)
- [Oracle Fusion Create Subledger Journal Entries](https://docs.oracle.com/en/cloud/saas/financials/24d/oafcf/subledger-journal-entries.html)
- [SAP Document Posting Architecture (FI-GL Integration)](https://help.sap.com/docs/SAP_S4HANA_ON-PREMISE/ee3509643e954b3da2e0ebfa846c02e1/5dc0ef593e3d2944e10000000a42189b.html)
- [Odoo Accounting Integration with Invoicing and Inventory](https://www.odoo.com/documentation/19.0/applications/finance/accounting/get_started/cheat_sheet.html)
- [NetSuite Subledger to GL Posting](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_N671498.html)
