Headless General Ledger Zero-Sum Double-Entry FMS for Laravel

Financial truth, behind one fluent API.

A headless, mathematically rigorous Financial Management System (FMS) and General Ledger for Laravel and Obelawium ERP. Enforces zero-sum integer parity down to minor units, immutable Storno reversals, Maker-Checker governance, multi-currency ledger snapshots, and Anti-Corruption Layer (ACL) ingestion.

$ composer require obelaw/ium-accounting
JournalVoucherDraft.php
// Create a balanced journal voucher with minor unit integer precision
$entry = ium()->accounting()->journalEntries()->createDraft(
    CreateJournalEntryDto::fromMajor([
        'entry_date'    => '2026-03-31',
        'currency_code' => 'USD',
        'memo'          => 'Enterprise Q1 SaaS Subscription Invoicing & Sales Tax',
        'lines' => [
            ['account_code' => '1120', 'side' => 'debit',  'amount' => 11500.00, 'memo' => 'Accounts Receivable'],
            ['account_code' => '4100', 'side' => 'credit', 'amount' => 10000.00, 'memo' => 'Recurring Cloud Revenue'],
            ['account_code' => '2150', 'side' => 'credit', 'amount' =>  1500.00, 'memo' => 'Output VAT / Sales Tax Payable'],
        ],
    ])
);

// Strict Maker-Checker governance: Distinct approver posts to the General Ledger
ium()->accounting()->journalEntries()->submit($entry->id, $accountantId);
ium()->accounting()->journalEntries()->approve($entry->id, $controllerId);
ium()->accounting()->journalEntries()->post($entry->id, $controllerId);

Accounting by numbers

0
Imbalance Tolerated
Debits = Credits down to minor units
9
Core Services
Accounts, Ledger, ACL, Closing, etc.
100%
Immutable Postings
Storno reversals only; zero row edits
ISO 4217
Multi-Currency
Automated functional GL denomination
Statutory Compliance

The 8 Non-Negotiable Domain Invariants.

Financial ledgers must never compromise on mathematical truth. Every write operation through the fluent gateway is guarded by hard architectural invariants.

1. Zero-Sum Parity

Every voucher must balance perfectly: Σ Debits = Σ Credits down to integer minor units. Imbalanced vouchers are rejected immediately.

UnbalancedJournalEntryException

2. GL Immutability

Posted entries are strictly immutable. Row-level updates and deletions are forbidden by Eloquent hooks. Corrections require equal-and-opposite Storno reversal vouchers.

ImmutableJournalEntryException

3. Leaf-Only Postings

Transactions are only permitted on leaf accounts (is_leaf = true). Parent aggregators hold tree rolls but reject direct financial postings.

NonPostingAccountException

4. Fiscal Period Locks

Transactions resolve automatically to fiscal calendars. Closed or locked months/quarters strictly reject any new voucher submissions or backdated modifications.

FiscalPeriodClosedException

5. Maker-Checker Rules

Under strict governance, the creator of a voucher cannot approve their own entry. This enforces four-eyes segregation of duties for high-value journal postings.

MakerCheckerViolationException

6. Base Rate Immutability

The reporting base currency is the immutable ledger denominator. Its exchange rate is locked to 1.000000. All foreign currencies quote relative to base.

BaseCurrencyRateImmutableException

7. Functional GL Postings

While vouchers record in their original transaction currency, all General Ledger postings convert and persist in functional base currency minor units at posting time.

amount_functional minor units

8. ACL Isolation

External domains (WMS, POS, Billing, CRM) never touch accounting database tables. All upstream domain events route strictly through the Anti-Corruption Layer.

ium()->accounting()->acl()
Service Catalog

9 Core Financial Engine Services.

Orchestrated effortlessly through the unified ium()->accounting() gateway.

accounts()

Chart of Accounts (COA)

Hierarchical multi-level account tree. Distinguishes assets, liabilities, equity, revenues, and expenses. Enforces leaf-only postings and automated aggregator classification.

tree() · create() · find()
journalEntries()

Journal Vouchers

Draft, submit, approve, and post double-entry vouchers. Features strict Maker-Checker segregation, zero-sum minor unit validation, and statutory Storno reversals.

createDraft() · approve() · reverse()
ledger()

General Ledger & Reports

Immutable book of entry. Instantly compile real-time Trial Balances, Balance Sheets, and Income Statements (P&L) partitioned by open or closed fiscal periods.

generateTrialBalance() · generateBalanceSheet()
fiscalPeriods()

Fiscal Calendar & Locks

