PHPackages                             3mad/fee-collection - 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. [Payment Processing](/categories/payments)
4. /
5. 3mad/fee-collection

ActiveLibrary[Payment Processing](/categories/payments)

3mad/fee-collection
===================

Laravel package for fee collection with upcoming payments, invoices, receipts, wallet balance tracking, and optional PDF documents.

1.1(1mo ago)12MITPHPPHP ^8.2

Since May 6Pushed 1mo agoCompare

[ Source](https://github.com/3mad0o/fee-collection)[ Packagist](https://packagist.org/packages/3mad/fee-collection)[ RSS](/packages/3mad-fee-collection/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (1)Dependencies (3)Versions (3)Used By (0)

 [![FeeCollection logo](https://camo.githubusercontent.com/675d04bf6be742d1966aaf3bca44c93ae14a98b57300700a8fb0d845cc4bb32d/68747470733a2f2f336d6164306f2e6769746875622e696f2f6665652d636f6c6c656374696f6e2d646f63756d656e746174696f6e2f6c6f676f2e737667)](https://camo.githubusercontent.com/675d04bf6be742d1966aaf3bca44c93ae14a98b57300700a8fb0d845cc4bb32d/68747470733a2f2f336d6164306f2e6769746875622e696f2f6665652d636f6c6c656374696f6e2d646f63756d656e746174696f6e2f6c6f676f2e737667)

FeeCollection
=============

[](#feecollection)

 Laravel fee workflow package for scheduled payments, invoices, receipts, credit notes, statement history, wallet balances, and optional PDF documents.

FeeCollection is a Laravel package for fee workflows:

- register upcoming payments
- create invoices and receipts
- create manual credit notes
- split payments
- detect overdue payments and generate due invoices
- keep account statements recalculated
- track one wallet balance row per payable model
- optionally generate/store invoice/receipt PDFs

See the documentation below, or browse the full documentation site:

Table of Contents
-----------------

[](#table-of-contents)

- [Requirements](#requirements)
- [Installation](#installation)
- [Getting Started](#getting-started)
- [Configuration](#configuration)
- [Core Concepts](#core-concepts)
- [Usage Examples](#usage-examples)
- [PDF Documents](#pdf-documents)
- [Events](#events)
- [API Quick Reference](#api-quick-reference)
- [What Gets Stored](#what-gets-stored)
- [License](#license)

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

[](#requirements)

- PHP 8.3+
- Laravel 13+

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

[](#installation)

Install package in your Laravel app:

```
composer require 3mad/fee-collection
```

If your app does not auto-discover providers, register:

```
Emad\FeeCollection\Providers\FeeCollectionServiceProvider::class
```

For PDF generation support (optional):

```
composer require barryvdh/laravel-dompdf
```

Publish Package Files
---------------------

[](#publish-package-files)

Publish config:

```
php artisan vendor:publish --provider="Emad\FeeCollection\Providers\FeeCollectionServiceProvider" --tag=config
```

Publish default PDF blade views:

```
php artisan vendor:publish --provider="Emad\FeeCollection\Providers\FeeCollectionServiceProvider" --tag=views
```

Published views path:

`resources/views/vendor/fee-collection/pdf`

Migrations
----------

[](#migrations)

Run migrations:

```
php artisan migrate
```

This creates:

- `upcoming_payments`
- `account_statements`
- `account_statement_upcoming_payments`
- `wallet_transactions` (single row per walletable with current balance)

Getting Started
---------------

[](#getting-started)

### Setup Model

[](#setup-model)

Add `UseFeeable` trait to any Eloquent model (for example `User`):

```
use Emad\FeeCollection\Traits\UseFeeable;

class User extends Model
{
    use UseFeeable;
}
```

After this, the model can register payments, create receipts, generate due invoices, query statements, and read its wallet balance.

Configuration
-------------

[](#configuration)

File: `config/fee_collection.php`

```
return [
    'invoice_prefix' => 'I-',
    'invoice_suffix' => '',
    'receipt_prefix' => 'R-',
    'receipt_suffix' => '',
    'credit_note_prefix' => 'CN-',
    'credit_note_suffix' => '',
    'auto_invoice_on_receipt' => true,
    'invoice_view' => 'fee-collection::pdf.invoice',
    'receipt_view' => 'fee-collection::pdf.receipt',
    'credit_note_view' => 'fee-collection::pdf.invoice',
    'pdf' => [
        'enabled' => env('FEE_COLLECTION_PDF_ENABLED', true),
        'paper' => 'a4',
        'orientation' => 'portrait',
        'disk' => env('FEE_COLLECTION_PDF_DISK', 'public'),
        'path' => env('FEE_COLLECTION_PDF_PATH', 'fee-collection/documents'),
    ],
];
```

### Notes

[](#notes)

- `account_statements.number` stores numeric value only.
- Prefix/suffix are added on retrieval via `formatted_number`.
- If `pdf.enabled = true`, generated PDF path is saved in `account_statements.document`.
- `auto_invoice_on_receipt` may be overridden per receipt call.
- Credit notes are always manual. Splitting a payment never creates a credit note automatically.

Core Concepts
-------------

[](#core-concepts)

FeeCollection is built around payable models, upcoming payments, account statements, and wallet balances.

### Payable Models

[](#payable-models)

Any Eloquent model using `UseFeeable` can own fee workflows. Typical examples include `User`, `Student`, `Customer`, and `Tenant`.

The trait adds methods for payment registration, statement access, wallet balance checks, overdue detection, and due invoice generation.

### Upcoming Payments

[](#upcoming-payments)

An upcoming payment represents a scheduled amount due on a future date.

Upcoming payments can be:

- registered from a payable model
- invoiced manually
- receipted manually
- split into child payments
- detected as overdue
- invoiced automatically when due

### Account Statements

[](#account-statements)

Account statements represent financial documents and history entries such as invoices, receipts, and credit notes.

Statements include a `status` field for reporting and filtering.

### Wallet Balance

[](#wallet-balance)

The package tracks one wallet balance row per payable model in `wallet_transactions`.

```
$balance = $user->balance();
```

### Credit Notes

[](#credit-notes)

Credit notes are created from invoices. A credit note:

- references the original invoice through `reference_id`
- uses a negative `amount`
- changes the original invoice status to `credited`

Credit notes are not created automatically during payment splitting.

### Voided Invoices

[](#voided-invoices)

A voided invoice is excluded from balance recalculation.

Use voiding only for invoices that should be killed internally before customer settlement.

Usage Examples
--------------

[](#usage-examples)

### 1) Create receipt, then register payments (wallet consumption flow)

[](#1-create-receipt-then-register-payments-wallet-consumption-flow)

```
$user = User::factory()->create();

$user->createReceipt(1000, 'Initial credit', now());

$user->registerPayment(100, now()->addDays(1));
$user->registerPayment(100, now()->addDays(2));
$user->registerPayment(100, now()->addDays(3));
```

If wallet balance is enough, registered payments can be invoiced automatically.

Disable receipt-driven invoice generation per call:

```
$user->createReceipt(1000, 'Initial credit', now(), autoInvoice: false);
```

### 2) Manual invoice and receipt on one upcoming payment

[](#2-manual-invoice-and-receipt-on-one-upcoming-payment)

```
$payment = $user->registerPayment(100, now()->addDays(10));
$payment->createInvoice('Test Invoice', now());
$payment->createReceipt('Test Receipt', now());
```

### 3) Split an upcoming payment

[](#3-split-an-upcoming-payment)

```
$payment = $user->registerPayment(1000, now()->addDays(1));

$children = $payment->split([
    ['amount' => 100, 'due_date' => now()->addDays(2)],
    ['amount' => 100, 'due_date' => now()->addDays(3)],
    ['amount' => 800, 'due_date' => now()->addDays(4)],
]);
```

If the original payment already had an invoice, create the credit note manually:

```
$invoice = $payment->invoice;

$children = $payment->split([
    ['amount' => 500, 'due_date' => now()->addMonth()],
    ['amount' => 500, 'due_date' => now()->addMonths(2)],
]);

$invoice->createCreditNote('Customer requested installment split', now());
```

### 4) Create a credit note

[](#4-create-a-credit-note)

```
$payment = $user->registerPayment(1000, now()->addDay());
$invoice = $payment->createInvoice('Original invoice', now());

$creditNote = $invoice->createCreditNote('Invoice cancelled', now());
```

Credit notes:

- can only be created from invoices
- reference the original invoice through `reference_id`
- use a negative `amount`
- move the original invoice status to `credited`

### 5) Void an invoice

[](#5-void-an-invoice)

```
$payment = $user->registerPayment(1000, now()->addDay());
$invoice = $payment->createInvoice('Draft invoice', now());

$invoice->void('Created by mistake');
```

Voided invoices are excluded from balance recalculation. Use this only for invoices that should be killed internally before customer settlement.

### 6) Detect overdue payments

[](#6-detect-overdue-payments)

```
if ($payment->isOverdue()) {
    // notify the customer
}

$overduePayments = $user->overduePayments();
```

An overdue payment has a due date before today, still has remaining amount, and has no linked receipt.

### 7) Generate invoices due today

[](#7-generate-invoices-due-today)

```
$invoices = $user->generateDueInvoices();
```

Scheduler example:

```
use App\Models\User;

$schedule->call(function () {
    User::each(fn (User $user) => $user->generateDueInvoices());
})->daily();
```

### 8) Statement status

[](#8-statement-status)

Statements include a `status` field for filtering/reporting:

- `issued`
- `paid`
- `overdue`
- `credited`
- `voided`

```
$paidStatements = $user->accountStatements()->where('status', 'paid')->get();
$creditedStatements = $user->accountStatements()->where('status', 'credited')->get();
```

Status is a reporting helper. Balances are still calculated from statement debit/credit values, excluding voided invoices.

### 9) List statements and check wallet balance

[](#9-list-statements-and-check-wallet-balance)

```
$statements = $user->accountStatements()->orderByDesc('date')->get();
$balance = $user->balance();
```

Events
------

[](#events)

The package dispatches these events after successful changes:

- `Emad\FeeCollection\Events\InvoiceCreated`
- `Emad\FeeCollection\Events\ReceiptCreated`
- `Emad\FeeCollection\Events\CreditNoteCreated`
- `Emad\FeeCollection\Events\PaymentOverdue`
- `Emad\FeeCollection\Events\PaymentSplit`
- `Emad\FeeCollection\Events\InvoiceVoided`

Common uses include customer notifications, internal audit logs, reporting updates, accounting exports, and webhook dispatching.

PDF Documents
-------------

[](#pdf-documents)

FeeCollection can generate and store PDF documents for invoices, receipts, and credit notes.

Install DomPDF support:

```
composer require barryvdh/laravel-dompdf
```

PDF generation is controlled by `config/fee_collection.php`:

```
'pdf' => [
    'enabled' => env('FEE_COLLECTION_PDF_ENABLED', true),
    'paper' => 'a4',
    'orientation' => 'portrait',
    'disk' => env('FEE_COLLECTION_PDF_DISK', 'public'),
    'path' => env('FEE_COLLECTION_PDF_PATH', 'fee-collection/documents'),
],
```

Useful environment variables:

```
FEE_COLLECTION_PDF_ENABLED=true
FEE_COLLECTION_PDF_DISK=public
FEE_COLLECTION_PDF_PATH=fee-collection/documents

```

Configure the Blade views used for generated documents:

```
'invoice_view' => 'fee-collection::pdf.invoice',
'receipt_view' => 'fee-collection::pdf.receipt',
'credit_note_view' => 'fee-collection::pdf.invoice',
```

### Generate PDF manually

[](#generate-pdf-manually)

```
$statement = $user->accountStatements()->latest('id')->first();
$pdf = $statement->toPdf();

return $pdf->download($statement->formatted_number . '.pdf');
```

When PDF generation is enabled, the generated PDF path is saved in `account_statements.document`.

API Quick Reference
-------------------

[](#api-quick-reference)

### Payable model methods

[](#payable-model-methods)

```
$user->createReceipt(1000, 'Initial credit', now());
$user->createReceipt(1000, 'Initial credit', now(), autoInvoice: false);

$payment = $user->registerPayment(100, now()->addDays(10));

$overduePayments = $user->overduePayments();
$invoices = $user->generateDueInvoices();
$statements = $user->accountStatements()->orderByDesc('date')->get();
$balance = $user->balance();
```

### Upcoming payment methods

[](#upcoming-payment-methods)

```
$invoice = $payment->createInvoice('Original invoice', now());
$payment->createReceipt('Test Receipt', now());

$children = $payment->split([
    ['amount' => 500, 'due_date' => now()->addMonth()],
    ['amount' => 500, 'due_date' => now()->addMonths(2)],
]);

if ($payment->isOverdue()) {
    // notify the customer
}
```

### Statement methods

[](#statement-methods)

```
$creditNote = $invoice->createCreditNote('Invoice cancelled', now());
$invoice->void('Created by mistake');
$pdf = $statement->toPdf();
```

What Gets Stored
----------------

[](#what-gets-stored)

- `account_statements.number`: numeric sequence (no prefix/suffix)
- `account_statements.document`: stored PDF relative path (when enabled)
- `account_statements.reference_id`: original invoice for credit notes
- `account_statements.status`: reporting status
- `account_statements.voided_at`: timestamp for voided invoices
- `account_statements.void_reason`: reason for voiding
- `wallet_transactions.balance`: current wallet balance for the payable

License
-------

[](#license)

MIT

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance94

Actively maintained with recent releases

Popularity5

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% 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

Every ~3 days

Total

2

Last Release

31d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/07241ee96de153a8304e7fa43260c29e8455c9915eb5d99464d5e59058d57eb8?d=identicon)[3mad](/maintainers/3mad)

---

Top Contributors

[![3mad0o](https://avatars.githubusercontent.com/u/87212157?v=4)](https://github.com/3mad0o "3mad0o (3 commits)")

### Embed Badge

![Health badge](/badges/3mad-fee-collection/health.svg)

```
[![Health](https://phpackages.com/badges/3mad-fee-collection/health.svg)](https://phpackages.com/packages/3mad-fee-collection)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

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

Larastan - Discover bugs in your code without running it. A phpstan/phpstan extension for Laravel

6.4k51.0M7.4k](/packages/larastan-larastan)[laravel/ai

The official AI SDK for Laravel.

9782.1M153](/packages/laravel-ai)[spatie/laravel-health

Monitor the health of a Laravel application

88011.3M149](/packages/spatie-laravel-health)[pressbooks/pressbooks

Pressbooks is an open source book publishing tool built on a WordPress multisite platform. Pressbooks outputs books in multiple formats, including PDF, EPUB, web, and a variety of XML flavours, using a theming/templating system, driven by CSS.

45344.0k1](/packages/pressbooks-pressbooks)[api-platform/laravel

API Platform support for Laravel

59156.3k10](/packages/api-platform-laravel)

PHPackages © 2026

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