diff --git a/readme.md b/readme.md
index d4f5ce1..d7c014f 100644
--- a/readme.md
+++ b/readme.md
@@ -1,121 +1,175 @@
-**Introduction**
+# Introduction
-This package seeks to help php developers implement the various Mpesa APIs without much hustle. It is based on the REST API whose documentation is available on http://developer.safaricom.co.ke.
-
- **Installation using composer**
- `composer require safaricom/mpesa`
-
+This package seeks to help php developers implement the various Mpesa APIs without much hustle. It is based on the REST API whose documentation is available on [Safaricom Developer](http://developer.safaricom.co.ke).
+
+## Installation using composer
+
+ ```
+ composer require safaricom/mpesa
+ ```
+
+## Configuration
+
+At your project root, create a .env file and in it set the consumer key and consumer secret as follows
+```.dotenv
+MPESA_CONSUMER_KEY=[consumer key]
+MPESA_CONSUMER_SECRET=[consumer secret]
+MPESA_ENV=[live or sandbox]
+```
- **Configuration**
- At your project root, create a .env file and in it set the consumer key and consumer secret as follows
- `MPESA_CONSUMER_KEY= [consumer key]`
- `MPESA_CONSUMER_SECRET=[consumer secret]`
- `MPESA_ENV=[live or sandbox]`
- For Laravel users, open the Config/App.php file and add `\Safaricom\Mpesa\MpesaServiceProvider::class` under providers and ` 'Mpesa'=> \Safaricom\Mpesa\MpesaServiceProvider::class` under aliases.
+For Laravel users, open the Config/App.php file and add `\Safaricom\Mpesa\MpesaServiceProvider::class` under providers and ` 'Mpesa'=> \Safaricom\Mpesa\MpesaServiceProvider::class` under aliases.
_Remember to edit the consumer_key and consumer_secret values appropriately when switching between sandbox and live_
-
- **Usage**
-
- **Confirmation and validation urls**
-**B2C Payment Request**
-
- This creates transaction between an M-Pesa short code to a phone number registered on M-Pesa.
-
-`$mpesa= new \Safaricom\Mpesa\Mpesa();`
+In order to transact from multiple paybill numbers or till numbers , you can change the configs at runtime using the config helper.
-`$b2cTransaction=$mpesa->b2c($InitiatorName, $SecurityCredential, $CommandID, $Amount, $PartyA, $PartyB, $Remarks, $QueueTimeOutURL, $ResultURL, $Occasion);`
+So we need to add the following to the services config file (config/services.php)
+```php
+return = [
+// More configs here
-**Account Balance Request**
-
-This is used to enquire the balance on an M-Pesa BuyGoods (Till Number)
+'mpesa' => [
+ 'MPESA_CONSUMER_KEY' => env('MPESA_CONSUMER_KEY'),
+ 'MPESA_CONSUMER_SECRET' => env('MPESA_CONSUMER_SECRET'),
+ 'MPESA_ENV' => env('MPESA_ENV')
+ ]
+];
+```
-`$mpesa= new \Safaricom\Mpesa\Mpesa();`
+## Usage
-`$balanceInquiry=$mpesa->accountBalance($CommandID, $Initiator, $SecurityCredential, $PartyA, $IdentifierType, $Remarks, $QueueTimeOutURL, $ResultURL);`
+### Confirmation and validation urls
+### B2C Payment Request
+This creates transaction between an M-Pesa short code to a phone number registered on M-Pesa.
-**Transaction Status Request**
-This is used to check the status of transaction.
+```php
+$mpesa= new \Safaricom\Mpesa\Mpesa();
-`$mpesa= new \Safaricom\Mpesa\Mpesa();`
+$b2cTransaction=$mpesa->b2c($InitiatorName, $SecurityCredential, $CommandID, $Amount, $PartyA, $PartyB, $Remarks, $QueueTimeOutURL, $ResultURL, $Occasion);
+```
-`$trasactionStatus=$mpesa->transactionStatus($Initiator, $SecurityCredential, $CommandID, $TransactionID, $PartyA, $IdentifierType, $ResultURL, $QueueTimeOutURL, $Remarks, $Occasion);`
+### Account Balance Request
+This is used to enquire the balance on an M-Pesa BuyGoods (Till Number)
+```php
+$mpesa= new \Safaricom\Mpesa\Mpesa();
-**B2B Payment Request**
+$balanceInquiry = $mpesa->accountBalance($CommandID, $Initiator, $SecurityCredential, $PartyA, $IdentifierType, $Remarks, $QueueTimeOutURL, $ResultURL);
+```
-This is used to transfer funds between two companies.
+### Transaction Status Request
-`$mpesa= new \Safaricom\Mpesa\Mpesa();`
+This is used to check the status of transaction.
-`$b2bTransaction=$mpesa->b2b($ShortCode, $CommandID, $Amount, $Msisdn, $BillRefNumber );`
+```php
+$mpesa = new \Safaricom\Mpesa\Mpesa();`
+$trasactionStatus = $mpesa->transactionStatus($Initiator, $SecurityCredential, $CommandID, $TransactionID, $PartyA, $IdentifierType, $ResultURL, $QueueTimeOutURL, $Remarks, $Occasion);
+```
+### B2B Payment Request
-**C2B Payment Request**
+This is used to transfer funds between two companies.
-This is used to Simulate transfer of funds between a customer and business.
+```php
+$mpesa = new \Safaricom\Mpesa\Mpesa();
+$b2bTransaction = $mpesa->b2b($ShortCode, $CommandID, $Amount, $Msisdn, $BillRefNumber );
+```
-`$mpesa= new \Safaricom\Mpesa\Mpesa();`
+### C2B Payment Request
-`$b2bTransaction=$mpesa->c2b($ShortCode, $CommandID, $Amount, $Msisdn, $BillRefNumber );`
+This is used to Simulate transfer of funds between a customer and business.
-_Also important to note is that you should have registered validation and confirmation urls where the callback responses will be sent._
+```php
+$mpesa = new \Safaricom\Mpesa\Mpesa();
+$b2bTransaction = $mpesa->c2b($ShortCode, $CommandID, $Amount, $Msisdn, $BillRefNumber );
+```
+_Also important to note is that you should have registered validation and confirmation urls where the callback responses will be sent._
-**STK Push Simulation**
+### STK Push Simulation
This is used to initiate online payment on behalf of a customer.
-`$mpesa= new \Safaricom\Mpesa\Mpesa();`
+```php
+$mpesa = new \Safaricom\Mpesa\Mpesa();
-`$stkPushSimulation=$mpesa->STKPushSimulation($BusinessShortCode, $LipaNaMpesaPasskey, $TransactionType, $Amount, $PartyA, $PartyB, $PhoneNumber, $CallBackURL, $AccountReference, $TransactionDesc, $Remarks);`
+$stkPushSimulation = $mpesa->STKPushSimulation($BusinessShortCode, $LipaNaMpesaPasskey, $TransactionType, $Amount, $PartyA, $PartyB, $PhoneNumber, $CallBackURL, $AccountReference, $TransactionDesc, $Remarks);
+```
+### STK Push Status Query
+ This is used to check the status of a Lipa Na M-Pesa Online Payment.
-**STK Push Status Query**
+ ```php
+$mpesa = new \Safaricom\Mpesa\Mpesa();`
- This is used to check the status of a Lipa Na M-Pesa Online Payment.
-
-`$mpesa= new \Safaricom\Mpesa\Mpesa();`
+$STKPushRequestStatus = $mpesa->STKPushQuery($checkoutRequestID,$businessShortCode,$password,$timestamp);
+```
-`$STKPushRequestStatus=$mpesa->STKPushQuery($checkoutRequestID,$businessShortCode,$password,$timestamp);`
+### Callback Routes
+M-Pesa APIs are asynchronous. When a valid M-Pesa API request is received by the API Gateway, it is sent to M-Pesa where it is added to a queue. M-Pesa then processes the requests in the queue and sends a response to the API Gateway which then forwards the response to the URL registered in the CallBackURL or ResultURL request parameter. Whenever M-Pesa receives more requests than the queue can handle, M-Pesa responds by rejecting any more requests and the API Gateway sends a queue timeout response to the URL registered in the QueueTimeOutURL request parameter.
+### Obtaining post data from callbacks
+This is used to get post data from callback in json format. The data can be decoded and stored in a database.
-**Callback Routes**
-M-Pesa APIs are asynchronous. When a valid M-Pesa API request is received by the API Gateway, it is sent to M-Pesa where it is added to a queue. M-Pesa then processes the requests in the queue and sends a response to the API Gateway which then forwards the response to the URL registered in the CallBackURL or ResultURL request parameter. Whenever M-Pesa receives more requests than the queue can handle, M-Pesa responds by rejecting any more requests and the API Gateway sends a queue timeout response to the URL registered in the QueueTimeOutURL request parameter.
+ ```php
+ $mpesa= new \Safaricom\Mpesa\Mpesa();
-**Obtaining post data from callbacks**
- This is used to get post data from callback in json format. The data can be decoded and stored in a database.
-
- `$mpesa= new \Safaricom\Mpesa\Mpesa();`
-
- `$callbackData=$mpesa->getDataFromCallback();`
+ $callbackData = $mpesa->getDataFromCallback();
+ ```
- **Finishing a transaction**
+### Finishing a transaction
+
After obtaining the Post data from the callbacks, use this at the end of your callback routes to complete the transaction
- `$mpesa= new \Safaricom\Mpesa\Mpesa();`
+ ```php
+ $mpesa = new \Safaricom\Mpesa\Mpesa();
- `$callbackData=$mpesa->finishTransaction();`
-
+ $callbackData = $mpesa->finishTransaction();
+ ```
If validation fails, pass `false` to `finishTransaction()`
- `$mpesa= new \Safaricom\Mpesa\Mpesa();`
+ ```php
+ $mpesa = new \Safaricom\Mpesa\Mpesa();
- `$callbackData=$mpesa->finishTransaction(false);`
+ $callbackData = $mpesa->finishTransaction(false);
+ ```
+
+## Multitenancy support
+
+When handling transactions you do as follows
+
+```php
+/** Get client preferably from a database somewhere.
+ * You can use a dynamic url or even an api key to identify which client the transaction belongs to.
+ * This can be done using a middleware implementation triggered before the transaction is processed.
+ * (Ignore this part if you don't want Multitenancy support as it will default to the values in the .env file)
+ */
+$clientA = [
+ 'MPESA_CONSUMER_KEY' => 'MPESA_CONSUMER_KEY_HERE',
+ 'MPESA_CONSUMER_SECRET' => 'MPESA_CONSUMER_SECRET_HERE',
+ 'MPESA_ENV' => 'MPESA_ENV_HERE'
+];
+
+// change the configs depending on the client
+config(['services.mpesa' => $clientA ]);
+// Instanciate the mpesa class ONLY after changing the configs
+$mpesa = new \Safaricom\Mpesa\Mpesa();
+// Do your business logic here
+$b2bTransaction=$mpesa->b2b($ShortCode, $CommandID, $Amount, $Msisdn, $BillRefNumber );
+```
\ No newline at end of file
diff --git a/src/Mpesa.php b/src/Mpesa.php
index cb37a32..b3943c2 100644
--- a/src/Mpesa.php
+++ b/src/Mpesa.php
@@ -19,8 +19,8 @@ class Mpesa
* @return mixed
*/
public static function generateLiveToken(){
- $consumer_key=env("MPESA_CONSUMER_KEY");
- $consumer_secret=env("MPESA_CONSUMER_SECRET");
+ $consumer_key = self::getConfig("services.mpesa.MPESA_CONSUMER_KEY");
+ $consumer_secret = self::getConfig("services.mpesa.MPESA_CONSUMER_SECRET");
if(!isset($consumer_key)||!isset($consumer_secret)){
die("please declare the consumer key and consumer secret as defined in the documentation");
@@ -48,8 +48,8 @@ public static function generateLiveToken(){
* @return mixed
*/
public static function generateSandBoxToken(){
- $consumer_key= env("MPESA_CONSUMER_KEY");
- $consumer_secret= env("MPESA_CONSUMER_SECRET");
+ $consumer_key = self::getConfig("services.mpesa.MPESA_CONSUMER_KEY");
+ $consumer_secret= self::getConfig("services.mpesa.MPESA_CONSUMER_SECRET");
if(!isset($consumer_key)||!isset($consumer_secret)){
die("please declare the consumer key and consumer secret as defined in the documentation");
}
@@ -84,7 +84,7 @@ public static function generateSandBoxToken(){
* @return mixed|string
*/
public static function reversal($CommandID, $Initiator, $SecurityCredential, $TransactionID, $Amount, $ReceiverParty, $RecieverIdentifierType, $ResultURL, $QueueTimeOutURL, $Remarks, $Occasion){
- $environment=env("MPESA_ENV");
+ $environment = self::getConfig("services.mpesa.MPESA_ENV");
if( $environment =="live"){
$url = 'https://api.safaricom.co.ke/mpesa/reversal/v1/request';
@@ -93,7 +93,7 @@ public static function reversal($CommandID, $Initiator, $SecurityCredential, $Tr
$url = 'https://sandbox.safaricom.co.ke/mpesa/reversal/v1/request';
$token=self::generateSandBoxToken();
}else{
- return json_encode(["Message"=>"invalid application status"]);
+ return json_encode(array("Message"=>"invalid application status"));
}
@@ -142,16 +142,16 @@ public static function reversal($CommandID, $Initiator, $SecurityCredential, $Tr
* @return string
*/
public static function b2c($InitiatorName, $SecurityCredential, $CommandID, $Amount, $PartyA, $PartyB, $Remarks, $QueueTimeOutURL, $ResultURL, $Occasion){
- $environment=env("MPESA_ENV");
+ $environment = self::getConfig("services.mpesa.MPESA_ENV");
- if( $environment =="live"){
+ if( $environment == "live"){
$url = 'https://api.safaricom.co.ke/mpesa/b2c/v1/paymentrequest';
$token=self::generateLiveToken();
}elseif ($environment=="sandbox"){
$url = 'https://sandbox.safaricom.co.ke/mpesa/b2c/v1/paymentrequest';
$token=self::generateSandBoxToken();
}else{
- return json_encode(["Message"=>"invalid application status"]);
+ return json_encode(array("Message"=>"invalid application status"));
}
@@ -194,7 +194,7 @@ public static function b2c($InitiatorName, $SecurityCredential, $CommandID, $Amo
* @return mixed|string
*/
public static function c2b($ShortCode, $CommandID, $Amount, $Msisdn, $BillRefNumber ){
- $environment=env("MPESA_ENV");
+ $environment = self::getConfig("services.mpesa.MPESA_ENV");
if( $environment =="live"){
$url = 'https://api.safaricom.co.ke/mpesa/c2b/v1/simulate';
@@ -203,7 +203,7 @@ public static function c2b($ShortCode, $CommandID, $Amount, $Msisdn, $BillRef
$url = 'https://sandbox.safaricom.co.ke/mpesa/c2b/v1/simulate';
$token=self::generateSandBoxToken();
}else{
- return json_encode(["Message"=>"invalid application status"]);
+ return json_encode(array("Message"=>"invalid application status"));
}
@@ -245,7 +245,7 @@ public static function c2b($ShortCode, $CommandID, $Amount, $Msisdn, $BillRef
* @return mixed|string
*/
public static function accountBalance($CommandID, $Initiator, $SecurityCredential, $PartyA, $IdentifierType, $Remarks, $QueueTimeOutURL, $ResultURL){
- $environment=env("MPESA_ENV");
+ $environment = self::getConfig("services.mpesa.MPESA_ENV");
if( $environment =="live"){
@@ -255,7 +255,7 @@ public static function accountBalance($CommandID, $Initiator, $SecurityCredentia
$url = 'https://sandbox.safaricom.co.ke/mpesa/accountbalance/v1/query';
$token=self::generateSandBoxToken();
}else{
- return json_encode(["Message"=>"invalid application status"]);
+ return json_encode(array("Message"=>"invalid application status"));
}
@@ -300,7 +300,7 @@ public static function accountBalance($CommandID, $Initiator, $SecurityCredentia
* @return mixed|string
*/
public function transactionStatus($Initiator, $SecurityCredential, $CommandID, $TransactionID, $PartyA, $IdentifierType, $ResultURL, $QueueTimeOutURL, $Remarks, $Occasion){
- $environment=env("MPESA_ENV");
+ $environment = $this->getConfig("services.mpesa.MPESA_ENV");
if( $environment =="live"){
$url = 'https://api.safaricom.co.ke/mpesa/transactionstatus/v1/query';
@@ -309,7 +309,7 @@ public function transactionStatus($Initiator, $SecurityCredential, $CommandID, $
$url = 'https://sandbox.safaricom.co.ke/mpesa/transactionstatus/v1/query';
$token=self::generateSandBoxToken();
}else{
- return json_encode(["Message"=>"invalid application status"]);
+ return json_encode(array("Message"=>"invalid application status"));
}
$curl = curl_init();
@@ -361,7 +361,7 @@ public function transactionStatus($Initiator, $SecurityCredential, $CommandID, $
* @return mixed|string
*/
public function b2b($Initiator, $SecurityCredential, $Amount, $PartyA, $PartyB, $Remarks, $QueueTimeOutURL, $ResultURL, $AccountReference, $commandID, $SenderIdentifierType, $RecieverIdentifierType){
- $environment=env("MPESA_ENV");
+ $environment = $this->getConfig("services.mpesa.MPESA_ENV");
if( $environment =="live"){
$url = 'https://api.safaricom.co.ke/mpesa/b2b/v1/paymentrequest';
@@ -370,7 +370,7 @@ public function b2b($Initiator, $SecurityCredential, $Amount, $PartyA, $PartyB,
$url = 'https://sandbox.safaricom.co.ke/mpesa/b2b/v1/paymentrequest';
$token=self::generateSandBoxToken();
}else{
- return json_encode(["Message"=>"invalid application status"]);
+ return json_encode(array("Message"=>"invalid application status"));
}
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
@@ -414,7 +414,7 @@ public function b2b($Initiator, $SecurityCredential, $Amount, $PartyA, $PartyB,
* @return mixed|string
*/
public function STKPushSimulation($BusinessShortCode, $LipaNaMpesaPasskey, $TransactionType, $Amount, $PartyA, $PartyB, $PhoneNumber, $CallBackURL, $AccountReference, $TransactionDesc, $Remark){
- $environment=env("MPESA_ENV");
+ $environment = $this->getConfig("services.mpesa.MPESA_ENV");
if( $environment =="live"){
$url = 'https://api.safaricom.co.ke/mpesa/stkpush/v1/processrequest';
$token=self::generateLiveToken();
@@ -422,7 +422,7 @@ public function STKPushSimulation($BusinessShortCode, $LipaNaMpesaPasskey, $Tran
$url = 'https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest';
$token=self::generateSandBoxToken();
}else{
- return json_encode(["Message"=>"invalid application status"]);
+ return json_encode(array("Message"=>"invalid application status"));
}
@@ -472,7 +472,7 @@ public function STKPushSimulation($BusinessShortCode, $LipaNaMpesaPasskey, $Tran
* @return mixed|string
*/
public static function STKPushQuery($environment, $checkoutRequestID, $businessShortCode, $password, $timestamp){
- $environment=env("MPESA_ENV");
+ $environment = self::getConfig("services.mpesa.MPESA_ENV");
if( $environment =="live"){
$url = 'https://api.safaricom.co.ke/mpesa/stkpushquery/v1/query';
@@ -481,7 +481,7 @@ public static function STKPushQuery($environment, $checkoutRequestID, $businessS
$url = 'https://sandbox.safaricom.co.ke/mpesa/stkpushquery/v1/query';
$token=self::generateSandBoxToken();
}else{
- return json_encode(["Message"=>"invalid application status"]);
+ return json_encode(array("Message"=>"invalid application status"));
}
@@ -511,19 +511,20 @@ public static function STKPushQuery($environment, $checkoutRequestID, $businessS
/**
*Use this function to confirm all transactions in callback routes
+ * @param bool $status
*/
public function finishTransaction($status = true)
{
if ($status === true) {
- $resultArray=[
+ $resultArray = array(
"ResultDesc"=>"Confirmation Service request accepted successfully",
"ResultCode"=>"0"
- ];
+ );
} else {
- $resultArray=[
+ $resultArray = array(
"ResultDesc"=>"Confirmation Service not accepted",
"ResultCode"=>"1"
- ];
+ );
}
header('Content-Type: application/json');
@@ -540,5 +541,22 @@ public function getDataFromCallback(){
return $callbackJSONData;
}
+ /**
+ * Use this function to get the config from either the config() or env() functions
+ * @param $config | Environment config
+ * @return mixed|string
+ */
+ public static function getConfig($config)
+ {
+ if(function_exists('config')){
+ // fall through to env if config not found
+ if($value = config($config)){
+ return $value;
+ }
+ }
+ $var = explode('.',$config);
+ $key = (count($var) == 3)?$var[2]:$var[count($var)-1];
+ return env($key);
+ }
}