PHPackages                             azaharizaman/nexus-journal-entry - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. azaharizaman/nexus-journal-entry

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

azaharizaman/nexus-journal-entry
================================

Framework-agnostic journal entry management for general ledger systems

v0.1.0-alpha1(1mo ago)02↓100%1MITPHPPHP ^8.3

Since May 5Pushed 1mo agoCompare

[ Source](https://github.com/azaharizaman/nexus-journal-entry)[ Packagist](https://packagist.org/packages/azaharizaman/nexus-journal-entry)[ RSS](/packages/azaharizaman-nexus-journal-entry/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (3)Versions (2)Used By (1)

Nexus Journal Entry Package
===========================

[](#nexus-journal-entry-package)

A framework-agnostic PHP package for journal entry management in general ledger systems.

Overview
--------

[](#overview)

`Nexus\JournalEntry` provides a complete journal entry management engine for ERP systems, including:

- Double-entry bookkeeping with balance validation
- Journal entry creation, posting, and reversal
- Multi-currency support with exchange rate handling
- Fiscal period validation integration
- Balance calculation engine
- Trial balance generation

Requirements
------------

[](#requirements)

- PHP 8.3+
- `azaharizaman/nexus-common` ^1.0
- `azaharizaman/nexus-chart-of-account` ^1.0
- `azaharizaman/nexus-period` ^1.0

Installation
------------

[](#installation)

```
composer require azaharizaman/nexus-journal-entry
```

Key Concepts
------------

[](#key-concepts)

### Journal Entries

[](#journal-entries)

A journal entry represents a financial transaction recorded in the general ledger. Each entry:

- Contains multiple line items (minimum 2 for double-entry)
- Must be balanced (total debits = total credits)
- References valid accounts from the Chart of Accounts
- Is posted to an open fiscal period

### Status Lifecycle

[](#status-lifecycle)

```
Draft → Posted → Reversed

```

- **Draft**: Entry created but not yet posted
- **Posted**: Entry finalized and immutable
- **Reversed**: Entry has been reversed with offsetting entry

### Multi-Currency

[](#multi-currency)

Line items can be in different currencies:

- Transaction amount in original currency
- Base amount converted using effective exchange rate
- Exchange rate captured at posting time

**Important**: Multi-currency journal entries require a `CurrencyConverterInterface` implementation to be injected into `JournalEntryManager`. Without it, all lines must use the same currency.

```
// Single currency - works without CurrencyConverter
$entry = $manager->createEntry([
    'lines' => [
        ['account_id' => 'acc-1', 'debit' => '100.00', 'currency' => 'MYR'],
        ['account_id' => 'acc-2', 'credit' => '100.00', 'currency' => 'MYR'],
    ],
]);

// Multi-currency - requires CurrencyConverter
$manager = new JournalEntryManager(
    $query,
    $persist,
    $ledgerQuery,
    $clock,
    'MYR', // default currency
    $currencyConverter, // inject converter
    $logger
);

$entry = $manager->createEntry([
    'lines' => [
        ['account_id' => 'acc-1', 'debit' => '100.00', 'currency' => 'USD'],
        ['account_id' => 'acc-2', 'credit' => '475.00', 'currency' => 'MYR'], // ~100 USD at 4.75 rate
    ],
]);
```

Quick Start
-----------

[](#quick-start)

```
use Nexus\JournalEntry\Contracts\JournalEntryManagerInterface;

// Inject the manager (implementation provided by consuming application)
public function __construct(
    private readonly JournalEntryManagerInterface $journalManager
) {}

// Create and post a journal entry
public function recordSale(): void
{
    // Create journal entry
    $entry = $this->journalManager->createEntry([
        'date' => new DateTimeImmutable('2024-01-15'),
        'description' => 'Sales revenue - Invoice #1001',
        'reference' => 'INV-1001',
        'lines' => [
            [
                'account_id' => 'acc-cash-1000',
                'debit' => '1000.00',
                'credit' => '0.00',
                'currency' => 'MYR',
            ],
            [
                'account_id' => 'acc-revenue-4000',
                'debit' => '0.00',
                'credit' => '1000.00',
                'currency' => 'MYR',
            ],
        ],
    ]);

    // Post the entry
    $this->journalManager->postEntry($entry->getId());
}
```

Available Interfaces
--------------------

[](#available-interfaces)

### Core Contracts

[](#core-contracts)

InterfaceDescription`JournalEntryInterface`Journal entry entity contract`JournalEntryLineInterface`Line item entity contract`JournalEntryQueryInterface`Read operations (CQRS Query)`JournalEntryPersistInterface`Write operations (CQRS Command)`JournalEntryManagerInterface`High-level management operations### Supporting Contracts

[](#supporting-contracts)

InterfaceDescription`LedgerQueryInterface`Balance and ledger queries`CurrencyConverterInterface`Currency conversion for multi-currency entries`SequencingIntegrationInterface`Journal entry number generation`PeriodValidationInterface`Fiscal period validationServices
--------

[](#services)

### JournalEntryManager

[](#journalentrymanager)

High-level service for journal entry operations:

```
// Create entry
$entry = $manager->createEntry($data);

// Post entry (validates and marks as Posted)
$manager->postEntry($entryId);

// Reverse entry (creates offsetting entry)
$reversal = $manager->reverseEntry($entryId, $reason);
```

### PostingEngine

[](#postingengine)

Validates journal entries before posting:

```
// Validate entry
$engine->validate($entry);

// Calculate impact on accounts
$impacts = $engine->calculateImpact($entry);
```

### BalanceCalculator

[](#balancecalculator)

Calculates account balances:

```
// Balance as of date
$balance = $calculator->getAccountBalance($accountId, $asOfDate);

// Trial balance
$trialBalance = $calculator->generateTrialBalance($asOfDate);

// Running balance
$runningBalance = $calculator->calculateRunningBalance($accountId, $transactions);
```

Value Objects
-------------

[](#value-objects)

### Money

[](#money)

The `Money` value object is provided by `Nexus\Common` (shared across all packages):

```
use Nexus\Common\ValueObjects\Money;

$amount = Money::of(1000.00, 'MYR');
$sum = $amount->add(Money::of(500.00, 'MYR'));
$isEqual = $amount->equals($other);
$formatted = $amount->format(); // "1000.00 MYR"
```

### ExchangeRate

[](#exchangerate)

Effective-dated exchange rate:

```
use Nexus\JournalEntry\ValueObjects\ExchangeRate;

$rate = new ExchangeRate('USD', 'MYR', '4.7500', new DateTimeImmutable());
$converted = $rate->convert(Money::of('100.0000', 'USD'));
```

### JournalEntryNumber

[](#journalentrynumber)

Validated journal entry number:

```
use Nexus\JournalEntry\ValueObjects\JournalEntryNumber;

$number = JournalEntryNumber::fromString('JE-2024-001234');
$prefix = $number->getPrefix(); // 'JE'
$sequence = $number->getSequence(); // 1234
```

Integration with Other Packages
-------------------------------

[](#integration-with-other-packages)

### Chart of Account (`azaharizaman/nexus-chart-of-account`)

[](#chart-of-account-azaharizamannexus-chart-of-account)

Journal entries reference accounts for posting:

```
// Account validation during posting
$account = $accountQuery->find($line->getAccountId());

if (!$account->isPostable()) {
    throw new InvalidAccountException('Cannot post to header account');
}

if (!$account->isActive()) {
    throw new InvalidAccountException('Account is inactive');
}
```

### Period (`azaharizaman/nexus-period`)

[](#period-azaharizamannexus-period)

Period validation before posting:

```
// Validate posting date is in open period
if (!$periodValidator->isOpen($entry->getPostingDate())) {
    throw new PeriodClosedException('Cannot post to closed period');
}
```

### Sequencing (`azaharizaman/nexus-sequencing`)

[](#sequencing-azaharizamannexus-sequencing)

Journal entry number generation:

```
// Generate next number via sequencing integration
$number = $sequencing->getNext('journal_entry');
```

Consumer Implementation
-----------------------

[](#consumer-implementation)

Consuming applications must provide implementations for:

1. **Repository Interfaces** - Database persistence using Eloquent/Doctrine
2. **Currency Converter** - Convert money between currencies (required for multi-currency entries)
3. **Period Validator** - Integration with Period package

### Example: Laravel Implementation

[](#example-laravel-implementation)

```
// Service Provider bindings
$this->app->bind(
    JournalEntryQueryInterface::class,
    EloquentJournalEntryRepository::class
);

$this->app->bind(
    JournalEntryPersistInterface::class,
    EloquentJournalEntryRepository::class
);

$this->app->bind(
    CurrencyConverterInterface::class,
    CurrencyExchangeRateAdapter::class // Wraps Nexus\Currency\ExchangeRateService
);
```

Testing
-------

[](#testing)

```
composer test
```

License
-------

[](#license)

MIT License. See [LICENSE](LICENSE) for details.

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance93

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity34

Early-stage or recently created project

 Bus Factor1

Top contributor holds 55.6% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

36d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/117408?v=4)[Azahari Zaman](/maintainers/azaharizaman)[@azaharizaman](https://github.com/azaharizaman)

---

Top Contributors

[![Copilot](https://avatars.githubusercontent.com/in/1143301?v=4)](https://github.com/Copilot "Copilot (10 commits)")[![azaharizaman](https://avatars.githubusercontent.com/u/117408?v=4)](https://github.com/azaharizaman "azaharizaman (8 commits)")

---

Tags

financeAccountingdouble entryERPbookkeepinggeneral ledgerjournal-entry

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/azaharizaman-nexus-journal-entry/health.svg)

```
[![Health](https://phpackages.com/badges/azaharizaman-nexus-journal-entry/health.svg)](https://phpackages.com/packages/azaharizaman-nexus-journal-entry)
```

###  Alternatives

[grumpydictator/firefly-iii

Firefly III: a personal finances manager.

23.6k69.4k](/packages/grumpydictator-firefly-iii)[ecotone/ecotone

Enterprise architecture layer for Laravel and Symfony — CQRS, Event Sourcing, Durable Workflows (Sagas, Orchestrators), Projections, and Outbox messaging via PHP attributes.

562565.8k41](/packages/ecotone-ecotone)[civicrm/civicrm-core

Open source constituent relationship management for non-profits, NGOs and advocacy organizations.

744284.3k34](/packages/civicrm-civicrm-core)[illuminatech/balance

Provides support for Balance accounting system based on debit and credit principle

16040.4k](/packages/illuminatech-balance)[byrokrat/accounting

Analysis and generation of bookkeeping data according to Swedish standards

121.6k](/packages/byrokrat-accounting)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
