PHPackages                             nml/fincore - 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. [Database &amp; ORM](/categories/database)
4. /
5. nml/fincore

ActiveLibrary[Database &amp; ORM](/categories/database)

nml/fincore
===========

NML FinCore - Robust Double-Entry Accounting Engine for Laravel ERPs

v1.0.7(yesterday)01↑2900%MITPHPPHP ^8.1

Since Jun 18Pushed yesterdayCompare

[ Source](https://github.com/Premod1/nml-fincore)[ Packagist](https://packagist.org/packages/nml/fincore)[ Docs](https://premod.me/)[ RSS](/packages/nml-fincore/feed)WikiDiscussions main Synced today

READMEChangelog (5)Dependencies (2)Versions (8)Used By (0)

NML FinCore
===========

[](#nml-fincore)

NML FinCore is a robust, decoupled double-entry accounting engine designed for Laravel applications. It enables real-time ledger generation, polymorphic linking to transactional models, multi-SBU reporting, and strict period locks.

---

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

[](#installation)

Install the package via Composer:

```
composer require nml/fincore
```

### Migration Setup

[](#migration-setup)

The package migrations will be loaded automatically. Run the database migrations to create the necessary tables:

```
php artisan migrate
```

### Configuration (Optional)

[](#configuration-optional)

Publish the configuration file to customize the table prefix, rounding tolerance, currency, and period locks:

```
php artisan vendor:publish --tag=fincore-config
```

---

Core Feature List
-----------------

[](#core-feature-list)

- **Double-entry accounting engine**: Enforces exact balance matching for debit and credit lines within a configurable rounding tolerance.
- **Dynamic chart of accounts**: Classifies and rolls up accounts hierarchically under Assets, Liabilities, Equity, Revenue, and Expenses with parent-child relationship support.
- **Real-time general ledger generation**: Generates real-time ledger entries and balances.
- **Trial Balance reporting**: Dynamic Trial Balance generation based on date range and SBU codes.
- **Balance Sheet reporting**: Dynamic Balance Sheet generation showing Assets, Liabilities, and Equity.
- **Income Statement (P&amp;L)**: Dynamic Profit &amp; Loss reporting based on Revenue and Expense accounts.
- **Cash Flow statements**: Automatically generated Cash Flow statements based on account movements.
- **Multi-SBU / branch reporting**: Tracks entries using Strategic Business Unit (SBU) codes for departmental or branch-level accounting.
- **Fiscal period locking**: Prevents retrospective postings or modifications to closed accounting periods and years.
- **Polymorphic transaction linking**: Links journal entries directly to external source models (Invoices, Sales, Purchases, Payments).
- **Multi-currency support**: Supports transactions in foreign currencies with exchange rates.
- **Tax/VAT handling**: Enforces tax rules, inclusive/exclusive calculations, and automated tax line generation.
- **Fixed asset management**: Fixed asset register with purchase cost and accumulated depreciation tracking.
- **Automated depreciation posting**: Automatically calculates and posts monthly straight-line depreciation entries.
- **Budgeting &amp; variance reporting**: Sets monthly budget targets per account and generates Budget vs. Actual variance reports.
- **Bank reconciliation matching**: Automatically matches bank statement transactions with ledger lines and supports manual clearing.
- **AR/AP ageing reports**: Tracks partner receivables and payables with FIFO payment allocation and ageing buckets.
- **Fiscal year closing engine**: Automatically zero-out temporary Revenue/Expense accounts and transfers Net Profit/Loss to Retained Earnings.
- **Full audit trail &amp; activity logging**: Automatically logs all creations, updates, status transitions, and deletions, capturing user ID, IP address, user agent, and JSON diffs.

---

Initialization
--------------

[](#initialization)

Seed the standard Chart of Accounts using the provided seeder or calling the initializer class directly:

### Option A: Using Laravel Database Seeder

[](#option-a-using-laravel-database-seeder)

Add the package seeder class to your main `database/seeders/DatabaseSeeder.php` file:

```
public function run(): void
{
    $this->call(\Nml\FinCore\Database\Seeders\FinCoreSeeder::class);
}
```

Or run it directly from the terminal:

```
php artisan db:seed --class="Nml\FinCore\Database\Seeders\FinCoreSeeder"
```

### Option B: Programmatic Initialization

[](#option-b-programmatic-initialization)

You can seed the standard Chart of Accounts programmatically (e.g., in a tenant setup flow or custom script):

```
use Nml\FinCore\Services\ChartOfAccountsInitializer;

// Seeds the default chart of accounts (idempotent, safe to rerun)
ChartOfAccountsInitializer::initialize('LKR');
```

### Chart of Accounts Management

[](#chart-of-accounts-management)

To create and manage custom accounts (including parent-child hierarchies), use the `Account` model:

#### Creating a Root Account

[](#creating-a-root-account)

```
use Nml\FinCore\Models\Account;
use Nml\FinCore\Enums\AccountType;

$assetsParent = Account::create([
    'code' => '1000',
    'name' => 'Assets',
    'type' => AccountType::ASSET->value,
    'subtype' => 'asset',
    'parent_id' => null, // Root account
]);
```

#### Creating a Sub-Account (Child Account)

[](#creating-a-sub-account-child-account)

Link it to its parent by passing the parent's `id`:

```
$bankAccount = Account::create([
    'code' => '1100',
    'name' => 'Seylan Bank A/C',
    'type' => AccountType::ASSET->value,
    'subtype' => 'current_asset',
    'parent_id' => $assetsParent->id, // Linked to the parent account
]);
```

---

Usage Scenarios
---------------

[](#usage-scenarios)

### 1. Creating and Posting a Journal Entry

[](#1-creating-and-posting-a-journal-entry)

Create a journal entry as a draft, validate it, and post it to the General Ledger.

```
use Nml\FinCore\Facades\FinCore;
use Nml\FinCore\Enums\JvType;

// Create the journal entry draft
$entry = FinCore::createJournalEntry([
    'date' => '2026-06-18',
    'reference' => 'INV-2026-0001',
    'type' => JvType::GENERAL->value,
    'description' => 'Credit sale invoice registration',
    'sbu_code' => 'COLOMBO_SBU',
    'journalable_type' => 'App\Models\Invoice', // Optional polymorphic model link
    'journalable_id' => 45,
    'lines' => [
        [
            'account_id' => 3, // Accounts Receivable (Asset)
            'type' => 'debit',
            'amount' => 50000.00,
            'description' => 'Debit A/R for customer invoice'
        ],
        [
            'account_id' => 20, // Sales Revenue (Revenue)
            'type' => 'credit',
            'amount' => 50000.00,
            'description' => 'Credit Sales Revenue'
        ]
    ]
]);

// Post to General Ledger (Performs balance matching & period lock checks)
try {
    $entry->post();
} catch (\Nml\FinCore\Exceptions\AccountingException $e) {
    // Handle validation errors (e.g., Unbalanced Debits/Credits or Closed Period)
    Log::error($e->getMessage());
}
```

#### 1.1. Creating a Manual Journal Voucher (JV)

[](#11-creating-a-manual-journal-voucher-jv)

For manual journal adjustments entered by accountants via a voucher UI, collect the form inputs (rows with Account, Type, Debit/Credit, and optional Notes) and post them directly:

```
use Nml\FinCore\Facades\FinCore;
use Nml\FinCore\Enums\JvType;

// Map the dynamic rows of a manual JV interface to the lines array:
$entry = FinCore::createJournalEntry([
    'date' => '2026-06-18',
    'reference' => 'JV-2026-0045',
    'type' => JvType::GENERAL->value,
    'description' => 'Manual adjustment for prepaid rent',
    'lines' => [
        [
            'account_id' => 12, // Prepaid Expense Account
            'type' => 'debit',
            'amount' => 15000.00, // Debit amount from Row 1
            'description' => 'Amortization of rent'
        ],
        [
            'account_id' => 25, // Rent Expense Account
            'type' => 'credit',
            'amount' => 15000.00, // Credit amount from Row 2
            'description' => 'Corresponding rent credit'
        ]
    ]
]);

// Post to ledger
$entry->post();
```

#### Parameter Details

[](#parameter-details)

- **`type`**: Indicates the category of the journal entry. Developers should use the `Nml\FinCore\Enums\JvType` enum:
    - `JvType::GENERAL->value` (`'general'`): Normal business transactions (e.g., sales invoices, supplier purchases, payments).
    - `JvType::ADJUSTMENT->value` (`'adjustment'`): End-of-period adjustments (e.g., depreciation, accruals, prepayments).
    - `JvType::CLOSING->value` (`'closing'`): Year-end closing entries to reset revenue/expense balances to the retained earnings account.
- **`sbu_code`**: Strategic Business Unit (Branch, Department, or Division) code. Tagging entries with this code enables department-wise or branch-wise filtering on all financial statements.
- **`journalable_type` &amp; `journalable_id`**: Polymorphic relationship columns that map this journal entry to the source document in the ERP (e.g., `App\Models\Invoice` or `App\Models\Payment`). This provides an audit trail back to the originating business transaction.

### 2. Generating a Trial Balance

[](#2-generating-a-trial-balance)

Generate a Trial Balance report within a specific date range or filter by SBU.

```
use Nml\FinCore\Facades\FinCore;

$trialBalance = FinCore::getTrialBalance(
    startDate: '2026-01-01',
    endDate: '2026-06-30',
    sbuCode: 'COLOMBO_SBU' // Optional SBU filter
);

// Format of the returned array:
// [
//     'accounts' => [
//          ['account' => AccountModel, 'debit' => 50000.00, 'credit' => 0.00, 'balance' => 50000.00],
//          ...
//      ],
//     'total_debits' => 50000.00,
//     'total_credits' => 50000.00,
//     'is_balanced' => true
// ]
```

### 3. Generating an Income Statement (Profit &amp; Loss)

[](#3-generating-an-income-statement-profit--loss)

Get the revenue, expense, and net income metrics for a specified period.

```
use Nml\FinCore\Facades\FinCore;

$incomeStatement = FinCore::getIncomeStatement(
    startDate: '2026-04-01',
    endDate: '2026-06-30'
);

$netIncome = $incomeStatement['net_income'];
$totalRevenue = $incomeStatement['revenue']['total'];
$totalExpenses = $incomeStatement['expenses']['total'];
```

### 4. Generating a Balance Sheet

[](#4-generating-a-balance-sheet)

Generate the statement of financial position as of a specific date.

```
use Nml\FinCore\Facades\FinCore;

$balanceSheet = FinCore::getBalanceSheet(
    date: '2026-06-18'
);

$assets = $balanceSheet['assets']['total'];
$liabilities = $balanceSheet['liabilities']['total'];
$equity = $balanceSheet['equity']['total'];
$isBalanced = $balanceSheet['is_balanced']; // Assets = Liabilities + Equity
```

### 5. Generating a General Ledger (Account Ledger)

[](#5-generating-a-general-ledger-account-ledger)

Generate a detailed General Ledger report for a specific account, supporting memory-efficient pagination for large datasets:

```
use Nml\FinCore\Facades\FinCore;

$ledger = FinCore::getGeneralLedger(
    accountId: 3, // Accounts Receivable
    startDate: '2026-01-01',
    endDate: '2026-06-30',
    sbuCode: 'COLOMBO_SBU',
    perPage: 50,  // Optional pagination limit
    page: 1       // Optional page number
);

foreach ($ledger['accounts'] as $accountReport) {
    $account = $accountReport['account']; // Account model instance
    $openingBalance = $accountReport['opening_balance'];
    $closingBalance = $accountReport['closing_balance'];

    // Pagination metadata (only returned if perPage is specified)
    $pagination = $accountReport['pagination'] ?? null;

    foreach ($accountReport['entries'] as $entry) {
        $entryNumber = $entry['entry_number'];
        $date = $entry['date'];
        $type = $entry['type']; // 'debit' or 'credit'
        $amount = $entry['amount'];
        $runningBalance = $entry['running_balance'];
    }
}
```

### 6. Generating a Cash Flow Statement

[](#6-generating-a-cash-flow-statement)

Generate a Cash Flow statement (indirect method) for a date range:

```
use Nml\FinCore\Facades\FinCore;

$cashFlow = FinCore::getCashFlowStatement(
    startDate: '2026-01-01',
    endDate: '2026-06-30'
);

$operatingTotal = $cashFlow['operating_activities']['total'];
$investingTotal = $cashFlow['investing_activities']['total'];
$financingTotal = $cashFlow['financing_activities']['total'];
$netIncreaseDecrease = $cashFlow['net_increase_decrease'];
$beginningCash = $cashFlow['beginning_cash'];
$endingCash = $cashFlow['ending_cash'];
$isReconciled = $cashFlow['is_reconciled']; // true if beginningCash + netIncreaseDecrease matches endingCash
```

### 7. Managing Entry Statuses

[](#7-managing-entry-statuses)

Transitions draft entries to submitted, and void or reject them:

```
// Submit for review
$entry->submit($userId);

// Reject and send back to draft
$entry->returnToDraft('Reason for rejection');

// Void posted journal entry
$entry->void();
```

### 8. Advanced: Tax/VAT &amp; Multi-Currency

[](#8-advanced-taxvat--multi-currency)

#### Registering a Tax Rate

[](#registering-a-tax-rate)

Create a tax rate mapping it to a general ledger account for tax postings:

```
use Nml\FinCore\Models\Tax;

$vatTax = Tax::create([
    'name' => 'VAT 15%',
    'code' => 'VAT-15',
    'rate' => 15.00,
    'account_id' => 15, // Output VAT Payable account ID
    'is_active' => true
]);
```

#### Creating a Multi-Currency Entry with Automatic Tax Calculation

[](#creating-a-multi-currency-entry-with-automatic-tax-calculation)

When creating a foreign currency transaction with tax:

1. Provide the `currency` (e.g. `'USD'`) and `exchange_rate` (e.g. `300.000000`).
2. Provide `fc_amount` (Foreign Currency amount) on lines. The system automatically computes the functional currency `amount = fc_amount * exchange_rate`.
3. Provide `tax_id` and `tax_behavior` (`'inclusive'` or `'exclusive'`). The system calculates the tax and automatically creates the corresponding tax ledger entry.

```
use Nml\FinCore\Facades\FinCore;
use Nml\FinCore\Enums\JvType;

$entry = FinCore::createJournalEntry([
    'date' => '2026-06-18',
    'reference' => 'TX-USD-001',
    'type' => JvType::GENERAL->value,
    'description' => 'Foreign sale invoice with tax',
    'currency' => 'USD',
    'exchange_rate' => 300.000000,
    'lines' => [
        [
            'account_id' => 3, // Accounts Receivable (Asset)
            'type' => 'debit',
            'fc_amount' => 115.00, // Total USD including tax
            'description' => 'A/R for foreign sale'
        ],
        [
            'account_id' => 20, // Sales Revenue (Revenue)
            'type' => 'credit',
            'fc_amount' => 115.00,
            'tax_id' => $vatTax->id,
            'tax_behavior' => 'inclusive', // Tax amount (15 USD / 4500 LKR) is extracted and posted to Output VAT
            'description' => 'Sales revenue inclusive of VAT'
        ]
    ]
]);

// Post to ledger. Validates balancing in both USD (115.00) and LKR (34500.00).
$entry->post();
```

### 9. Fixed Assets &amp; Depreciation

[](#9-fixed-assets--depreciation)

#### Registering a Fixed Asset

[](#registering-a-fixed-asset)

Register a fixed asset with purchase costs, depreciation parameters, and its target ledger accounts:

```
use Nml\FinCore\Models\FixedAsset;

$asset = FixedAsset::create([
    'name' => 'Delivery Van',
    'code' => 'FA-VAN-001',
    'purchase_date' => '2026-01-01',
    'purchase_cost' => 2400000.00,
    'salvage_value' => 400000.00,
    'useful_life_years' => 5,
    'depreciation_method' => 'straight_line', // 'straight_line' or 'reducing_balance'
    'depreciation_rate' => 20.00, // 20% annual rate
    'asset_account_id' => 5, // Motor Vehicles cost account
    'accumulated_depreciation_account_id' => 6, // Accumulated Depreciation account
    'depreciation_expense_account_id' => 25, // Depreciation Expense account
    'status' => 'active'
]);
```

#### Calculating and Posting Depreciation

[](#calculating-and-posting-depreciation)

Calculate monthly depreciation for a specific asset or all active assets, which automatically creates and posts the corresponding double-entry journal:

```
use Nml\FinCore\Facades\FinCore;

// 1. Calculate the monthly depreciation amount for a specific asset
$amount = FinCore::calculateMonthlyDepreciation($asset, '2026-06-30');

// 2. Post depreciation for a specific asset (Creates Debit Depreciation Expense, Credit Accumulated Depreciation)
$entry = FinCore::postDepreciationForAsset($asset->id, '2026-06-30');

// 3. Post monthly depreciation for all active fixed assets in bulk
$results = FinCore::postDepreciationForAllActiveAssets('2026-06-30');
```

---

### 10. Budgeting &amp; Variance Reporting

[](#10-budgeting--variance-reporting)

#### Setting Monthly Budget Targets

[](#setting-monthly-budget-targets)

Set a target monthly budget amount for a specific account and SBU:

```
use Nml\FinCore\Facades\FinCore;

$budget = FinCore::setMonthlyBudget(
    accountId: 25, // Depreciation Expense account
    year: 2026,
    month: 6,
    amount: 40000.00,
    sbuCode: 'COLOMBO_SBU' // Optional
);
```

#### Generating a Budget vs. Actual Variance Report

[](#generating-a-budget-vs-actual-variance-report)

Fetch target budgets, actual ledger movements, and variance details for a specific month:

```
use Nml\FinCore\Facades\FinCore;

$report = FinCore::getBudgetVarianceReport(
    year: 2026,
    month: 6,
    sbuCode: 'COLOMBO_SBU' // Optional
);

foreach ($report as $row) {
    $accountName = $row['account_name'];
    $budgetAmount = $row['budget_amount'];
    $actualAmount = $row['actual_amount'];
    $variance = $row['variance']; // Positive is Favorable, Negative is Unfavorable
    $variancePercentage = $row['variance_percentage'];
    $status = $row['status']; // 'Favorable' or 'Unfavorable'
}
```

---

### 11. Bank Reconciliation Matcher

[](#11-bank-reconciliation-matcher)

#### Starting a Bank Reconciliation Statement

[](#starting-a-bank-reconciliation-statement)

Create a bank reconciliation session for a specific bank ledger account, date, opening and closing balance:

```
use Nml\FinCore\Facades\FinCore;

$reconciliation = FinCore::createReconciliation(
    accountId: 1, // Bank Account
    statementDate: '2026-06-30',
    openingBalance: 150000.00,
    closingBalance: 185000.00
);
```

#### Fetching Unreconciled Ledger Lines

[](#fetching-unreconciled-ledger-lines)

Get all posted journal entry lines for this account that remain uncleared:

```
use Nml\FinCore\Facades\FinCore;

$unreconciled = FinCore::getUnreconciledLines(
    accountId: 1,
    endDate: '2026-06-30'
);
```

#### Running the Auto-Matcher

[](#running-the-auto-matcher)

Match uploaded bank statement transactions against unreconciled ledger entries automatically. The engine matches based on exact amount, type (debit/credit), and transaction date differences:

```
use Nml\FinCore\Facades\FinCore;

$statementTransactions = [
    ['date' => '2026-06-10', 'amount' => 5000.00, 'type' => 'debit', 'reference' => 'TXN-1'],
    ['date' => '2026-06-15', 'amount' => 30000.00, 'type' => 'credit', 'reference' => 'TXN-2'],
];

$results = FinCore::autoMatchStatementTransactions(
    reconciliationId: $reconciliation->id,
    statementTransactions: $statementTransactions
);

$matched = $results['matched'];     // List of successfully matched items
$unmatched = $results['unmatched']; // List of bank statement items not found in ledger
```

#### Manual Clear and Finalization

[](#manual-clear-and-finalization)

Reconcile lines manually or finalize the statement. Finalization requires the cleared balance to match the statement closing balance perfectly:

```
use Nml\FinCore\Facades\FinCore;

// Manually clear a ledger line
FinCore::manuallyClearLine($reconciliation->id, $lineId = 42, '2026-06-25');

// Finalize and close the reconciliation statement
FinCore::finalizeReconciliation($reconciliation->id);
```

---

### 12. Accounts Receivable (AR) &amp; Accounts Payable (AP) Ageing Reports

[](#12-accounts-receivable-ar--accounts-payable-ap-ageing-reports)

#### Recording Entries with Partner Metadata

[](#recording-entries-with-partner-metadata)

To track receivables and payables per customer or vendor, pass the polymorphic `partnerable` object and optional `due_date` when creating double-entry records:

```
use Nml\FinCore\Facades\FinCore;

// Create sales invoice entry with partner tracking
$entry = FinCore::createJournalEntry([
    'date' => '2026-06-01',
    'reference' => 'INV-2026-001',
    'lines' => [
        [
            'account_id' => 3, // Accounts Receivable (Receivable type)
            'type' => 'debit',
            'amount' => 120000.00,
            'due_date' => '2026-06-30',
            'partnerable_type' => 'App\Models\Customer',
            'partnerable_id' => 105,
            'description' => 'Sales invoice for Customer #105'
        ],
        [
            'account_id' => 20, // Sales Revenue
            'type' => 'credit',
            'amount' => 120000.00
        ]
    ]
]);
$entry->post();
```

#### Generating Ageing Reports

[](#generating-ageing-reports)

Fetch the ageing analysis report for all partners. The engine allocates credits against debits using a FIFO (First In, First Out) algorithm and classifies outstanding amounts into age buckets based on the `due_date`:

```
use Nml\FinCore\Facades\FinCore;

// 1. Get Accounts Receivable Ageing Report
$arReport = FinCore::getReceivablesAgeingReport('2026-06-30');

// 2. Get Accounts Payable Ageing Report
$apReport = FinCore::getPayablesAgeingReport('2026-06-30');

foreach ($arReport as $row) {
    $partnerName = $row['partner_name'];
    $totalOutstanding = $row['total_outstanding'];
    $current = $row['current'];       // Not due yet
    $bucket1 = $row['1_30'];          // 1 - 30 days overdue
    $bucket2 = $row['31_60'];         // 31 - 60 days overdue
    $bucket3 = $row['61_90'];         // 61 - 90 days overdue
    $bucket4 = $row['91_plus'];       // 91+ days overdue
}
```

---

### 13. Fiscal Year-End Closing Engine

[](#13-fiscal-year-end-closing-engine)

#### Closing a Fiscal Year

[](#closing-a-fiscal-year)

At the end of a fiscal year, close the year by calling `closeFiscalYear`. The engine automatically:

1. Calculates the net balance of all Revenue and Expense accounts for that year.
2. Generates and posts a closing journal entry on the last day of the fiscal year, transferring the net profit or loss to the specified Retained Earnings account.
3. Sets the balance of all Revenue and Expense accounts to zero relative to the next period.
4. Marks the `FiscalYear` and all its monthly `FiscalPeriod`s as closed, locking them against future postings or modifications.

```
use Nml\FinCore\Facades\FinCore;

// Close Fiscal Year ID 1, transferring net profit/loss to Retained Earnings Account ID 8
$closingEntry = FinCore::closeFiscalYear(
    fiscalYearId: 1,
    retainedEarningsAccountId: 8,
    userId: 1 // Optional user ID of the approver
);
```

---

### 14. Audit Trail / Activity Log

[](#14-audit-trail--activity-log)

#### Retrieving Audit History

[](#retrieving-audit-history)

The engine automatically logs all creations, updates, state changes (`submitted`, `posted`, `voided`), and deletions of journal entries. This includes capturing the actor's user ID, IP address, user agent, action type, and a JSON diff of modified attributes (`old_values` vs `new_values`).

Retrieve the history for any journal entry:

```
use Nml\FinCore\Facades\FinCore;

$logs = FinCore::getAuditHistory($journalEntryId);

foreach ($logs as $log) {
    Log::info("Action: " . $log->action);
    Log::info("Performed by User: " . $log->user_id);
    Log::info("IP: " . $log->ip_address);
    Log::info("User Agent: " . $log->user_agent);
    Log::info("Old State: ", (array) $log->old_values);
    Log::info("New State: ", (array) $log->new_values);
}
```

```

```

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance100

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

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

Every ~0 days

Total

7

Last Release

1d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/106421882?v=4)[premod suraweera](/maintainers/Premod1)[@Premod1](https://github.com/Premod1)

---

Tags

accounting-moduledouble-entrylaravelledger

### Embed Badge

![Health badge](/badges/nml-fincore/health.svg)

```
[![Health](https://phpackages.com/badges/nml-fincore/health.svg)](https://phpackages.com/packages/nml-fincore)
```

###  Alternatives

[kirschbaum-development/eloquent-power-joins

The Laravel magic applied to joins.

1.6k29.9M42](/packages/kirschbaum-development-eloquent-power-joins)[psalm/plugin-laravel

Psalm plugin for Laravel

3325.1M337](/packages/psalm-plugin-laravel)[yajra/laravel-oci8

Oracle DB driver for Laravel via OCI8

8723.1M23](/packages/yajra-laravel-oci8)[glushkovds/phpclickhouse-laravel

Adapter of the most popular library https://github.com/smi2/phpClickHouse to Laravel

2051.4M2](/packages/glushkovds-phpclickhouse-laravel)[clickbar/laravel-magellan

This package provides functionality for working with the postgis extension in Laravel.

436834.4k1](/packages/clickbar-laravel-magellan)[laravel-liberu/laravel-gedcom

A package that converts gedcom files to Eloquent models

782.5k1](/packages/laravel-liberu-laravel-gedcom)

PHPackages © 2026

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