Fiscal years and quarterly/monthly periods. Resolves transactions to active periods automatically. Enforces soft audit review locks and statutory hard closing locks.

findPeriodForDate() · closePeriod()
costCenters()

Analytical Dimensions

Multi-dimensional cost accounting. Tag individual journal voucher lines with Cost Centers, Projects, Departments, and Business Units for granular managerial P&L breakdown.

create() · find() · active()
currencies()

Multi-Currency & FX Engine

ISO 4217 currency registry with daily exchange rate snapshots. Convert amounts cleanly, format major/sub-units, and automatically denominate GL entries to base currency.

setRate() · convertMinor() · formatMinor()
acl()

Anti-Corruption Layer (ACL)

Isolates financial accounting from operational domains. Ingests facts from WMS, CRM, and Billing, automatically mapping domain events into posted double-entry journal vouchers.

ingest() · registerMapping()
closing()

Year-End Closing

Executes statutory annual closing. Automatically sweeps and zeroes nominal revenue/expense accounts, creating an equity transfer voucher into Retained Earnings.

closeFiscalYear()
audit()

Forensic Audit Trail

Append-only forensic log recording all lifecycle actions, author IDs, approver IDs, IP addresses, timestamps, and payload snapshots for external statutory auditors.

log() · forEntry()
Fluent API DSL

Intuitive syntax for mission-critical accounting.

Zero HTTP controllers. Zero presentation coupling. Pure PHP 8.2+ domain orchestration through a chainable, type-safe interface.

// 1. Draft a zero-sum journal voucher (amounts in minor units / cents)
$entry = ium()->accounting()->journalEntries()->createDraft(
    CreateJournalEntryDto::fromMajor([
        'entry_date'    => '2026-03-31',
        'entry_type'    => JournalEntryType::Standard,
        'currency_code' => 'USD',
        'memo'          => 'Payroll Processing - Engineering Dept',
        'lines' => [
            ['account_code' => '5110', 'side' => 'debit',  'amount' => 25000.00, 'cost_center_code' => 'CC-ENG'],
            ['account_code' => '2110', 'side' => 'credit', 'amount' => 20000.00, 'memo' => 'Net Salaries Payable'],
            ['account_code' => '2130', 'side' => 'credit', 'amount' =>  5000.00, 'memo' => 'Payroll Tax Withholding'],
        ],
    ])
);

// 2. Submit for review
ium()->accounting()->journalEntries()->submit($entry->id, $preparerId);

// 3. Maker-Checker Segregation: Distinct approver authorises posting
ium()->accounting()->journalEntries()->approve($entry->id, $managerId);
ium()->accounting()->journalEntries()->post($entry->id, $managerId);

// 4. If correction is needed: Never edit! Issue an immutable Storno reversal
$reversalVoucher = ium()->accounting()->journalEntries()->reverse(
    $entry->id,
    $managerId,
    'Erroneous payroll calculation reissued'
);
Decoupled Architecture

How Accounting anchors the ERP ecosystem.

Operational domains emit business events. The Anti-Corruption Layer translates them into zero-sum vouchers. The General Ledger remains an immutable financial sanctuary.

Upstream Bounded Contexts

Operational Domains

Emits facts; holds no foreign keys to accounting tables.

Billing & POS InvoiceFinalized
Inventory (WMS) StockWritedown
Purchasing GoodsReceived
Pure asynchronous events
Anti-Corruption Layer (ACL)

Boundary Translation

Translates operational metadata into balanced debit/credit lines.

1. Event Mapping

Resolves DR/CR chart accounts

2. Minor-Unit Math

Exact integer cents conversion

3. Zero-Sum Check

Σ Debits === Σ Credits ($0 drift)

ium()->accounting()->acl()
Accounting Bounded Context

General Ledger

Statutory book of truth; strictly immutable tables.

ium_accounting_journal_entries
ium_accounting_gl_postings
ium_accounting_audit_logs
100% Immutable & Audited
Agentic AI Coding Assistant Skill

Supercharge AI Agents with Accounting Intelligence.

Financial domains are complex. Equip Google Antigravity, Claude Code, and Cursor AI with the official Obelawium Accounting skill to ensure every line of code complies with strict GAAP invariants.

obelaw/skill-ium-accounting-developmint

Turnkey AI pair-programming for double-entry ledgers.

The skill provides AI assistants with step-by-step decision matrices, automated DTO blueprints, invariant verification procedures, and Pest PHP testing harnesses.

  • Zero-sum math parity and integer minor unit precision awareness
  • Automatic Storno reversal generation instead of forbidden row edits
  • Maker-Checker duty segregation compliance checking
  • ACL cross-domain ingestion mapping patterns
