How to use the Payfast onsite module with subscriptions in a new Laravel project
This article explains how to create a new Laravel project from scratch and then implement Payfast onsite payments and subscription billing.
In 2022 I created a Payfast Onsite Payments testable code library that enables subscription billing and published it to GitHub.
This library allows one to easily add subscriptions to a Laravel project and uses Jetstream views and Livewire.
To set up an entire system that does subscription billing can be quite a lot of work so the goal of this article is to document it from start to finish. For this deployment we're using Valet Linux.
Installation Steps
Deploy a new Laravel project:
cd ~/Code
laravel new test-payfast2
Secure the new project as Payfast won't accept form posts that aren't SSL:
valet secure test-payfast2
Change into the directory:
cd test-payfast2
Install Jetstream and set it up to use Livewire:
composer require laravel/jetstream
php artisan jetstream:install livewire
Set up NPM:
npm install
npm run build
Create a local database:
mysql -u root -p -e "CREATE DATABASE test_payfast2"
Edit the .env
file to ensure the correct database password is present.
Install the Github library:
composer require fintechsystems/payfast-onsite-subscriptions
Publish the configuration and views:
php artisan vendor:publish --provider="FintechSystems\PayFast\PayFastServiceProvider" --tag="config"
php artisan vendor:publish --provider="FintechSystems\PayFast\PayFastServiceProvider" --tag="views"
Migrate the database:
php artisan migrate
Configuration
Update the User
model to include the billable trait:
use FintechSystems\PayFast\Billable;
...
class User extends Authenticatable
{
...
use Billable;
Copy the following directives to the .env
file:
PAYFAST_TESTMODE=true
PAYFAST_DEBUG=true
PAYFAST_MERCHANT_ID_TEST=
PAYFAST_MERCHANT_KEY_TEST=
PAYFAST_PASSPHRASE_TEST=
PAYFAST_CALLBACK_URL_TEST=
PAYFAST_MERCHANT_ID=
PAYFAST_MERCHANT_KEY=
PAYFAST_PASSPHRASE=
PAYFAST_TRIAL_DAYS=30
Setup a Payfast sandbox account at https://sandbox.payfast.co.za and put your Payfast Merchant ID, Merchant Key, and Passphrase into the following parts of the environment file:
PAYFAST_MERCHANT_ID_TEST=
PAYFAST_MERCHANT_KEY_TEST=
PAYFAST_PASSPHRASE_TEST=
For local callback testing, we use Expose:
expose share --subdomain=payfast --server=eu-1 https://test-payfast2.test
The PAYFAST_CALLBACK_URL_TEST=
must match your Expose subdomain:
PAYFAST_CALLBACK_URL_TEST=https://payfast.eu-1.sharedwithexpose.com
Preparing the Views
Payfast needs to have it's Javascript injected in order to make it work. Futhermore we have our own Javascript that detects when the callback has finished and updates the UI.
Find app.blade.php
and add this code block to the head section:
@if (config('payfast.testmode') == true)
<!-- PayFast Test Mode -->
<script src="https://sandbox.payfast.co.za/onsite/engine.js" defer></script>
@else
<script src="https://www.payfast.co.za/onsite/engine.js" defer></script>
@endif
At the bottom of app.blade.php
add this below @livewirescripts
:
@stack('payfast-event-listener')
Adding the Billing Menu
Add a Billing menu in the Account Management sections of navigation-menu.blade.php
. You'll have to do this twice, once for non-response and once for responsive:
Non-responsive:
<!-- Account Management -->
...
<x-dropdown-link href="{{ route('profile.billing') }}">
{{ __('Billing') }}
</x-dropdown-link>
Responsive:
<!-- Account Management -->
...
<x-responsive-nav-link href="{{ route('profile.billing') }}" :active="request()->routeIs('profile.billing')">
{{ __('Billing') }}
</x-responsive-nav-link>
Adding a Subscription
Next register a new client and click "Billing" from the dropdown menu:
Subscriptions & Receipts
The Billing panel shows plans and a Subscribe button.
Complete the Payment
Click the Subscribe button and complete the payment.
Payment complete
New subscription created
Conclusion
Creating a Laravel Payfast module for subscription billing that has a UI was quite a lot of work and testing. For boilerplate I used the Laravel Cashier Paddle source code as a base because it already has foundation tests for subscription billing. This saved a ton of time because I only had to focus on the Payfast differences.
I wanted to do something to easily maintain testability since I find creating ecommerce solution requires a lot of mission critical testing in order work work properly. A lot of the tests were copied over but I had to eliminate some Paddle specific ones.
If you want to contribute to this library, add the following to composer.json:
"repositories": [
{
"type": "path",
"url": "../payfast-onsite-subscriptions"
}
],
Require the dev-main package instead of the release version:
composer require fintechsystems/payfast-onsite-subscriptions:dev-main
Troubleshooting
For Javascript troubleshooting turn on inspect element.
Uncaught (in promise) TypeError: window.payfast_do_onsite_payment is not a function
That means your app.blade.php
doesn't know about the Payfast Javascript @if @else @endif
block.
Uncaught (in promise) ReferenceError: refreshComponent is not defined
Check you have this line at the bottom of app.blade.php
:
@stack('payfast-event-listener')
Integration error
There was a problem loading the payment interface. Please contact the merchant about the integration error.
Make sure you have secured HTTPS
In Expose:
301 POST /payfast/notify
Your expose URL doesn't have https://
Contact the author: Eugene +27823096710 (call or WhatsApp)