PHPackages                             eugenefvdm/billing - 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. eugenefvdm/billing

ActiveLibrary[Payment Processing](/categories/payments)

eugenefvdm/billing
==================

A Laravel service provider and Livewire UI components for Payfast and EFT subscription billing

v1(6mo ago)034↓100%MITPHPPHP ^8.3CI passing

Since Nov 1Pushed 6mo agoCompare

[ Source](https://github.com/eugenefvdm/billing)[ Packagist](https://packagist.org/packages/eugenefvdm/billing)[ RSS](/packages/eugenefvdm-billing/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (4)Dependencies (12)Versions (6)Used By (0)

Payfast and EFT subscriptions billing
-------------------------------------

[](#payfast-and-eft-subscriptions-billing)

[![GitHub release (latest by date)](https://camo.githubusercontent.com/5457dba6d991ec802ef3ca92f70c68b32f6fd85352d45941c8af0b51a45a6019/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f657567656e656676646d2f62696c6c696e67)](https://camo.githubusercontent.com/5457dba6d991ec802ef3ca92f70c68b32f6fd85352d45941c8af0b51a45a6019/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f657567656e656676646d2f62696c6c696e67) [![Tests](https://github.com/eugenefvdm/billing/actions/workflows/tests.yml/badge.svg)](https://github.com/eugenefvdm/billing/actions/workflows/tests.yml/badge.svg)[![GitHub](https://camo.githubusercontent.com/de36396f1870211fa5946db6daf4245b79f5d64d4cb0faa5ab5c055b223483eb/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f657567656e656676646d2f62696c6c696e67)](https://camo.githubusercontent.com/de36396f1870211fa5946db6daf4245b79f5d64d4cb0faa5ab5c055b223483eb/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f657567656e656676646d2f62696c6c696e67)[![Downloads](https://camo.githubusercontent.com/2329713a3512bfaae15ed8d394ad7e339c4877267c6fe4b91e82d7f5f5622444/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f657567656e656676646d2f62696c6c696e672e737667)](https://packagist.org/packages/eugenefvdm/billing)

A billing package for Laravel to use for EFT and credit card payment using [Payfast Onsite Payments](https://developers.payfast.co.za/docs#onsite_payments). Includes UI components for [Livewire](https://livewire.laravel.com/).

Requirements:

- PHP 8.3
- Laravel 11.x or higher
- Livewire
- Optional: If you're using Payfast, a [Payfast account](https://www.payfast.co.za/registration)
- Optional: For testing Payfast, a free [Payfast sandbox account](https://sandbox.payfast.co.za/)

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

[](#installation)

Install the package via composer:

```
composer require eugenefvdm/billing
```

Config file and views
---------------------

[](#config-file-and-views)

Optional: Publish the config file:

```
php artisan vendor:publish --provider="Eugenefvdm\Billing\BillingServiceProvider" --tag="config"
```

Optional: Publish the views:

```
php artisan vendor:publish --provider="Eugenefvdm\Billing\BillingServiceProvider" --tag="views"
```

Add this to `/resources/css/app.css` to have the Tailwind CSS classes compiled properly:

```
@source '../../vendor/eugenefvdm/billing/resources/views/**/*.blade.php';
```

Setup
-----

[](#setup)

Add the `Billable()` trait to your user model.

```
use Eugenefvdm\Payfast\Billable;

class User extends Authenticatable
{
    use Billable;
```

In your head section of your HTML you'll need this snippet:
-----------------------------------------------------------

[](#in-your-head-section-of-your-html-youll-need-this-snippet)

```
@payfastScripts
```

If you're using Flux, add this to `/resources/views/partials/head.blade.php` say like below `@fluxAppearance`.

Migrations
----------

[](#migrations)

A migration is needed to create Customers, Orders, Receipts and Subscriptions tables:

```
php artisan migrate
```

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

[](#configuration)

See `config/billing.php`.

For testing you'll need:

```
PAYFAST_TEST_MODE=true
PAYFAST_MERCHANT_ID_TEST=
PAYFAST_MERCHANT_KEY_TEST=
PAYFAST_PASSPHRASE_TEST=
```

For live you'll need:

```
PAYFAST_MERCHANT_ID=
PAYFAST_MERCHANT_KEY=
PAYFAST_PASSPHRASE=
```

For localhost testing and to receive the Payfast ITN, you'll need `Ngrok` or `Expose`, and then add it's URL:

```
PAYFAST_TEST_MODE_ITN_URL=https://your-ngrok-url.ngrok-free.app
```

Here is an example Ngrok command to run when working on localhost:

```
ngrok http https://myapp.test --host-header=rewrite --domain=ngrok-supplied-url.ngrok-free.app
```

Pricing component
-----------------

[](#pricing-component)

To include the pricing component on a page, do this:

In your header:

```
@vite(['resources/css/app.css', 'resources/js/app.js'])
```

In your view:

```
@include('billing::components.pricing')
```

Livewire setup
--------------

[](#livewire-setup)

### Views

[](#views)

#### Flux

[](#flux)

`/resources/views/components/layouts/app/sidebar.blade.php`

```

    {{ __('Settings1') }}
    {{ __('Billing') }}

```

The Livewire views are modelled to blend into a [Laravel Jetstream](https://jetstream.laravel.com) user profile page.

#### Adding the subscriptions and receipts views

[](#adding-the-subscriptions-and-receipts-views)

When calling the Livewire component, you can override any [Payfast form field](https://developers.payfast.co.za/docs#step_1_form_fields) by specifying a `mergeFields` array.

Example modification Jetstream Livewire's `resources/views/profiles/show.php`:

Replace `$user->name` with your first name and last name fields.

```

    @livewire('subscriptions', ['mergeFields' => [
            'name_first' => $user->name,
            'name_last' => $user->name,
            'item_description' => 'Subscription to Online Service'
        ]] )

        @livewire('receipts')

```

Usage
-----

[](#usage)

### Examples

[](#examples)

- Generate a payment link
- Create an adhoc token optionally specifying the amount
- Cancel a subscription
- Update a card

```
use Eugenefvdm\Payfast\Facades\Payfast;

Route::get('/payment', function() {
    return Payfast::payment(5,'Order #1');
});

Route::get('/cancel-subscription', function() {
    return Payfast::cancelSubscription('73d2a218-695e-4bb5-9f62-383e53bef68f');
});

Route::get('/create-subscription', function() {
    return Payfast::createSubscription(
        Carbon::now()->addDay()->format('Y-m-d'),
        5, // Amount
        6 // Frequency (6 = annual, 3 = monthly)
    );
});

Route::get('/create-adhoc-token', function() {
    return Payfast::createAdhocToken(5);
});

Route::get('/fetch-subscription', function() {
    return Payfast::fetchSubscription('21189d52-12eb-4108-9c0e-53343c7ac692');
});

Route::get('/update-card', function() {
    return Payfast::updateCardLink('40ab3194-20f0-4814-8c89-4d2a6b5462ed');
});
```

Workflows
---------

[](#workflows)

### How to determine when a user's subscription ends

[](#how-to-determine-when-a-users-subscription-ends)

```
$user->subscription('default')->ends_at = [date in the past]
```

Testing
-------

[](#testing)

```
composer test
```

If you're developing against a project, you can use the `./switch` script to switch your project in and out of the repository.

This has the same effect as adding a repository and symlinking, and reversing it again when done.

Adding a repo manually instead of using `./switch`:

```
"repositories": [
        {
            "type": "path",
            "url": "../billing"
        }
],
```

Symlinking manually:

```
composer require fintechsystems/payfast-onsite-subscriptions:dev-main
```

If you want to test trials, use this one-liner to activate a billable user and a trial using say Tinker or [Tinkerwell](https://tinkerwell.app/):

```
$user = User::find(x)->createAsCustomer(['trial_ends_at' => now()->addDays(30)]);
```

EFT Billing
-----------

[](#eft-billing)

This package supports both **Card payments** (via Payfast onsite) and **EFT (bank transfer) payments** with automated invoice generation and reminders.

### How EFT Billing Works

[](#how-eft-billing-works)

1. **Subscription Creation**: Create an EFT subscription with a start date
2. **Forward Mechanism**: A scheduled command "forwards" the subscription by one billing period
3. **Invoice Generation**: When forwarding, an invoice is automatically created with a PDF
4. **Email Delivery**: The invoice PDF is emailed to the customer
5. **Overdue Reminders**: Automated reminders are sent at configurable intervals

### Configuration

[](#configuration-1)

Add these to your `.env`:

```
# Invoice Settings
INVOICE_DEFAULT_DUE_DAYS=7
INVOICE_PDF_PATH=invoices

# Overdue Notice Intervals (days after due date)
INVOICE_FIRST_OVERDUE_NOTICE=3
INVOICE_SECOND_OVERDUE_NOTICE=6
INVOICE_THIRD_OVERDUE_NOTICE=9
```

### Scheduled Commands

[](#scheduled-commands)

Add to your `routes/console.php`:

```
use Illuminate\Support\Facades\Schedule;

// Forward EFT subscriptions - creates invoices and moves subscription forward
Schedule::command('subscriptions:forward')->hourly();

// Send overdue reminders for unpaid EFT invoices
Schedule::command('invoices:check-overdue')->daily();
```

**Important**: The `subscriptions:forward` command will create invoices even when there are outstanding unpaid invoices. This is by design to ensure continuous billing cycles - subscriptions continue to advance and generate invoices regardless of payment status. Only manual resubscription via the UI will check for outstanding invoices before creating a new subscription.

### Creating an EFT Subscription

[](#creating-an-eft-subscription)

```
use Eugenefvdm\Billing\Enums\PaymentMethod;

// Create EFT subscription
$subscription = $user->subscriptions()->create([
    'name' => 'default',
    'type' => 'monthly', // or 'yearly'
    'payment_method' => PaymentMethod::Eft,
    'status' => 'ACTIVE',
    'ends_at' => now()->addMonth(),
]);

// First invoice is created immediately
// Forward command will create subsequent invoices automatically
```

### Accessing Invoices

[](#accessing-invoices)

```
// Get all invoices for a user
$invoices = $user->invoices;

// Find invoice by UUID (for guest viewing)
$invoice = $user->findInvoice($uuid);

// Check invoice status
if ($invoice->isPaid()) {
    // Invoice is paid
}

if ($invoice->isOverdue()) {
    $daysPastDue = $invoice->days_past_due;
}
```

### Guest Invoice Viewing

[](#guest-invoice-viewing)

Invoices can be viewed without authentication using their UUID:

```
https://yourapp.com/invoices/{uuid}
https://yourapp.com/invoices/{uuid}/download

```

These URLs are included in email notifications and are secure (UUID is hard to guess).

### Manual Invoice Operations

[](#manual-invoice-operations)

```
use Eugenefvdm\Billing\Services\InvoiceService;

// Manually create an invoice for a subscription
$invoice = InvoiceService::createSubscriptionInvoice($subscription);

// Generate PDF
InvoiceService::createPdf($invoice);

// Stream PDF to browser
InvoiceService::createPdf($invoice, stream: true);

// Mark as paid
$invoice->markAsPaid();
```

### Payment Instructions

[](#payment-instructions)

Update the payment instructions in:

- `resources/views/vendor/billing/pdf/invoice.blade.php`
- `resources/views/vendor/billing/mail/invoice-created.blade.php`
- `resources/views/vendor/billing/invoices/show.blade.php`

Replace `[Your Bank Name]`, `[Your Account Number]`, etc. with your actual banking details.

### Reminder System

[](#reminder-system)

The reminder system is **notification only** - it never changes subscription status automatically:

1. **First Notice** (3 days overdue by default): Friendly reminder
2. **Second Notice** (6 days overdue): Firmer tone
3. **Third Notice** (9 days overdue): Final notice

Reminders are only sent once per period. The system tracks when each reminder was sent.

### Testing EFT Flow

[](#testing-eft-flow)

```
// In Tinker or a test
$user = User::first();

// Create EFT subscription
$subscription = $user->subscriptions()->create([
    'type' => 'monthly',
    'payment_method' => \Eugenefvdm\Billing\Enums\PaymentMethod::Eft,
    'status' => 'ACTIVE',
    'ends_at' => now()->subDay(), // Period already ended
]);

// Run forward command
php artisan subscriptions:forward

// Check that invoice was created
$user->invoices; // Should have 1 invoice

// Check that subscription moved forward
$subscription->refresh();
$subscription->ends_at; // Should be ~1 month from now
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Credits
-------

[](#credits)

- [Eugene van der Merwe](https://github.com/eugenevdm) - Package author and maintainer
- [Taylor Otwell](https://github.com/taylorotwell) - Portions of this package were derived from [Laravel Cashier](https://github.com/laravel/cashier-paddle), particularly the Billable trait, subscription management, and customer handling patterns

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

This package includes code derived from Laravel Cashier (Paddle) which is also licensed under the MIT License. Copyright (c) Taylor Otwell.

###  Health Score

37

—

LowBetter than 83% of packages

Maintenance68

Regular maintenance activity

Popularity9

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity54

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 ~1 days

Total

5

Last Release

186d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/932743c076390240ecdefe58dc5f81b60cb5fe9ed38b3bead0541f640a7bb2a8?d=identicon)[eugenevdm](/maintainers/eugenevdm)

---

Top Contributors

[![eugenefvdm](https://avatars.githubusercontent.com/u/1836436?v=4)](https://github.com/eugenefvdm "eugenefvdm (42 commits)")

---

Tags

phplaravellivewiresubscriptionsinvoicepayment gatewaypayfastcredit-cardsubscription billingrecurring billingpdf-invoicesSouth Africaeft

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/eugenefvdm-billing/health.svg)

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

###  Alternatives

[laraveldaily/laravel-invoices

Missing invoices for Laravel

1.5k1.3M4](/packages/laraveldaily-laravel-invoices)[chargebee/chargebee-php

ChargeBee API client implementation for PHP

768.0M9](/packages/chargebee-chargebee-php)[mollie/laravel-cashier-mollie

Laravel Cashier provides an expressive, fluent interface to Mollie's subscription billing services.

172155.4k1](/packages/mollie-laravel-cashier-mollie)[lemonsqueezy/laravel

A package to easily integrate your Laravel application with Lemon Squeezy.

58596.1k](/packages/lemonsqueezy-laravel)[omalizadeh/laravel-multi-payment

A driver-based laravel package for online payments via multiple gateways

491.1k](/packages/omalizadeh-laravel-multi-payment)

PHPackages © 2026

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