SKILL.md & Invariants Reference Antigravity Compatible
---
name: ium-accounting-development
description: Guide for AI agents developing with
  or extending Obelawium Accounting (FMS & GL).
---

## Non-Negotiable Domain Invariants:
1. Zero-Sum Parity: Sum(Debits) === Sum(Credits)
2. GL Immutability: Storno reversals only
3. Leaf-Only Postings on Chart of Accounts
4. Hard Fiscal Period Lockout
5. Maker-Checker Duty Segregation
6. Base Functional Currency Rate = 1.000000
7. amount_functional Minor Units Denomination
8. Anti-Corruption Layer (ACL) Isolation
Accounting FAQ

Answers for Engineers & Auditors.

Everything you need to know about Obelawium Accounting's invariants, immutability, and architecture.

Why does Obelawium Accounting store amounts in integer minor units instead of floats?
Floating-point numbers in computer systems introduce binary approximation errors (e.g., 0.1 + 0.2 !== 0.3). In enterprise financial ledgers, fractional rounding drift can cause statutory audit discrepancies. Obelawium Accounting mandates integer minor units (e.g., $100.50 is stored as 10050 cents) across all database columns, DTOs, and postings, guaranteeing exact zero-variance arithmetic.
What is the Storno reversal pattern, and why are posted vouchers immutable?
In statutory accounting and GAAP/IFRS standards, altering or deleting a posted financial transaction is strictly illegal. Obelawium Accounting enforces strict database immutability: once a journal entry transitions to POSTED, any attempt to update or delete rows throws an ImmutableJournalEntryException. To correct an erroneous entry, the system generates a Storno reversal voucher with equal and opposite debits and credits, preserving a complete, tamper-proof forensic audit trail.
How does Maker-Checker segregation of duties prevent internal fraud?
When strict governance is enabled (ium.accounting.maker_checker.strict), the creator of a journal voucher (creator_id) cannot approve that voucher (approver_id). If the same actor attempts approval, the engine throws a MakerCheckerViolationException. This enforces institutional segregation of duties, ensuring that financial disbursements and ledger adjustments require independent dual-authorization.
How does the Anti-Corruption Layer (ACL) isolate Accounting from operational domains?
Upstream operational domains (such as Sales, Inventory, Billing, and Subcontracting) must never write directly to accounting tables or know the internal Chart of Accounts codes. Instead, they emit domain events (e.g., InvoiceFinalized, StockDisposed) or invoke ium()->accounting()->acl()->ingest($dto). The ACL translates operational facts into balanced, zero-sum double-entry vouchers without coupling business logistics to financial ledgers.
Can I use Obelawium Accounting with Filament, Laravel Nova, or custom Blade dashboards?
Yes, absolutely. Obelawium Accounting is strictly headless—it contains zero HTTP routes, Blade views, or frontend bindings. Because every capability is exposed through the clean ium()->accounting() fluent API and validated DTOs, you can effortlessly build administrative UIs using Filament, Laravel Nova, Inertia/Vue, Livewire, or standard REST/GraphQL controllers without compromising domain rules.
How does Multi-Currency accounting handle daily FX fluctuations and reporting?
While journal vouchers can be created in any active ISO 4217 currency (e.g., EUR, GBP, JPY), the General Ledger postings are always denominated and converted into your organization's functional base currency at the transaction date's exchange rate. Historical rates are captured immutably per entry, preventing retroactive reporting skew when currency market rates fluctuate.
How does the Fiscal Year-End closing workflow work?
At the end of a fiscal year, the closing service automatically identifies all nominal (temporary) accounts—Revenues and Expenses. It generates a sealed closing journal entry that zeroes out all nominal account balances and transfers the net profit or loss directly into the designated Balance Sheet Retained Earnings equity account, locking the year against future entries.
What is the AI Agent Skill and how does it help development?
The Obelawium Accounting development skill (skill-ium-accounting-developmint) is a specialized AI development toolkit designed for Google Antigravity, Claude Code, and Cursor. It equips AI pair programmers with deep semantic understanding of the 8 ledger invariants, DTO validation structures, and fluent gateway workflows, preventing hallucinations and domain rule violations when building financial applications.

Ready for mathematical financial precision?

Eliminate floating-point drift, enforce Maker-Checker duty segregation, and anchor your Laravel enterprise applications on an immutable General Ledger.

$ composer require obelaw/ium-accounting