Skip to content

Commit

Permalink
Merge pull request #7 from maina401/main
Browse files Browse the repository at this point in the history
FEAT: Add B2B API
  • Loading branch information
Iankumu committed Jun 8, 2023
2 parents aae5883 + 299f217 commit aca5d07
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 0 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The package contains implementation of the following Daraja APIs

- Lipa na Mpesa Express Online(STKPUSH)
- Business to Customer(B2C)
- Business to Business(B2B)
- Customer to Business(C2B)
- Transaction status
- Account Balance
Expand Down Expand Up @@ -152,6 +153,12 @@ return [
|------------------------------------------
*/
'reversal_timeout_url' => env('MPESA_REVERSAL_TIMEOUT_URL'),
/*-----------------------------------------
|Mpesa B2C urls
|------------------------------------------
*/
'b2b_result_url' => env('MPESA_B2B_RESULT_URL'),
'b2b_timeout_url' => env('MPESA_B2B_TIMEOUT_URL'),
];

```
Expand Down Expand Up @@ -181,6 +188,7 @@ Thank you for considering contributing to Laravel Mpesa! All contributions and P
### Credits

- [Ian Kumu](https://github.com/IanKumu)
- [Mugwanjira Maina](https://github.com/maina401)
- [All Contributors](../../contributors)

### License
Expand Down
7 changes: 7 additions & 0 deletions config/mpesa.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,11 @@
|------------------------------------------
*/
'reversal_timeout_url' => env('MPESA_REVERSAL_TIMEOUT_URL'),

/*-----------------------------------------
|Mpesa B2C urls
|------------------------------------------
*/
'b2b_result_url' => env('MPESA_B2B_RESULT_URL'),
'b2b_timeout_url' => env('MPESA_B2B_TIMEOUT_URL'),
];
47 changes: 47 additions & 0 deletions src/Mpesa.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ public function __construct()
$this->baltimeout = config('mpesa.balance_timeout_url');
$this->reverseresult = config('mpesa.reversal_result_url');
$this->reversetimeout = config('mpesa.reversal_timeout_url');
$this->b2b_result_url = config('mpesa.b2b_result_url');
$this->b2b_timeout_url = config('mpesa.b2b_timeout_url');
$this->url = config('mpesa.environment') == 'sandbox'
? 'https://sandbox.safaricom.co.ke'
: 'https://api.safaricom.co.ke';
Expand Down Expand Up @@ -280,6 +282,51 @@ public function validated_b2c($phonenumber, $command_id, $amount, $remarks, $id_
return $this->MpesaRequest($url, $body);
}

/**
* Business to Business
*
* This method is used to send money to a business's Mpesa account.
*
* @param int $amount The amount to send to the recipient
* @param int $receiver_shortcode The shortcode of the recipient
* @param string $command_id The type of transaction being made. Can be BusinessPayBill, MerchantToMerchantTransfer, MerchantTransferFromMerchantToWorking, MerchantServicesMMFAccountTransfer, AgencyFloatAdvance
* @param string $remarks Any additional information. Must be present.
* @param string $account_number Required for “BusinessPaybill” CommandID.
* @return object Curl Response from Mpesa
*/
public function b2b($receiver_shortcode, $command_id, $amount, $remarks, $account_number=null)
{
$url = $this->url . "/mpesa/b2b/v1/paymentrequest";

$body = [
"Initiator" => $this->initiator_name,
"SecurityCredential" => $this->security_credential,
"CommandID" => $command_id, //can be BusinessPayBill, MerchantToMerchantTransfer, MerchantTransferFromMerchantToWorking, MerchantServicesMMFAccountTransfer, AgencyFloatAdvance
"SenderIdentifierType" => '4', //4 for shortcode
"RecieverIdentifierType" => '4', //4 for shortcode
"Amount" => $amount,
"PartyA" => $this->b2c_shortcode,//uses same shortcode as b2c
"PartyB" => $receiver_shortcode,
"AccountReference" => $account_number,
"Remarks" => $remarks
];
if ($command_id == 'BusinessPayBill') {
if ($account_number == null)
throw new \Exception("Account Number is required for BusinessPayBill CommandID");

$body['AccountReference'] = $account_number;
}
//check urls
if (!filter_var($this->b2b_result_url, FILTER_VALIDATE_URL))
throw new CallbackException("Result URL is not valid");
if (!filter_var($this->b2b_timeout_url, FILTER_VALIDATE_URL))
throw new CallbackException("Timeout URL is not valid");
$body['QueueTimeOutURL'] = $this->b2b_timeout_url;
$body['ResultURL'] = $this->b2b_result_url;
$response = $this->MpesaRequest($url, $body);
return $response;
}

/**
* Client to Business
*
Expand Down
32 changes: 32 additions & 0 deletions tests/Unit/B2BTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Iankumu\Mpesa\Tests\Unit;

use Iankumu\Mpesa\Exceptions\CallbackException;
use Iankumu\Mpesa\Mpesa;
use Illuminate\Support\Facades\Http;

test('that b2b will throw an exception when the callbacks are null', function () {
(new Mpesa())->b2b('403043','BusinessPayBill',100,'test','test');
})->expectException(CallbackException::class);

it('can initiate b2b', function () {
config()->set('mpesa.b2b_result_url', 'http://test.test/result');
config()->set('mpesa.b2b_timeout_url', 'http://test.test/timeout');
Http::fake([
'https://sandbox.safaricom.co.ke/mpesa/b2b/v1/paymentrequest' => Http::response([
'ResponseCode' => '0',
'ResponseDescription' => 'Success',
'ConversationID' => 'AG_20200708_00008d7b7b7b7b7b7b7b',
'OriginatorConversationID' => '12345-67890-2',
'TransactionID' => 'LGR019GK1W',
], 200),
]);

$mpesa = new Mpesa();
$response = $mpesa->b2b('403043','BusinessPayBill',100,'test','test');
expect($response->status())->toBe(200);
$result = json_decode($response->body(), true);
expect($result)->toHaveKeys(['ResponseCode', 'ResponseDescription', 'ConversationID', 'OriginatorConversationID', 'TransactionID']);
expect($result['ResponseCode'])->toBe('0');
});

0 comments on commit aca5d07

Please sign in to comment.