-
Notifications
You must be signed in to change notification settings - Fork 19
Setup SDK on CodeIgniter Project.
Create a .env
file as the package does not acknowledge the env
file that ships with CodeIgniter 4. Ensure the following keys/value pairs are present in the .env file.
SECRET_KEY=FLWSECK_TEST-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-X
PUBLIC_KEY=FLWPUBK_TEST-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-X
ENCRYPTION_KEY=FLWSECK_TESTXXXXXXXXXX
ENV=staging
Install the Software Development Kit via the command.
composer require flutterwavedev/flutterwave-v3
Create a Controller to initiate a Payment in your App\Controllers
directory. If you do not wish to store your keys in a .env file. you can review the wiki on how to setup custom configurations here.
<?php
# file path: app/Controllers/PaymentController.php
namespace App\Controllers;
use App\ThirdParty\Flutterwave\Config; # use if you do not wish to use the .env file.
use App\ThirdParty\Flutterwave\EventHandler;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Flutterwave\Flutterwave;
use Flutterwave\Util\Currency;
use Psr\Log\LoggerInterface;
class PaymentController extends BaseController
{
public function initController(
RequestInterface $request,
ResponseInterface $response,
LoggerInterface $logger
) {
parent::initController($request, $response, $logger);
if (! $this->request->isSecure()) {
$this->forceHTTPS();
}
Flutterwave::bootstrap(); # To read the environment variables in .env and load other flutterwave services.
}
# Your business logic.
}
Ensure all the data fields are passed to the payload builder before initiating the payment.
<?php
# file path: app/Controllers/PaymentController.php
namespace App\Controllers;
use App\ThirdParty\Flutterwave\Config; # use if you do not wish to use the .env file.
use App\ThirdParty\Flutterwave\EventHandler;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Flutterwave\Flutterwave;
use Flutterwave\Util\Currency;
use Psr\Log\LoggerInterface;
class PaymentController extends BaseController
{
public function initController( ... ) {
...
}
public function index()
{
$session = \Config\Services::session();
# prefix can be company initials.
$transactionPrefix = "FLW_";
$overrideRef = false;
$redirect_url = base_url('callback');
$data = [
'amount' => 2000,
'payment_options' => 'card,ussd,mobilemoneyghana',
'currency' => Currency::NGN,
'logo' => '',
'title' => 'Payment Sample',
'country' => 'NG',
'email' => '[email protected]',
'firstname' => 'john',
'lastname' => 'doe',
'description' => 'Payment for some rando',
'phonenumber' => '+2348000000000',
'pay_button_text' => 'Pay Now',
'redirect_url' => $redirect_url
];
# TODO: validate data input.
$payment = new Flutterwave( $transactionPrefix, $overrideRef);
$payment
->eventHandler(new EventHandler())
->setAmount($data['amount'])
->setPaymentOptions($data['payment_options']) // value can be a card, account or both
->setDescription($data['description'])
->setLogo($data['logo'])
->setTitle($data['title'])
->setCountry($data['country'])
->setCurrency($data['currency'])
->setEmail($data['email'])
->setFirstname($data['firstname'])
->setLastname($data['lastname'])
->setPhoneNumber($data['phonenumber'])
->setPayButtonText($data['pay_button_text'])
->setRedirectUrl( $data['redirect_url'])
// ->setMetaData(array('metaname' => 'SomeDataName', 'metavalue' => 'SomeValue')) // can be called multiple times. Uncomment this to add meta datas
// ->setMetaData(array('metaname' => 'SomeOtherDataName', 'metavalue' => 'SomeOtherValue')) // can be called multiple times. Uncomment this to add meta datas
->initialize();
$session->set([ 'p' => $payment ]);
}
}
<?php
# file path: app/Controllers/PaymentController.php
namespace App\Controllers;
use App\ThirdParty\Flutterwave\Config; # use if you do not wish to use the .env file.
use App\ThirdParty\Flutterwave\EventHandler;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Flutterwave\Flutterwave;
use Flutterwave\Util\Currency;
use Psr\Log\LoggerInterface;
class PaymentController extends BaseController
{
public function initController( ... ) {
...
}
public function index()
{
...
}
public function callback() {
# if it is not a get request deny.
if(!$this->request->is('get')) {
return 'Unauthorized access';
}
$session = \Config\Services::session();
if( $session->get( 'p' ) === null ) {
return redirect()->to( site_url() );
}
$tx_ref = $this->request->getVar('tx_ref');
$transaction_id = $this->request->getVar('transaction_id');
$payment = $session->get('p');
if( $this->request->getVar('cancelled') !== null && $this->request->getVar('cancelled') === 'cancelled' ) {
$payment
->eventHandler( new EventHandler() )
->paymentCanceled($tx_ref);
}
$payment
->eventHandler( new EventHandler() )
->requeryTransaction( $transaction_id );
}
public function webhook() {
# if it is not a post request deny.
if(!$this->request->is('post')) {
return 'Unauthorized access';
}
}
}
The handler would handler payment events. you are to add actions that would be triggered on each event.
<?php
# file path: app/ThirdParty/Flutterwave/EventHandler.php
namespace App\ThirdParty\Flutterwave;
use Flutterwave\EventHandlers\EventHandlerInterface;
class EventHandler implements EventHandlerInterface
{
/**
* This is called when the Rave class is initialized
* */
public function onInit($initializationData): void
{
// Save the transaction to your DB.
}
/**
* This is called only when a transaction is successful
* */
public function onSuccessful($transactionData): void
{
// Get the transaction from your DB using the transaction reference (txref)
// Check if you have previously given value for the transaction. If you have, redirect to your successpage else, continue
// Comfirm that the transaction is successful
// Confirm that the chargecode is 00 or 0
// Confirm that the currency on your db transaction is equal to the returned currency
// Confirm that the db transaction amount is equal to the returned amount
// Update the db transaction record (includeing parameters that didn't exist before the transaction is completed. for audit purpose)
// Give value for the transaction
// Update the transaction to note that you have given value for the transaction
// You can also redirect to your success page from here
if ($transactionData->status === 'successful') {
$session = \Config\Services::session();
$currency = $session->get('p')->getCurrency();
$amount = $session->get('p')->getAmount();
if ($transactionData->currency === $currency && floatval( $transactionData->amount ) === floatval( $amount ) ) {
# TODO: replace this a custom action.
echo "Successful! replace this with an action on Line:".__LINE__. " in ". __CLASS__;
$session->destroy();
}
if ($transactionData->currency === $currency && floatval( $transactionData->amount ) < floatval( $amount ) ) {
# TODO: replace this a custom action.
echo "Partial Payment Made ! replace this with an action on Line:".__LINE__. " in ". __CLASS__;
$session->destroy();
}
if ($transactionData->currency !== $currency && floatval( $transactionData->amount ) === floatval( $amount ) ) {
# TODO: replace this a custom action.
echo "Currency mismatch. please look into it ! replace this with an action on Line:".__LINE__. " in ". __CLASS__;
$session->destroy();
}
} else {
$this->onFailure($transactionData);
}
}
/**
* This is called only when a transaction failed
* */
public function onFailure($transactionData): void
{
$session = \Config\Services::session();
// Get the transaction from your DB using the transaction reference (txref)
// Update the db transaction record (includeing parameters that didn't exist before the transaction is completed. for audit purpose)
// You can also redirect to your failure page from here.
# TODO: replace this a custom action.
echo "Payment failed ! replace this with an action on Line:".__LINE__. " in ". __CLASS__;
$session->destroy();
}
/**
* This is called when a transaction is requeryed from the payment gateway
* */
public function onRequery($transactionReference): void
{
# TODO: replace this a custom action.
}
/**
* This is called a transaction requery returns with an error
* */
public function onRequeryError($requeryResponse): void
{
}
/**
* This is called when a transaction is canceled by the user
* */
public function onCancel($transactionReference): void
{
# TODO: replace this a custom action.
echo "Payment was cancelled ! replace this with an action.";
$session->destroy();
}
/**
* This is called when a transaction doesn't return with a success or a failure response. This can be a timedout transaction on the Rave server or an abandoned transaction by the customer.
* */
public function onTimeout($transactionReference, $data): void
{
# trigger webhook notification from Flutterwave.
$service = new Flutterwave\Service\Transaction();
$service->resendFailedHooks( $data->id );
header('Location: ' . base_url());
}
}
After the Home route add the /pay
and callback
routes with their respective controllers and methods.
# file path: app/Config/Routes.php
/*
* --------------------------------------------------------------------
* Route Definitions
* --------------------------------------------------------------------
*/
// We get a performance increase by specifying the default
// route since we don't have to scan directories.
$routes->get('/', 'Home::index');
+ $routes->get('/pay', 'PaymentController::index');
+ $routes->get('/callback', 'PaymentController::callback');
Run the application with this command.
php spark serve
Go to https://{base_url}/pay
and the modal should load automatically.
Use test cards here to test.