From bb9598736a40015d96656251fb9a26fdc9e4c0d6 Mon Sep 17 00:00:00 2001 From: Olusegun Ayeni Date: Fri, 18 Jun 2021 16:42:13 +0100 Subject: [PATCH 01/10] add split feature and allow package to support php 8 and laravel 8 --- README.md | 14 ++++++ composer.json | 108 ++++++++++++++++++++++++++--------------------- src/Paystack.php | 30 +++++++++++-- 3 files changed, 101 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index a6f1caf..bf99db7 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,13 @@ Route::post('/pay', [ 'as' => 'pay' ]); ``` +OR + +```php +// Laravel 8 +Route::post('/pay', [App\Http\Controllers\PaymentController::class, 'redirectToGateway'])->name('pay'); +``` + ```php Route::get('/payment/callback', 'PaymentController@handleGatewayCallback'); @@ -161,6 +168,13 @@ Route::get('payment/callback', [ ]); ``` +OR + +```php +// Laravel 8 +Route::get('/payment/callback', [App\Http\Controllers\PaymentController::class, 'handleGatewayCallback']); +``` + ```php request()->last_name, "callback_url" => request()->callback_url, "currency" => (request()->currency != "" ? request()->currency : "NGN"), - + /* Paystack allows for transactions to be split into a subaccount - The following lines trap the subaccount ID - as well as the ammount to charge the subaccount (if overriden in the form) @@ -132,11 +132,35 @@ public function makePaymentRequest( $data = null) */ "subaccount" => request()->subaccount, "transaction_charge" => request()->transaction_charge, - + + /** + * Paystack allows for transaction to be split into multi accounts(subaccounts) + * The following lines trap the split ID handling the split + * More details here: https://paystack.com/docs/payments/multi-split-payments/#using-transaction-splits-with-payments + */ + "split_code" => request()->split_code, + + /** + * Paystack allows transaction to be split into multi account(subaccounts) on the fly without predefined split + * form need an input field: + * array must be set up as: + * $split = [ + * "type" => "percentage", + * "currency" => "KES", + * "subaccounts" => [ + * { "subaccount" => "ACCT_li4p6kte2dolodo", "share" => 10 }, + * { "subaccount" => "ACCT_li4p6kte2dolodo", "share" => 30 }, + * ], + * "bearer_type" => "all", + * "main_account_share": 70, + * ] + * More details here: https://paystack.com/docs/payments/multi-split-payments/#dynamic-splits + */ + "split" => request()->split, /* * to allow use of metadata on Paystack dashboard and a means to return additional data back to redirect url * form need an input field: - * array must be set up as: + * array must be set up as: * $array = [ 'custom_fields' => [ * ['display_name' => "Cart Id", "variable_name" => "cart_id", "value" => "2"], * ['display_name' => "Sex", "variable_name" => "sex", "value" => "female"], From e47e4247ae826a4d60cc715a272b961cb9437c0a Mon Sep 17 00:00:00 2001 From: Olusegun Ayeni Date: Fri, 18 Jun 2021 16:58:42 +0100 Subject: [PATCH 02/10] add documentation to readme --- README.md | 20 ++++++++++++++++++++ src/Paystack.php | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bf99db7..c2b3b57 100644 --- a/README.md +++ b/README.md @@ -344,6 +344,23 @@ paystack()->updateSubAccount(); A sample form will look like so: +```php + "percentage", + "currency" => "KES", + "subaccounts" => [ + [ "subaccount" => "ACCT_li4p6kte2dolodo", "share" => 10 ], + [ "subaccount" => "ACCT_li4p6kte2dolodo", "share" => 30 ], + ], + "bearer_type" => "all", + "main_account_share" => 70 +]; +?> +``` + ```html
@@ -361,6 +378,9 @@ A sample form will look like so: {{-- For other necessary things you want to add to your payload. it is optional though --}} {{-- required --}} + + {{-- to support transaction split. more details https://paystack.com/docs/payments/multi-split-payments/#using-transaction-splits-with-payments --}} + {{-- to support dynamic transaction split. More details https://paystack.com/docs/payments/multi-split-payments/#dynamic-splits --}} {{ csrf_field() }} {{-- works only when using laravel 5.1, 5.2 --}} {{-- employ this in place of csrf_field only in laravel 5.0 --}} diff --git a/src/Paystack.php b/src/Paystack.php index db2404f..1a298a7 100644 --- a/src/Paystack.php +++ b/src/Paystack.php @@ -152,7 +152,7 @@ public function makePaymentRequest( $data = null) * { "subaccount" => "ACCT_li4p6kte2dolodo", "share" => 30 }, * ], * "bearer_type" => "all", - * "main_account_share": 70, + * "main_account_share" => 70, * ] * More details here: https://paystack.com/docs/payments/multi-split-payments/#dynamic-splits */ From eec5ecd960cdc96b961d4e33284df58fae1fa0fc Mon Sep 17 00:00:00 2001 From: Ibidapo Adeolu Date: Tue, 1 Feb 2022 12:53:31 +0100 Subject: [PATCH 03/10] Add option for controller I added an option for user to provide the data (request data) from controller instead of a form. This adds some levels of security to the data and also ability to provide default values. --- README.md | 22 ++++++++++++++++++++++ src/Paystack.php | 6 +++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c2b3b57..38eac4b 100644 --- a/README.md +++ b/README.md @@ -219,6 +219,28 @@ class PaymentController extends Controller } ``` +```php +/** + * In the case where you need to pass the data from your + * controller instead of a form + * Make sure to send: + * required: email, amount, reference, orderID(probably) + * optionally: currency, description, metadata + * e.g: + * + */ +$data = array( + "amount" => 700 * 100, + "reference" => '4g4g5485g8545jg8gj', + "email" => 'user@mail.com', + "currency" => "NGN", + "orderID" => 23456, + ); + +return Paystack::getAuthorizationUrl($data)->redirectNow(); + +``` + Let me explain the fluent methods this package provides a bit here. ```php /** diff --git a/src/Paystack.php b/src/Paystack.php index 1a298a7..c1a5ea7 100644 --- a/src/Paystack.php +++ b/src/Paystack.php @@ -109,7 +109,7 @@ private function setRequestOptions() * @return Paystack */ - public function makePaymentRequest( $data = null) + public function makePaymentRequest($data = null) { if ( $data == null ) { @@ -205,9 +205,9 @@ private function setHttpResponse($relativeUrl, $method, $body = []) * Get the authorization url from the callback response * @return Paystack */ - public function getAuthorizationUrl() + public function getAuthorizationUrl($data = null) { - $this->makePaymentRequest(); + $this->makePaymentRequest($data); $this->url = $this->getResponse()['data']['authorization_url']; From 579bb6bad90635f13aeb851e76dc8fc7f34a2ef4 Mon Sep 17 00:00:00 2001 From: stojan kukrika Date: Fri, 11 Feb 2022 03:32:33 +0100 Subject: [PATCH 04/10] added support for laravel 9 and php 8.1 --- README.md | 4 ++-- composer.json | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c2b3b57..3289e1e 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,7 @@ Route::post('/pay', [ OR ```php -// Laravel 8 +// Laravel 8 & 9 Route::post('/pay', [App\Http\Controllers\PaymentController::class, 'redirectToGateway'])->name('pay'); ``` @@ -171,7 +171,7 @@ Route::get('payment/callback', [ OR ```php -// Laravel 8 +// Laravel 8 & 9 Route::get('/payment/callback', [App\Http\Controllers\PaymentController::class, 'handleGatewayCallback']); ``` diff --git a/composer.json b/composer.json index 98db5e4..1aea8b3 100644 --- a/composer.json +++ b/composer.json @@ -27,9 +27,9 @@ ], "minimum-stability": "stable", "require": { - "php": "^7.2|^8.0", - "illuminate/support": "~6|~7|~8", - "guzzlehttp/guzzle": "~6|~7|~8" + "php": "^7.2|^8.0|^8.1", + "illuminate/support": "~6|~7|~8|~9", + "guzzlehttp/guzzle": "~6|~7|~8|~9" }, "require-dev": { "phpunit/phpunit": "^8.4|^9.0", From 7fd0f9613fdf1823c67b0756a646a7843899848b Mon Sep 17 00:00:00 2001 From: a4anthony <55565463+a4anthony@users.noreply.github.com> Date: Fri, 5 Aug 2022 04:57:57 +0100 Subject: [PATCH 05/10] added channels option to request initialize data --- src/Paystack.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Paystack.php b/src/Paystack.php index c1a5ea7..55e30e7 100644 --- a/src/Paystack.php +++ b/src/Paystack.php @@ -119,6 +119,7 @@ public function makePaymentRequest($data = null) "amount" => intval(request()->amount) * $quantity, "reference" => request()->reference, "email" => request()->email, + "channels" => request()->channels, "plan" => request()->plan, "first_name" => request()->first_name, "last_name" => request()->last_name, From 7aea445ef452ce2c93a410e3f048ea2a5932be0a Mon Sep 17 00:00:00 2001 From: Chinedu Ukpe Date: Tue, 20 Sep 2022 15:31:32 +0100 Subject: [PATCH 06/10] Pass transaction_id to verify transaction --- src/Paystack.php | 53 ++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/src/Paystack.php b/src/Paystack.php index c1a5ea7..ed54091 100644 --- a/src/Paystack.php +++ b/src/Paystack.php @@ -86,7 +86,7 @@ public function setKey() */ private function setRequestOptions() { - $authBearer = 'Bearer '. $this->secretKey; + $authBearer = 'Bearer ' . $this->secretKey; $this->client = new Client( [ @@ -101,7 +101,7 @@ private function setRequestOptions() } - /** + /** * Initiate a payment request to Paystack * Included the option to pass the payload to this method for situations @@ -111,7 +111,7 @@ private function setRequestOptions() public function makePaymentRequest($data = null) { - if ( $data == null ) { + if ($data == null) { $quantity = intval(request()->quantity ?? 1); @@ -214,7 +214,7 @@ public function getAuthorizationUrl($data = null) return $this; } - /** + /** * Get the authorization callback response * In situations where Laravel serves as an backend for a detached UI, the api cannot redirect * and might need to take different actions based on the success or not of the transaction @@ -232,9 +232,9 @@ public function getAuthorizationResponse($data) /** * Hit Paystack Gateway to Verify that the transaction is valid */ - private function verifyTransactionAtGateway() + private function verifyTransactionAtGateway($transaction_id = null) { - $transactionRef = request()->query('trxref'); + $transactionRef = $transaction_id ?? request()->query('trxref'); $relativeUrl = "/transaction/verify/{$transactionRef}"; @@ -245,9 +245,9 @@ private function verifyTransactionAtGateway() * True or false condition whether the transaction is verified * @return boolean */ - public function isTransactionVerificationValid() + public function isTransactionVerificationValid($transaction_id = null) { - $this->verifyTransactionAtGateway(); + $this->verifyTransactionAtGateway($transaction_id); $result = $this->getResponse()['message']; @@ -375,7 +375,6 @@ public function createPlan() $this->setRequestOptions(); return $this->setHttpResponse("/plan", 'POST', $data)->getResponse(); - } /** @@ -436,7 +435,7 @@ public function createCustomer() public function fetchCustomer($customer_id) { $this->setRequestOptions(); - return $this->setHttpResponse('/customer/'. $customer_id, 'GET', [])->getResponse(); + return $this->setHttpResponse('/customer/' . $customer_id, 'GET', [])->getResponse(); } /** @@ -456,7 +455,7 @@ public function updateCustomer($customer_id) ]; $this->setRequestOptions(); - return $this->setHttpResponse('/customer/'. $customer_id, 'PUT', $data)->getResponse(); + return $this->setHttpResponse('/customer/' . $customer_id, 'PUT', $data)->getResponse(); } /** @@ -566,7 +565,7 @@ public function disableSubscription() public function fetchSubscription($subscription_id) { $this->setRequestOptions(); - return $this->setHttpResponse('/subscription/'.$subscription_id, 'GET', [])->getResponse(); + return $this->setHttpResponse('/subscription/' . $subscription_id, 'GET', [])->getResponse(); } /** @@ -602,7 +601,7 @@ public function getAllPages() public function fetchPage($page_id) { $this->setRequestOptions(); - return $this->setHttpResponse('/page/'.$page_id, 'GET', [])->getResponse(); + return $this->setHttpResponse('/page/' . $page_id, 'GET', [])->getResponse(); } /** @@ -619,16 +618,17 @@ public function updatePage($page_id) ]; $this->setRequestOptions(); - return $this->setHttpResponse('/page/'.$page_id, 'PUT', $data)->getResponse(); + return $this->setHttpResponse('/page/' . $page_id, 'PUT', $data)->getResponse(); } - /** + /** * Creates a subaccount to be used for split payments . Required params are business_name , settlement_bank , account_number , percentage_charge * * @return array */ - public function createSubAccount(){ + public function createSubAccount() + { $data = [ "business_name" => request()->business_name, "settlement_bank" => request()->settlement_bank, @@ -643,31 +643,30 @@ public function createSubAccount(){ $this->setRequestOptions(); return $this->setHttpResponse('/subaccount', 'POST', array_filter($data))->getResponse(); - } - /** + /** * Fetches details of a subaccount * @param subaccount code * @return array */ - public function fetchSubAccount($subaccount_code){ + public function fetchSubAccount($subaccount_code) + { $this->setRequestOptions(); - return $this->setHttpResponse("/subaccount/{$subaccount_code}","GET",[])->getResponse(); - + return $this->setHttpResponse("/subaccount/{$subaccount_code}", "GET", [])->getResponse(); } - /** + /** * Lists all the subaccounts associated with the account * @param $per_page - Specifies how many records to retrieve per page , $page - SPecifies exactly what page to retrieve * @return array */ - public function listSubAccounts($per_page,$page){ + public function listSubAccounts($per_page, $page) + { $this->setRequestOptions(); - return $this->setHttpResponse("/subaccount/?perPage=".(int) $per_page."&page=".(int) $page,"GET")->getResponse(); - + return $this->setHttpResponse("/subaccount/?perPage=" . (int) $per_page . "&page=" . (int) $page, "GET")->getResponse(); } @@ -677,7 +676,8 @@ public function listSubAccounts($per_page,$page){ * @return array */ - public function updateSubAccount($subaccount_code){ + public function updateSubAccount($subaccount_code) + { $data = [ "business_name" => request()->business_name, "settlement_bank" => request()->settlement_bank, @@ -693,6 +693,5 @@ public function updateSubAccount($subaccount_code){ $this->setRequestOptions(); return $this->setHttpResponse("/subaccount/{$subaccount_code}", "PUT", array_filter($data))->getResponse(); - } } From 15dac8a5bf0a9dbf20f889465476773c561db026 Mon Sep 17 00:00:00 2001 From: Md Omor Faruk Date: Wed, 15 Mar 2023 16:10:01 +0600 Subject: [PATCH 07/10] laravel 10 done --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 1aea8b3..e93effc 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "minimum-stability": "stable", "require": { "php": "^7.2|^8.0|^8.1", - "illuminate/support": "~6|~7|~8|~9", + "illuminate/support": "~6|~7|~8|~9|^10.0", "guzzlehttp/guzzle": "~6|~7|~8|~9" }, "require-dev": { From 1dd3cabff72292939ea25c33d238caa465dfccb9 Mon Sep 17 00:00:00 2001 From: PrevailExcel Date: Mon, 9 Oct 2023 12:50:50 +0100 Subject: [PATCH 08/10] Added Get Banks list and Account Confirmation --- src/Paystack.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/Paystack.php b/src/Paystack.php index ed54091..21443c2 100644 --- a/src/Paystack.php +++ b/src/Paystack.php @@ -694,4 +694,32 @@ public function updateSubAccount($subaccount_code) $this->setRequestOptions(); return $this->setHttpResponse("/subaccount/{$subaccount_code}", "PUT", array_filter($data))->getResponse(); } + + + /** + * Get a list of all supported banks and their properties + * @param $country - The country from which to obtain the list of supported banks, $per_page - Specifies how many records to retrieve per page , + * $use_cursor - Flag to enable cursor pagination on the endpoint + * @return array + */ + public function getBanks(?string $country, int $per_page = 50, bool $use_cursor = false) + { + if (!$country) + $country = request()->country ?? 'nigeria'; + + $this->setRequestOptions(); + return $this->setHttpResponse("/bank/?country=" . $country . "&use_cursor=" . $use_cursor . "&perPage=" . (int) $per_page, "GET")->getResponse(); + } + + /** + * Confirm an account belongs to the right customer + * @param $account_number - Account Number, $bank_code - You can get the list of bank codes by calling the List Banks endpoint + * @return array + */ + public function confirmAccount(string $account_number, string $bank_code) + { + + $this->setRequestOptions(); + return $this->setHttpResponse("/bank/resolve/?account_number=" . $account_number . "&bank_code=" . $bank_code, "GET")->getResponse(); + } } From 244dc70314d72b3281ae224e9dfa02d17c6f86f1 Mon Sep 17 00:00:00 2001 From: theJohnCode Date: Wed, 13 Dec 2023 18:21:31 +0100 Subject: [PATCH 09/10] allowed the createCustomer method to accept a data parameter --- .phpunit.result.cache | 1 + src/Paystack.php | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) create mode 100644 .phpunit.result.cache diff --git a/.phpunit.result.cache b/.phpunit.result.cache new file mode 100644 index 0000000..5c6751f --- /dev/null +++ b/.phpunit.result.cache @@ -0,0 +1 @@ +{"version":1,"defects":[],"times":{"Unicodeveloper\\Paystack\\Test\\HelpersTest::it_returns_instance_of_paystack":0.213,"Unicodeveloper\\Paystack\\Test\\PaystackTest::testAllCustomersAreReturned":0.089,"Unicodeveloper\\Paystack\\Test\\PaystackTest::testAllTransactionsAreReturned":0.001,"Unicodeveloper\\Paystack\\Test\\PaystackTest::testAllPlansAreReturned":0.001}} \ No newline at end of file diff --git a/src/Paystack.php b/src/Paystack.php index ed54091..453eea8 100644 --- a/src/Paystack.php +++ b/src/Paystack.php @@ -412,17 +412,20 @@ public function updatePlan($plan_code) /** * Create a customer */ - public function createCustomer() + public function createCustomer($data = null) { - $data = [ - "email" => request()->email, - "first_name" => request()->fname, - "last_name" => request()->lname, - "phone" => request()->phone, - "metadata" => request()->additional_info /* key => value pairs array */ + if ($data == null) { - ]; + $data = [ + "email" => request()->email, + "first_name" => request()->fname, + "last_name" => request()->lname, + "phone" => request()->phone, + "metadata" => request()->additional_info /* key => value pairs array */ + ]; + } + $this->setRequestOptions(); return $this->setHttpResponse('/customer', 'POST', $data)->getResponse(); } From aba26bebbb19dcdb3d78437a309c64f7547da30c Mon Sep 17 00:00:00 2001 From: Shift Date: Tue, 27 Feb 2024 16:13:56 +0000 Subject: [PATCH 10/10] Bump dependencies for Laravel 11 --- composer.json | 124 +++++++++++++++++++++++++------------------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/composer.json b/composer.json index e93effc..e67e985 100644 --- a/composer.json +++ b/composer.json @@ -1,66 +1,66 @@ { - "name": "unicodeveloper/laravel-paystack", - "description": "A Laravel Package for Paystack", - "keywords": [ - "php", - "github", - "laravel", - "Open Source", - "payments", - "subscription", - "paystack", - "paystack.co", - "laravel 6", - "laravel 7", - "laravel 8" - ], - "license": "MIT", - "authors": [ - { - "name": "unicodeveloper", - "email": "prosperotemuyiwa@gmail.com" - }, - { - "name": "iamfunsho", - "email": "info@devfunsho.com" - } - ], - "minimum-stability": "stable", - "require": { - "php": "^7.2|^8.0|^8.1", - "illuminate/support": "~6|~7|~8|~9|^10.0", - "guzzlehttp/guzzle": "~6|~7|~8|~9" - }, - "require-dev": { - "phpunit/phpunit": "^8.4|^9.0", - "scrutinizer/ocular": "~1.1", - "php-coveralls/php-coveralls": "^2.0", - "mockery/mockery": "^1.3" - }, - "autoload": { - "files": [ - "src/Support/helpers.php" + "name": "unicodeveloper/laravel-paystack", + "description": "A Laravel Package for Paystack", + "keywords": [ + "php", + "github", + "laravel", + "Open Source", + "payments", + "subscription", + "paystack", + "paystack.co", + "laravel 6", + "laravel 7", + "laravel 8" ], - "psr-4": { - "Unicodeveloper\\Paystack\\": "src/" - } - }, - "autoload-dev": { - "psr-4": { - "Unicodeveloper\\Paystack\\Test\\": "tests" - } - }, - "scripts": { - "test": "vendor/bin/phpunit" - }, - "extra": { - "laravel": { - "providers": [ - "Unicodeveloper\\Paystack\\PaystackServiceProvider" - ], - "aliases": { - "Paystack": "Unicodeveloper\\Paystack\\Facades\\Paystack" - } + "license": "MIT", + "authors": [ + { + "name": "unicodeveloper", + "email": "prosperotemuyiwa@gmail.com" + }, + { + "name": "iamfunsho", + "email": "info@devfunsho.com" + } + ], + "minimum-stability": "stable", + "require": { + "php": "^7.2|^8.0|^8.1", + "illuminate/support": "~6|~7|~8|~9|^10.0|^11.0", + "guzzlehttp/guzzle": "~6|~7|~8|~9" + }, + "require-dev": { + "phpunit/phpunit": "^8.4|^9.0|^10.5", + "scrutinizer/ocular": "~1.1", + "php-coveralls/php-coveralls": "^2.0", + "mockery/mockery": "^1.3" + }, + "autoload": { + "files": [ + "src/Support/helpers.php" + ], + "psr-4": { + "Unicodeveloper\\Paystack\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Unicodeveloper\\Paystack\\Test\\": "tests" + } + }, + "scripts": { + "test": "vendor/bin/phpunit" + }, + "extra": { + "laravel": { + "providers": [ + "Unicodeveloper\\Paystack\\PaystackServiceProvider" + ], + "aliases": { + "Paystack": "Unicodeveloper\\Paystack\\Facades\\Paystack" + } + } } - } }