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)

Updated: 1 year ago

© 2022 Eugene's Blog