kabangi / mpesa-laravel
Laravel M-Pesa API implementation
v1.0.4
2018-03-06 09:14 UTC
Requires
- php: >=5.6.0
- illuminate/support: ^5.2
- kabangi/mpesa: >=3.0.1
Requires (Dev)
- mockery/mockery: dev-master
- phpunit/phpunit: ~5.7|~6.2
This package is not auto-updated.
Last update: 2025-04-13 07:56:48 UTC
README
This is a wrapper implementation from this package https://github.com/Kabangi/mpesa
Installation
- In order to install mpesalaravel, just add the following to your composer.json. Then run
composer update
:
"kabangi/mpesa-laravel": "^1.0.4",
- Open your
config/app.php
and add the following to theproviders
array:
Kabangi\MpesaLaravel\MpesaServiceProvider::class,
- In the same
config/app.php
and add the following to thealiases
array:
'MPESA' => Kabangi\MpesaLaravel\Facades\Mpesa::class,
- Run the command below to publish the package config file
config/mpesa.php
:
php artisan vendor:publish
Usage
<?php namespace YOURNAMESPACE; use Illuminate\Http\Request; use MPESA; use Checkout; use Invoice; class CheckoutController extends Controller { /** * @param Request $request * @return mixed */ public function checkout(Request $request){ $rules = [ 'invoice_id' => 'required', ]; $validator = Validator::make($request->all(),$rules); if ($validator->fails()) { return $validator->errors(); } try { if(!$request->has('invoice_id')){ // If no invoice create invoice $data = []; $invoice = $this->createInvoice($data); }else{ $invoice = Invoice::findOrFail($request->input('invoice_id')); } if((bool) $invoice->paid === true){ abort(403,'You have already made a payment for this invoice. Thank you!'); } // Prevent double checkout. $previousCheckoutAttempt = Checkout::where('invoice_id',$invoice->id) ->where('user_id',$request->input('user_id')) ->where('status','INPROGRESS') ->orWhere(function ($query) use ($invoice) { $query->where('status','PROCESSED') ->where('user_id',$request->input('user_id')) ->where('invoice_id',$invoice->id); }) ->orderBy('created_at', 'desc') ->first(); if($previousCheckoutAttempt){ try{ $response = $this->fetchCheckoutStatus($previousCheckoutAttempt->request_id); $payment = Payment::where('checkout_id',$previousCheckoutAttempt->id)->first(); if($response->status == 'INPROGRESS' || $response->status == 'PROCESSED'){ // TODO: if no payment is reflected on the DB should invoke the processing of that payment. // since it means there is a delay to us receiving the callback. $errorMsg = $response->status == 'INPROGRESS' ? 'You have a checkout request in progress' : 'You have already made a payment for this invoice. Thank you!'; abort(403,$errorMsg); } }catch(\Exception $e){ abort(403,$e->getMessage()); } } $mpResponse = MPESA::STKPush([ 'amount' => intval($request->input('amount')), 'phoneNumber' => str_replace('+','',$phone), 'accountReference' => '12', 'transactionDesc' => "Test Transaction" ]); // TODO: Handle both errors and response errors from our end if(!empty($mpResponse->CheckoutRequestID)){ $checkout = null; // save to db. $data = [ 'request_id' => $mpResponse->CheckoutRequestID, 'invoice_id' => $invoice->id, 'status' => "INPROGRESS", 'user_id' => $request->input('user_id') ]; $checkout = Checkout::create($data); $response = $checkout; }else{ return abort(503,"Something went wrong. Please try again."); } return $response; }catch(\Exception $e){ throw $e; } } private function fetchCheckoutStatus($requestId){ try{ $checkout = Checkout::where('request_id',$requestId)->firstOrFail(); if($checkout->status !== 'INPROGRESS'){ return $checkout; } $mpRes = MPESA::STKStatus([ 'checkoutRequestID' => $requestId ]); Slack::post(json_encode($mpRes)); if(!isset($mpRes->ResultCode)){ // TODO: Figure out what to do. Meanwhile just wait until the // server responds // if(!empty($mpRes->errorCode)){ // $checkout->status = 'CANCELLED'; // $checkout->save(); // } return $checkout; }else{ // Update the local persisted checkouts $resultCode = intval($mpRes->ResultCode); switch($resultCode){ case 0: $checkout->status = 'PROCESSED'; $this->processMPESAPayment([],$checkout); break; case 1001: $checkout->status = 'FAULTY'; break; case 1037: $checkout->status = 'TIMEDOUT'; break; case 1036: $checkout->status = 'NOTSUPPORTED'; break; case 1032: $checkout->status = 'CANCELLED'; break; default: $checkout->status = 'NOTSUPPORTED'; $mpRes->{'cMessage'} = "Please handle this case"; Slack::post(json_encode($mpRes)); // Do nothing } $checkout->save(); return $checkout; } }catch(\Exception $e){ abort(403,$e->getMessage()); } } }