Skip to content

Commit

Permalink
Merge pull request #5 from Iankumu/dev
Browse files Browse the repository at this point in the history
Added Exceptions and Refine docs
  • Loading branch information
Iankumu authored Mar 3, 2023
2 parents cf33371 + 06db208 commit f6c06ff
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 35 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ Code examples and usage can be found in [Usage.md](USAGE.md)

If you prefer a step by step tutorial, you can read the article I wrote on [How to integrate Mpesa into your Laravel Application](https://www.iankumu.com/blog/laravel-mpesa).

You can also find a [demo application](https://github.com/Iankumu/Payments) I created that uses the package. It provides a starting point on how to integrate Mpesa into a Laravel Application.

### Testing

```bash
Expand Down
17 changes: 17 additions & 0 deletions src/Exceptions/CallbackException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace Iankumu\Mpesa\Exceptions;

use Exception;

class CallbackException extends Exception
{
public static function make(string $callback, string $message = null): self
{
if (!is_null($message)) {
return new self("The {$callback} cannot be null. " . $message);
} else {
return new self("The {$callback} cannot be null.");
}
}
}
136 changes: 107 additions & 29 deletions src/Mpesa.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Iankumu\Mpesa;

use Iankumu\Mpesa\Exceptions\CallbackException;
use Iankumu\Mpesa\Utils\MpesaHelper;
use Illuminate\Http\Response;
use Illuminate\Support\Carbon;
Expand Down Expand Up @@ -101,7 +102,7 @@ public function __construct()
* @param int $phonenumber The phone number that will receive the stkpush prompt in the format 254xxxxxxxxx
* @param int $amount The amount to be transacted
* @param string $account_number The account number for a paybill
* @return object Curl Response from Mpesa
* @return \Illuminate\Http\Client\Response
*/
public function stkpush($phonenumber, $amount, $account_number, $callbackurl = null)
{
Expand Down Expand Up @@ -134,13 +135,13 @@ public function stkpush($phonenumber, $amount, $account_number, $callbackurl = n
'CallBackURL' => $callbackurl
];
} else {
return response()->json([
'error' => 'Callback URL cannot be null'
], Response::HTTP_NOT_ACCEPTABLE);
throw CallbackException::make(
'callback_url',
'Ensure you have set a Callback URL in the mpesa config file'
);
}

$response = $this->MpesaRequest($url, $data);
return $response;
return $this->MpesaRequest($url, $data);
}

/**
Expand All @@ -149,7 +150,7 @@ public function stkpush($phonenumber, $amount, $account_number, $callbackurl = n
* This method is used to check the status of a Lipa Na M-Pesa Online Payment.
*
* @param string $checkoutRequestId This is a global unique identifier of the processed checkout transaction request.
* @return object Curl Response from Mpesa
* @return \Illuminate\Http\Client\Response
*/

public function stkquery($checkoutRequestId)
Expand All @@ -163,8 +164,7 @@ public function stkquery($checkoutRequestId)

$url = $this->url . "/mpesa/stkpushquery/v1/query";

$response = $this->MpesaRequest($url, $post_data);
return $response;
return $this->MpesaRequest($url, $post_data);
}


Expand All @@ -177,7 +177,7 @@ public function stkquery($checkoutRequestId)
* @param int $phonenumber The phone number of the recipient in the format 254xxxxxxxxx
* @param string $command_id The type of transaction being made. Can be SalaryPayment,BusinessPayment or PromotionPayment
* @param string $remarks Any additional information. Must be present.
* @return object Curl Response from Mpesa
* @return \Illuminate\Http\Client\Response
*/
public function b2c($phonenumber, $command_id, $amount, $remarks)
{
Expand All @@ -196,8 +196,21 @@ public function b2c($phonenumber, $command_id, $amount, $remarks)
"Occassion" => '', //can be null
];

$response = $this->MpesaRequest($url, $body);
return $response;
if (is_null($this->b2cresult)) {
throw CallbackException::make(
'b2c_result_url',
'Ensure you have set the B2C Result URL in the mpesa config file'
);
}

if (is_null($this->b2ctimeout)) {
throw CallbackException::make(
'b2c_timeout_url',
'Ensure you have set the B2C Timeout URL in the mpesa config file'
);
}

return $this->MpesaRequest($url, $body);
}
/**
* Business to Client With Validation
Expand All @@ -220,7 +233,7 @@ public function b2c($phonenumber, $command_id, $amount, $remarks)
* @param string $command_id The type of transaction being made. Can be SalaryPayment,BusinessPayment or PromotionPayment
* @param string $remarks Any additional information. Must be present.
* @param string $id_number The id number of the recipient
* @return object Curl Response from Mpesa
* @return \Illuminate\Http\Client\Response
*/
public function validated_b2c($phonenumber, $command_id, $amount, $remarks, $id_number)
{
Expand All @@ -240,6 +253,21 @@ public function validated_b2c($phonenumber, $command_id, $amount, $remarks, $id_
"IDType" => "01", //01 for national id
"IDNumber" => $id_number,
];

if (is_null($this->b2cresult)) {
throw CallbackException::make(
'b2c_result_url',
'Ensure you have set the B2C Result URL in the mpesa config file'
);
}

if (is_null($this->b2ctimeout)) {
throw CallbackException::make(
'b2c_timeout_url',
'Ensure you have set the B2C Timeout URL in the mpesa config file'
);
}

return $this->MpesaRequest($url, $body);
}

Expand All @@ -249,7 +277,7 @@ public function validated_b2c($phonenumber, $command_id, $amount, $remarks, $id_
* This method is used to register URLs for callbacks when money is sent from the MPesa toolkit menu
*
* @param string $shortcode The till number or paybill number the urls will be associated with
* @return object Curl Response from Mpesa
* @return \Illuminate\Http\Client\Response
*/
public function c2bregisterURLS($shortcode)
{
Expand All @@ -263,8 +291,21 @@ public function c2bregisterURLS($shortcode)
"ValidationURL" => $this->c2bvalidate, //url should be https and should not contain keywords such as mpesa,safaricom etc
];

$response = $this->MpesaRequest($url, $body);
return $response;
if (is_null($this->c2bconfirm)) {
throw CallbackException::make(
'c2b_confirmation_url',
'Ensure you have set the C2B Confirmation URL in the mpesa config file'
);
}

if (is_null($this->c2bvalidate)) {
throw CallbackException::make(
'c2b_validation_url',
'Ensure you have set the C2B Validate URL in the mpesa config file'
);
}

return $this->MpesaRequest($url, $body);
}

/**
Expand All @@ -277,7 +318,7 @@ public function c2bregisterURLS($shortcode)
* @param string $shortcode The Paybill/Till number receiving the funds
* @param string $command_id The Type of transaction. Whether it is a paybill transaction(CustomerPayBillOnline) or a Till number transaction(CustomerBuyGoodsOnline)
* @param string $account_number The account number for a paybill. The default is null
* @return object Curl Response from Safaricom
* @return \Illuminate\Http\Client\Response
*/
public function c2bsimulate($phonenumber, $amount, $shortcode, $command_id, $account_number = null)
{
Expand All @@ -303,9 +344,7 @@ public function c2bsimulate($phonenumber, $amount, $shortcode, $command_id, $acc

$url = $this->url . '/mpesa/c2b/v2/simulate';


$response = $this->MpesaRequest($url, $data);
return $response;
return $this->MpesaRequest($url, $data);
}


Expand All @@ -318,7 +357,7 @@ public function c2bsimulate($phonenumber, $amount, $shortcode, $command_id, $acc
* @param string $transactionid Unique identifier to identify a transaction on M-Pesa
* @param int $identiertype identifier to identify the orginization
* @param string $remarks Any additional information. Must be present.
* @return object Curl Response from Safaricom
* @return \Illuminate\Http\Client\Response
*/
public function transactionStatus($shortcode, $transactionid, $identiertype, $remarks)
{
Expand All @@ -338,8 +377,21 @@ public function transactionStatus($shortcode, $transactionid, $identiertype, $re
"Occassion" => "",
];

$response = $this->MpesaRequest($url, $body);
return $response;
if (is_null($this->statusresult)) {
throw CallbackException::make(
'status_result_url',
'Ensure you have set the Transaction Status Result URL in the mpesa config file'
);
}

if (is_null($this->statustimeout)) {
throw CallbackException::make(
'status_timeout_url',
'Ensure you have set the Transaction Status Timeout URL in the mpesa config file'
);
}

return $this->MpesaRequest($url, $body);
}

/**
Expand All @@ -350,7 +402,7 @@ public function transactionStatus($shortcode, $transactionid, $identiertype, $re
* @param int $shortcode Organization/MSISDN receiving the transaction
* @param int $identiertype identifier to identify the orginization
* @param string $remarks Any additional information. Must be present.
* @return object Curl Response from Safaricom
* @return \Illuminate\Http\Client\Response
*/
public function accountBalance($shortcode, $identiertype, $remarks)
{
Expand All @@ -367,8 +419,21 @@ public function accountBalance($shortcode, $identiertype, $remarks)
"QueueTimeOutURL" => $this->baltimeout,
];

$response = $this->MpesaRequest($url, $body);
return $response;
if (is_null($this->statusresult)) {
throw CallbackException::make(
'balance_result_url',
'Ensure you have set the Account Balance Result URL in the mpesa config file'
);
}

if (is_null($this->statustimeout)) {
throw CallbackException::make(
'balance_timeout_url',
'Ensure you have set the Account Balance Timeout URL in the mpesa config file'
);
}

return $this->MpesaRequest($url, $body);
}

/**
Expand All @@ -380,7 +445,7 @@ public function accountBalance($shortcode, $identiertype, $remarks)
* @param int $shortcode Your Org's shortcode.
* @param string $transactionid This is the M-Pesa Transaction ID of the transaction which you wish to reverse.
* @param string $remarks Any additional information. Must be present.
* @return object Curl Response from Safaricom
* @return \Illuminate\Http\Client\Response
*/
public function reversal($shortcode, $transactionid, $amount, $remarks)
{
Expand All @@ -401,7 +466,20 @@ public function reversal($shortcode, $transactionid, $amount, $remarks)
"Occasion" => ""
];

$response = $this->MpesaRequest($url, $body);
return $response;
if (is_null($this->reverseresult)) {
throw CallbackException::make(
'reversal_result_url',
'Ensure you have set the Reversal Result URL in the mpesa config file'
);
}

if (is_null($this->reversetimeout)) {
throw CallbackException::make(
'reversal_timeout_url',
'Ensure you have set the Reversal Timeout URL in the mpesa config file'
);
}

return $this->MpesaRequest($url, $body);
}
}
10 changes: 7 additions & 3 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Iankumu\Mpesa\Tests;

use Iankumu\Mpesa\Mpesa;
use Iankumu\Mpesa\MpesaServiceProvider;
use Orchestra\Testbench\TestCase as Orchestra;

class TestCase extends Orchestra
Expand All @@ -13,7 +13,6 @@ class TestCase extends Orchestra
protected function setUp(): void
{
parent::setUp();
config(['app.url' => 'https://49cb48b01f608f.lhr.life']);
}

/*
Expand All @@ -27,6 +26,9 @@ protected function getEnvironmentSetUp($app)
{
// Alter the testing mpesa environment
$app['config']->set('mpesa.environment', 'sandbox');
$app['config']->set('mpesa.mpesa_consumer_key', '12345');
$app['config']->set('mpesa.mpesa_consumer_secret', '12345');
$app['config']->set('mpesa.callback_url', null);
}

/**
Expand All @@ -35,7 +37,9 @@ protected function getEnvironmentSetUp($app)
*/
protected function getPackageProviders($app)
{
return ['Iankumu\Mpesa\MpesaServiceProvider'];
return [
MpesaServiceProvider::class
];
}

/** @test */
Expand Down
10 changes: 10 additions & 0 deletions tests/Unit/B2CTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Iankumu\Mpesa\Mpesa;
use Iankumu\Mpesa\Tests\TestCase;
use Iankumu\Mpesa\Exceptions\CallbackException;

class B2CTest extends TestCase
{
Expand All @@ -19,4 +20,13 @@ public function can_initiate_b2c()
$result = $mpesa->b2c('0707070707', 'SalaryPayment', 100, 'Salary Payment');
$this->assertSame(true, $result);
}

/** @test */
public function b2c_will_throw_an_exception_when_the_callbacks_are_null()
{
$this->expectException(CallbackException::class);

//Should Throw an Exception as the callback is null
(new Mpesa())->b2c('0707070707', 'SalaryPayment', 100, 'Salary Payment');
}
}
10 changes: 10 additions & 0 deletions tests/Unit/C2BRegisterURLSTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Iankumu\Mpesa\Tests\Unit;

use Iankumu\Mpesa\Exceptions\CallbackException;
use Iankumu\Mpesa\Mpesa;
use Iankumu\Mpesa\Tests\TestCase;

Expand All @@ -18,4 +19,13 @@ public function can_register_c2b_urls()

$this->assertSame(true, $mpesa->c2bregisterURLS(12345));
}

/** @test */
public function c2b_will_throw_an_exception_when_the_callbacks_are_null()
{
$this->expectException(CallbackException::class);

//Should Throw an Exception as the callback is null
(new Mpesa())->c2bregisterURLS(12345);
}
}
1 change: 0 additions & 1 deletion tests/Unit/GenerateSecurityCredentialTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use Iankumu\Mpesa\Mpesa;
use Iankumu\Mpesa\Tests\TestCase;
use Iankumu\Mpesa\Utils\MpesaHelper;

class GenerateSecurityCredentialTest extends TestCase
{
Expand Down
Loading

0 comments on commit f6c06ff

Please sign in to comment.