From 001d0a2a924f710e9690913db10020f7da9de51c Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham <39011309+bajoski34@users.noreply.github.com> Date: Mon, 6 Feb 2023 12:35:13 +0000 Subject: [PATCH 01/70] add TZS currency --- src/Util/Currency.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Util/Currency.php b/src/Util/Currency.php index e5c4c88..23eb0f3 100644 --- a/src/Util/Currency.php +++ b/src/Util/Currency.php @@ -14,7 +14,7 @@ class Currency public const ZMW = 'ZMW'; public const EUR = 'EUR'; public const GHS = 'GHS'; - public const TNZ = 'TNZ'; + public const TZS = 'TZS'; public const RWF = 'RWF'; public const XAF = 'XAF'; public const XOF = 'XOF'; From fdfc3bb77cbf36f1f1e172ddfa340fdd80f2a139 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham <39011309+bajoski34@users.noreply.github.com> Date: Mon, 6 Feb 2023 14:51:35 +0000 Subject: [PATCH 02/70] update avs test card --- tests/Unit/Service/CardTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Unit/Service/CardTest.php b/tests/Unit/Service/CardTest.php index 81fe1e8..85d6b01 100644 --- a/tests/Unit/Service/CardTest.php +++ b/tests/Unit/Service/CardTest.php @@ -144,8 +144,8 @@ public function testAuthModeReturnAVS() "card_details" => [ "card_number" => "4556052704172643", "cvv" => "899", - "expiry_month" => "01", - "expiry_year" => "23" + "expiry_month" => "09", + "expiry_year" => "32" ] ], ]; From ed986e3b51fcf11f1ef413634da2bc530af95a4f Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham <39011309+bajoski34@users.noreply.github.com> Date: Mon, 27 Feb 2023 13:34:56 +0000 Subject: [PATCH 03/70] setup docker configuration --- .docker/nginx/default.conf | 18 ++++++++++++ .docker/php/Dockerfile | 52 +++++++++++++++++++++++++++++++++++ .docker/php/conf.d/xdebug.ini | 1 + 3 files changed, 71 insertions(+) create mode 100644 .docker/nginx/default.conf create mode 100644 .docker/php/Dockerfile create mode 100644 .docker/php/conf.d/xdebug.ini diff --git a/.docker/nginx/default.conf b/.docker/nginx/default.conf new file mode 100644 index 0000000..deea96f --- /dev/null +++ b/.docker/nginx/default.conf @@ -0,0 +1,18 @@ +server { + listen 80; + server_name localhost; + root /var/www/html/public; + index index.php; + + location ~ \.php$ { + fastcgi_pass app:9000; + fastcgi_index index.php; + fastcgi_param REQUEST_METHOD $request_method; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + include fastcgi_params; + } + + location / { + try_files $uri $uri/ /index.php?$query_string; + } +} \ No newline at end of file diff --git a/.docker/php/Dockerfile b/.docker/php/Dockerfile new file mode 100644 index 0000000..0b11c16 --- /dev/null +++ b/.docker/php/Dockerfile @@ -0,0 +1,52 @@ +FROM php:8.1-fpm-alpine as app + +# Useful PHP extension installer image, copy binary into your container +COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ + +# Install php extensions +# exit on errors, exit on unset variables, print every command as it is executed +RUN set -eux; \ + install-php-extensions pdo pdo_mysql; + +# RUN docker-php-ext-install pdo pdo_mysql + +# allow super user - set this if you use Composer as a +# super user at all times like in docker containers +ENV COMPOSER_ALLOW_SUPERUSER=1 + +# obtain composer using multi-stage build +# https://docs.docker.com/build/building/multi-stage/ +COPY --from=composer:2.4 /usr/bin/composer /usr/bin/composer + +#Here, we are copying only composer.json and composer.lock (instead of copying the entire source) +# right before doing composer install. +# This is enough to take advantage of docker cache and composer install will +# be executed only when composer.json or composer.lock have indeed changed!- +# https://medium.com/@softius/faster-docker-builds-with-composer-install-b4d2b15d0fff +COPY ./app/composer.* ./ + +# install +RUN composer install --prefer-dist --no-dev --no-scripts --no-progress --no-interaction + +# copy application files to the working directory +COPY ./app . + +# run composer dump-autoload --optimize +RUN composer dump-autoload --optimize + +# Dev image +# This stage is meant to be target-built into a separate image +# https://docs.docker.com/develop/develop-images/multistage-build/#stop-at-a-specific-build-stage +# https://docs.docker.com/compose/compose-file/#target +FROM app as app_dev + +# Xdebug has different modes / functionalities. We can default to 'off' and set to 'debug' +# when we run docker compose up if we need it +ENV XDEBUG_MODE=off + +# Copy xdebug config file into container +COPY ./php/conf.d/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini + +# Install xdebug +RUN set -eux; \ + install-php-extensions xdebug \ No newline at end of file diff --git a/.docker/php/conf.d/xdebug.ini b/.docker/php/conf.d/xdebug.ini new file mode 100644 index 0000000..0b4327e --- /dev/null +++ b/.docker/php/conf.d/xdebug.ini @@ -0,0 +1 @@ +xdebug.client_host = 'host.docker.internal' \ No newline at end of file From 4e97b8b7bd1aa95046840152da34edeb6005b18f Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham <39011309+bajoski34@users.noreply.github.com> Date: Mon, 27 Feb 2023 13:43:12 +0000 Subject: [PATCH 04/70] update infrastructure settings --- .distignore | 3 ++- .gitignore | 2 +- docker-compose.yml | 8 ++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.distignore b/.distignore index dbd5845..e573ecf 100644 --- a/.distignore +++ b/.distignore @@ -2,4 +2,5 @@ docker-compose.yml .gitignore .github -.env.example \ No newline at end of file +.env.example +.docker \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3011762..2b5f84f 100644 --- a/.gitignore +++ b/.gitignore @@ -195,4 +195,4 @@ examples/*.log examples/endpoint/*.log example.php .phpunit.result.cache -.env.local +.env.local \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 869968b..c816d03 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,12 +1,16 @@ services: web: - image: nginx + image: nginx:latest ports: - "80:80" volumes: - - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf + - ./.docker/nginx/default.conf:/etc/nginx/conf.d/default.conf depends_on: - app + app: + build: + context: . + dockerfile: ./.docker/php/Dockerfile db: image: mysql:5.7 volumes: From bf64c79af900a8a30f2cf083f191f81f2cbdebc9 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham <39011309+bajoski34@users.noreply.github.com> Date: Mon, 27 Feb 2023 13:47:10 +0000 Subject: [PATCH 05/70] update docker-compose.yml --- docker-compose.yml => .docker/docker-compose.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename docker-compose.yml => .docker/docker-compose.yml (59%) diff --git a/docker-compose.yml b/.docker/docker-compose.yml similarity index 59% rename from docker-compose.yml rename to .docker/docker-compose.yml index c816d03..2e89b0e 100644 --- a/docker-compose.yml +++ b/.docker/docker-compose.yml @@ -4,14 +4,14 @@ services: ports: - "80:80" volumes: - - ./.docker/nginx/default.conf:/etc/nginx/conf.d/default.conf + - ./nginx/default.conf:/etc/nginx/conf.d/default.conf depends_on: - app app: build: context: . - dockerfile: ./.docker/php/Dockerfile + dockerfile: ./php/Dockerfile db: image: mysql:5.7 volumes: - - ./docker/mysql:/var/lib/mysql \ No newline at end of file + - ./mysql:/var/lib/mysql \ No newline at end of file From 3f0f7cc66a686122b823d3e1677a29b2349421d6 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham <39011309+bajoski34@users.noreply.github.com> Date: Mon, 27 Feb 2023 18:01:55 +0000 Subject: [PATCH 06/70] test: resource and test update --- tests/Resources/{setup => Setup}/Config.php | 30 ++- tests/Unit/Service/AccountTest.php | 118 +++++------ tests/Unit/Service/AchTest.php | 56 +++--- tests/Unit/Service/VirtualCardTest.php | 207 ++++++++++---------- 4 files changed, 217 insertions(+), 194 deletions(-) rename tests/Resources/{setup => Setup}/Config.php (77%) diff --git a/tests/Resources/setup/Config.php b/tests/Resources/Setup/Config.php similarity index 77% rename from tests/Resources/setup/Config.php rename to tests/Resources/Setup/Config.php index ed7ae94..eea6a86 100644 --- a/tests/Resources/setup/Config.php +++ b/tests/Resources/Setup/Config.php @@ -5,12 +5,14 @@ namespace Flutterwave\Test\Resources\Setup; use Flutterwave\Contract\ConfigInterface; +use Flutterwave\Helper\EnvVariables; use GuzzleHttp\Client; -use GuzzleHttp\ClientInterface; + use function is_null; use Monolog\Handler\RotatingFileHandler; use Monolog\Logger; use Psr\Log\LoggerInterface; +use Psr\Http\Client\ClientInterface; class Config implements ConfigInterface { @@ -18,8 +20,6 @@ class Config implements ConfigInterface public const SECRET_KEY = 'SECRET_KEY'; public const ENCRYPTION_KEY = 'ENCRYPTION_KEY'; public const ENV = 'ENV'; - public const VERSION = 'v3'; - public const BASE_URL = 'https://api.flutterwave.com/'.self::VERSION; public const DEFAULT_PREFIX = 'FW|PHP'; public const LOG_FILE_NAME = 'flutterwave-php.log'; protected Logger $logger; @@ -31,19 +31,21 @@ class Config implements ConfigInterface private ClientInterface $http; private string $enc; - private function __construct(string $secretKey, string $publicKey, string $encryptKey, string $env) + private function __construct( + string $secretKey, + string $publicKey, + string $encryptKey, + string $env + ) { $this->secret = $secretKey; $this->public = $publicKey; $this->enc = $encryptKey; $this->env = $env; - - $this->http = new Client([ - 'base_uri' => $this->getBaseUrl(), - 'timeout' => 60, - ]); - - $log = new Logger('Flutterwave/PHP'); + # when creating a custom config, you may choose to use other dependencies here. + # http-client - Guzzle, logger - Monolog. + $this->http = new Client(['base_uri' => EnvVariables::BASE_URL, 'timeout' => 60 ]); + $log = new Logger('Flutterwave/PHP'); // making use of Monolog; $this->logger = $log; $log->pushHandler(new RotatingFileHandler(self::LOG_FILE_NAME, 90)); } @@ -58,6 +60,7 @@ public static function setUp(string $secretKey, string $publicKey, string $enc, public function getHttp(): ClientInterface { + # for custom implementation, please ensure the return $this->http ?? new Client(); } @@ -76,11 +79,6 @@ public function getPublicKey(): string return $this->public; } - public static function getBaseUrl(): string - { - return self::BASE_URL; - } - public function getSecretKey(): string { return $this->secret; diff --git a/tests/Unit/Service/AccountTest.php b/tests/Unit/Service/AccountTest.php index d3a629c..e4d216e 100644 --- a/tests/Unit/Service/AccountTest.php +++ b/tests/Unit/Service/AccountTest.php @@ -3,69 +3,77 @@ namespace Unit\Service; use PHPUnit\Framework\TestCase; +use Flutterwave\Flutterwave; use Flutterwave\Util\AuthMode; use Flutterwave\Util\Currency; -use Flutterwave\Helper\Config; +use Flutterwave\Test\Resources\Setup\Config; class AccountTest extends TestCase { protected function setUp(): void { - \Flutterwave\Flutterwave::bootstrap(); + Flutterwave::bootstrap( + Config::setUp( + $_SERVER[Config::SECRET_KEY], + $_SERVER[Config::PUBLIC_KEY], + $_SERVER[Config::ENCRYPTION_KEY], + $_SERVER[Config::ENV] + ) + ); } -// public function testAuthModeReturn() -// { -// //currently returning "Sorry, we could not connect to your bank"; -// -// $data = [ -// "amount" => 2000, -// "currency" => Currency::NGN, -// "tx_ref" => uniqid().time(), -// "additionalData" => [ -// "account_details" => [ -// "account_bank" => "044", -// "account_number" => "0690000034", -// "country" => "NG" -// ] -// ], -// ]; -// -// $accountpayment = \Flutterwave\Flutterwave::create("account"); -// $customerObj = $accountpayment->customer->create([ -// "full_name" => "Temi Adekunle", -// "email" => "developers@flutterwavego.com", -// "phone" => "+2349067985861" -// ]); -// -// $data['customer'] = $customerObj; -// $payload = $accountpayment->payload->create($data); -// $this->expectException(\Exception::class); -// $result = $accountpayment->initiate($payload); -// -// //check mode returned is either OTP or Redirect -//// $this->assertTrue($result['mode'] === AuthMode::OTP || $result['mode'] === AuthMode::REDIRECT ); -// } + public function testAuthModeReturn() + { + //currently returning "Sorry, we could not connect to your bank"; + + $data = [ + "amount" => 2000, + "currency" => Currency::NGN, + "tx_ref" => uniqid().time(), + "additionalData" => [ + "account_details" => [ + "account_bank" => "044", + "account_number" => "0690000034", + "country" => "NG" + ] + ], + ]; + + $accountpayment = \Flutterwave\Flutterwave::create("account"); + $customerObj = $accountpayment->customer->create([ + "full_name" => "Temi Adekunle", + "email" => "developers@flutterwavego.com", + "phone" => "+2349067985861" + ]); + + $data['customer'] = $customerObj; + $payload = $accountpayment->payload->create($data); + $this->expectException(\Exception::class); + $result = $accountpayment->initiate($payload); + + //check mode returned is either OTP or Redirect +// $this->assertTrue($result['mode'] === AuthMode::OTP || $result['mode'] === AuthMode::REDIRECT ); + } + + public function testInvalidParam() + { + $data = [ + "amount" => 2000, + "currency" => Currency::NGN, + "tx_ref" => uniqid().time(), + "additionalData" => null, + ]; -// public function testInvalidParam() -// { -// $data = [ -// "amount" => 2000, -// "currency" => Currency::NGN, -// "tx_ref" => uniqid().time(), -// "additionalData" => null, -// ]; -// -// $accountpayment = \Flutterwave\Flutterwave::create("account"); -// $customerObj = $accountpayment->customer->create([ -// "full_name" => "Jake Jesulayomi Ola", -// "email" => "developers@flutterwavego.com", -// "phone" => "+2349067985861" -// ]); -// -// $data['customer'] = $customerObj; -// $payload = $accountpayment->payload->create($data); -// $this->expectException(\InvalidArgumentException::class); -// $result = $accountpayment->initiate($payload); -// } + $accountpayment = \Flutterwave\Flutterwave::create("account"); + $customerObj = $accountpayment->customer->create([ + "full_name" => "Jake Jesulayomi Ola", + "email" => "developers@flutterwavego.com", + "phone" => "+2349067985861" + ]); + + $data['customer'] = $customerObj; + $payload = $accountpayment->payload->create($data); + $this->expectException(\InvalidArgumentException::class); + $result = $accountpayment->initiate($payload); + } } \ No newline at end of file diff --git a/tests/Unit/Service/AchTest.php b/tests/Unit/Service/AchTest.php index cd5dc79..8bd2cbf 100644 --- a/tests/Unit/Service/AchTest.php +++ b/tests/Unit/Service/AchTest.php @@ -4,13 +4,23 @@ use Flutterwave\Util\AuthMode; use PHPUnit\Framework\TestCase; +use Flutterwave\Flutterwave; use Flutterwave\Util\Currency; +use Flutterwave\Test\Resources\Setup\Config; + class AchTest extends TestCase { protected function setUp(): void { - \Flutterwave\Flutterwave::bootstrap(); + Flutterwave::bootstrap( + Config::setUp( + $_SERVER[Config::SECRET_KEY], + $_SERVER[Config::PUBLIC_KEY], + $_SERVER[Config::ENCRYPTION_KEY], + $_SERVER[Config::ENV] + ) + ); } // public function testAuthModeReturnRedirect() @@ -22,7 +32,7 @@ protected function setUp(): void // "redirectUrl" => "https://google.com" // ]; // -// $achpayment = \Flutterwave\Flutterwave::create("ach"); +// $achpayment = Flutterwave::create("ach"); // $customerObj = $achpayment->customer->create([ // "full_name" => "Olaobaju Jesulayomi Abraham", // "email" => "vicomma@gmail.com", @@ -37,25 +47,25 @@ protected function setUp(): void // $this->assertSame(AuthMode::REDIRECT, $result['mode']); // } -// public function testBankPermittedToMerchant() -// { -// $data = [ -// "amount" => 2000, -// "currency" => Currency::ZAR, -// "tx_ref" => uniqid().time(), -// "redirectUrl" => "https://google.com" -// ]; -// -// $achpayment = \Flutterwave\Flutterwave::create("ach"); -// $customerObj = $achpayment->customer->create([ -// "full_name" => "Olaobaju Jesulayomi Abraham", -// "email" => "vicomma@gmail.com", -// "phone" => "+2349067985861" -// ]); -// -// $data['customer'] = $customerObj; -// $payload = $achpayment->payload->create($data); -// $this->expectExceptionMessage("This bank payment option is not permitted to the merchant"); -// $result = $achpayment->initiate($payload); -// } + public function testBankPermittedToMerchant() + { + $data = [ + "amount" => 2000, + "currency" => Currency::ZAR, + "tx_ref" => uniqid().time(), + "redirectUrl" => "https://google.com" + ]; + + $achpayment = Flutterwave::create("ach"); + $customerObj = $achpayment->customer->create([ + "full_name" => "Olaobaju Jesulayomi Abraham", + "email" => "vicomma@gmail.com", + "phone" => "+2349067985861" + ]); + + $data['customer'] = $customerObj; + $payload = $achpayment->payload->create($data); + $this->expectExceptionMessage("This bank payment option is not permitted to the merchant"); + $result = $achpayment->initiate($payload); + } } \ No newline at end of file diff --git a/tests/Unit/Service/VirtualCardTest.php b/tests/Unit/Service/VirtualCardTest.php index a2d6e8c..d684850 100644 --- a/tests/Unit/Service/VirtualCardTest.php +++ b/tests/Unit/Service/VirtualCardTest.php @@ -5,113 +5,120 @@ use Flutterwave\Payload; use Flutterwave\Service\VirtualCard; use Flutterwave\Util\Currency; +use Flutterwave\Test\Resources\Setup\Config; use PHPUnit\Framework\TestCase; + class VirtualCardTest extends TestCase { -// public function testVirtualCardCreation() -// { -// $payload = new Payload(); -// $service = new VirtualCard(); -// -// $payload->set("first_name","PHP"); -// $payload->set("last_name","SDK"); -// $payload->set("date_of_birth","1994-03-01"); -// $payload->set("title","Mr"); -// $payload->set("gender","M"); //M or F -// $payload->set("email","developers@flutterwavego.com"); -// $payload->set("currency", Currency::NGN); -// $payload->set("amount", "5000"); -// $payload->set("debit_currency", Currency::NGN); -// $payload->set("phone", "+234505394568"); -// $payload->set("billing_name", "Abraham Ola"); -// $payload->set("firstname", "Abraham"); -// $response = $service->create($payload); -// $this->assertTrue(property_exists( -// $response, "data") && !empty($response->data->id) && isset($response->data->card_pan) -// ); -// -// return $response->data->id; -// } -// -// public function testRetrievingAllVirtualCards() -// { -// $service = new VirtualCard(); -// $request = $service->list(); -// $this->assertTrue(property_exists($request,'data') && \is_array($request->data)); -// } -// -// /** -// * @depends testVirtualCardCreation -// */ -// public function testRetrievingVirtualCard(string $id) -// { -// $service = new VirtualCard(); -// $request = $service->get($id); -// $this->assertTrue(property_exists($request,'data') && !empty($request->data->id)); -// } -// -// -// /** -// * @depends testVirtualCardCreation -// */ -// public function testVirtualCardFund(string $id) -// { -// $data = [ -// "amount"=>"3500", -// "debit_currency" => Currency::NGN -// ]; -// $service = new VirtualCard(); -// $request = $service->fund($id, $data); -// $this->assertTrue(property_exists($request,'data') && $request->message == "Card funded successfully"); -// } -// -// /** -// * @depends testVirtualCardCreation -// */ -// public function testVirtualCardWithdraw(string $id) -// { -// $card_id = $id; -// $amount = "3500"; -// $service = new VirtualCard(); -// $request = $service->withdraw($card_id,$amount); -// $this->assertTrue(property_exists($request,'data')); -// } -// -//// /** -//// * @depends testVirtualCardCreation -//// */ -//// public function testVirtualCardBlock(string $id) -//// { -//// $service = new VirtualCard(); -//// $request = $service->block($id); -//// $this->assertTrue(property_exists($request,'data') && $request->message == "Card blocked successfully"); -//// } -// -// /** -// * @depends testVirtualCardCreation -// */ -// public function testVirtualCardTerminate(string $id) -// { -// $service = new VirtualCard(); -// $request = $service->terminate($id); -// $this->assertTrue(property_exists($request,'data') && $request->message == "Card terminated successfully"); -// } -// + public VirtualCard $service; + protected function setUp(): void + { + $this->service = new VirtualCard( + Config::setUp( + $_SERVER[Config::SECRET_KEY], + $_SERVER[Config::PUBLIC_KEY], + $_SERVER[Config::ENCRYPTION_KEY], + $_SERVER[Config::ENV] + ) + ); + } + + public function testVirtualCardCreation() + { + $payload = new Payload(); + + $payload->set("first_name","PHP"); + $payload->set("last_name","SDK"); + $payload->set("date_of_birth","1994-03-01"); + $payload->set("title","Mr"); + $payload->set("gender","M"); //M or F + $payload->set("email","developers@flutterwavego.com"); + $payload->set("currency", Currency::NGN); + $payload->set("amount", "5000"); + $payload->set("debit_currency", Currency::NGN); + $payload->set("phone", "+234505394568"); + $payload->set("billing_name", "Abraham Ola"); + $payload->set("firstname", "Abraham"); + $response = $this->service->create($payload); + $this->assertTrue(property_exists( + $response, "data") && !empty($response->data->id) && isset($response->data->card_pan) + ); + + return $response->data->id; + } + + public function testRetrievingAllVirtualCards() + { + $request = $this->service->list(); + $this->assertTrue(property_exists($request,'data') && \is_array($request->data)); + } + + /** + * @depends testVirtualCardCreation + */ + public function testRetrievingVirtualCard(string $id) + { + $request = $this->service->get($id); + $this->assertTrue(property_exists($request,'data') && !empty($request->data->id)); + } + + + /** + * @depends testVirtualCardCreation + */ + public function testVirtualCardFund(string $id) + { + $data = [ + "amount"=>"3500", + "debit_currency" => Currency::NGN + ]; + $request = $this->service->fund($id, $data); + $this->assertTrue(property_exists($request,'data') && $request->message == "Card funded successfully"); + } + + /** + * @depends testVirtualCardCreation + */ + public function testVirtualCardWithdraw(string $id) + { + $card_id = $id; + $amount = "3500"; + $request = $this->service->withdraw($card_id,$amount); + $this->assertTrue(property_exists($request,'data')); + } + // /** // * @depends testVirtualCardCreation // */ -// public function testRetrievingCardTransactions(string $id) +// public function testVirtualCardBlock(string $id) // { -// $data = [ -// "from" => "2019-01-01", -// "to" => "2020-01-13", -// "index" => "2", -// "size" => "3" -// ]; -// -// $service = new VirtualCard(); -// $request = $service->getTransactions($id, $data); -// $this->assertTrue(property_exists($request,'data') && $request->message == "Card transactions fetched successfully"); +// $request = $this->service->block($id); +// $this->assertTrue(property_exists($request,'data') && $request->message == "Card blocked successfully"); // } + + /** + * @depends testVirtualCardCreation + */ + public function testVirtualCardTerminate(string $id) + { + $request = $this->service->terminate($id); + $this->assertTrue(property_exists($request,'data') && $request->message == "Card terminated successfully"); + } + + /** + * @depends testVirtualCardCreation + */ + public function testRetrievingCardTransactions(string $id) + { + $data = [ + "from" => "2019-01-01", + "to" => "2020-01-13", + "index" => "2", + "size" => "3" + ]; + + $request = $this->service->getTransactions($id, $data); + $this->assertTrue(property_exists($request,'data') && $request->message == "Card transactions fetched successfully"); + } } \ No newline at end of file From 04bd561b7825c526e400f202a545d0cc60e23129 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham <39011309+bajoski34@users.noreply.github.com> Date: Mon, 27 Feb 2023 18:03:10 +0000 Subject: [PATCH 07/70] handle Network, Client and Request exceptions --- src/Exception/AuthenticationException.php | 7 ++++ src/Exception/ClientException.php | 13 +++++++ src/Exception/NetworkException.php | 46 +++++++++++++++++++++++ src/Exception/RequestException.php | 46 +++++++++++++++++++++++ 4 files changed, 112 insertions(+) create mode 100644 src/Exception/ClientException.php create mode 100644 src/Exception/NetworkException.php create mode 100644 src/Exception/RequestException.php diff --git a/src/Exception/AuthenticationException.php b/src/Exception/AuthenticationException.php index 8c4f648..e3d2e26 100644 --- a/src/Exception/AuthenticationException.php +++ b/src/Exception/AuthenticationException.php @@ -6,4 +6,11 @@ class AuthenticationException extends \Exception { + public function InvalidBearerToken() { + $this->message = "Invalid Secret Key passed."; + } + + public function UnauthorizedAccess() { + $this->message = "You currently do not have permission to access this feature. kindly reachout to the Account owner."; + } } diff --git a/src/Exception/ClientException.php b/src/Exception/ClientException.php new file mode 100644 index 0000000..c45877d --- /dev/null +++ b/src/Exception/ClientException.php @@ -0,0 +1,13 @@ +request = $request; + } + + /** + * {@inheritdoc} + */ + public function getRequest() : RequestInterface + { + return $this->request; + } +} \ No newline at end of file diff --git a/src/Exception/RequestException.php b/src/Exception/RequestException.php new file mode 100644 index 0000000..a2db5ea --- /dev/null +++ b/src/Exception/RequestException.php @@ -0,0 +1,46 @@ +request = $request; + } + + /** + * {@inheritdoc} + */ + public function getRequest() : RequestInterface + { + return $this->request; + } +} \ No newline at end of file From 497d0134cae03a90eeddf753a4e400281d98a13b Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham <39011309+bajoski34@users.noreply.github.com> Date: Mon, 27 Feb 2023 18:06:51 +0000 Subject: [PATCH 08/70] allow other Psr/ClientInterface implementations --- src/Contract/ConfigInterface.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Contract/ConfigInterface.php b/src/Contract/ConfigInterface.php index 0e4c2d2..bc7cc04 100644 --- a/src/Contract/ConfigInterface.php +++ b/src/Contract/ConfigInterface.php @@ -4,7 +4,7 @@ namespace Flutterwave\Contract; -use GuzzleHttp\ClientInterface; +use Psr\Http\Client\ClientInterface; use Psr\Log\LoggerInterface; interface ConfigInterface @@ -21,8 +21,6 @@ public function getPublicKey(): string; public function getSecretKey(): string; - public static function getBaseUrl(): string; - public function getEnv(): string; public static function getDefaultTransactionPrefix(): string; From 32cbd7a0e9f6c08d99f6c1f20d3a97a26ec0823c Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham <39011309+bajoski34@users.noreply.github.com> Date: Mon, 27 Feb 2023 18:08:59 +0000 Subject: [PATCH 09/70] remove BASE_URL variable from config implementation --- src/Helper/Config.php | 18 +++++------------- src/Helper/EnvVariables.php | 10 ++++++++++ 2 files changed, 15 insertions(+), 13 deletions(-) create mode 100644 src/Helper/EnvVariables.php diff --git a/src/Helper/Config.php b/src/Helper/Config.php index 9313d1e..052f7e8 100644 --- a/src/Helper/Config.php +++ b/src/Helper/Config.php @@ -6,7 +6,7 @@ use Flutterwave\Contract\ConfigInterface; use GuzzleHttp\Client; -use GuzzleHttp\ClientInterface; +use Psr\Http\Client\ClientInterface; use function is_null; use Monolog\Handler\RotatingFileHandler; use Monolog\Logger; @@ -17,8 +17,7 @@ class Config implements ConfigInterface public const PUBLIC_KEY = 'PUBLIC_KEY'; public const SECRET_KEY = 'SECRET_KEY'; public const ENCRYPTION_KEY = 'ENCRYPTION_KEY'; - public const VERSION = 'v3'; - public const BASE_URL = 'https://api.flutterwave.com/'.self::VERSION; + public const ENV = 'ENV'; public const DEFAULT_PREFIX = 'FW|PHP'; public const LOG_FILE_NAME = 'flutterwave-php.log'; protected Logger $logger; @@ -37,11 +36,9 @@ private function __construct(string $secretKey, string $publicKey, string $encry $this->enc = $encryptKey; $this->env = $env; - $this->http = new Client([ - 'base_uri' => $this->getBaseUrl(), - 'timeout' => 60, - ]); - + # when creating a custom config, you may choose to use other dependencies here. + # http-client - Guzzle, logger - Monolog. + $this->http = new Client(['base_uri' => EnvVariables::BASE_URL, 'timeout' => 60 ]); $log = new Logger('Flutterwave/PHP'); $this->logger = $log; $log->pushHandler(new RotatingFileHandler(__DIR__."../../../../../../".self::LOG_FILE_NAME, 90)); @@ -75,11 +72,6 @@ public function getPublicKey(): string return $this->public; } - public static function getBaseUrl(): string - { - return self::BASE_URL; - } - public function getSecretKey(): string { return $this->secret; diff --git a/src/Helper/EnvVariables.php b/src/Helper/EnvVariables.php new file mode 100644 index 0000000..5acda13 --- /dev/null +++ b/src/Helper/EnvVariables.php @@ -0,0 +1,10 @@ + Date: Mon, 27 Feb 2023 18:10:38 +0000 Subject: [PATCH 10/70] update Service.php --- src/Service/Service.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Service/Service.php b/src/Service/Service.php index d065d68..4ce601a 100644 --- a/src/Service/Service.php +++ b/src/Service/Service.php @@ -7,6 +7,7 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\Contract\ServiceInterface; use Flutterwave\Helper\Config; +use Flutterwave\Helper\EnvVariables; use GuzzleHttp\ClientInterface; use GuzzleHttp\Exception\GuzzleException; use InvalidArgumentException; @@ -37,8 +38,8 @@ public function __construct(?ConfigInterface $config = null) $this->http = $this->config->getHttp(); $this->logger = $this->config->getLoggerInstance(); $this->secret = $this->config->getSecretKey(); - $this->url = $this->config::getBaseUrl().'/'; - $this->baseUrl = $this->config::getBaseUrl(); + $this->url = EnvVariables::BASE_URL.'/'; + $this->baseUrl = EnvVariables::BASE_URL; } public function getName(): string From 69c196b9cac21efe6d4c656fe10a29aa0dcfcf5b Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham <39011309+bajoski34@users.noreply.github.com> Date: Mon, 27 Feb 2023 18:11:58 +0000 Subject: [PATCH 11/70] feat: add CurlClient implementation --- composer.json | 4 ++- src/Adapter/CurlClient.php | 64 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 src/Adapter/CurlClient.php diff --git a/composer.json b/composer.json index d289016..922ac0d 100644 --- a/composer.json +++ b/composer.json @@ -17,8 +17,10 @@ "monolog/monolog": "^2.0 || ^3.0", "vlucas/phpdotenv": "^2.5 || ^3.0 || ^5.0", "ext-json": "*", + "ext-curl": "*" "guzzlehttp/guzzle": "^7.5", - "psr/http-client": "^1.0" + "psr/http-client": "^1.0", + "php-http/guzzle7-adapter": "^1.0", }, "require-dev": { "phpunit/phpunit": ">=6.0", diff --git a/src/Adapter/CurlClient.php b/src/Adapter/CurlClient.php new file mode 100644 index 0000000..6195154 --- /dev/null +++ b/src/Adapter/CurlClient.php @@ -0,0 +1,64 @@ + + */ + protected array $curlOptions; + + public function isCompatible(): bool + { + return \extension_loaded('curl'); + } + + public function sendRequest(\Psr\Http\Message\RequestInterface $request): \Psr\Http\Message\ResponseInterface + { + if(!$this->isCompatible()) { + throw new \RuntimeException('You do not have the curl extension enabled or installed.'); + } + + $ch = \curl_init(); + + \curl_setopt($ch, CURLOPT_URL, $request->getUri()->__toString()); + + \curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + \curl_setopt($ch, CURLOPT_HTTPHEADER, $this->getHeaders($request)); + + \curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $request->getMethod()); + + \curl_setopt($ch, CURLOPT_POSTFIELDS, $request->getBody()->__toString()); + + $response = curl_exec($ch); + + curl_close($ch); + + return $this->createResponse($response); + } + + private function createResponse(bool $response) + { + //TODO: complete createResponse method for curlclient implementation + } + + private function getHeaders(\Psr\Http\Message\RequestInterface $request) + { + $headers = []; + + foreach ($request->getHeaders() as $name => $values) { + $headers[] = $name . ': ' . implode(', ', $values); + } + + return $headers; + } +} From 51bef9a16617cc44d6c9f096d74ee0d38a4aa346 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham <39011309+bajoski34@users.noreply.github.com> Date: Mon, 27 Feb 2023 18:14:48 +0000 Subject: [PATCH 12/70] fix: composer.json vaild json error --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 922ac0d..e50d891 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "monolog/monolog": "^2.0 || ^3.0", "vlucas/phpdotenv": "^2.5 || ^3.0 || ^5.0", "ext-json": "*", - "ext-curl": "*" + "ext-curl": "*", "guzzlehttp/guzzle": "^7.5", "psr/http-client": "^1.0", "php-http/guzzle7-adapter": "^1.0", From 5b5babd1d1e9351258d7cc7be4237f4d471d9b2b Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham <39011309+bajoski34@users.noreply.github.com> Date: Mon, 27 Feb 2023 18:27:02 +0000 Subject: [PATCH 13/70] fix: composer.json vaild json error 2 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e50d891..7ff9412 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "ext-curl": "*", "guzzlehttp/guzzle": "^7.5", "psr/http-client": "^1.0", - "php-http/guzzle7-adapter": "^1.0", + "php-http/guzzle7-adapter": "^1.0" }, "require-dev": { "phpunit/phpunit": ">=6.0", From 4bfafa152f0a9158763092cdd627af8528dc05e9 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham <39011309+bajoski34@users.noreply.github.com> Date: Thu, 2 Mar 2023 12:20:03 +0000 Subject: [PATCH 14/70] add change-review workflow --- .github/workflows/change-review.yml | 63 +++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 .github/workflows/change-review.yml diff --git a/.github/workflows/change-review.yml b/.github/workflows/change-review.yml new file mode 100644 index 0000000..68a970f --- /dev/null +++ b/.github/workflows/change-review.yml @@ -0,0 +1,63 @@ +name: Review changes on Dev (Commits/PRs) + +on: + push: + branches: ['development'] + pull_request: + types: + - opened + +jobs: + code-check: + runs-on: ubuntu-latest + + strategy: + fail-fast: true + matrix: + php: [8.1, 8.2] + + env: + PUBLIC_KEY: ${{ secrets.PUBLIC_KEY }} + SECRET_KEY: ${{ secrets.SECRET_KEY }} + ENCRYPTION_KEY: ${{ secrets.ENCRYPTION_KEY }} + ENV: ${{ secrets.ENV }} + + steps: + - uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite + coverage: xdebug + + - name: Validate composer.json and composer.lock + run: composer validate --strict + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v3 + with: + path: vendor + key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php- + + - name: Install dependencies + run: composer install --prefer-dist --no-progress + + - name: run unit tests and coverage scan + run: ./vendor/bin/pest --coverage --min=90 + + - name: upload coverage report to codecov + uses: codecov/codecov-action@v2 + + - name: push build status to Slack + uses: 8398a7/action-slack@v3 + with: + status: ${{ job.status }} + fields: repo,message,commit,author,action,eventName,ref,workflow,job,took,pullRequest + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + if: always() \ No newline at end of file From 2d1f37e03e2a2e870c6915347851562df236c753 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham <39011309+bajoski34@users.noreply.github.com> Date: Thu, 2 Mar 2023 13:24:26 +0000 Subject: [PATCH 15/70] update AchTest --- .github/workflows/change-review.yml | 10 ++++---- tests/Unit/Service/AchTest.php | 38 ++++++++++++++--------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/change-review.yml b/.github/workflows/change-review.yml index 68a970f..ce566ac 100644 --- a/.github/workflows/change-review.yml +++ b/.github/workflows/change-review.yml @@ -2,7 +2,7 @@ name: Review changes on Dev (Commits/PRs) on: push: - branches: ['development'] + branches: ["development"] pull_request: types: - opened @@ -21,7 +21,7 @@ jobs: SECRET_KEY: ${{ secrets.SECRET_KEY }} ENCRYPTION_KEY: ${{ secrets.ENCRYPTION_KEY }} ENV: ${{ secrets.ENV }} - + steps: - uses: actions/checkout@v3 @@ -43,12 +43,12 @@ jobs: key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} restore-keys: | ${{ runner.os }}-php- - + - name: Install dependencies run: composer install --prefer-dist --no-progress - name: run unit tests and coverage scan - run: ./vendor/bin/pest --coverage --min=90 + run: ./vendor/bin/pest --coverage --min=80 --coverage-clover ./coverage.xml - name: upload coverage report to codecov uses: codecov/codecov-action@v2 @@ -60,4 +60,4 @@ jobs: fields: repo,message,commit,author,action,eventName,ref,workflow,job,took,pullRequest env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} - if: always() \ No newline at end of file + if: always() diff --git a/tests/Unit/Service/AchTest.php b/tests/Unit/Service/AchTest.php index 8bd2cbf..aa5d3fb 100644 --- a/tests/Unit/Service/AchTest.php +++ b/tests/Unit/Service/AchTest.php @@ -47,25 +47,25 @@ protected function setUp(): void // $this->assertSame(AuthMode::REDIRECT, $result['mode']); // } - public function testBankPermittedToMerchant() - { - $data = [ - "amount" => 2000, - "currency" => Currency::ZAR, - "tx_ref" => uniqid().time(), - "redirectUrl" => "https://google.com" - ]; + // public function testBankPermittedToMerchant() + // { + // $data = [ + // "amount" => 2000, + // "currency" => Currency::ZAR, + // "tx_ref" => uniqid().time(), + // "redirectUrl" => "https://google.com" + // ]; - $achpayment = Flutterwave::create("ach"); - $customerObj = $achpayment->customer->create([ - "full_name" => "Olaobaju Jesulayomi Abraham", - "email" => "vicomma@gmail.com", - "phone" => "+2349067985861" - ]); + // $achpayment = Flutterwave::create("ach"); + // $customerObj = $achpayment->customer->create([ + // "full_name" => "Olaobaju Jesulayomi Abraham", + // "email" => "vicomma@gmail.com", + // "phone" => "+2349067985861" + // ]); - $data['customer'] = $customerObj; - $payload = $achpayment->payload->create($data); - $this->expectExceptionMessage("This bank payment option is not permitted to the merchant"); - $result = $achpayment->initiate($payload); - } + // $data['customer'] = $customerObj; + // $payload = $achpayment->payload->create($data); + // $this->expectExceptionMessage("This bank payment option is not permitted to the merchant"); + // $result = $achpayment->initiate($payload); + // } } \ No newline at end of file From 0a0c9b9ebc885257679ff6b9c99372f69a0eba6f Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham <39011309+bajoski34@users.noreply.github.com> Date: Thu, 2 Mar 2023 15:10:17 +0000 Subject: [PATCH 16/70] update test workflow --- .github/workflows/change-review.yml | 2 +- phpunit.xml.dist | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/change-review.yml b/.github/workflows/change-review.yml index ce566ac..09107aa 100644 --- a/.github/workflows/change-review.yml +++ b/.github/workflows/change-review.yml @@ -48,7 +48,7 @@ jobs: run: composer install --prefer-dist --no-progress - name: run unit tests and coverage scan - run: ./vendor/bin/pest --coverage --min=80 --coverage-clover ./coverage.xml + run: ./vendor/bin/pest --coverage --min=0 --coverage-clover ./coverage.xml - name: upload coverage report to codecov uses: codecov/codecov-action@v2 diff --git a/phpunit.xml.dist b/phpunit.xml.dist index ec3a541..242b53d 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -15,7 +15,14 @@ tests - + + + src + + + + + \ No newline at end of file From 930a56e407cb7eff82481035c87a2cd965536b4a Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Thu, 2 Mar 2023 16:29:37 +0100 Subject: [PATCH 17/70] remove inital workflow --- .github/workflows/test.yml | 44 -------------------------------------- 1 file changed, 44 deletions(-) delete mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 596af21..0000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: PHP Test - -on: - push: - branches: [ "development" ] - pull_request: - branches: [ "development" ] -permissions: - contents: read - -jobs: - build: - - runs-on: ubuntu-latest - - env: - PUBLIC_KEY: ${{ secrets.PUBLIC_KEY }} - SECRET_KEY: ${{ secrets.SECRET_KEY }} - ENCRYPTION_KEY: ${{ secrets.ENCRYPTION_KEY }} - ENV: ${{ secrets.ENV }} - - steps: - - uses: actions/checkout@v3 - - - name: Validate composer.json and composer.lock - run: composer validate --strict - - - name: Cache Composer packages - id: composer-cache - uses: actions/cache@v3 - with: - path: vendor - key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} - restore-keys: | - ${{ runner.os }}-php- - - - name: Install dependencies - run: composer install --prefer-dist --no-progress - - - name: PHPStan analysis - run: vendor/bin/phpstan analyse tests --no-progress --no-interaction --error-format=table - - - name: Run test suite - run: ./vendor/bin/pest From 5bb4738092cda63fd393de8247c2c3934c0a92ee Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Thu, 2 Mar 2023 21:33:07 +0100 Subject: [PATCH 18/70] update: distignore list --- .distignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.distignore b/.distignore index e573ecf..d1908d7 100644 --- a/.distignore +++ b/.distignore @@ -3,4 +3,5 @@ docker-compose.yml .gitignore .github .env.example -.docker \ No newline at end of file +.docker +Makefile From 3d769d76eccb842c8623b1523b869ccd6e291227 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Thu, 2 Mar 2023 21:33:43 +0100 Subject: [PATCH 19/70] update: gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 2b5f84f..718c9d8 100644 --- a/.gitignore +++ b/.gitignore @@ -195,4 +195,6 @@ examples/*.log examples/endpoint/*.log example.php .phpunit.result.cache +.phpunit.cache +coverage.xml .env.local \ No newline at end of file From d4aa7f3afbf55120939589e7ba31b5215a5461db Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Thu, 2 Mar 2023 21:39:09 +0100 Subject: [PATCH 20/70] add reference to envvariable class --- src/AbstractPayment.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/AbstractPayment.php b/src/AbstractPayment.php index 032b4dc..517601b 100644 --- a/src/AbstractPayment.php +++ b/src/AbstractPayment.php @@ -6,6 +6,7 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\EventHandlers\EventHandlerInterface; +use Flutterwave\Helper\EnvVariables; use Flutterwave\Traits\ApiOperations as Api; use Flutterwave\Traits\PayloadOperations as Payload; use Psr\Log\LoggerInterface; @@ -57,7 +58,7 @@ abstract class AbstractPayment public function __construct(string $prefix, bool $overrideRefWithPrefix) { $this->transactionPrefix = $overrideRefWithPrefix ? $prefix : self::$config::DEFAULT_PREFIX . '_'; - $this->baseUrl = self::$config::BASE_URL; + $this->baseUrl = EnvVariables::BASE_URL; } abstract public function initialize(): void; From 19c02fc67bd7743bd845e9947b4d2a51f672b096 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Thu, 2 Mar 2023 21:42:31 +0100 Subject: [PATCH 21/70] refactor: eventHandler error reporting request --- src/EventHandlers/AccountEventHandler.php | 8 ++++++ src/EventHandlers/AchEventHandler.php | 8 ++++++ src/EventHandlers/ApplePayEventHandler.php | 8 ++++++ .../BankTransferEventHandler.php | 8 ++++++ src/EventHandlers/BillEventHandler.php | 8 ++++++ src/EventHandlers/BvnEventHandler.php | 8 ++++++ src/EventHandlers/CardEventHandler.php | 7 +++++ src/EventHandlers/EventTracker.php | 11 +++++--- src/EventHandlers/MomoEventHandler.php | 7 +++++ src/EventHandlers/MpesaEventHandler.php | 15 ++++++++-- src/EventHandlers/PaymentPlanEventHandler.php | 8 ++++++ .../PayoutSubaccoutEventHandler.php | 8 ++++++ src/EventHandlers/PreEventHandler.php | 8 ++++++ src/EventHandlers/RecipientEventHandler.php | 8 ++++++ src/EventHandlers/SettlementEventHandler.php | 8 ++++++ src/EventHandlers/SubaccountEventHandler.php | 8 ++++++ .../SubscriptionEventHandler.php | 8 ++++++ src/EventHandlers/TkEventHandler.php | 8 ++++++ .../TransactionVerificationEventHandler.php | 8 ++++++ src/EventHandlers/TransferEventHandler.php | 7 +++++ src/EventHandlers/UssdEventHandler.php | 8 ++++++ .../VirtualAccountEventHandler.php | 8 ++++++ src/EventHandlers/VoucherEventHandler.php | 8 ++++++ src/Service/AccountPayment.php | 2 +- src/Service/AchPayment.php | 2 +- src/Service/ApplePay.php | 2 +- src/Service/BankTransfer.php | 13 +++++---- src/Service/Banks.php | 11 ++++---- src/Service/Bill.php | 12 ++++---- src/Service/CardPayment.php | 2 +- src/Service/Misc.php | 16 +++++------ src/Service/MobileMoney.php | 8 +++--- src/Service/Mpesa.php | 6 ++-- src/Service/Otps.php | 4 +-- src/Service/PaymentPlan.php | 12 ++++---- src/Service/PayoutSubaccount.php | 27 ++++++++++-------- src/Service/Preauth.php | 18 ++++++------ src/Service/Service.php | 28 +++++++++++++------ src/Service/Settlement.php | 6 ++-- src/Service/Subscription.php | 8 +++--- src/Service/TokenizedCharge.php | 8 +++--- src/Service/Transactions.php | 20 ++++++------- src/Service/Transfer.php | 21 +++++++------- src/Service/Ussd.php | 11 ++++---- src/Service/VirtualAccount.php | 14 +++++----- src/Service/VirtualCard.php | 20 ++++++------- 46 files changed, 331 insertions(+), 131 deletions(-) diff --git a/src/EventHandlers/AccountEventHandler.php b/src/EventHandlers/AccountEventHandler.php index 335c47e..52fc503 100644 --- a/src/EventHandlers/AccountEventHandler.php +++ b/src/EventHandlers/AccountEventHandler.php @@ -4,8 +4,16 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; + class AccountEventHandler implements EventHandlerInterface { + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + use EventTracker; /** diff --git a/src/EventHandlers/AchEventHandler.php b/src/EventHandlers/AchEventHandler.php index a428dc8..c8e3544 100644 --- a/src/EventHandlers/AchEventHandler.php +++ b/src/EventHandlers/AchEventHandler.php @@ -4,10 +4,18 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; + class AchEventHandler implements EventHandlerInterface { use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + /** * This is called only when a transaction is successful * diff --git a/src/EventHandlers/ApplePayEventHandler.php b/src/EventHandlers/ApplePayEventHandler.php index 6096a83..411b352 100644 --- a/src/EventHandlers/ApplePayEventHandler.php +++ b/src/EventHandlers/ApplePayEventHandler.php @@ -4,10 +4,18 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; + class ApplePayEventHandler implements EventHandlerInterface { use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + public function onSuccessful($transactionData): void { // TODO: Implement onSuccessful() method. diff --git a/src/EventHandlers/BankTransferEventHandler.php b/src/EventHandlers/BankTransferEventHandler.php index d69d149..6f39ed2 100644 --- a/src/EventHandlers/BankTransferEventHandler.php +++ b/src/EventHandlers/BankTransferEventHandler.php @@ -4,10 +4,18 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; + class BankTransferEventHandler implements EventHandlerInterface { use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + /** * @inheritDoc */ diff --git a/src/EventHandlers/BillEventHandler.php b/src/EventHandlers/BillEventHandler.php index f5fbb8e..e4752ee 100644 --- a/src/EventHandlers/BillEventHandler.php +++ b/src/EventHandlers/BillEventHandler.php @@ -4,10 +4,18 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; + class BillEventHandler implements EventHandlerInterface { use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + /** * This is called only when a transaction is successful * */ diff --git a/src/EventHandlers/BvnEventHandler.php b/src/EventHandlers/BvnEventHandler.php index 2fe5105..34a3eb7 100644 --- a/src/EventHandlers/BvnEventHandler.php +++ b/src/EventHandlers/BvnEventHandler.php @@ -4,10 +4,18 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; + class BvnEventHandler implements EventHandlerInterface { use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + /** * This is called only when a transaction is successful * */ diff --git a/src/EventHandlers/CardEventHandler.php b/src/EventHandlers/CardEventHandler.php index e817c07..68b232c 100644 --- a/src/EventHandlers/CardEventHandler.php +++ b/src/EventHandlers/CardEventHandler.php @@ -4,12 +4,19 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; use Flutterwave\Util\AuthMode; class CardEventHandler implements EventHandlerInterface { use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + /** * This is called only when a transaction is successful * diff --git a/src/EventHandlers/EventTracker.php b/src/EventHandlers/EventTracker.php index d5b8c11..0c8ba00 100644 --- a/src/EventHandlers/EventTracker.php +++ b/src/EventHandlers/EventTracker.php @@ -4,8 +4,8 @@ namespace Flutterwave\EventHandlers; -use Unirest\Request; -use Unirest\Request\Body; +use Flutterwave\Service\Service as Http; +use Psr\Http\Client\ClientExceptionInterface; trait EventTracker { @@ -22,6 +22,9 @@ public static function setResponseTime(): void self::$response_time = microtime(true) - self::$time_start; } + /** + * @throws ClientExceptionInterface + */ public static function sendAnalytics($title): void { if (self::$response_time <= 0) { @@ -37,8 +40,8 @@ public static function sendAnalytics($title): void 'title' => $title, 'message' => self::$response_time, ]; - $body = Body::json($data); - Request::post($url, [], $body); + + $response = (new Http(static::$config))->request($data, 'POST', $url, true); self::resetTime(); } diff --git a/src/EventHandlers/MomoEventHandler.php b/src/EventHandlers/MomoEventHandler.php index 37991ed..fa88516 100644 --- a/src/EventHandlers/MomoEventHandler.php +++ b/src/EventHandlers/MomoEventHandler.php @@ -4,12 +4,19 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; use Flutterwave\Util\AuthMode; class MomoEventHandler implements EventHandlerInterface { use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + /** * This is called only when a transaction is successful * diff --git a/src/EventHandlers/MpesaEventHandler.php b/src/EventHandlers/MpesaEventHandler.php index 230f504..5c0530e 100644 --- a/src/EventHandlers/MpesaEventHandler.php +++ b/src/EventHandlers/MpesaEventHandler.php @@ -4,15 +4,26 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; +use Psr\Http\Client\ClientExceptionInterface; + class MpesaEventHandler implements EventHandlerInterface { use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + /** * This is called only when a transaction is successful * - * @param array - * */ + * @param array $transactionData + * + * @throws ClientExceptionInterface + */ public function onSuccessful($transactionData): void { // Get the transaction from your DB using the transaction reference (txref) diff --git a/src/EventHandlers/PaymentPlanEventHandler.php b/src/EventHandlers/PaymentPlanEventHandler.php index eed7e55..1469b9e 100644 --- a/src/EventHandlers/PaymentPlanEventHandler.php +++ b/src/EventHandlers/PaymentPlanEventHandler.php @@ -4,10 +4,18 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; + class PaymentPlanEventHandler implements EventHandlerInterface { use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + /** * This is called only when a transaction is successful * */ diff --git a/src/EventHandlers/PayoutSubaccoutEventHandler.php b/src/EventHandlers/PayoutSubaccoutEventHandler.php index 403734d..cf96c90 100644 --- a/src/EventHandlers/PayoutSubaccoutEventHandler.php +++ b/src/EventHandlers/PayoutSubaccoutEventHandler.php @@ -4,10 +4,18 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; + class PayoutSubaccoutEventHandler implements EventHandlerInterface { use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + public function onSuccessful($transactionData): void { // TODO: Implement onSuccessful() method. diff --git a/src/EventHandlers/PreEventHandler.php b/src/EventHandlers/PreEventHandler.php index 75a5c81..c6e0384 100644 --- a/src/EventHandlers/PreEventHandler.php +++ b/src/EventHandlers/PreEventHandler.php @@ -4,10 +4,18 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; + class PreEventHandler implements EventHandlerInterface { use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + public function onSuccessful($transactionData): void { self::sendAnalytics('Initiate-Preauth'); diff --git a/src/EventHandlers/RecipientEventHandler.php b/src/EventHandlers/RecipientEventHandler.php index 9f43599..b5f7326 100644 --- a/src/EventHandlers/RecipientEventHandler.php +++ b/src/EventHandlers/RecipientEventHandler.php @@ -4,10 +4,18 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; + class RecipientEventHandler implements EventHandlerInterface { use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + /** * This is called only when a transaction is successful * */ diff --git a/src/EventHandlers/SettlementEventHandler.php b/src/EventHandlers/SettlementEventHandler.php index 66d4620..1ad3927 100644 --- a/src/EventHandlers/SettlementEventHandler.php +++ b/src/EventHandlers/SettlementEventHandler.php @@ -4,10 +4,18 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; + class SettlementEventHandler implements EventHandlerInterface { use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + /** * This is called only when a transaction is successful * */ diff --git a/src/EventHandlers/SubaccountEventHandler.php b/src/EventHandlers/SubaccountEventHandler.php index 33e610e..450fa4d 100644 --- a/src/EventHandlers/SubaccountEventHandler.php +++ b/src/EventHandlers/SubaccountEventHandler.php @@ -4,10 +4,18 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; + class SubaccountEventHandler implements EventHandlerInterface { use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + /** * This is called only when a transaction is successful * */ diff --git a/src/EventHandlers/SubscriptionEventHandler.php b/src/EventHandlers/SubscriptionEventHandler.php index af103d1..06bb87b 100644 --- a/src/EventHandlers/SubscriptionEventHandler.php +++ b/src/EventHandlers/SubscriptionEventHandler.php @@ -4,10 +4,18 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; + class SubscriptionEventHandler implements EventHandlerInterface { use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + /** * This is called only when a transaction is successful * */ diff --git a/src/EventHandlers/TkEventHandler.php b/src/EventHandlers/TkEventHandler.php index 697a69e..cba58a5 100644 --- a/src/EventHandlers/TkEventHandler.php +++ b/src/EventHandlers/TkEventHandler.php @@ -4,10 +4,18 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; + class TkEventHandler implements EventHandlerInterface { use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + /** * This is called only when a transaction is successful * */ diff --git a/src/EventHandlers/TransactionVerificationEventHandler.php b/src/EventHandlers/TransactionVerificationEventHandler.php index 5e4cf9c..bd857db 100644 --- a/src/EventHandlers/TransactionVerificationEventHandler.php +++ b/src/EventHandlers/TransactionVerificationEventHandler.php @@ -4,6 +4,8 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; + class TransactionVerificationEventHandler implements EventHandlerInterface { /** @@ -12,6 +14,12 @@ class TransactionVerificationEventHandler implements EventHandlerInterface use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + public function onSuccessful($transactionData): void { // Get the transaction from your DB using the transaction reference (txref) diff --git a/src/EventHandlers/TransferEventHandler.php b/src/EventHandlers/TransferEventHandler.php index da3dee0..159a7a0 100644 --- a/src/EventHandlers/TransferEventHandler.php +++ b/src/EventHandlers/TransferEventHandler.php @@ -5,12 +5,19 @@ namespace Flutterwave\EventHandlers; use Exception; +use Flutterwave\Contract\ConfigInterface; use stdClass; class TransferEventHandler implements EventHandlerInterface { use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + /** * This is called only when a transaction is successful * diff --git a/src/EventHandlers/UssdEventHandler.php b/src/EventHandlers/UssdEventHandler.php index 610c8b1..c37b4d7 100644 --- a/src/EventHandlers/UssdEventHandler.php +++ b/src/EventHandlers/UssdEventHandler.php @@ -4,10 +4,18 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; + class UssdEventHandler implements EventHandlerInterface { use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + /** * This is called only when a transaction is successful * */ diff --git a/src/EventHandlers/VirtualAccountEventHandler.php b/src/EventHandlers/VirtualAccountEventHandler.php index eeb4269..99e7ae7 100644 --- a/src/EventHandlers/VirtualAccountEventHandler.php +++ b/src/EventHandlers/VirtualAccountEventHandler.php @@ -4,10 +4,18 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; + class VirtualAccountEventHandler implements EventHandlerInterface { use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + /** * This is called only when a transaction is successful * */ diff --git a/src/EventHandlers/VoucherEventHandler.php b/src/EventHandlers/VoucherEventHandler.php index 04034d6..0d6d530 100644 --- a/src/EventHandlers/VoucherEventHandler.php +++ b/src/EventHandlers/VoucherEventHandler.php @@ -4,10 +4,18 @@ namespace Flutterwave\EventHandlers; +use Flutterwave\Contract\ConfigInterface; + class VoucherEventHandler implements EventHandlerInterface { use EventTracker; + private static ConfigInterface $config; + public function __construct($config) + { + self::$config = $config; + } + /** * This is called only when a transaction is successful * diff --git a/src/Service/AccountPayment.php b/src/Service/AccountPayment.php index ef7c605..06b9a58 100644 --- a/src/Service/AccountPayment.php +++ b/src/Service/AccountPayment.php @@ -35,7 +35,7 @@ public function __construct(?ConfigInterface $config = null) $endpoint = $this->getEndpoint(); $this->url = $this->baseUrl.'/'.$endpoint.'?type='; - $this->eventHandler = new AccountEventHandler(); + $this->eventHandler = new AccountEventHandler($config); } public function setCountry(string $country): void diff --git a/src/Service/AchPayment.php b/src/Service/AchPayment.php index 75e4816..70848b9 100644 --- a/src/Service/AchPayment.php +++ b/src/Service/AchPayment.php @@ -33,7 +33,7 @@ public function __construct(?ConfigInterface $config = null) $endpoint = $this->getEndpoint(); $this->url = $this->baseUrl.'/'.$endpoint.'?type='; - $this->eventHandler = new AchEventHandler(); + $this->eventHandler = new AchEventHandler($config); } public function setCountry(string $country): void diff --git a/src/Service/ApplePay.php b/src/Service/ApplePay.php index 5ab7812..60dc94c 100644 --- a/src/Service/ApplePay.php +++ b/src/Service/ApplePay.php @@ -25,7 +25,7 @@ public function __construct(?ConfigInterface $config = null) $endpoint = $this->getEndpoint(); $this->url = $this->baseUrl.'/'.$endpoint.'?type='; - $this->eventHandler = new ApplePayEventHandler(); + $this->eventHandler = new ApplePayEventHandler($config); } /** diff --git a/src/Service/BankTransfer.php b/src/Service/BankTransfer.php index b150213..136daeb 100644 --- a/src/Service/BankTransfer.php +++ b/src/Service/BankTransfer.php @@ -11,6 +11,7 @@ use Flutterwave\Payload; use Flutterwave\Traits\Group\Charge; use GuzzleHttp\Exception\GuzzleException; +use Psr\Http\Client\ClientExceptionInterface; use stdClass; class BankTransfer extends Service implements Payment @@ -27,7 +28,7 @@ public function __construct(?ConfigInterface $config = null) $endpoint = $this->getEndpoint(); $this->url = $this->baseUrl.'/'.$endpoint.'?type='; - $this->eventHandler = new BankTransferEventHandler(); + $this->eventHandler = new BankTransferEventHandler($config); } public function makePermanent(): void @@ -41,7 +42,7 @@ public function makePermanent(): void * @param Payload $payload * @return array * - * @throws GuzzleException + * @throws ClientExceptionInterface */ public function initiate(Payload $payload): array { @@ -52,8 +53,8 @@ public function initiate(Payload $payload): array * @param Payload $payload * @return array * - * @throws GuzzleException - * @throws Exception + * @throws ClientExceptionInterface + * @throws Exception|ClientExceptionInterface */ public function charge(Payload $payload): array { @@ -65,9 +66,9 @@ public function charge(Payload $payload): array //request payload $body = $payload; - BankTransferEventHandler::startRecording(); + $this->eventHandler::startRecording(); $request = $this->request($body, 'POST', self::TYPE); - BankTransferEventHandler::setResponseTime(); + $this->eventHandler::setResponseTime(); return $this->handleAuthState($request, $body); } diff --git a/src/Service/Banks.php b/src/Service/Banks.php index 132f180..0286e45 100644 --- a/src/Service/Banks.php +++ b/src/Service/Banks.php @@ -6,7 +6,8 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\EventHandlers\EventTracker; -use GuzzleHttp\Exception\GuzzleException; +use Psr\Http\Client\ClientExceptionInterface; +use stdClass; class Banks extends Service { @@ -18,9 +19,9 @@ public function __construct(?ConfigInterface $config = null) } /** - * @throws GuzzleException + * @throws ClientExceptionInterface */ - public function getByCountry(string $country = 'NG'): \stdClass + public function getByCountry(string $country = 'NG'): stdClass { $this->logger->notice("Bank Service::Retrieving banks in country:({$country})."); self::startRecording(); @@ -30,9 +31,9 @@ public function getByCountry(string $country = 'NG'): \stdClass } /** - * @throws GuzzleException + * @throws ClientExceptionInterface */ - public function getBranches(string $id): \stdClass + public function getBranches(string $id): stdClass { $this->logger->notice("Bank Service::Retrieving Bank Branches bank_id:({$id})."); self::startRecording(); diff --git a/src/Service/Bill.php b/src/Service/Bill.php index dcc177e..0fb0111 100644 --- a/src/Service/Bill.php +++ b/src/Service/Bill.php @@ -6,7 +6,7 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\EventHandlers\EventTracker; -use Unirest\Exception; +use Psr\Http\Client\ClientExceptionInterface; class Bill extends Service { @@ -23,7 +23,7 @@ public function __construct(?ConfigInterface $config = null) } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function getCategories(): \stdClass { @@ -35,7 +35,7 @@ public function getCategories(): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function validateService(string $item_code): \stdClass { @@ -47,7 +47,7 @@ public function validateService(string $item_code): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function createPayment(\Flutterwave\Payload $payload): \stdClass { @@ -87,7 +87,7 @@ public function createBulkPayment(array $bulkPayload): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function getBillStatus(string $reference): \stdClass { @@ -99,7 +99,7 @@ public function getBillStatus(string $reference): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function getBillPayments(): \stdClass { diff --git a/src/Service/CardPayment.php b/src/Service/CardPayment.php index f6eb668..b7b9388 100644 --- a/src/Service/CardPayment.php +++ b/src/Service/CardPayment.php @@ -33,7 +33,7 @@ public function __construct(?ConfigInterface $config = null) $this->url = $this->baseUrl.'/'.$endpoint.'?type='.self::TYPE; $this->end_point = self::ENDPOINT.'?type='.self::TYPE; - $this->eventHandler = new CardEventHandler(); + $this->eventHandler = new CardEventHandler($config); } /** diff --git a/src/Service/Misc.php b/src/Service/Misc.php index 59cf6b7..5d71dbb 100644 --- a/src/Service/Misc.php +++ b/src/Service/Misc.php @@ -6,7 +6,7 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\EventHandlers\EventTracker; -use Unirest\Exception; +use Psr\Http\Client\ClientExceptionInterface; class Misc extends Service { @@ -27,7 +27,7 @@ public function __construct(?ConfigInterface $config = null) } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function getWallet($currency): \stdClass { @@ -39,7 +39,7 @@ public function getWallet($currency): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function getWallets(): \stdClass { @@ -51,7 +51,7 @@ public function getWallets(): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function getBalanceHistory(array $queryParams): \stdClass { @@ -71,7 +71,7 @@ public function getBalanceHistory(array $queryParams): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function resolveAccount(\Flutterwave\Payload $payload): \stdClass { @@ -91,7 +91,7 @@ public function resolveAccount(\Flutterwave\Payload $payload): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function resolveBvn(string $bvn): \stdClass { @@ -103,7 +103,7 @@ public function resolveBvn(string $bvn): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function resolveCardBin(string $bin): \stdClass { @@ -115,7 +115,7 @@ public function resolveCardBin(string $bin): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function userBackgroundCheck(array $data): \stdClass { diff --git a/src/Service/MobileMoney.php b/src/Service/MobileMoney.php index 9a2369f..1325f78 100644 --- a/src/Service/MobileMoney.php +++ b/src/Service/MobileMoney.php @@ -10,7 +10,7 @@ use Flutterwave\Payload; use Flutterwave\Traits\Group\Charge; use Flutterwave\Util\Currency; -use GuzzleHttp\Exception\GuzzleException; +use Psr\Http\Client\ClientExceptionInterface; class MobileMoney extends Service implements Payment { @@ -41,13 +41,13 @@ public function __construct(?ConfigInterface $config = null) parent::__construct($config); $endpoint = $this->getEndpoint(); $this->url = $this->baseUrl.'/'.$endpoint.'?type='; - $this->eventHandler = new MomoEventHandler(); + $this->eventHandler = new MomoEventHandler($config); } /** * @param Payload $payload * @return array - * @throws \Exception + * @throws ClientExceptionInterface */ public function initiate(\Flutterwave\Payload $payload): array { @@ -57,7 +57,7 @@ public function initiate(\Flutterwave\Payload $payload): array /** * @param Payload $payload * @return array - * @throws GuzzleException + * @throws ClientExceptionInterface */ public function charge(\Flutterwave\Payload $payload): array { diff --git a/src/Service/Mpesa.php b/src/Service/Mpesa.php index 5ac7a02..871f1e3 100644 --- a/src/Service/Mpesa.php +++ b/src/Service/Mpesa.php @@ -8,7 +8,7 @@ use Flutterwave\Contract\Payment; use Flutterwave\EventHandlers\MpesaEventHandler; use Flutterwave\Traits\Group\Charge; -use Unirest\Exception; +use Psr\Http\Client\ClientExceptionInterface; class Mpesa extends Service implements Payment { @@ -27,7 +27,7 @@ public function __construct(?ConfigInterface $config = null) } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function initiate(\Flutterwave\Payload $payload): array { @@ -35,7 +35,7 @@ public function initiate(\Flutterwave\Payload $payload): array } /** - * @throws Exception + * @throws ClientExceptionInterface * @throws \Exception */ public function charge(\Flutterwave\Payload $payload): array diff --git a/src/Service/Otps.php b/src/Service/Otps.php index b4fc496..d8bfb13 100644 --- a/src/Service/Otps.php +++ b/src/Service/Otps.php @@ -6,7 +6,7 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\EventHandlers\EventTracker; -use Unirest\Exception; +use Psr\Http\Client\ClientExceptionInterface; class Otps extends Service { @@ -19,7 +19,7 @@ public function __construct(?ConfigInterface $config = null) } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function create(\Flutterwave\Payload $payload): \stdClass { diff --git a/src/Service/PaymentPlan.php b/src/Service/PaymentPlan.php index 0f433af..922e708 100644 --- a/src/Service/PaymentPlan.php +++ b/src/Service/PaymentPlan.php @@ -6,7 +6,7 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\EventHandlers\EventTracker; -use Unirest\Exception; +use Psr\Http\Client\ClientExceptionInterface; class PaymentPlan extends Service { @@ -21,7 +21,7 @@ public function __construct(?ConfigInterface $config = null) } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function create(\Flutterwave\Payload $payload): \stdClass { @@ -44,7 +44,7 @@ public function create(\Flutterwave\Payload $payload): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function get(string $id): \stdClass { @@ -56,7 +56,7 @@ public function get(string $id): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function list(): \stdClass { @@ -68,7 +68,7 @@ public function list(): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function update(string $id, \Flutterwave\Payload $payload): \stdClass { @@ -86,7 +86,7 @@ public function update(string $id, \Flutterwave\Payload $payload): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function cancel(string $id): \stdClass { diff --git a/src/Service/PayoutSubaccount.php b/src/Service/PayoutSubaccount.php index 73b45ab..f005d6a 100644 --- a/src/Service/PayoutSubaccount.php +++ b/src/Service/PayoutSubaccount.php @@ -7,7 +7,8 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\EventHandlers\PayoutSubaccoutEventHandler; use Flutterwave\Payload; -use Unirest\Exception; +use Psr\Http\Client\ClientExceptionInterface; +use stdClass; class PayoutSubaccount extends Service { @@ -41,9 +42,11 @@ public function confirmPayload(Payload $payload): array } /** - * @throws Exception + * @param Payload $payload + * @return stdClass + * @throws ClientExceptionInterface */ - public function create(Payload $payload): \stdClass + public function create(Payload $payload): stdClass { $this->logger->notice('PSA Service::Creating new Payout Subaccount.'); $body = $this->confirmPayload($payload); @@ -55,9 +58,9 @@ public function create(Payload $payload): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ - public function list(): \stdClass + public function list(): stdClass { $this->eventHandler::startRecording(); $response = $this->request(null, 'GET'); @@ -66,18 +69,18 @@ public function list(): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function get(string $account_reference): \stdClass { $this->eventHandler::startRecording(); - $response = $this->request(null, 'GET', "/{$account_reference}"); + $response = $this->request(null, 'GET', "/$account_reference"); $this->eventHandler::setResponseTime(); return $response; } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function update(string $account_reference, Payload $payload): \stdClass { @@ -94,7 +97,7 @@ public function update(string $account_reference, Payload $payload): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function fetchTransactions(string $account_reference): \stdClass { @@ -105,7 +108,7 @@ public function fetchTransactions(string $account_reference): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function fetchAvailableBalance(string $account_reference, string $currency = 'NGN'): \stdClass { @@ -116,9 +119,9 @@ public function fetchAvailableBalance(string $account_reference, string $currenc } /** - * @throws Exception + * @throws ClientExceptionInterface */ - public function fetchStaticVirtualAccounts(string $account_reference, string $currency = 'NGN'): \stdClass + public function fetchStaticVirtualAccounts(string $account_reference, string $currency = 'NGN'): stdClass { $this->eventHandler::startRecording(); $response = $this->request(null, 'GET', "/{$account_reference}/static-account?currency={$currency}"); diff --git a/src/Service/Preauth.php b/src/Service/Preauth.php index f8565b9..a13b561 100644 --- a/src/Service/Preauth.php +++ b/src/Service/Preauth.php @@ -7,8 +7,9 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\Contract\Payment; use Flutterwave\EventHandlers\PreEventHandler; +use Flutterwave\Payload; use Flutterwave\Traits\Group\Charge; -use Unirest\Exception; +use Psr\Http\Client\ClientExceptionInterface; class Preauth extends Service implements Payment { @@ -27,9 +28,10 @@ public function __construct(?ConfigInterface $config = null) } /** - * @throws Exception + * @param Payload $payload + * @return array|null */ - public function initiate(\Flutterwave\Payload $payload): ?array + public function initiate(\Flutterwave\Payload $payload): array { $this->logger->info('Preauth Service::Updated Payload...'); $payload->set('preauthorize', 1); @@ -39,9 +41,9 @@ public function initiate(\Flutterwave\Payload $payload): ?array } /** - * @throws Exception + * @throws ClientExceptionInterface */ - public function charge(\Flutterwave\Payload $payload): ?array + public function charge(\Flutterwave\Payload $payload): array { PreEventHandler::startRecording(); $response = $this->cardService->initiate($payload); @@ -55,7 +57,7 @@ public function save(callable $callback): void } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function capture(string $flw_ref, string $method = 'card', string $amount = '0'): array { @@ -94,7 +96,7 @@ public function capture(string $flw_ref, string $method = 'card', string $amount } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function void(string $flw_ref, string $method = 'card'): array { @@ -136,7 +138,7 @@ public function void(string $flw_ref, string $method = 'card'): array } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function refund(string $flw_ref): array { diff --git a/src/Service/Service.php b/src/Service/Service.php index 4ce601a..61d7f7f 100644 --- a/src/Service/Service.php +++ b/src/Service/Service.php @@ -8,9 +8,9 @@ use Flutterwave\Contract\ServiceInterface; use Flutterwave\Helper\Config; use Flutterwave\Helper\EnvVariables; -use GuzzleHttp\ClientInterface; -use GuzzleHttp\Exception\GuzzleException; +use Psr\Http\Client\ClientInterface; use InvalidArgumentException; +use Psr\Http\Client\ClientExceptionInterface; use function is_null; use Psr\Log\LoggerInterface; use stdClass; @@ -52,15 +52,21 @@ public function getName(): string * @param string $verb * @param string $additionalurl * @return stdClass - * @throws GuzzleException + * @throws ClientExceptionInterface */ - protected function request(?array $data = null, string $verb = 'GET', string $additionalurl = ''): stdClass + protected function request( + ?array $data = null, + string $verb = 'GET', + string $additionalurl = '', + bool $overrideUrl = false + ): stdClass { $secret = $this->config->getSecretKey(); + $url = $this->getUrl($overrideUrl, $additionalurl); switch ($verb) { case 'POST': - $response = $this->http->request('POST', $this->url.$additionalurl, [ + $response = $this->http->request('POST', $url, [ 'debug' => false, # TODO: turn to false on release. 'headers' => [ 'Authorization' => "Bearer $secret", @@ -70,7 +76,7 @@ protected function request(?array $data = null, string $verb = 'GET', string $ad ]); break; case 'PUT': - $response = $this->http->request('PUT', $this->url.$additionalurl, [ + $response = $this->http->request('PUT', $url, [ 'debug' => false, # TODO: turn to false on release. 'headers' => [ 'Authorization' => "Bearer $secret", @@ -80,7 +86,7 @@ protected function request(?array $data = null, string $verb = 'GET', string $ad ]); break; case 'DELETE': - $response = $this->http->request('DELETE', $this->url.$additionalurl, [ + $response = $this->http->request('DELETE', $url, [ 'debug' => false, 'headers' => [ 'Authorization' => "Bearer $secret", @@ -89,7 +95,7 @@ protected function request(?array $data = null, string $verb = 'GET', string $ad ]); break; default: - $response = $this->http->request('GET', $this->url.$additionalurl, [ + $response = $this->http->request('GET', $url, [ 'debug' => false, 'headers' => [ 'Authorization' => "Bearer $secret", @@ -127,4 +133,10 @@ private static function bootstrap(?ConfigInterface $config = null): void } self::$spareConfig = $config; } + private function getUrl(bool $overrideUrl, string $additionalurl ): string + { + if($overrideUrl) return $additionalurl; + + return $this->url.$additionalurl; + } } diff --git a/src/Service/Settlement.php b/src/Service/Settlement.php index 8f56990..7e7a4ad 100644 --- a/src/Service/Settlement.php +++ b/src/Service/Settlement.php @@ -6,7 +6,7 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\EventHandlers\EventTracker; -use Unirest\Exception; +use Psr\Http\Client\ClientExceptionInterface; class Settlement extends Service { @@ -18,7 +18,7 @@ public function __construct(?ConfigInterface $config = null) } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function get(string $id): \stdClass { @@ -30,7 +30,7 @@ public function get(string $id): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function list(): \stdClass { diff --git a/src/Service/Subscription.php b/src/Service/Subscription.php index 40a154c..1b27433 100644 --- a/src/Service/Subscription.php +++ b/src/Service/Subscription.php @@ -6,7 +6,7 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\EventHandlers\EventTracker; -use Unirest\Exception; +use Psr\Http\Client\ClientExceptionInterface; class Subscription extends Service { @@ -18,7 +18,7 @@ public function __construct(?ConfigInterface $config = null) } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function list(): \stdClass { @@ -30,7 +30,7 @@ public function list(): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function activate(string $id): \stdClass { @@ -42,7 +42,7 @@ public function activate(string $id): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function deactivate(string $id): \stdClass { diff --git a/src/Service/TokenizedCharge.php b/src/Service/TokenizedCharge.php index 548c82d..ab366e6 100644 --- a/src/Service/TokenizedCharge.php +++ b/src/Service/TokenizedCharge.php @@ -8,7 +8,7 @@ use Flutterwave\Contract\Payment; use Flutterwave\EventHandlers\TkEventHandler; use Flutterwave\Traits\Group\Charge; -use Unirest\Exception; +use Psr\Http\Client\ClientExceptionInterface; class TokenizedCharge extends Service implements Payment { @@ -26,9 +26,9 @@ public function __construct(?ConfigInterface $config = null) } /** - * @throws Exception + * @throws ClientExceptionInterface */ - public function initiate(\Flutterwave\Payload $payload) + public function initiate(\Flutterwave\Payload $payload): array { $this->logger->notice('Tokenize Service::Initiating Card Payment...'); if (! $this->checkPayloadIsValid($payload, 'token')) { @@ -42,7 +42,7 @@ public function initiate(\Flutterwave\Payload $payload) } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function charge(\Flutterwave\Payload $payload): array { diff --git a/src/Service/Transactions.php b/src/Service/Transactions.php index 14439ac..1d77789 100644 --- a/src/Service/Transactions.php +++ b/src/Service/Transactions.php @@ -7,7 +7,7 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\EventHandlers\TransactionVerificationEventHandler; use Flutterwave\Traits\ApiOperations\Post; -use Unirest\Exception; +use Psr\Http\Client\ClientExceptionInterface; class Transactions extends Service { @@ -36,7 +36,7 @@ public function __construct(?ConfigInterface $config = null) } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function verify(string $transactionId): \stdClass { @@ -54,7 +54,7 @@ public function verify(string $transactionId): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function verifyWithTxref(string $tx_ref): \stdClass { @@ -70,7 +70,7 @@ public function verifyWithTxref(string $tx_ref): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function refund(string $trasanctionId): \stdClass { @@ -87,7 +87,7 @@ public function refund(string $trasanctionId): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function getAllTransactions(): \stdClass { @@ -103,7 +103,7 @@ public function getAllTransactions(): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function getRefundInfo(string $trasanctionId): \stdClass { @@ -120,7 +120,7 @@ public function getRefundInfo(string $trasanctionId): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function getTransactionFee(string $amount, string $currency = 'NGN', string $payment_type = 'card'): \stdClass { @@ -158,7 +158,7 @@ public function getTransactionFee(string $amount, string $currency = 'NGN', stri } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function resendFailedHooks(string $transactionId): \stdClass { @@ -175,7 +175,7 @@ public function resendFailedHooks(string $transactionId): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function retrieveTimeline(string $transactionId): \stdClass { @@ -192,7 +192,7 @@ public function retrieveTimeline(string $transactionId): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function validate(string $otp, string $flw_ref): \stdClass { diff --git a/src/Service/Transfer.php b/src/Service/Transfer.php index 2b574c3..3544f9b 100644 --- a/src/Service/Transfer.php +++ b/src/Service/Transfer.php @@ -11,6 +11,7 @@ use Flutterwave\Traits\Group\Charge; use GuzzleHttp\Exception\GuzzleException; use InvalidArgumentException; +use Psr\Http\Client\ClientExceptionInterface; use stdClass; class Transfer extends Service implements Payment @@ -31,7 +32,7 @@ public function __construct(?ConfigInterface $config = null) $endpoint = 'transfers'; $this->url = $this->baseUrl.'/'.$endpoint; - $this->eventHandler = new TransferEventHandler(); + $this->eventHandler = new TransferEventHandler($config); } /** @@ -52,7 +53,7 @@ public function initiate(Payload $payload): array /** * @param Payload $payload * @return array - * @throws GuzzleException + * @throws ClientExceptionInterface */ public function charge(Payload $payload): array { @@ -104,7 +105,7 @@ public function save(callable $callback): void * @return stdClass * retry a previously failed transfer. * - * @throws GuzzleException + * @throws ClientExceptionInterface */ public function retry(?string $transactionId): stdClass { @@ -119,7 +120,7 @@ public function retry(?string $transactionId): stdClass /** * @param Payload $payload * @return stdClass - * @throws GuzzleException + * @throws ClientExceptionInterface */ public function createBulk(Payload $payload): stdClass { @@ -140,7 +141,7 @@ public function createBulk(Payload $payload): stdClass /** * @param string $id * @return stdClass - * @throws GuzzleException + * @throws ClientExceptionInterface */ public function get(string $id): stdClass { @@ -153,7 +154,7 @@ public function get(string $id): stdClass /** * @return stdClass - * @throws GuzzleException + * @throws ClientExceptionInterface */ public function getAll(): stdClass { @@ -167,7 +168,7 @@ public function getAll(): stdClass /** * @param array $params * @return stdClass - * @throws GuzzleException + * @throws ClientExceptionInterface */ public function getFee(array $params = []): stdClass { @@ -189,7 +190,7 @@ public function getFee(array $params = []): stdClass /** * @param string $id * @return stdClass - * @throws GuzzleException + * @throws ClientExceptionInterface */ public function getRetry(string $id): stdClass { @@ -204,7 +205,7 @@ public function getRetry(string $id): stdClass /** * @param string $batch_id * @return stdClass - * @throws GuzzleException + * @throws ClientExceptionInterface */ public function getBulk(string $batch_id): stdClass { @@ -219,7 +220,7 @@ public function getBulk(string $batch_id): stdClass /** * @param array $params * @return stdClass - * @throws GuzzleException + * @throws ClientExceptionInterface */ public function getRates(array $params): stdClass { diff --git a/src/Service/Ussd.php b/src/Service/Ussd.php index 39f1ef1..b441544 100644 --- a/src/Service/Ussd.php +++ b/src/Service/Ussd.php @@ -10,6 +10,7 @@ use Flutterwave\Payload; use Flutterwave\Traits\Group\Charge; use GuzzleHttp\Exception\GuzzleException; +use Psr\Http\Client\ClientExceptionInterface; class Ussd extends Service implements Payment { @@ -46,13 +47,13 @@ public function __construct(?ConfigInterface $config = null) $endpoint = $this->getEndpoint(); $this->url = $this->baseUrl.'/'.$endpoint.'?type='; - $this->eventHandler = new UssdEventHandler(); + $this->eventHandler = new UssdEventHandler($config); } /** * @param Payload $payload * @return array - * @throws \Exception + * @throws ClientExceptionInterface */ public function initiate(\Flutterwave\Payload $payload): array { @@ -63,7 +64,7 @@ public function initiate(\Flutterwave\Payload $payload): array /** * @param Payload $payload * @return array - * @throws GuzzleException + * @throws ClientExceptionInterface */ public function charge(\Flutterwave\Payload $payload): array { @@ -98,11 +99,11 @@ public function charge(\Flutterwave\Payload $payload): array unset($body['country']); unset($body['address']); - UssdEventHandler::startRecording(); + $this->eventHandler::startRecording(); $this->logger->info('Ussd Service::Generating Ussd Code'); $request = $this->request($body, 'POST', self::TYPE); $this->logger->info('Ussd Service::Generated Ussd Code Successfully'); - UssdEventHandler::setResponseTime(); + $this->eventHandler::setResponseTime(); return $this->handleAuthState($request, $body); } diff --git a/src/Service/VirtualAccount.php b/src/Service/VirtualAccount.php index 8248f9a..1d643a8 100644 --- a/src/Service/VirtualAccount.php +++ b/src/Service/VirtualAccount.php @@ -6,7 +6,7 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\EventHandlers\EventTracker; -use Unirest\Exception; +use Psr\Http\Client\ClientExceptionInterface; class VirtualAccount extends Service { @@ -18,7 +18,7 @@ public function __construct(?ConfigInterface $config = null) } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function create(array $payload): \stdClass { @@ -38,7 +38,7 @@ public function create(array $payload): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function createBulk(array $payload): \stdClass { @@ -62,7 +62,7 @@ public function createBulk(array $payload): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function get($order_ref): \stdClass { @@ -74,7 +74,7 @@ public function get($order_ref): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function getBulk($batch_id): \stdClass { @@ -86,7 +86,7 @@ public function getBulk($batch_id): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function update(array $payload): \stdClass { @@ -108,7 +108,7 @@ public function update(array $payload): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function delete($order_ref): \stdClass { diff --git a/src/Service/VirtualCard.php b/src/Service/VirtualCard.php index 07e7933..42e43b4 100644 --- a/src/Service/VirtualCard.php +++ b/src/Service/VirtualCard.php @@ -8,7 +8,7 @@ use Flutterwave\EventHandlers\EventTracker; use Flutterwave\Payload; use InvalidArgumentException; -use Unirest\Exception; +use Psr\Http\Client\ClientExceptionInterface; class VirtualCard extends Service { @@ -34,7 +34,7 @@ public function confirmPayload(Payload $payload): array } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function create(Payload $payload): \stdClass { @@ -48,7 +48,7 @@ public function create(Payload $payload): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function get(string $id): \stdClass { @@ -60,7 +60,7 @@ public function get(string $id): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function list(): \stdClass { @@ -72,7 +72,7 @@ public function list(): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function fund(string $id, array $data): \stdClass { @@ -91,7 +91,7 @@ public function fund(string $id, array $data): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function withdraw(string $id, string $amount = '0'): \stdClass { @@ -103,7 +103,7 @@ public function withdraw(string $id, string $amount = '0'): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function block(string $id): \stdClass { @@ -115,7 +115,7 @@ public function block(string $id): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function unblock(string $id): \stdClass { @@ -127,7 +127,7 @@ public function unblock(string $id): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function terminate(string $id): \stdClass { @@ -139,7 +139,7 @@ public function terminate(string $id): \stdClass } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function getTransactions(string $id, array $options = ['index' => 0, 'size' => 20]): \stdClass { From 7b9996e5f3c2afbd7e7c44594e97f8f58bcc54c5 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Thu, 2 Mar 2023 21:43:15 +0100 Subject: [PATCH 22/70] refactor: ApiOperation traits --- src/Traits/ApiOperations/Delete.php | 15 +++++++-------- src/Traits/ApiOperations/Get.php | 21 ++++++++++++--------- src/Traits/ApiOperations/Post.php | 24 +++++++++++------------- src/Traits/ApiOperations/Put.php | 23 +++++++++++------------ src/Traits/Group/Charge.php | 4 ++-- 5 files changed, 43 insertions(+), 44 deletions(-) diff --git a/src/Traits/ApiOperations/Delete.php b/src/Traits/ApiOperations/Delete.php index e3fd677..584a3f7 100644 --- a/src/Traits/ApiOperations/Delete.php +++ b/src/Traits/ApiOperations/Delete.php @@ -4,17 +4,16 @@ namespace Flutterwave\Traits\ApiOperations; -use Unirest\Request; +use Flutterwave\Contract\ConfigInterface; +use Flutterwave\Service\Service as Http; +use Psr\Http\Client\ClientExceptionInterface; trait Delete { - public function delURL(string $url): string + public function deleteURL(ConfigInterface $config, string $url): string { - $bearerTkn = 'Bearer ' . $this->secretKey; - $headers = ['Content-Type' => 'application/json', 'Authorization' => $bearerTkn]; - //$body = Body::json($data); - $path = $this->baseUrl . '/' . $this->end_point; - $response = Request::delete($path . $url, $headers); - return $response->raw_body; + $response = (new Http($config))->request(null, 'DELETE', $url); + + return ''; } } diff --git a/src/Traits/ApiOperations/Get.php b/src/Traits/ApiOperations/Get.php index 640d8c8..8dcd04f 100644 --- a/src/Traits/ApiOperations/Get.php +++ b/src/Traits/ApiOperations/Get.php @@ -4,18 +4,21 @@ namespace Flutterwave\Traits\ApiOperations; -use Unirest\Request; +use Flutterwave\Contract\ConfigInterface; +use Flutterwave\Service\Service as Http; +use Psr\Http\Client\ClientExceptionInterface; trait Get { - public function getURL(string $url): string + /** + * @param string $url + * @return string + * @throws ClientExceptionInterface + */ + public function getURL(ConfigInterface $config, string $url): string { - // make request to endpoint using unirest. - $bearerTkn = 'Bearer ' . $this->secretKey; - $headers = ['Content-Type' => 'application/json', 'Authorization' => $bearerTkn]; - //$body = Body::json($data); - $path = $this->baseUrl . '/' . $this->end_point; - $response = Request::get($path . $url, $headers); - return $response->raw_body; // Unparsed body + $response = (new Http($config))->request(null, 'GET', $url); + + return ''; } } diff --git a/src/Traits/ApiOperations/Post.php b/src/Traits/ApiOperations/Post.php index 801392e..931574d 100644 --- a/src/Traits/ApiOperations/Post.php +++ b/src/Traits/ApiOperations/Post.php @@ -4,25 +4,23 @@ namespace Flutterwave\Traits\ApiOperations; -use Unirest\Exception; -use Unirest\Request; -use Unirest\Request\Body; +use Flutterwave\Contract\ConfigInterface; +use Flutterwave\Service\Service as Http; +use Psr\Http\Client\ClientExceptionInterface; trait Post { /** - * @param array $data + * @param ConfigInterface $config + * @param array $data * - * @throws Exception + * @return string + * @throws ClientExceptionInterface */ - public function postURL(array $data): string + public function postURL(ConfigInterface $config, array $data): string { - // make request to endpoint using unirest - $bearerTkn = 'Bearer ' . $this->config->getSecretKey(); - $headers = ['Content-Type' => 'application/json', 'Authorization' => $bearerTkn]; - $body = Body::json($data); - $url = $this->baseUrl . '/' . $this->end_point; - $response = Request::post($url, $headers, $body); - return $response->raw_body; // Unparsed body + $response = (new Http($config))->request($data, 'POST', $this->end_point); + + return ''; } } diff --git a/src/Traits/ApiOperations/Put.php b/src/Traits/ApiOperations/Put.php index 48560cb..aef4f06 100644 --- a/src/Traits/ApiOperations/Put.php +++ b/src/Traits/ApiOperations/Put.php @@ -4,24 +4,23 @@ namespace Flutterwave\Traits\ApiOperations; -use Unirest\Exception; -use Unirest\Request; -use Unirest\Request\Body; +use Flutterwave\Contract\ConfigInterface; +use Flutterwave\Service\Service as Http; +use Psr\Http\Client\ClientExceptionInterface; trait Put { /** - * @param array $data + * @param ConfigInterface $config + * @param array $data * - * @throws Exception + * @return string + * @throws ClientExceptionInterface */ - public function putURL(array $data): string + public function putURL(ConfigInterface $config, array $data): string { - $bearerTkn = 'Bearer ' . $this->secretKey; - $headers = ['Content-Type' => 'application/json', 'Authorization' => $bearerTkn]; - $body = Body::json($data); - $url = $this->baseUrl . '/' . $this->end_point; - $response = Request::put($url, $headers, $body); - return $response->raw_body; + $response = (new Http($config))->request($data, 'PUT', $this->end_point); + + return ''; } } diff --git a/src/Traits/Group/Charge.php b/src/Traits/Group/Charge.php index b3be91e..15cd87a 100644 --- a/src/Traits/Group/Charge.php +++ b/src/Traits/Group/Charge.php @@ -5,7 +5,7 @@ namespace Flutterwave\Traits\Group; use Flutterwave\Service\Transactions; -use Unirest\Exception; +use Psr\Http\Client\ClientExceptionInterface; trait Charge { @@ -15,7 +15,7 @@ public function getEndpoint(): string } /** - * @throws Exception + * @throws ClientExceptionInterface */ public function verify(?string $transactionId = null): \stdClass { From bcadfdd217eaa6ce78c7052de22b9d5f802840a2 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Thu, 2 Mar 2023 21:44:07 +0100 Subject: [PATCH 23/70] update ApiException Class --- src/Exception/ApiException.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Exception/ApiException.php b/src/Exception/ApiException.php index 370151d..3ead755 100644 --- a/src/Exception/ApiException.php +++ b/src/Exception/ApiException.php @@ -4,6 +4,8 @@ namespace Flutterwave\Exception; -class ApiException extends \Unirest\Exception +use Psr\Http\Client\ClientExceptionInterface; + +class ApiException extends \Exception { } From 13e809d0e1919fcfc221760c9987d66b19659722 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Thu, 2 Mar 2023 21:44:53 +0100 Subject: [PATCH 24/70] update endpoint example --- examples/endpoint/validate.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/endpoint/validate.php b/examples/endpoint/validate.php index b1065fe..f44d3d0 100644 --- a/examples/endpoint/validate.php +++ b/examples/endpoint/validate.php @@ -23,7 +23,7 @@ if ($res->status === 'success') { echo "Your payment status: " . $res->processor_response; } - } catch (\Unirest\Exception $e) { + } catch (\Psr\Http\Client\ClientExceptionInterface $e) { echo "error: ". $e->getMessage(); } From daff508c6fa8f1fc585d3ee9b2fe7d67fdddc2b1 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Thu, 2 Mar 2023 21:46:51 +0100 Subject: [PATCH 25/70] update phpunit configuration --- phpunit.xml.dist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 242b53d..6ac29fa 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -15,9 +15,9 @@ tests - + - src + ./src From 647764687137b79cf448764b81894473f8ca1b5e Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Thu, 2 Mar 2023 21:48:49 +0100 Subject: [PATCH 26/70] update codecov on change-review workflow --- .github/workflows/change-review.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/change-review.yml b/.github/workflows/change-review.yml index 09107aa..ccecc6b 100644 --- a/.github/workflows/change-review.yml +++ b/.github/workflows/change-review.yml @@ -17,6 +17,7 @@ jobs: php: [8.1, 8.2] env: + XDEBUG_MODE: coverage PUBLIC_KEY: ${{ secrets.PUBLIC_KEY }} SECRET_KEY: ${{ secrets.SECRET_KEY }} ENCRYPTION_KEY: ${{ secrets.ENCRYPTION_KEY }} @@ -50,8 +51,12 @@ jobs: - name: run unit tests and coverage scan run: ./vendor/bin/pest --coverage --min=0 --coverage-clover ./coverage.xml - - name: upload coverage report to codecov + - name: Upload to Codecov uses: codecov/codecov-action@v2 + with: + token: ${{ secrets.CODE_COV_TOKEN }} + files: ./coverage.xml + verbose: true - name: push build status to Slack uses: 8398a7/action-slack@v3 From 392f1e84917b90d06b6148f711048d93575eea69 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Thu, 2 Mar 2023 21:49:10 +0100 Subject: [PATCH 27/70] add Makefile --- Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0fa8af9 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +.PHONY: init +test: + @echo "Installing dependencies..." + @composer install + @echo "Installing dependencies... Done" + @./vendor/bin/pest --coverage --min=0 --coverage-clover ./coverage.xml + + From ab5afbbfab7a7ddc6b5cf8d69071d7136f8a0424 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Thu, 2 Mar 2023 22:16:38 +0100 Subject: [PATCH 28/70] refactor: requeryTransaction --- src/Flutterwave.php | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/Flutterwave.php b/src/Flutterwave.php index b1b8849..7268b15 100644 --- a/src/Flutterwave.php +++ b/src/Flutterwave.php @@ -5,8 +5,10 @@ namespace Flutterwave; use Flutterwave\EventHandlers\EventHandlerInterface; +use Flutterwave\Exception\ApiException; use Flutterwave\Traits\PaymentFactory; use Flutterwave\Traits\Setup\Configure; +use Psr\Http\Client\ClientExceptionInterface; define('FLW_PHP_ASSET_DIR', __DIR__.'../assets/'); @@ -204,6 +206,8 @@ public function eventHandler(EventHandlerInterface $handler): object * Requerys a previous transaction from the Rave payment gateway * * @param string $referenceNumber This should be the reference number of the transaction you want to requery + * @throws ClientExceptionInterface + * @throws ApiException */ public function requeryTransaction(string $referenceNumber): object { @@ -219,24 +223,19 @@ public function requeryTransaction(string $referenceNumber): object // 'only_successful' => '1' ]; - // make request to endpoint using unirest. - $headers = ['Content-Type' => 'application/json', 'Authorization' => 'Bearer '.self::$config->getSecretKey()]; - $body = Body::json($data); - $url = $this->baseUrl . '/transactions/' . $data['id'] . '/verify'; + $url = '/transactions/' . $data['id'] . '/verify'; // Make `POST` request and handle response with unirest - $response = Request::get($url, $headers); - -// print_r($response); + $response = $this->getURL(static::$config, $url); //check the status is success - if ($response->body && $response->body->status === 'success') { - if ($response->body && $response->body->data && $response->body->data->status === 'successful') { + if ($response->status === 'success') { + if ($response->data && $response->data->status === 'successful') { $this->logger->notice('Requeryed a successful transaction....' . json_encode($response->body->data)); // Handle successful if (isset($this->handler)) { $this->handler->onSuccessful($response->body->data); } - } elseif ($response->body && $response->body->data && $response->body->data->status === 'failed') { + } elseif ($response->data && $response->data->status === 'failed') { // Handle Failure $this->logger->warning('Requeryed a failed transaction....' . json_encode($response->body->data)); if (isset($this->handler)) { @@ -244,12 +243,12 @@ public function requeryTransaction(string $referenceNumber): object } } else { // Handled an undecisive transaction. Probably timed out. - $this->logger->warning('Requeryed an undecisive transaction....' . json_encode($response->body->data)); + $this->logger->warning('Requeryed an undecisive transaction....' . json_encode($response->data)); // I will requery again here. Just incase we have some devs that cannot setup a queue for requery. I don't like this. if ($this->requeryCount > 4) { // Now you have to setup a queue by force. We couldn't get a status in 5 requeries. if (isset($this->handler)) { - $this->handler->onTimeout($this->txref, $response->body); + $this->handler->onTimeout($this->txref, $response->data); } } else { $this->logger->notice('delaying next requery for 3 seconds'); @@ -259,7 +258,6 @@ public function requeryTransaction(string $referenceNumber): object } } } else { - // $this->logger->warn('Requery call returned error for transaction reference.....'.json_encode($response->body).'Transaction Reference: '. $this->txref); // Handle Requery Error if (isset($this->handler)) { $this->handler->onRequeryError($response->body); From 4df16455be48c454d08218747872812bbcf081db Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Thu, 2 Mar 2023 22:18:42 +0100 Subject: [PATCH 29/70] update: ApiOperation get trait --- src/Traits/ApiOperations/Get.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Traits/ApiOperations/Get.php b/src/Traits/ApiOperations/Get.php index 8dcd04f..77f98f4 100644 --- a/src/Traits/ApiOperations/Get.php +++ b/src/Traits/ApiOperations/Get.php @@ -5,20 +5,26 @@ namespace Flutterwave\Traits\ApiOperations; use Flutterwave\Contract\ConfigInterface; +use Flutterwave\Exception\ApiException; use Flutterwave\Service\Service as Http; use Psr\Http\Client\ClientExceptionInterface; +use stdClass; trait Get { /** + * @param ConfigInterface $config * @param string $url - * @return string + * @return stdClass * @throws ClientExceptionInterface + * @throws ApiException */ - public function getURL(ConfigInterface $config, string $url): string + public function getURL(ConfigInterface $config, string $url): stdClass { $response = (new Http($config))->request(null, 'GET', $url); - - return ''; + if ($response->status === 'success') { + return $response; + } + throw new ApiException($response->message); } } From f7259efa2bdf8229dfaf60d4104973c4a377136d Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Thu, 2 Mar 2023 22:46:51 +0100 Subject: [PATCH 30/70] depricated: customer and payload class --- src/Customer.php | 19 ++--- src/Entities/Customer.php | 34 +++++++++ src/Entities/Payload.php | 142 ++++++++++++++++++++++++++++++++++++++ src/Payload.php | 115 ++++++------------------------ 4 files changed, 210 insertions(+), 100 deletions(-) create mode 100644 src/Entities/Customer.php create mode 100644 src/Entities/Payload.php diff --git a/src/Customer.php b/src/Customer.php index de4a426..36d1f28 100644 --- a/src/Customer.php +++ b/src/Customer.php @@ -4,33 +4,36 @@ namespace Flutterwave; +/** + * Class Customer + * @package Flutterwave + * @deprecated Use Flutterwave\Entities\Customer instead. + */ class Customer { - private array $data = []; - + private Entities\Customer $instance; public function __construct(array $data = []) { - //TODO: validate data contains the required fields. - $this->data = [...$data]; + $this->instance = new \Flutterwave\Entities\Customer($data); } public function get(string $param) { - return $this->data[$param]; + return $this->instance->get($param); } public function set(string $param, $value): void { - $this->data[$param] = $value; + $this->instance->set($param, $value); } public function has(string $param): bool { - return isset($this->data[$param]); + return $this->instance->has($param); } public function toArray(): array { - return $this->data; + return $this->instance->toArray(); } } diff --git a/src/Entities/Customer.php b/src/Entities/Customer.php new file mode 100644 index 0000000..0de83ac --- /dev/null +++ b/src/Entities/Customer.php @@ -0,0 +1,34 @@ +data = [...$data]; + } + + public function get(string $param) + { + return $this->data[$param]; + } + + public function set(string $param, $value): void + { + $this->data[$param] = $value; + } + + public function has(string $param): bool + { + return isset($this->data[$param]); + } + + public function toArray(): array + { + return $this->data; + } +} diff --git a/src/Entities/Payload.php b/src/Entities/Payload.php new file mode 100644 index 0000000..0c482dc --- /dev/null +++ b/src/Entities/Payload.php @@ -0,0 +1,142 @@ +has($param)) { + return null; + } + return $this->data[$param]; + } + + public function set(string $param, $value): void + { + if ($param === AuthMode::PIN) { + $this->data['otherData']['authorization']['mode'] = self::PIN; + $this->data['otherData']['authorization'][AuthMode::PIN] = $value; + } else { + $this->data[$param] = $value; + } + } + + public function delete(string $param, array $assoc_option = []): void + { + if (! isset($param)) { + return; + } + + if ($param === 'otherData' && count($assoc_option) > 0) { + foreach ($assoc_option as $option) { + unset($this->data['otherData'][$option]); + } + } + unset($this->data[$param]); + } + + public function setPayloadType(string $type): self + { + $this->type = $type; + return $this; + } + + public function toArray(?string $payment_method = null): array + { + $data = $this->data; + $customer = $data['customer'] ?? new Customer(); + $additionalData = $data['otherData'] ?? []; + + if (gettype($customer) === 'string') { + $string_value = $customer; + $customer = new Customer(); + $customer->set('customer', $string_value); + } + + switch ($payment_method) { + case 'card': + $card_details = $additionalData['card_details']; + unset($additionalData['card_details']); + $data = array_merge($data, $additionalData, $customer->toArray(), $card_details); + break; + case 'account': + $account_details = $additionalData['account_details']; + unset($additionalData['account_details']); + $data = array_merge($data, $additionalData, $customer->toArray(), $account_details); + break; + default: + $data = array_merge($data, $additionalData, $customer->toArray()); + break; + } + + unset($data['customer']); + unset($data['otherData']); + + //convert customer obj to array + $data = array_merge($additionalData, $data, $customer->toArray()); + + //if $data['preauthorize'] is false unset + if (isset($data['preauthorize']) && empty($data['preauthorize'])) { + unset($data['preauthorize']); + } + + if (array_key_exists('phone_number', $data) && is_null($data['phone_number'])) { + unset($data['phone_number']); + } + + //if $data['payment_plan'] is null unset + if (isset($data['payment_plan']) && empty($data['payment_plan'])) { + unset($data['payment_plan']); + } + return $data; + } + + public function update($param, $value): void + { + if ($param === 'otherData' && \is_array($value)) { + foreach ($value as $key => $item) { + $this->data['otherData'][$key] = $item; + } + } + + $this->data = array_merge($this->data, [$param => $value]); + } + + public function empty(): void + { + $this->data = []; + } + + public function has(string $param): bool + { + if (! isset($this->data[$param])) { + return false; + } + return true; + } + + public function size(): int + { + return count($this->data); + } + + public function generateTxRef(): void + { + if ($this->has('tx_ref')) { + $this->set('tx_ref', 'FLWPHP|' . (mt_rand(2, 101) + time())); + } + } +} diff --git a/src/Payload.php b/src/Payload.php index 01e65de..50118a1 100644 --- a/src/Payload.php +++ b/src/Payload.php @@ -4,141 +4,72 @@ namespace Flutterwave; -use Flutterwave\Util\AuthMode; - +/** + * Class Payload + * @package Flutterwave + * @deprecated Use Flutterwave\Entities\Payload instead. + */ class Payload { - public const PIN = 'pin'; - public const OTP = 'otp'; - public const REDIRECT = 'redirect'; - public const NOAUTH = 'noauth'; - public const AVS = 'avs'; - protected array $data = []; + private Entities\Payload $instance; - protected ?string $type = null; + public function __construct() + { + $this->instance = new \Flutterwave\Entities\Payload(); + } public function get(string $param) { - if (! $this->has($param)) { + if (! $this->instance->has($param)) { return null; } - return $this->data[$param]; + return $this->instance->get($param); } public function set(string $param, $value): void { - if ($param === AuthMode::PIN) { - $this->data['otherData']['authorization']['mode'] = self::PIN; - $this->data['otherData']['authorization'][AuthMode::PIN] = $value; - } else { - $this->data[$param] = $value; - } + $this->instance->set($param, $value); } public function delete(string $param, array $assoc_option = []): void { - if (! isset($param)) { - return; - } - - if ($param === 'otherData' && count($assoc_option) > 0) { - foreach ($assoc_option as $option) { - unset($this->data['otherData'][$option]); - } - } - unset($this->data[$param]); + $this->instance->delete($param, $assoc_option); } - public function setPayloadType(string $type): self + public function setPayloadType(string $type): Entities\Payload { - $this->type = $type; - return $this; + $this->instance->setPayloadType($type); + return $this->instance; } public function toArray(?string $payment_method = null): array { - $data = $this->data; - $customer = $data['customer'] ?? new Customer(); - $additionalData = $data['otherData'] ?? []; - - if (gettype($customer) === 'string') { - $string_value = $customer; - $customer = new Customer(); - $customer->set('customer', $string_value); - } - - switch ($payment_method) { - case 'card': - $card_details = $additionalData['card_details']; - unset($additionalData['card_details']); - $data = array_merge($data, $additionalData, $customer->toArray(), $card_details); - break; - case 'account': - $account_details = $additionalData['account_details']; - unset($additionalData['account_details']); - $data = array_merge($data, $additionalData, $customer->toArray(), $account_details); - break; - default: - $data = array_merge($data, $additionalData, $customer->toArray()); - break; - } - - unset($data['customer']); - unset($data['otherData']); - - //convert customer obj to array - $data = array_merge($additionalData, $data, $customer->toArray()); - - //if $data['preauthorize'] is false unset - if (isset($data['preauthorize']) && empty($data['preauthorize'])) { - unset($data['preauthorize']); - } - - if (array_key_exists('phone_number', $data) && is_null($data['phone_number'])) { - unset($data['phone_number']); - } - - //if $data['payment_plan'] is null unset - if (isset($data['payment_plan']) && empty($data['payment_plan'])) { - unset($data['payment_plan']); - } - return $data; + return $this->instance->toArray($payment_method); } public function update($param, $value): void { - if ($param === 'otherData' && \is_array($value)) { - foreach ($value as $key => $item) { - $this->data['otherData'][$key] = $item; - } - } - - $this->data = array_merge($this->data, [$param => $value]); + $this->instance->update($param, $value); } public function empty(): void { - $this->data = []; + $this->instance->empty(); } public function has(string $param): bool { - if (! isset($this->data[$param])) { - return false; - } - return true; + return $this->instance->has($param); } public function size(): int { - return count($this->data); + return $this->instance->size(); } public function generateTxRef(): void { - if ($this->has('tx_ref')) { - $this->set('tx_ref', 'FLWPHP|' . (mt_rand(2, 101) + time())); - } + $this->instance->generateTxRef(); } } From 8572cbbfb92017a72e52c1e7d977f0e0f3a68479 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Fri, 3 Mar 2023 00:14:09 +0100 Subject: [PATCH 31/70] depricated: customer and payload factory class --- src/Contract/CustomerInterface.php | 2 +- src/Contract/EntityInterface.php | 10 ++++ src/Contract/FactoryInterface.php | 9 ++++ src/Contract/Payment.php | 4 +- src/Entities/Customer.php | 4 +- src/Entities/Payload.php | 3 +- src/Factories/CustomerFactory.php | 27 +++++++++++ src/Factories/PayloadFactory.php | 70 ++++++++++++++++++++++++++++ src/Service/AccountPayment.php | 8 ++-- src/Service/AchPayment.php | 2 +- src/Service/ApplePay.php | 6 ++- src/Service/BankTransfer.php | 2 +- src/Service/Beneficiaries.php | 18 +++++-- src/Service/CardPayment.php | 16 +++++-- src/Service/CollectionSubaccount.php | 2 +- src/Service/Customer.php | 29 ++++++------ src/Service/MobileMoney.php | 6 +-- src/Service/Mpesa.php | 10 ++-- src/Service/Payload.php | 64 ++++++------------------- src/Service/Preauth.php | 7 +-- src/Service/Service.php | 7 ++- src/Service/TokenizedCharge.php | 4 +- src/Service/Transfer.php | 4 +- src/Service/Ussd.php | 6 +-- src/Traits/Group/Charge.php | 2 +- 25 files changed, 213 insertions(+), 109 deletions(-) create mode 100644 src/Contract/EntityInterface.php create mode 100644 src/Contract/FactoryInterface.php create mode 100644 src/Factories/CustomerFactory.php create mode 100644 src/Factories/PayloadFactory.php diff --git a/src/Contract/CustomerInterface.php b/src/Contract/CustomerInterface.php index 38d5f92..cc90e41 100644 --- a/src/Contract/CustomerInterface.php +++ b/src/Contract/CustomerInterface.php @@ -4,7 +4,7 @@ namespace Flutterwave\Contract; -use Flutterwave\Customer; +use Flutterwave\Entities\Customer; interface CustomerInterface { diff --git a/src/Contract/EntityInterface.php b/src/Contract/EntityInterface.php new file mode 100644 index 0000000..0f1b4c7 --- /dev/null +++ b/src/Contract/EntityInterface.php @@ -0,0 +1,10 @@ +set('fullname', $data['full_name']); + $person->set('email', $data['email']); + $person->set('phone_number', $data['phone']); + $person->set('address', $data['address'] ?? null); + + return $person; + } +} diff --git a/src/Factories/PayloadFactory.php b/src/Factories/PayloadFactory.php new file mode 100644 index 0000000..1eec483 --- /dev/null +++ b/src/Factories/PayloadFactory.php @@ -0,0 +1,70 @@ +validSuppliedData($data); + if (! $check['result']) { + throw new \InvalidArgumentException("".$check['missing_param'].''.' is required in the payload'); + } + + $currency = $data['currency']; + $amount = $data['amount']; + $customer = $data['customer']; + $redirectUrl = $data['redirectUrl'] ?? null; + $otherData = $data['additionalData'] ?? null; + $phone_number = $data['phone'] ?? null; + + if (isset($data['pin']) && ! empty($data['pin'])) { + $otherData['pin'] = $data['pin']; + } + + $payload = new Load(); + + if (! \is_null($phone_number)) { + $payload->set('phone', $phone_number); + } + + $tx_ref = $data['tx_ref'] ?? $payload->generateTxRef(); + +// $payload->set('phone_number', $phone_number); // customer factory handles that + $payload->set('currency', $currency); + $payload->set('amount', $amount); + $payload->set('tx_ref', $tx_ref); + $payload->set('customer', $customer); + $payload->set('redirect_url', $redirectUrl); + $payload->set('otherData', $otherData); + + return $payload; + } + + public function validSuppliedData(array $data): array + { + $params = $this->requiredParams; + + foreach ($params as $param) { + if (! array_key_exists($param, $data)) { + return ['missing_param' => $param, 'result' => false]; + } + } + + if (! $data['customer'] instanceof \Flutterwave\Entities\Customer) { + return ['missing_param' => 'customer', 'result' => false]; + } + + return ['missing_param' => null, 'result' => true]; + } +} diff --git a/src/Service/AccountPayment.php b/src/Service/AccountPayment.php index 06b9a58..f721811 100644 --- a/src/Service/AccountPayment.php +++ b/src/Service/AccountPayment.php @@ -8,10 +8,11 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\Contract\Payment; use Flutterwave\EventHandlers\AccountEventHandler; -use Flutterwave\Payload; +use Flutterwave\Entities\Payload; use Flutterwave\Traits\Group\Charge; use GuzzleHttp\Exception\GuzzleException; use InvalidArgumentException; +use Psr\Http\Client\ClientExceptionInterface; use stdClass; class AccountPayment extends Service implements Payment @@ -62,10 +63,10 @@ public function initiate(Payload $payload): array } /** + * @param Payload $payload * @return array * - * @throws GuzzleException - * @throws Exception + * @throws ClientExceptionInterface */ public function charge(Payload $payload): array { @@ -125,6 +126,7 @@ private function checkSpecialCasesParams(Payload $payload) } /** + * @param stdClass $response * @param array $payload * * @return array diff --git a/src/Service/AchPayment.php b/src/Service/AchPayment.php index 70848b9..239e985 100644 --- a/src/Service/AchPayment.php +++ b/src/Service/AchPayment.php @@ -8,7 +8,7 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\Contract\Payment; use Flutterwave\EventHandlers\AchEventHandler; -use Flutterwave\Payload; +use Flutterwave\Entities\Payload; use Flutterwave\Traits\Group\Charge; use GuzzleHttp\Exception\GuzzleException; use stdClass; diff --git a/src/Service/ApplePay.php b/src/Service/ApplePay.php index 60dc94c..2081629 100644 --- a/src/Service/ApplePay.php +++ b/src/Service/ApplePay.php @@ -7,9 +7,10 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\Contract\Payment; use Flutterwave\EventHandlers\ApplePayEventHandler; -use Flutterwave\Payload; +use Flutterwave\Entities\Payload; use Flutterwave\Traits\Group\Charge; use GuzzleHttp\Exception\GuzzleException; +use Psr\Http\Client\ClientExceptionInterface; use stdClass; class ApplePay extends Service implements Payment @@ -39,9 +40,10 @@ public function initiate(Payload $payload): array } /** + * @param Payload $payload * @return array * - * @throws GuzzleException + * @throws ClientExceptionInterface */ public function charge(Payload $payload): array { diff --git a/src/Service/BankTransfer.php b/src/Service/BankTransfer.php index 136daeb..0a85783 100644 --- a/src/Service/BankTransfer.php +++ b/src/Service/BankTransfer.php @@ -8,7 +8,7 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\Contract\Payment; use Flutterwave\EventHandlers\BankTransferEventHandler; -use Flutterwave\Payload; +use Flutterwave\Entities\Payload; use Flutterwave\Traits\Group\Charge; use GuzzleHttp\Exception\GuzzleException; use Psr\Http\Client\ClientExceptionInterface; diff --git a/src/Service/Beneficiaries.php b/src/Service/Beneficiaries.php index d4c5f04..52f5026 100644 --- a/src/Service/Beneficiaries.php +++ b/src/Service/Beneficiaries.php @@ -6,9 +6,10 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\EventHandlers\EventTracker; -use Flutterwave\Payload; +use Flutterwave\Entities\Payload; use GuzzleHttp\Exception\GuzzleException; use InvalidArgumentException; +use Psr\Http\Client\ClientExceptionInterface; use stdClass; class Beneficiaries extends Service @@ -24,7 +25,9 @@ public function __construct(?ConfigInterface $config = null) } /** - * @throws GuzzleException + * @param Payload $payload + * @return stdClass + * @throws ClientExceptionInterface */ public function create(Payload $payload): stdClass { @@ -53,7 +56,8 @@ public function create(Payload $payload): stdClass } /** - * @throws GuzzleException + * @return stdClass + * @throws ClientExceptionInterface */ public function list(): stdClass { @@ -65,7 +69,9 @@ public function list(): stdClass } /** - * @throws GuzzleException + * @param string $id + * @return stdClass + * @throws ClientExceptionInterface */ public function get(string $id): stdClass { @@ -77,7 +83,9 @@ public function get(string $id): stdClass } /** - * @throws GuzzleException + * @param string $id + * @return stdClass + * @throws ClientExceptionInterface */ public function delete(string $id): stdClass { diff --git a/src/Service/CardPayment.php b/src/Service/CardPayment.php index b7b9388..7e87af4 100644 --- a/src/Service/CardPayment.php +++ b/src/Service/CardPayment.php @@ -4,13 +4,15 @@ namespace Flutterwave\Service; +use Exception; use Flutterwave\Contract\ConfigInterface; use Flutterwave\Contract\Payment; use Flutterwave\EventHandlers\CardEventHandler; -use Flutterwave\Payload; +use Flutterwave\Entities\Payload; use Flutterwave\Traits\Group\Charge; use GuzzleHttp\Exception\GuzzleException; use InvalidArgumentException; +use Psr\Http\Client\ClientExceptionInterface; class CardPayment extends Service implements Payment { @@ -41,7 +43,7 @@ public function __construct(?ConfigInterface $config = null) * @return array * @throws GuzzleException */ - public function initiate(\Flutterwave\Payload $payload): array + public function initiate(Payload $payload): array { if (self::$count >= 2) { //TODO: if payload does not have pin on 2nd request, trigger a warning. @@ -64,11 +66,12 @@ public function save(callable $callback): void } /** + * @param Payload $payload * @return array * - * @throws GuzzleException + * @throws ClientExceptionInterface */ - public function charge(\Flutterwave\Payload $payload): array + public function charge(Payload $payload): array { $tx_ref = $payload->get('tx_ref'); $this->logger->notice("Card Service::Started Charging Card tx_ref:({$tx_ref})..."); @@ -118,7 +121,10 @@ public function encryption(string $params): string } /** - * @throws \Exception + * @param \stdClass $response + * @param $payload + * @return array + * @throws Exception */ public function handleAuthState(\stdClass $response, $payload): array { diff --git a/src/Service/CollectionSubaccount.php b/src/Service/CollectionSubaccount.php index 9fd56d4..3ce7bcb 100644 --- a/src/Service/CollectionSubaccount.php +++ b/src/Service/CollectionSubaccount.php @@ -6,7 +6,7 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\EventHandlers\SubaccountEventHandler; -use Flutterwave\Payload; +use Flutterwave\Entities\Payload; use GuzzleHttp\Exception\GuzzleException; class CollectionSubaccount extends Service diff --git a/src/Service/Customer.php b/src/Service/Customer.php index bfaf444..03b40fa 100644 --- a/src/Service/Customer.php +++ b/src/Service/Customer.php @@ -5,24 +5,25 @@ namespace Flutterwave\Service; use Flutterwave\Contract\CustomerInterface; -use Flutterwave\Customer as Person; +use Flutterwave\Entities\Customer as Person; +use Flutterwave\Factories\CustomerFactory; use InvalidArgumentException; -class Customer implements CustomerInterface +/** + * Class Customer. + * @deprecated use \Flutterwave\Factories\CustomerFactory instead + */ +class Customer { - public function create(array $data = []): Person - { - $data = array_change_key_case($data); - if (empty($data)) { - throw new InvalidArgumentException('Customer data is empty'); - } + protected CustomerInterface $customerFactory; - $person = new Person(); - $person->set('fullname', $data['full_name']); - $person->set('email', $data['email']); - $person->set('phone_number', $data['phone']); - $person->set('address', $data['address'] ?? null); + public function __construct() + { + $this->customerFactory = new CustomerFactory(); + } - return $person; + public function create(array $data = []): Person + { + return $this->customerFactory->create($data); } } diff --git a/src/Service/MobileMoney.php b/src/Service/MobileMoney.php index 1325f78..3356f02 100644 --- a/src/Service/MobileMoney.php +++ b/src/Service/MobileMoney.php @@ -7,7 +7,7 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\Contract\Payment; use Flutterwave\EventHandlers\MomoEventHandler; -use Flutterwave\Payload; +use Flutterwave\Entities\Payload; use Flutterwave\Traits\Group\Charge; use Flutterwave\Util\Currency; use Psr\Http\Client\ClientExceptionInterface; @@ -49,7 +49,7 @@ public function __construct(?ConfigInterface $config = null) * @return array * @throws ClientExceptionInterface */ - public function initiate(\Flutterwave\Payload $payload): array + public function initiate(Payload $payload): array { return $this->charge($payload); } @@ -59,7 +59,7 @@ public function initiate(\Flutterwave\Payload $payload): array * @return array * @throws ClientExceptionInterface */ - public function charge(\Flutterwave\Payload $payload): array + public function charge(Payload $payload): array { $currency = $payload->get('currency'); $otherData = $payload->get('otherData'); diff --git a/src/Service/Mpesa.php b/src/Service/Mpesa.php index 871f1e3..fa428b6 100644 --- a/src/Service/Mpesa.php +++ b/src/Service/Mpesa.php @@ -23,13 +23,13 @@ public function __construct(?ConfigInterface $config = null) $endpoint = $this->getEndpoint(); $this->url = $this->baseUrl.'/'.$endpoint.'?type='; - $this->eventHandler = new MpesaEventHandler(); + $this->eventHandler = new MpesaEventHandler($config); } /** * @throws ClientExceptionInterface */ - public function initiate(\Flutterwave\Payload $payload): array + public function initiate(\Flutterwave\Entities\Payload $payload): array { return $this->charge($payload); } @@ -38,7 +38,7 @@ public function initiate(\Flutterwave\Payload $payload): array * @throws ClientExceptionInterface * @throws \Exception */ - public function charge(\Flutterwave\Payload $payload): array + public function charge(\Flutterwave\Entities\Payload $payload): array { $this->logger->notice('Charging via Mpesa ...'); @@ -63,9 +63,9 @@ public function charge(\Flutterwave\Payload $payload): array unset($body['country']); unset($body['address']); - MpesaEventHandler::startRecording(); + $this->eventHandler::startRecording(); $request = $this->request($body, 'POST', self::TYPE); - MpesaEventHandler::setResponseTime(); + $this->eventHandler::setResponseTime(); return $this->handleAuthState($request, $body); } diff --git a/src/Service/Payload.php b/src/Service/Payload.php index 37c22f8..f0e2339 100644 --- a/src/Service/Payload.php +++ b/src/Service/Payload.php @@ -4,65 +4,27 @@ namespace Flutterwave\Service; -use Flutterwave\Payload as Load; +use Flutterwave\Factories\PayloadFactory as Factory; +/** + * Class Payload. + * @deprecated use \Flutterwave\Factories\PayloadFactory instead + */ class Payload { - protected array $requiredParams = [ - 'amount','tx_ref','currency','customer', - ]; - - public function create(array $data): Load + private Factory $payloadFactory; + public function __construct() { - $check = $this->validSuppliedData($data); - if (! $check['result']) { - throw new \InvalidArgumentException("".$check['missing_param'].''.' is required in the payload'); - } - - $currency = $data['currency']; - $amount = $data['amount']; - $customer = $data['customer']; - $redirectUrl = $data['redirectUrl'] ?? null; - $otherData = $data['additionalData'] ?? null; - $phone_number = $data['phone'] ?? null; - - if (isset($data['pin']) && ! empty($data['pin'])) { - $otherData['pin'] = $data['pin']; - } - - $payload = new Load(); - - if (! \is_null($phone_number)) { - $payload->set('phone', $phone_number); - } - - $tx_ref = $data['tx_ref'] ?? $payload->generateTxRef(); - -// $payload->set('phone_number', $phone_number); // customer factory handles that - $payload->set('currency', $currency); - $payload->set('amount', $amount); - $payload->set('tx_ref', $tx_ref); - $payload->set('customer', $customer); - $payload->set('redirect_url', $redirectUrl); - $payload->set('otherData', $otherData); + $this->payloadFactory = new Factory(); + } - return $payload; + public function create(array $data): \Flutterwave\Entities\Payload + { + return $this->payloadFactory->create($data); } public function validSuppliedData(array $data): array { - $params = $this->requiredParams; - - foreach ($params as $param) { - if (! array_key_exists($param, $data)) { - return ['missing_param' => $param, 'result' => false]; - } - } - - if (! $data['customer'] instanceof \Flutterwave\Customer) { - return ['missing_param' => 'customer', 'result' => false]; - } - - return ['missing_param' => null, 'result' => true]; + return $this->payloadFactory->validSuppliedData($data); } } diff --git a/src/Service/Preauth.php b/src/Service/Preauth.php index a13b561..5eb867a 100644 --- a/src/Service/Preauth.php +++ b/src/Service/Preauth.php @@ -7,7 +7,7 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\Contract\Payment; use Flutterwave\EventHandlers\PreEventHandler; -use Flutterwave\Payload; +use Flutterwave\Entities\Payload; use Flutterwave\Traits\Group\Charge; use Psr\Http\Client\ClientExceptionInterface; @@ -31,7 +31,7 @@ public function __construct(?ConfigInterface $config = null) * @param Payload $payload * @return array|null */ - public function initiate(\Flutterwave\Payload $payload): array + public function initiate(Payload $payload): array { $this->logger->info('Preauth Service::Updated Payload...'); $payload->set('preauthorize', 1); @@ -43,7 +43,7 @@ public function initiate(\Flutterwave\Payload $payload): array /** * @throws ClientExceptionInterface */ - public function charge(\Flutterwave\Payload $payload): array + public function charge(Payload $payload): array { PreEventHandler::startRecording(); $response = $this->cardService->initiate($payload); @@ -163,3 +163,4 @@ public function refund(string $flw_ref): array return $data ?? [ 'message' => 'Charge Refund Failed!']; } } + diff --git a/src/Service/Service.php b/src/Service/Service.php index 61d7f7f..6b9ce00 100644 --- a/src/Service/Service.php +++ b/src/Service/Service.php @@ -5,7 +5,10 @@ namespace Flutterwave\Service; use Flutterwave\Contract\ConfigInterface; +use Flutterwave\Contract\FactoryInterface; use Flutterwave\Contract\ServiceInterface; +use Flutterwave\Factories\CustomerFactory as Customer; +use Flutterwave\Factories\PayloadFactory as Payload; use Flutterwave\Helper\Config; use Flutterwave\Helper\EnvVariables; use Psr\Http\Client\ClientInterface; @@ -18,8 +21,8 @@ class Service implements ServiceInterface { public const ENDPOINT = ''; - public ?Payload $payload; - public ?Customer $customer; + public ?FactoryInterface $payload; + public ?FactoryInterface $customer; protected string $baseUrl; protected LoggerInterface $logger; protected ConfigInterface $config; diff --git a/src/Service/TokenizedCharge.php b/src/Service/TokenizedCharge.php index ab366e6..2c24b2f 100644 --- a/src/Service/TokenizedCharge.php +++ b/src/Service/TokenizedCharge.php @@ -28,7 +28,7 @@ public function __construct(?ConfigInterface $config = null) /** * @throws ClientExceptionInterface */ - public function initiate(\Flutterwave\Payload $payload): array + public function initiate(\Flutterwave\Entities\Payload $payload): array { $this->logger->notice('Tokenize Service::Initiating Card Payment...'); if (! $this->checkPayloadIsValid($payload, 'token')) { @@ -44,7 +44,7 @@ public function initiate(\Flutterwave\Payload $payload): array /** * @throws ClientExceptionInterface */ - public function charge(\Flutterwave\Payload $payload): array + public function charge(\Flutterwave\Entities\Payload $payload): array { # format the customer object to extract the first_name and the last name. $customer = $payload->get('customer')->toArray(); diff --git a/src/Service/Transfer.php b/src/Service/Transfer.php index 3544f9b..7c3d39c 100644 --- a/src/Service/Transfer.php +++ b/src/Service/Transfer.php @@ -7,7 +7,7 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\Contract\Payment; use Flutterwave\EventHandlers\TransferEventHandler; -use Flutterwave\Payload; +use Flutterwave\Entities\Payload; use Flutterwave\Traits\Group\Charge; use GuzzleHttp\Exception\GuzzleException; use InvalidArgumentException; @@ -38,7 +38,7 @@ public function __construct(?ConfigInterface $config = null) /** * @param Payload $payload * @return array - * @throws GuzzleException + * @throws ClientExceptionInterface */ public function initiate(Payload $payload): array { diff --git a/src/Service/Ussd.php b/src/Service/Ussd.php index b441544..af6c027 100644 --- a/src/Service/Ussd.php +++ b/src/Service/Ussd.php @@ -7,7 +7,7 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\Contract\Payment; use Flutterwave\EventHandlers\UssdEventHandler; -use Flutterwave\Payload; +use Flutterwave\Entities\Payload; use Flutterwave\Traits\Group\Charge; use GuzzleHttp\Exception\GuzzleException; use Psr\Http\Client\ClientExceptionInterface; @@ -55,7 +55,7 @@ public function __construct(?ConfigInterface $config = null) * @return array * @throws ClientExceptionInterface */ - public function initiate(\Flutterwave\Payload $payload): array + public function initiate(Payload $payload): array { $this->logger->info('Ussd Service::Initiated Ussd Charge'); return $this->charge($payload); @@ -66,7 +66,7 @@ public function initiate(\Flutterwave\Payload $payload): array * @return array * @throws ClientExceptionInterface */ - public function charge(\Flutterwave\Payload $payload): array + public function charge(Payload $payload): array { $otherData = $payload->get('otherData'); diff --git a/src/Traits/Group/Charge.php b/src/Traits/Group/Charge.php index 15cd87a..160bc27 100644 --- a/src/Traits/Group/Charge.php +++ b/src/Traits/Group/Charge.php @@ -26,7 +26,7 @@ public function verify(?string $transactionId = null): \stdClass return (new Transactions($this->config))->verify($transactionId); } - private function checkPayloadIsValid(\Flutterwave\Payload $payload, string $criteria): bool + private function checkPayloadIsValid(\Flutterwave\Entities\Payload $payload, string $criteria): bool { $this->logger->notice('Charge Group::Verifying Payload ...'); //if does not payload contains $criteria :: false From 5826ea129b27e2dae0e8330e83e37100ffe8bf03 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Fri, 3 Mar 2023 00:19:51 +0100 Subject: [PATCH 32/70] remove test with php 8.1 --- .github/workflows/change-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/change-review.yml b/.github/workflows/change-review.yml index ccecc6b..0ab70ca 100644 --- a/.github/workflows/change-review.yml +++ b/.github/workflows/change-review.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: true matrix: - php: [8.1, 8.2] + php: [8.2] env: XDEBUG_MODE: coverage From 8a9bd88f364027644677d122fa539c2f332ddd04 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Fri, 3 Mar 2023 00:31:07 +0100 Subject: [PATCH 33/70] add test php 8.1 --- .github/workflows/change-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/change-review.yml b/.github/workflows/change-review.yml index 0ab70ca..ccecc6b 100644 --- a/.github/workflows/change-review.yml +++ b/.github/workflows/change-review.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: true matrix: - php: [8.2] + php: [8.1, 8.2] env: XDEBUG_MODE: coverage From f78d4782139083d94a0c76527074c9fc27db5660 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Fri, 3 Mar 2023 00:54:42 +0100 Subject: [PATCH 34/70] add package publish workflow --- .github/workflows/package-publish.yml | 43 +++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .github/workflows/package-publish.yml diff --git a/.github/workflows/package-publish.yml b/.github/workflows/package-publish.yml new file mode 100644 index 0000000..69bbe57 --- /dev/null +++ b/.github/workflows/package-publish.yml @@ -0,0 +1,43 @@ +name: Publish to Packagist + +on: + release: + types: [created] + +jobs: + check-docs-update: + runs-on: ubuntu-latest + env: + OS: ubuntu-latest + PYTHON: '3.7' + steps: + - uses: actions/checkout@v2 + - uses: technote-space/get-diff-action@v6 + with: + PATTERNS: | + +(documentation)/*.md + *.md + CHANGE*.md + FILES: | + CHANGELOG.md + + - name: log git diff + run: | + echo ${{ env.GIT_DIFF }} + echo ${{ env.MATCHED_FILES }} + echo ${{ env.GIT_DIFF_FILTERED }} + + - name: Check if README.md or Doc/** is updated else exit + if: (env.GIT_DIFF == '') + run: | + echo Update documentation files and README.md before push + exit 1 + + - name: push build status to Slack + uses: 8398a7/action-slack@v3 + with: + status: ${{ job.status }} + fields: repo,message,commit,author,action,eventName,ref,workflow,job,took,pullRequest + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + if: always() \ No newline at end of file From e4ca54c640a7898300bfb0ff1e4475f41cd8f7fa Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Fri, 3 Mar 2023 01:39:31 +0100 Subject: [PATCH 35/70] refactor: access env variables --- src/Service/Service.php | 10 ++++++---- src/Traits/Setup/Configure.php | 8 ++++---- tests/Unit/Service/AccountTest.php | 8 ++++---- tests/Unit/Service/AchTest.php | 8 ++++---- tests/Unit/Service/BankTest.php | 8 ++++---- tests/Unit/Service/BankTransferTest.php | 8 ++++---- tests/Unit/Service/BillTest.php | 8 ++++---- tests/Unit/Service/CardTest.php | 8 ++++---- tests/Unit/Service/MomoTest.php | 8 ++++---- tests/Unit/Service/PaymentPlanTest.php | 8 ++++---- tests/Unit/Service/TransferTest.php | 8 ++++---- tests/Unit/Service/UssdTest.php | 8 ++++---- tests/Unit/Service/VirtualAccountTest.php | 8 ++++---- tests/Unit/Service/VirtualCardTest.php | 8 ++++---- 14 files changed, 58 insertions(+), 56 deletions(-) diff --git a/src/Service/Service.php b/src/Service/Service.php index 6b9ce00..a88071e 100644 --- a/src/Service/Service.php +++ b/src/Service/Service.php @@ -128,11 +128,13 @@ private static function bootstrap(?ConfigInterface $config = null): void if (is_null($config)) { require __DIR__.'/../../setup.php'; $config = Config::setUp( - $_SERVER[Config::SECRET_KEY], - $_SERVER[Config::PUBLIC_KEY], - $_SERVER[Config::ENCRYPTION_KEY], - $_SERVER['ENV'] + getenv(Config::SECRET_KEY), + getenv(Config::PUBLIC_KEY), + getenv(Config::ENCRYPTION_KEY), + getenv(Config::ENV) ); + + } self::$spareConfig = $config; } diff --git a/src/Traits/Setup/Configure.php b/src/Traits/Setup/Configure.php index be8de8d..e95aa0f 100644 --- a/src/Traits/Setup/Configure.php +++ b/src/Traits/Setup/Configure.php @@ -14,10 +14,10 @@ public static function bootstrap(?ConfigInterface $config = null): void if (\is_null($config)) { require __DIR__.'/../../../setup.php'; $config = Config::setUp( - $_SERVER[Config::SECRET_KEY], - $_SERVER[Config::PUBLIC_KEY], - $_SERVER[Config::ENCRYPTION_KEY], - $_SERVER['ENV'] + getenv(Config::SECRET_KEY), + getenv(Config::PUBLIC_KEY), + getenv(Config::ENCRYPTION_KEY), + getenv(Config::ENV) ); } self::$config = $config; diff --git a/tests/Unit/Service/AccountTest.php b/tests/Unit/Service/AccountTest.php index e4d216e..a44cc63 100644 --- a/tests/Unit/Service/AccountTest.php +++ b/tests/Unit/Service/AccountTest.php @@ -14,10 +14,10 @@ protected function setUp(): void { Flutterwave::bootstrap( Config::setUp( - $_SERVER[Config::SECRET_KEY], - $_SERVER[Config::PUBLIC_KEY], - $_SERVER[Config::ENCRYPTION_KEY], - $_SERVER[Config::ENV] + getenv(Config::SECRET_KEY), + getenv(Config::PUBLIC_KEY), + getenv(Config::ENCRYPTION_KEY), + getenv(Config::ENV) ) ); } diff --git a/tests/Unit/Service/AchTest.php b/tests/Unit/Service/AchTest.php index aa5d3fb..1410298 100644 --- a/tests/Unit/Service/AchTest.php +++ b/tests/Unit/Service/AchTest.php @@ -15,10 +15,10 @@ protected function setUp(): void { Flutterwave::bootstrap( Config::setUp( - $_SERVER[Config::SECRET_KEY], - $_SERVER[Config::PUBLIC_KEY], - $_SERVER[Config::ENCRYPTION_KEY], - $_SERVER[Config::ENV] + getenv(Config::SECRET_KEY), + getenv(Config::PUBLIC_KEY), + getenv(Config::ENCRYPTION_KEY), + getenv(Config::ENV) ) ); } diff --git a/tests/Unit/Service/BankTest.php b/tests/Unit/Service/BankTest.php index c7cea09..6f3ea44 100644 --- a/tests/Unit/Service/BankTest.php +++ b/tests/Unit/Service/BankTest.php @@ -13,10 +13,10 @@ protected function setUp(): void { $this->service = new Banks( Config::setUp( - $_SERVER[Config::SECRET_KEY], - $_SERVER[Config::PUBLIC_KEY], - $_SERVER[Config::ENCRYPTION_KEY], - $_SERVER[Config::ENV] + getenv(Config::SECRET_KEY), + getenv(Config::PUBLIC_KEY), + getenv(Config::ENCRYPTION_KEY), + getenv(Config::ENV) ) ); } diff --git a/tests/Unit/Service/BankTransferTest.php b/tests/Unit/Service/BankTransferTest.php index 80959c1..0838630 100644 --- a/tests/Unit/Service/BankTransferTest.php +++ b/tests/Unit/Service/BankTransferTest.php @@ -15,10 +15,10 @@ protected function setUp(): void { Flutterwave::bootstrap( Config::setUp( - $_SERVER[Config::SECRET_KEY], - $_SERVER[Config::PUBLIC_KEY], - $_SERVER[Config::ENCRYPTION_KEY], - $_SERVER[Config::ENV] + getenv(Config::SECRET_KEY), + getenv(Config::PUBLIC_KEY), + getenv(Config::ENCRYPTION_KEY), + getenv(Config::ENV) ) ); } diff --git a/tests/Unit/Service/BillTest.php b/tests/Unit/Service/BillTest.php index b1c5efa..8a6cea9 100644 --- a/tests/Unit/Service/BillTest.php +++ b/tests/Unit/Service/BillTest.php @@ -15,10 +15,10 @@ protected function setUp(): void { $this->service = new Bill( Config::setUp( - $_SERVER[Config::SECRET_KEY], - $_SERVER[Config::PUBLIC_KEY], - $_SERVER[Config::ENCRYPTION_KEY], - $_SERVER[Config::ENV] + getenv(Config::SECRET_KEY), + getenv(Config::PUBLIC_KEY), + getenv(Config::ENCRYPTION_KEY), + getenv(Config::ENV) ) ); } diff --git a/tests/Unit/Service/CardTest.php b/tests/Unit/Service/CardTest.php index 85d6b01..7cb096e 100644 --- a/tests/Unit/Service/CardTest.php +++ b/tests/Unit/Service/CardTest.php @@ -15,10 +15,10 @@ protected function setUp(): void { Flutterwave::bootstrap( Config::setUp( - $_SERVER[Config::SECRET_KEY], - $_SERVER[Config::PUBLIC_KEY], - $_SERVER[Config::ENCRYPTION_KEY], - $_SERVER[Config::ENV] + getenv(Config::SECRET_KEY), + getenv(Config::PUBLIC_KEY), + getenv(Config::ENCRYPTION_KEY), + getenv(Config::ENV) ) ); } diff --git a/tests/Unit/Service/MomoTest.php b/tests/Unit/Service/MomoTest.php index 24a4d49..707110a 100644 --- a/tests/Unit/Service/MomoTest.php +++ b/tests/Unit/Service/MomoTest.php @@ -14,10 +14,10 @@ protected function setUp(): void { Flutterwave::bootstrap( Config::setUp( - $_SERVER[Config::SECRET_KEY], - $_SERVER[Config::PUBLIC_KEY], - $_SERVER[Config::ENCRYPTION_KEY], - $_SERVER[Config::ENV] + getenv(Config::SECRET_KEY), + getenv(Config::PUBLIC_KEY), + getenv(Config::ENCRYPTION_KEY), + getenv(Config::ENV) ) ); } diff --git a/tests/Unit/Service/PaymentPlanTest.php b/tests/Unit/Service/PaymentPlanTest.php index 16cee35..075ac71 100644 --- a/tests/Unit/Service/PaymentPlanTest.php +++ b/tests/Unit/Service/PaymentPlanTest.php @@ -15,10 +15,10 @@ protected function setUp(): void { $this->service = new PaymentPlan( Config::setUp( - $_SERVER[Config::SECRET_KEY], - $_SERVER[Config::PUBLIC_KEY], - $_SERVER[Config::ENCRYPTION_KEY], - $_SERVER[Config::ENV] + getenv(Config::SECRET_KEY), + getenv(Config::PUBLIC_KEY), + getenv(Config::ENCRYPTION_KEY), + getenv(Config::ENV) ) ); } diff --git a/tests/Unit/Service/TransferTest.php b/tests/Unit/Service/TransferTest.php index 1cabb23..85d3a35 100644 --- a/tests/Unit/Service/TransferTest.php +++ b/tests/Unit/Service/TransferTest.php @@ -15,10 +15,10 @@ protected function setUp(): void { $this->service = new Transfer( Config::setUp( - $_SERVER[Config::SECRET_KEY], - $_SERVER[Config::PUBLIC_KEY], - $_SERVER[Config::ENCRYPTION_KEY], - $_SERVER[Config::ENV] + getenv(Config::SECRET_KEY), + getenv(Config::PUBLIC_KEY), + getenv(Config::ENCRYPTION_KEY), + getenv(Config::ENV) ) ); } diff --git a/tests/Unit/Service/UssdTest.php b/tests/Unit/Service/UssdTest.php index 89d188a..69a5ab3 100644 --- a/tests/Unit/Service/UssdTest.php +++ b/tests/Unit/Service/UssdTest.php @@ -14,10 +14,10 @@ protected function setUp(): void { Flutterwave::bootstrap( Config::setUp( - $_SERVER[Config::SECRET_KEY], - $_SERVER[Config::PUBLIC_KEY], - $_SERVER[Config::ENCRYPTION_KEY], - $_SERVER[Config::ENV] + getenv(Config::SECRET_KEY), + getenv(Config::PUBLIC_KEY), + getenv(Config::ENCRYPTION_KEY), + getenv(Config::ENV) ) ); } diff --git a/tests/Unit/Service/VirtualAccountTest.php b/tests/Unit/Service/VirtualAccountTest.php index 402cb59..bfc719c 100644 --- a/tests/Unit/Service/VirtualAccountTest.php +++ b/tests/Unit/Service/VirtualAccountTest.php @@ -16,10 +16,10 @@ protected function setUp(): void { $this->service = new VirtualAccount( Config::setUp( - $_SERVER[Config::SECRET_KEY], - $_SERVER[Config::PUBLIC_KEY], - $_SERVER[Config::ENCRYPTION_KEY], - $_SERVER[Config::ENV] + getenv(Config::SECRET_KEY), + getenv(Config::PUBLIC_KEY), + getenv(Config::ENCRYPTION_KEY), + getenv(Config::ENV) ) ); } diff --git a/tests/Unit/Service/VirtualCardTest.php b/tests/Unit/Service/VirtualCardTest.php index d684850..99cf78c 100644 --- a/tests/Unit/Service/VirtualCardTest.php +++ b/tests/Unit/Service/VirtualCardTest.php @@ -16,10 +16,10 @@ protected function setUp(): void { $this->service = new VirtualCard( Config::setUp( - $_SERVER[Config::SECRET_KEY], - $_SERVER[Config::PUBLIC_KEY], - $_SERVER[Config::ENCRYPTION_KEY], - $_SERVER[Config::ENV] + getenv(Config::SECRET_KEY), + getenv(Config::PUBLIC_KEY), + getenv(Config::ENCRYPTION_KEY), + getenv(Config::ENV) ) ); } From e6599b1deccf0c39f3becdd627469aba223a6d45 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Fri, 3 Mar 2023 13:56:50 +0100 Subject: [PATCH 36/70] refactor: cardEventHandler --- CHANGELOG.md | 0 src/Service/CardPayment.php | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e69de29 diff --git a/src/Service/CardPayment.php b/src/Service/CardPayment.php index 7e87af4..db93acb 100644 --- a/src/Service/CardPayment.php +++ b/src/Service/CardPayment.php @@ -89,9 +89,9 @@ public function charge(Payload $payload): array 'client' => $client, ]; - CardEventHandler::startRecording(); + $this->eventHandler::startRecording(); $request = $this->request($body, 'POST'); - CardEventHandler::setResponseTime(); + $this->eventHandler::setResponseTime(); return $this->handleAuthState($request, $payload); } From 17b5e98f609e14e9c746ccbd1760b1392039e8cd Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Fri, 3 Mar 2023 13:57:58 +0100 Subject: [PATCH 37/70] add inline Js script --- src/Flutterwave.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Flutterwave.php b/src/Flutterwave.php index 7268b15..30eeb81 100644 --- a/src/Flutterwave.php +++ b/src/Flutterwave.php @@ -280,7 +280,7 @@ public function initialize(): void // $loader_img_src = FLW_PHP_ASSET_DIR."js/v3.js"; echo '
Proccessing...loading-gif
'; // $script_src = FLW_PHP_ASSET_DIR."js/v3.js"; - echo ''; + echo ''; echo ''; echo ''; + $html .= ''; + $html .= ''; + $html .= ''; + + $this->logger->info('Rendered Payment Modal Successfully..'); + return $html; + } + + public function getUrl() + { + + if ($this->type !== self::STANDARD) { + return $this->returnHtml(); + } + + $default_options = CheckoutHelper::getDefaultPaymentOptions(); + $payload = $this->payload->toArray('modal'); + $currency = $payload['currency']; + $country = CheckoutHelper::getSupportedCountry($currency); + + $payload['country'] = $country; + $payload['customer'] = $payload['customer']->toArray(); + $payload['payment_method'] ?? $default_options; + + $this->logger->info('Generating Payment link for [' . $payload['tx_ref'] . ']'); + $response = (new Http(self::$config))->request($payload, 'POST', 'payments'); + return $response->data->link; + } +} diff --git a/src/Payload.php b/src/Payload.php index 50118a1..cc4644a 100644 --- a/src/Payload.php +++ b/src/Payload.php @@ -6,12 +6,12 @@ /** * Class Payload - * @package Flutterwave + * + * @package Flutterwave * @deprecated Use Flutterwave\Entities\Payload instead. */ class Payload { - private Entities\Payload $instance; public function __construct() diff --git a/src/Service/AccountPayment.php b/src/Service/AccountPayment.php index f721811..b0a5558 100644 --- a/src/Service/AccountPayment.php +++ b/src/Service/AccountPayment.php @@ -18,6 +18,7 @@ class AccountPayment extends Service implements Payment { use Charge; + public const ENDPOINT = 'charge'; public const DEBIT_NG = 'debit_ng_account'; public const DEBIT_UK = 'debit_uk_account'; @@ -35,7 +36,7 @@ public function __construct(?ConfigInterface $config = null) $endpoint = $this->getEndpoint(); - $this->url = $this->baseUrl.'/'.$endpoint.'?type='; + $this->url = $this->baseUrl . '/' . $endpoint . '?type='; $this->eventHandler = new AccountEventHandler($config); } @@ -63,7 +64,7 @@ public function initiate(Payload $payload): array } /** - * @param Payload $payload + * @param Payload $payload * @return array * * @throws ClientExceptionInterface @@ -98,7 +99,7 @@ public function save(callable $callback): void private function checkSpecialCasesParams(Payload $payload) { $details = $payload->get('otherData')['account_details']; - $banks = require __DIR__ . '/../Util/unique_bank_cases.php'; + $banks = include __DIR__ . '/../Util/unique_bank_cases.php'; foreach ($banks as $code => $case) { if ($details['account_bank'] === $code) { @@ -127,7 +128,7 @@ private function checkSpecialCasesParams(Payload $payload) /** * @param stdClass $response - * @param array $payload + * @param array $payload * * @return array * diff --git a/src/Service/AchPayment.php b/src/Service/AchPayment.php index 239e985..924a8b8 100644 --- a/src/Service/AchPayment.php +++ b/src/Service/AchPayment.php @@ -32,7 +32,7 @@ public function __construct(?ConfigInterface $config = null) parent::__construct($config); $endpoint = $this->getEndpoint(); - $this->url = $this->baseUrl.'/'.$endpoint.'?type='; + $this->url = $this->baseUrl . '/' . $endpoint . '?type='; $this->eventHandler = new AchEventHandler($config); } diff --git a/src/Service/ApplePay.php b/src/Service/ApplePay.php index 2081629..498f7f5 100644 --- a/src/Service/ApplePay.php +++ b/src/Service/ApplePay.php @@ -25,7 +25,7 @@ public function __construct(?ConfigInterface $config = null) parent::__construct($config); $endpoint = $this->getEndpoint(); - $this->url = $this->baseUrl.'/'.$endpoint.'?type='; + $this->url = $this->baseUrl . '/' . $endpoint . '?type='; $this->eventHandler = new ApplePayEventHandler($config); } @@ -40,7 +40,7 @@ public function initiate(Payload $payload): array } /** - * @param Payload $payload + * @param Payload $payload * @return array * * @throws ClientExceptionInterface diff --git a/src/Service/BankTransfer.php b/src/Service/BankTransfer.php index 0a85783..748038d 100644 --- a/src/Service/BankTransfer.php +++ b/src/Service/BankTransfer.php @@ -27,7 +27,7 @@ public function __construct(?ConfigInterface $config = null) parent::__construct($config); $endpoint = $this->getEndpoint(); - $this->url = $this->baseUrl.'/'.$endpoint.'?type='; + $this->url = $this->baseUrl . '/' . $endpoint . '?type='; $this->eventHandler = new BankTransferEventHandler($config); } @@ -39,7 +39,7 @@ public function makePermanent(): void } /** - * @param Payload $payload + * @param Payload $payload * @return array * * @throws ClientExceptionInterface @@ -50,7 +50,7 @@ public function initiate(Payload $payload): array } /** - * @param Payload $payload + * @param Payload $payload * @return array * * @throws ClientExceptionInterface @@ -78,8 +78,8 @@ public function save(callable $callback): void } /** - * @param stdClass $response - * @param array $payload + * @param stdClass $response + * @param array $payload * @return array * @throws Exception */ diff --git a/src/Service/Banks.php b/src/Service/Banks.php index 0286e45..17795d7 100644 --- a/src/Service/Banks.php +++ b/src/Service/Banks.php @@ -12,6 +12,7 @@ class Banks extends Service { use EventTracker; + private string $name = 'banks'; public function __construct(?ConfigInterface $config = null) { @@ -25,7 +26,7 @@ public function getByCountry(string $country = 'NG'): stdClass { $this->logger->notice("Bank Service::Retrieving banks in country:({$country})."); self::startRecording(); - $response = $this->request(null, 'GET', $this->name."/{$country}"); + $response = $this->request(null, 'GET', $this->name . "/{$country}"); self::setResponseTime(); return $response; } @@ -37,7 +38,7 @@ public function getBranches(string $id): stdClass { $this->logger->notice("Bank Service::Retrieving Bank Branches bank_id:({$id})."); self::startRecording(); - $response = $this->request(null, 'GET', $this->name."/{$id}/branches"); + $response = $this->request(null, 'GET', $this->name . "/{$id}/branches"); self::setResponseTime(); return $response; } diff --git a/src/Service/Beneficiaries.php b/src/Service/Beneficiaries.php index 52f5026..de10433 100644 --- a/src/Service/Beneficiaries.php +++ b/src/Service/Beneficiaries.php @@ -15,6 +15,7 @@ class Beneficiaries extends Service { use EventTracker; + private string $name = 'beneficiaries'; private array $requiredParams = [ 'account_bank','account_number','beneficiary_name', @@ -25,7 +26,7 @@ public function __construct(?ConfigInterface $config = null) } /** - * @param Payload $payload + * @param Payload $payload * @return stdClass * @throws ClientExceptionInterface */ @@ -34,14 +35,16 @@ public function create(Payload $payload): stdClass $payload = $payload->toArray(); if (array_key_exists('customer', $payload)) { - $this->logger->error('Beneficiaries Service::The required parameter customer Object is not present in payload'); - throw new InvalidArgumentException('Beneficiaries Service:The required parameter Object is not present in payload'); + $msg = 'The required parameter customer Object is not present in payload'; + $this->logger->error('Beneficiaries Service::' . $msg); + throw new InvalidArgumentException('Beneficiaries Service:' . $msg); } foreach ($this->requiredParams as $param) { if (! array_key_exists($param, $payload)) { - $this->logger->error("Beneficiaries Service::The required parameter {$param} is not present in payload"); - throw new InvalidArgumentException("Beneficiaries Service:The required parameter {$param} is not present in payload"); + $msg = 'The required parameter {$param} is not present in payload'; + $this->logger->error("Beneficiaries Service::$msg"); + throw new InvalidArgumentException("Beneficiaries Service:$msg"); } } @@ -69,7 +72,7 @@ public function list(): stdClass } /** - * @param string $id + * @param string $id * @return stdClass * @throws ClientExceptionInterface */ @@ -77,13 +80,13 @@ public function get(string $id): stdClass { $this->logger->notice('Beneficiaries Service::Retrieving a Beneficiary.'); self::startRecording(); - $response = $this->request(null, 'GET', $this->name."/{$id}"); + $response = $this->request(null, 'GET', $this->name . "/{$id}"); self::setResponseTime(); return $response; } /** - * @param string $id + * @param string $id * @return stdClass * @throws ClientExceptionInterface */ @@ -91,7 +94,7 @@ public function delete(string $id): stdClass { $this->logger->notice('Beneficiaries Service::Delete a Beneficiary.'); self::startRecording(); - $response = $this->request(null, 'DELETE', $this->name."/{$id}"); + $response = $this->request(null, 'DELETE', $this->name . "/{$id}"); self::setResponseTime(); return $response; } diff --git a/src/Service/Bill.php b/src/Service/Bill.php index 0fb0111..661cce5 100644 --- a/src/Service/Bill.php +++ b/src/Service/Bill.php @@ -11,6 +11,7 @@ class Bill extends Service { use EventTracker; + protected ?array $categories = null; private string $name = 'bill-categories'; private array $requiredParams = [ @@ -19,7 +20,7 @@ class Bill extends Service public function __construct(?ConfigInterface $config = null) { parent::__construct($config); - $this->categories = require __DIR__ . '/../Util/bill_categories.php'; + $this->categories = include __DIR__ . '/../Util/bill_categories.php'; } /** @@ -41,7 +42,7 @@ public function validateService(string $item_code): \stdClass { $this->logger->notice('Bill Payment Service::Retrieving all Plans.'); self::startRecording(); - $response = $this->request(null, 'GET', $this->name."bill-item/{$item_code}/validate"); + $response = $this->request(null, 'GET', $this->name . "bill-item/{$item_code}/validate"); self::setResponseTime(); return $response; } @@ -51,12 +52,12 @@ public function validateService(string $item_code): \stdClass */ public function createPayment(\Flutterwave\Payload $payload): \stdClass { - $payload = $payload = $payload->toArray(); foreach ($this->requiredParams as $param) { if (! array_key_exists($param, $payload)) { - $this->logger->error("Bill Payment Service::The required parameter {$param} is not present in payload"); - throw new \InvalidArgumentException("Bill Payment Service:The required parameter {$param} is not present in payload"); + $msg = 'The required parameter {$param} is not present in payload'; + $this->logger->error("Bill Payment Service::$msg"); + throw new \InvalidArgumentException("Bill Payment Service:$msg"); } } @@ -73,8 +74,9 @@ public function createPayment(\Flutterwave\Payload $payload): \stdClass public function createBulkPayment(array $bulkPayload): \stdClass { if (empty($bulkPayload)) { - $this->logger->error('Bill Payment Service::Bulk Payload is empty. Pass a filled array'); - throw new \InvalidArgumentException('Bill Payment Service::Bulk Payload is currently empty. Pass a filled array'); + $msg = 'Bulk Payload is empty. Pass a filled array'; + $this->logger->error('Bill Payment Service::' . $msg); + throw new \InvalidArgumentException('Bill Payment Service::' . $msg); } $body = $bulkPayload; diff --git a/src/Service/CardPayment.php b/src/Service/CardPayment.php index db93acb..0bbf487 100644 --- a/src/Service/CardPayment.php +++ b/src/Service/CardPayment.php @@ -17,6 +17,7 @@ class CardPayment extends Service implements Payment { use Charge; + public const ENDPOINT = 'charges'; public const TYPE = 'card'; protected static int $count = 0; @@ -33,13 +34,13 @@ public function __construct(?ConfigInterface $config = null) $endpoint = $this->getEndpoint(); - $this->url = $this->baseUrl.'/'.$endpoint.'?type='.self::TYPE; - $this->end_point = self::ENDPOINT.'?type='.self::TYPE; + $this->url = $this->baseUrl . '/' . $endpoint . '?type=' . self::TYPE; + $this->end_point = self::ENDPOINT . '?type=' . self::TYPE; $this->eventHandler = new CardEventHandler($config); } /** - * @param Payload $payload + * @param Payload $payload * @return array * @throws GuzzleException */ @@ -66,7 +67,7 @@ public function save(callable $callback): void } /** - * @param Payload $payload + * @param Payload $payload * @return array * * @throws ClientExceptionInterface @@ -96,9 +97,11 @@ public function charge(Payload $payload): array } /** - * this is the encrypt3Des function that generates an encryption Key for you by passing your transaction Util and Secret Key as a parameter. - * @param string $data - * @param $key + * this is the encrypt3Des function that generates an encryption Key for you + * by passing your transaction Util and Secret Key as a parameter. + * + * @param string $data + * @param $key * @return string */ @@ -121,8 +124,8 @@ public function encryption(string $params): string } /** - * @param \stdClass $response - * @param $payload + * @param \stdClass $response + * @param $payload * @return array * @throws Exception */ diff --git a/src/Service/ChargeBacks.php b/src/Service/ChargeBacks.php index d5082fd..f61812d 100644 --- a/src/Service/ChargeBacks.php +++ b/src/Service/ChargeBacks.php @@ -11,6 +11,7 @@ class ChargeBacks extends Service { use EventTracker; + private string $name = 'chargebacks'; public function __construct(?ConfigInterface $config = null) { @@ -24,7 +25,7 @@ public function get(string $flw_ref): \stdClass { $this->logger->notice("ChargeBacks Service::Retrieving Chargeback.[flw_ref:{$flw_ref}]"); self::startRecording(); - $response = $this->request(null, 'GET', $this->name."?flw_ref={$flw_ref}"); + $response = $this->request(null, 'GET', $this->name . "?flw_ref={$flw_ref}"); self::setResponseTime(); return $response; } @@ -37,7 +38,7 @@ public function getAll(array $filters = []): \stdClass $query = http_build_query($filters) ?? ''; $this->logger->notice('ChargeBacks Service::Retrieving Chargebacks.[all]'); self::startRecording(); - $response = $this->request(null, 'GET', $this->name."?{$query}"); + $response = $this->request(null, 'GET', $this->name . "?{$query}"); self::setResponseTime(); return $response; } @@ -49,7 +50,7 @@ public function accept(string $chargeback_id): \stdClass { $this->logger->notice("ChargeBacks Service::Accepting Chargeback [{$chargeback_id}]."); self::startRecording(); - $response = $this->request([ 'action' => 'accept'], 'PUT', $this->name."/{$chargeback_id}"); + $response = $this->request([ 'action' => 'accept'], 'PUT', $this->name . "/{$chargeback_id}"); self::setResponseTime(); return $response; } @@ -61,7 +62,7 @@ public function decline(string $chargeback_id): \stdClass { $this->logger->notice("ChargeBacks Service::Declining Chargeback [{$chargeback_id}]."); self::startRecording(); - $response = $this->request([ 'action' => 'decline'], 'PUT', $this->name."/{$chargeback_id}"); + $response = $this->request([ 'action' => 'decline'], 'PUT', $this->name . "/{$chargeback_id}"); self::setResponseTime(); return $response; } diff --git a/src/Service/CollectionSubaccount.php b/src/Service/CollectionSubaccount.php index 3ce7bcb..b28ac75 100644 --- a/src/Service/CollectionSubaccount.php +++ b/src/Service/CollectionSubaccount.php @@ -12,14 +12,21 @@ class CollectionSubaccount extends Service { private SubaccountEventHandler $eventHandler; + private string $name = 'subaccounts'; - private array $requiredParams = [ 'account_bank', 'account_number', 'business_name', 'split_value', 'business_mobile','business_email', 'country' ]; + + private array $requiredParams = [ + 'account_bank', 'account_number', + 'business_name', 'split_value', + 'business_mobile','business_email', 'country' + ]; private array $requiredParamsUpdate = [ 'split_value']; + public function __construct(?ConfigInterface $config = null) { parent::__construct($config); $endpoint = $this->name; - $this->url = $this->baseUrl.'/'.$endpoint; + $this->url = $this->baseUrl . '/' . $endpoint; $this->eventHandler = new SubaccountEventHandler(); } @@ -27,8 +34,9 @@ public function confirmPayload(Payload $payload): array { foreach ($this->requiredParams as $param) { if (! $payload->has($param)) { - $this->logger->error("Subaccount Service::The required parameter {$param} is not present in payload"); - throw new \InvalidArgumentException("Subaccount Service:The required parameter {$param} is not present in payload"); + $msg = "The required parameter {$param} is not present in payload"; + $this->logger->error("Subaccount Service::" . $msg); + throw new \InvalidArgumentException("Subaccount Service:" . $msg); } } @@ -36,7 +44,7 @@ public function confirmPayload(Payload $payload): array } /** - * @param Payload $payload + * @param Payload $payload * @return \stdClass * @throws GuzzleException */ @@ -71,7 +79,7 @@ public function list(): \stdClass } /** - * @param string $id + * @param string $id * @return \stdClass * @throws GuzzleException */ @@ -84,8 +92,8 @@ public function get(string $id): \stdClass } /** - * @param string $id - * @param Payload $payload + * @param string $id + * @param Payload $payload * @return \stdClass * @throws GuzzleException */ @@ -93,8 +101,9 @@ public function update(string $id, Payload $payload): \stdClass { foreach ($this->requiredParamsUpdate as $param) { if (! $payload->has($param)) { - $this->logger->error("Subaccount Service::The required parameter {$param} is not present in payload"); - throw new \InvalidArgumentException("Subaccount Service:The required parameter {$param} is not present in payload"); + $msg = "The required parameter {$param} is not present in payload"; + $this->logger->error("Subaccount Service::" . $msg); + throw new \InvalidArgumentException("Subaccount Service:" . $msg); } } @@ -106,7 +115,7 @@ public function update(string $id, Payload $payload): \stdClass } /** - * @param string $id + * @param string $id * @return \stdClass * @throws GuzzleException */ diff --git a/src/Service/Customer.php b/src/Service/Customer.php index 03b40fa..f924b6a 100644 --- a/src/Service/Customer.php +++ b/src/Service/Customer.php @@ -11,6 +11,7 @@ /** * Class Customer. + * * @deprecated use \Flutterwave\Factories\CustomerFactory instead */ class Customer @@ -24,6 +25,6 @@ public function __construct() public function create(array $data = []): Person { - return $this->customerFactory->create($data); + return $this->customerFactory->create($data); } } diff --git a/src/Service/Misc.php b/src/Service/Misc.php index 5d71dbb..ac4f9fc 100644 --- a/src/Service/Misc.php +++ b/src/Service/Misc.php @@ -11,6 +11,7 @@ class Misc extends Service { use EventTracker; + private string $name = 'balances'; private array $requiredParamsHistory = [ 'from','to','currency', @@ -57,8 +58,9 @@ public function getBalanceHistory(array $queryParams): \stdClass { foreach ($this->requiredParamsHistory as $param) { if (! array_key_exists($param, $queryParams)) { - $this->logger->error("Misc Service::The following parameter is missing to check balance history: {$param}"); - throw new \InvalidArgumentException("The following parameter is missing to check balance history: {$param}"); + $msg = "The following parameter is missing to check balance history: {$param}"; + $this->logger->error("Misc Service::$msg"); + throw new \InvalidArgumentException($msg); } } @@ -121,8 +123,9 @@ public function userBackgroundCheck(array $data): \stdClass { foreach ($this->requiredParamsUserBackground as $param) { if (! array_key_exists($param, $data)) { - $this->logger->error("Misc Service::The following parameter is missing to check user background: {$param}"); - throw new \InvalidArgumentException("The following parameter is missing to check user background: {$param}"); + $msg = "The following parameter is missing to check user background: {$param}"; + $this->logger->error("Misc Service::$msg"); + throw new \InvalidArgumentException($msg); } } diff --git a/src/Service/MobileMoney.php b/src/Service/MobileMoney.php index 3356f02..6e05d64 100644 --- a/src/Service/MobileMoney.php +++ b/src/Service/MobileMoney.php @@ -40,12 +40,12 @@ public function __construct(?ConfigInterface $config = null) { parent::__construct($config); $endpoint = $this->getEndpoint(); - $this->url = $this->baseUrl.'/'.$endpoint.'?type='; + $this->url = $this->baseUrl . '/' . $endpoint . '?type='; $this->eventHandler = new MomoEventHandler($config); } /** - * @param Payload $payload + * @param Payload $payload * @return array * @throws ClientExceptionInterface */ @@ -55,7 +55,7 @@ public function initiate(Payload $payload): array } /** - * @param Payload $payload + * @param Payload $payload * @return array * @throws ClientExceptionInterface */ @@ -66,13 +66,16 @@ public function charge(Payload $payload): array if (! array_key_exists($currency, $this->types)) { $supported_currencies = json_encode(array_keys($this->types)); - $this->logger->warning("Momo Service::The currency {$currency} is not supported for this payment method. options [ {$supported_currencies} ]"); - throw new \InvalidArgumentException("The currency {$currency} is not supported for this payment method. options [ {$supported_currencies} ]"); + $msg = "The currency {$currency} is not supported for this payment method. + options [ {$supported_currencies} ]"; + $this->logger->warning("Momo Service:: $msg"); + throw new \InvalidArgumentException($msg); } if (is_null($otherData)) { - $this->logger->error("Momo Service::Please pass the parameter 'network' into the additionalData array"); - throw new \InvalidArgumentException("Please pass the parameter 'network' into the additionalData array"); + $msg = "Please pass the parameter 'network' into the additionalData array"; + $this->logger->error("Momo Service::$msg"); + throw new \InvalidArgumentException($msg); } $this->isNetworkValid($otherData, $currency); @@ -97,55 +100,60 @@ public function save(callable $callback): void private function isNetworkValid(array $otherData, string $currency): bool { - switch($currency) { - case Currency::GHS: - if (! isset($otherData['network'])) { - $this->logger->error('Ghana Momo Service::network parameter is required.'); - throw new \InvalidArgumentException('Ghana Momo Service: network parameter is required.'); - } - if (! in_array($otherData['network'], $this->networks['GH'])) { - $this->logger->error('network passed is not supported for ghana momo.'); - throw new \InvalidArgumentException('Ghana Momo Service: network passed is not supported. options: '. json_encode($this->networks['GH'])); - } - break; - case Currency::UGX: - if (! isset($otherData['network'])) { - $this->logger->error('Uganda Momo Service::network parameter is required.'); - throw new \InvalidArgumentException('Uganda Momo Service: network parameter is required.'); - } - if (! in_array($otherData['network'], $this->networks['UG'])) { - $this->logger->error('network passed is not supported for uganda momo.'); - throw new \InvalidArgumentException('Uganda Momo Service: network passed is not supported.'); - } - break; - case Currency::ZMW: - if (! isset($otherData['network'])) { - $this->logger->error('Zambia Momo Service::network parameter is required.'); - throw new \InvalidArgumentException('Uganda Momo Service: network parameter is required.'); - } - if (! in_array($otherData['network'], $this->networks['ZM'])) { - $this->logger->error('network passed is not supported for zambia momo.'); - throw new \InvalidArgumentException('Zambia Momo Service: network passed is not supported.'); - } - break; - case Currency::XAF: - if (! isset($otherData['country'])) { - $this->logger->error('Franco Momo Service::country parameter is required.'); - throw new \InvalidArgumentException('Franco Momo Service: country parameter is required.'); - } - if (! in_array($otherData['country'], $this->supported_countries_franco)) { - $this->logger->error('Franco Momo Service::country passed is not supported.'); - throw new \InvalidArgumentException('Franco Momo Service: country passed is not supported.'); - } - break; + switch ($currency) { + case Currency::GHS: + if (! isset($otherData['network'])) { + $msg = "network parameter is required."; + $this->logger->error('Ghana Momo Service::' . $msg); + throw new \InvalidArgumentException('Ghana Momo Service:' . $msg); + } + if (! in_array($otherData['network'], $this->networks['GH'])) { + $msg = "network passed is not supported."; + $this->logger->error('Ghana Momo Service::' . $msg); + throw new \InvalidArgumentException( + 'Ghana Momo Service: ' . $msg . + '. options: ' . json_encode($this->networks['GH']) + ); + } + break; + case Currency::UGX: + if (! isset($otherData['network'])) { + $this->logger->error('Uganda Momo Service::network parameter is required.'); + throw new \InvalidArgumentException('Uganda Momo Service: network parameter is required.'); + } + if (! in_array($otherData['network'], $this->networks['UG'])) { + $this->logger->error('network passed is not supported for uganda momo.'); + throw new \InvalidArgumentException('Uganda Momo Service: network passed is not supported.'); + } + break; + case Currency::ZMW: + if (! isset($otherData['network'])) { + $this->logger->error('Zambia Momo Service::network parameter is required.'); + throw new \InvalidArgumentException('Uganda Momo Service: network parameter is required.'); + } + if (! in_array($otherData['network'], $this->networks['ZM'])) { + $this->logger->error('network passed is not supported for zambia momo.'); + throw new \InvalidArgumentException('Zambia Momo Service: network passed is not supported.'); + } + break; + case Currency::XAF: + if (! isset($otherData['country'])) { + $this->logger->error('Franco Momo Service::country parameter is required.'); + throw new \InvalidArgumentException('Franco Momo Service: country parameter is required.'); + } + if (! in_array($otherData['country'], $this->supported_countries_franco)) { + $this->logger->error('Franco Momo Service::country passed is not supported.'); + throw new \InvalidArgumentException('Franco Momo Service: country passed is not supported.'); + } + break; } return true; } /** - * @param \stdClass $response - * @param array $payload + * @param \stdClass $response + * @param array $payload * @return array */ private function handleAuthState(\stdClass $response, array $payload): array diff --git a/src/Service/Mpesa.php b/src/Service/Mpesa.php index fa428b6..3949ae2 100644 --- a/src/Service/Mpesa.php +++ b/src/Service/Mpesa.php @@ -22,7 +22,7 @@ public function __construct(?ConfigInterface $config = null) parent::__construct($config); $endpoint = $this->getEndpoint(); - $this->url = $this->baseUrl.'/'.$endpoint.'?type='; + $this->url = $this->baseUrl . '/' . $endpoint . '?type='; $this->eventHandler = new MpesaEventHandler($config); } @@ -85,7 +85,8 @@ private function handleAuthState(\stdClass $response, array $payload): array return [ 'status' => $response->data->status, 'transactionId' => $response->data->id, - 'dev_instruction' => 'The customer should authorize the payment on their Phones via the Mpesa. status is pending', + 'dev_instruction' => 'The customer should authorize the payment on their Phones + via the Mpesa. status is pending', 'instruction' => 'Please kindly authorize the payment on your Mobile phone', 'mode' => $mode, ]; diff --git a/src/Service/Otps.php b/src/Service/Otps.php index d8bfb13..35f8763 100644 --- a/src/Service/Otps.php +++ b/src/Service/Otps.php @@ -11,6 +11,7 @@ class Otps extends Service { use EventTracker; + private string $name = 'otps'; public function __construct(?ConfigInterface $config = null) @@ -62,7 +63,7 @@ public function validate(?string $otp = null, ?string $reference = null): \stdCl $body = ['otp' => $otp]; $this->logger->notice('OTP Service::Validating OTP.'); self::startRecording(); - $response = $this->request($body, 'POST', $this->name."/{$reference}/validate"); + $response = $this->request($body, 'POST', $this->name . "/{$reference}/validate"); $this->logger->notice('OTP Service::Validated OTP Successfully.'); self::setResponseTime(); return $response; @@ -71,28 +72,38 @@ public function validate(?string $otp = null, ?string $reference = null): \stdCl private function checkPayloadOTP(\Flutterwave\Payload $payload): void { if (! $payload->has('length')) { - throw new \InvalidArgumentException("OTP Service:: Required Parameter 'length'. - This is Integer length of the OTP being generated. Expected values are between 5 and 7."); + throw new \InvalidArgumentException( + "OTP Service:: Required Parameter 'length'. + This is Integer length of the OTP being generated. Expected values are between 5 and 7." + ); } if (! $payload->has('customer')) { - throw new \InvalidArgumentException("OTP Service:: Required Parameter 'customer'. - This is customer object used to include the recipient information."); + throw new \InvalidArgumentException( + "OTP Service:: Required Parameter 'customer'. + This is customer object used to include the recipient information." + ); } if (! $payload->has('sender')) { - throw new \InvalidArgumentException("OTP Service:: Required Parameter 'sender'. - This is your merchant/business name. It would display when the OTP is sent."); + throw new \InvalidArgumentException( + "OTP Service:: Required Parameter 'sender'. + This is your merchant/business name. It would display when the OTP is sent." + ); } if (! $payload->has('send')) { - throw new \InvalidArgumentException("OTP Service:: Required Parameter 'send'. - Set to true to send otp to customer.."); + throw new \InvalidArgumentException( + "OTP Service:: Required Parameter 'send'. + Set to true to send otp to customer.." + ); } if (! $payload->has('medium')) { - throw new \InvalidArgumentException("OTP Service:: Required Parameter 'medium'. - Pass the medium you want your customers to receive the OTP on. Expected values are sms, email and whatsapp."); + throw new \InvalidArgumentException( + "OTP Service:: Required Parameter 'medium'. + Pass the medium you want your customers to receive the OTP on. Expected values are sms, email and whatsapp." + ); } } } diff --git a/src/Service/Payload.php b/src/Service/Payload.php index f0e2339..06d9318 100644 --- a/src/Service/Payload.php +++ b/src/Service/Payload.php @@ -8,6 +8,7 @@ /** * Class Payload. + * * @deprecated use \Flutterwave\Factories\PayloadFactory instead */ class Payload diff --git a/src/Service/PaymentPlan.php b/src/Service/PaymentPlan.php index 922e708..26c016f 100644 --- a/src/Service/PaymentPlan.php +++ b/src/Service/PaymentPlan.php @@ -11,6 +11,7 @@ class PaymentPlan extends Service { use EventTracker; + private array $requiredParams = [ 'amount','name','interval','duration', ]; @@ -28,8 +29,9 @@ public function create(\Flutterwave\Payload $payload): \stdClass $payload = $payload->toArray(); foreach ($this->requiredParams as $param) { if (! array_key_exists($param, $payload)) { - $this->logger->error("Payment Plan Service::The required parameter {$param} is not present in payload"); - throw new \InvalidArgumentException("Payment Plan Service:The required parameter {$param} is not present in payload"); + $msg = "The required parameter {$param} is not present in payload"; + $this->logger->error("Payment Plan Service::" . $msg); + throw new \InvalidArgumentException("Payment Plan Service:" . $msg); } } @@ -50,7 +52,7 @@ public function get(string $id): \stdClass { $this->logger->notice("Payment Plan Service::Retrieving a Plan ({$id})."); self::startRecording(); - $response = $this->request(null, 'GET', $this->name."/{$id}"); + $response = $this->request(null, 'GET', $this->name . "/{$id}"); self::setResponseTime(); return $response; } @@ -80,7 +82,7 @@ public function update(string $id, \Flutterwave\Payload $payload): \stdClass $this->logger->notice("Payment Plan Service::Updating Plan id:({$id})"); self::startRecording(); - $response = $this->request(null, 'PUT', $this->name."/{$id}"); + $response = $this->request(null, 'PUT', $this->name . "/{$id}"); self::setResponseTime(); return $response; } @@ -92,7 +94,7 @@ public function cancel(string $id): \stdClass { $this->logger->notice("Payment Plan Service::Canceling Plan id:({$id})"); self::startRecording(); - $response = $this->request(null, 'PUT', $this->name."/{$id}/cancel"); + $response = $this->request(null, 'PUT', $this->name . "/{$id}/cancel"); self::setResponseTime(); return $response; } diff --git a/src/Service/PayoutSubaccount.php b/src/Service/PayoutSubaccount.php index f005d6a..e63dcaf 100644 --- a/src/Service/PayoutSubaccount.php +++ b/src/Service/PayoutSubaccount.php @@ -20,7 +20,7 @@ public function __construct(?ConfigInterface $config = null) { parent::__construct($config); $endpoint = $this->name; - $this->url = $this->baseUrl.'/'.$endpoint; + $this->url = $this->baseUrl . '/' . $endpoint; $this->eventHandler = new PayoutSubaccoutEventHandler(); } @@ -42,7 +42,7 @@ public function confirmPayload(Payload $payload): array } /** - * @param Payload $payload + * @param Payload $payload * @return stdClass * @throws ClientExceptionInterface */ diff --git a/src/Service/Preauth.php b/src/Service/Preauth.php index 5eb867a..ec954dc 100644 --- a/src/Service/Preauth.php +++ b/src/Service/Preauth.php @@ -23,12 +23,12 @@ public function __construct(?ConfigInterface $config = null) parent::__construct($config); $this->cardService = new CardPayment($config); $endpoint = $this->getEndpoint(); - $this->url = $this->baseUrl.'/'.$endpoint; + $this->url = $this->baseUrl . '/' . $endpoint; $this->eventHandler = new PreEventHandler(); } /** - * @param Payload $payload + * @param Payload $payload * @return array|null */ public function initiate(Payload $payload): array @@ -63,18 +63,18 @@ public function capture(string $flw_ref, string $method = 'card', string $amount { $method = strtolower($method); switch ($method) { - case 'paypal': - $data = [ - 'flw_ref' => $flw_ref, - ]; - $this->logger->info("Preauth Service::Capturing PayPal Payment with FLW_REF:{$flw_ref}..."); - $response = $this->request($data, 'POST', '/paypal-capture'); - break; - default: - $data = ['amount' => $amount]; - $this->logger->info("Preauth Service::Capturing Payment with FLW_REF:{$flw_ref}..."); - $response = $this->request($data, 'POST', "/{$flw_ref}/capture"); - break; + case 'paypal': + $data = [ + 'flw_ref' => $flw_ref, + ]; + $this->logger->info("Preauth Service::Capturing PayPal Payment with FLW_REF:{$flw_ref}..."); + $response = $this->request($data, 'POST', '/paypal-capture'); + break; + default: + $data = ['amount' => $amount]; + $this->logger->info("Preauth Service::Capturing Payment with FLW_REF:{$flw_ref}..."); + $response = $this->request($data, 'POST', "/{$flw_ref}/capture"); + break; } $data['message'] = null; @@ -102,21 +102,21 @@ public function void(string $flw_ref, string $method = 'card'): array { $method = strtolower($method); switch ($method) { - case 'paypal': - $data = [ - 'flw_ref' => $flw_ref, - ]; - $this->logger->info("Preauth Service::Voiding Payment with FLW_REF:{$flw_ref}..."); - PreEventHandler::startRecording(); - $response = $this->request($data, 'POST', '/paypal-void'); - PreEventHandler::setResponseTime(); - break; - default: - PreEventHandler::startRecording(); - $this->logger->info("Preauth Service::Voiding Payment with FLW_REF:{$flw_ref}..."); - PreEventHandler::setResponseTime(); - $response = $this->request(null, 'POST', "/{$flw_ref}/void"); - break; + case 'paypal': + $data = [ + 'flw_ref' => $flw_ref, + ]; + $this->logger->info("Preauth Service::Voiding Payment with FLW_REF:{$flw_ref}..."); + PreEventHandler::startRecording(); + $response = $this->request($data, 'POST', '/paypal-void'); + PreEventHandler::setResponseTime(); + break; + default: + PreEventHandler::startRecording(); + $this->logger->info("Preauth Service::Voiding Payment with FLW_REF:{$flw_ref}..."); + PreEventHandler::setResponseTime(); + $response = $this->request(null, 'POST', "/{$flw_ref}/void"); + break; } $data['message'] = null; @@ -163,4 +163,3 @@ public function refund(string $flw_ref): array return $data ?? [ 'message' => 'Charge Refund Failed!']; } } - diff --git a/src/Service/Service.php b/src/Service/Service.php index a88071e..0ad3760 100644 --- a/src/Service/Service.php +++ b/src/Service/Service.php @@ -7,6 +7,7 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\Contract\FactoryInterface; use Flutterwave\Contract\ServiceInterface; +use Flutterwave\Config\ForkConfig; use Flutterwave\Factories\CustomerFactory as Customer; use Flutterwave\Factories\PayloadFactory as Payload; use Flutterwave\Helper\Config; @@ -14,10 +15,11 @@ use Psr\Http\Client\ClientInterface; use InvalidArgumentException; use Psr\Http\Client\ClientExceptionInterface; -use function is_null; use Psr\Log\LoggerInterface; use stdClass; +use function is_null; + class Service implements ServiceInterface { public const ENDPOINT = ''; @@ -41,7 +43,7 @@ public function __construct(?ConfigInterface $config = null) $this->http = $this->config->getHttp(); $this->logger = $this->config->getLoggerInstance(); $this->secret = $this->config->getSecretKey(); - $this->url = EnvVariables::BASE_URL.'/'; + $this->url = EnvVariables::BASE_URL . '/'; $this->baseUrl = EnvVariables::BASE_URL; } @@ -51,61 +53,69 @@ public function getName(): string } /** - * @param array|null $data - * @param string $verb - * @param string $additionalurl + * @param array|null $data + * @param string $verb + * @param string $additionalurl * @return stdClass * @throws ClientExceptionInterface */ - protected function request( + public function request( ?array $data = null, string $verb = 'GET', string $additionalurl = '', bool $overrideUrl = false - ): stdClass - { + ): stdClass { + $secret = $this->config->getSecretKey(); $url = $this->getUrl($overrideUrl, $additionalurl); switch ($verb) { - case 'POST': - $response = $this->http->request('POST', $url, [ - 'debug' => false, # TODO: turn to false on release. - 'headers' => [ - 'Authorization' => "Bearer $secret", - 'Content-Type' => 'application/json', - ], - 'json' => $data, - ]); - break; - case 'PUT': - $response = $this->http->request('PUT', $url, [ - 'debug' => false, # TODO: turn to false on release. - 'headers' => [ - 'Authorization' => "Bearer $secret", - 'Content-Type' => 'application/json', - ], - 'json' => $data ?? [], - ]); - break; - case 'DELETE': - $response = $this->http->request('DELETE', $url, [ - 'debug' => false, - 'headers' => [ - 'Authorization' => "Bearer $secret", - 'Content-Type' => 'application/json', - ], - ]); - break; - default: - $response = $this->http->request('GET', $url, [ - 'debug' => false, - 'headers' => [ - 'Authorization' => "Bearer $secret", - 'Content-Type' => 'application/json', - ], - ]); - break; + case 'POST': + $response = $this->http->request( + 'POST', $url, [ + 'debug' => false, // TODO: turn to false on release. + 'headers' => [ + 'Authorization' => "Bearer $secret", + 'Content-Type' => 'application/json', + ], + 'json' => $data, + ] + ); + break; + case 'PUT': + $response = $this->http->request( + 'PUT', $url, [ + 'debug' => false, // TODO: turn to false on release. + 'headers' => [ + 'Authorization' => "Bearer $secret", + 'Content-Type' => 'application/json', + ], + 'json' => $data ?? [], + ] + ); + break; + case 'DELETE': + $response = $this->http->request( + 'DELETE', $url, [ + 'debug' => false, + 'headers' => [ + 'Authorization' => "Bearer $secret", + 'Content-Type' => 'application/json', + ], + ] + ); + break; + default: + $response = $this->http->request( + 'GET', $url, [ + 'debug' => false, + 'headers' => [ + 'Authorization' => "Bearer $secret", + 'Content-Type' => 'application/json', + ], + ] + ); + break; } $body = $response->getBody()->getContents(); @@ -126,22 +136,34 @@ protected function checkTransactionId($transactionId): void private static function bootstrap(?ConfigInterface $config = null): void { if (is_null($config)) { - require __DIR__.'/../../setup.php'; - $config = Config::setUp( - getenv(Config::SECRET_KEY), - getenv(Config::PUBLIC_KEY), - getenv(Config::ENCRYPTION_KEY), - getenv(Config::ENV) - ); + include __DIR__ . '/../../setup.php'; + if ('composer' === $flutterwave_installation) { + $config = Config::setUp( + $keys[Config::SECRET_KEY], + $keys[Config::PUBLIC_KEY], + $keys[Config::ENCRYPTION_KEY], + $keys[Config::ENV] + ); + } + if ('manual' === $flutterwave_installation) { + $config = ForkConfig::setUp( + $keys[Config::SECRET_KEY], + $keys[Config::PUBLIC_KEY], + $keys[Config::ENCRYPTION_KEY], + $keys[Config::ENV] + ); + } } self::$spareConfig = $config; } - private function getUrl(bool $overrideUrl, string $additionalurl ): string + private function getUrl(bool $overrideUrl, string $additionalurl): string { - if($overrideUrl) return $additionalurl; + if ($overrideUrl) { + return $additionalurl; + } - return $this->url.$additionalurl; + return $this->url . $additionalurl; } } diff --git a/src/Service/Settlement.php b/src/Service/Settlement.php index 7e7a4ad..ab4ad05 100644 --- a/src/Service/Settlement.php +++ b/src/Service/Settlement.php @@ -11,6 +11,7 @@ class Settlement extends Service { use EventTracker; + private string $name = 'settlements'; public function __construct(?ConfigInterface $config = null) { @@ -24,7 +25,7 @@ public function get(string $id): \stdClass { $this->logger->notice("Settlement Service::Retrieving Settlement [{$id}]."); self::startRecording(); - $response = $this->request(null, 'GET', $this->name."/{$id}"); + $response = $this->request(null, 'GET', $this->name . "/{$id}"); self::setResponseTime(); return $response; } diff --git a/src/Service/Subscription.php b/src/Service/Subscription.php index 1b27433..48322d6 100644 --- a/src/Service/Subscription.php +++ b/src/Service/Subscription.php @@ -11,6 +11,7 @@ class Subscription extends Service { use EventTracker; + private string $name = 'subscriptions'; public function __construct(?ConfigInterface $config = null) { @@ -36,7 +37,7 @@ public function activate(string $id): \stdClass { $this->logger->notice("Subscription Service::Activating a Subscriptions [{$id}]."); self::startRecording(); - $response = $this->request(null, 'PUT', $this->name."/{$id}/activate"); + $response = $this->request(null, 'PUT', $this->name . "/{$id}/activate"); self::setResponseTime(); return $response; } @@ -48,7 +49,7 @@ public function deactivate(string $id): \stdClass { $this->logger->notice("Subscription Service::Deactivating a Subscriptions [{$id}]."); self::startRecording(); - $response = $this->request(null, 'PUT', $this->name."/{$id}/cancel"); + $response = $this->request(null, 'PUT', $this->name . "/{$id}/cancel"); self::setResponseTime(); return $response; } diff --git a/src/Service/TokenizedCharge.php b/src/Service/TokenizedCharge.php index 2c24b2f..ab080e0 100644 --- a/src/Service/TokenizedCharge.php +++ b/src/Service/TokenizedCharge.php @@ -21,7 +21,7 @@ public function __construct(?ConfigInterface $config = null) { parent::__construct($config); $endpoint = "tokenized-{$this->getEndpoint()}"; - $this->url = $this->baseUrl.'/'.$endpoint; + $this->url = $this->baseUrl . '/' . $endpoint; $this->eventHandler = new TkEventHandler(); } @@ -46,7 +46,7 @@ public function initiate(\Flutterwave\Entities\Payload $payload): array */ public function charge(\Flutterwave\Entities\Payload $payload): array { - # format the customer object to extract the first_name and the last name. + // format the customer object to extract the first_name and the last name. $customer = $payload->get('customer')->toArray(); $fullname = $customer['fullname']; $names = explode(' ', $fullname); diff --git a/src/Service/Transactions.php b/src/Service/Transactions.php index 1d77789..ea40d0e 100644 --- a/src/Service/Transactions.php +++ b/src/Service/Transactions.php @@ -12,8 +12,9 @@ class Transactions extends Service { use Post; + public const ENDPOINT = 'transactions'; - public const REFUND_PATH = '/:id'.'/refund'; + public const REFUND_PATH = '/:id' . '/refund'; public const MULTI_REFUND_ENDPOINT = '/refunds'; public const REFUND_DETAILS_PATH = 'refunds/:id'; public const TRANSACTION_FEE_PATH = '/fee'; @@ -41,12 +42,12 @@ public function __construct(?ConfigInterface $config = null) public function verify(string $transactionId): \stdClass { $this->checkTransactionId($transactionId); - $this->logger->notice('Transaction Service::Verifying Transaction...'.$transactionId); + $this->logger->notice('Transaction Service::Verifying Transaction...' . $transactionId); TransactionVerificationEventHandler::startRecording(); $response = $this->request( null, 'GET', - self::ENDPOINT."/{$transactionId}/verify", + self::ENDPOINT . "/{$transactionId}/verify", ); TransactionVerificationEventHandler::setResponseTime(); @@ -58,12 +59,12 @@ public function verify(string $transactionId): \stdClass */ public function verifyWithTxref(string $tx_ref): \stdClass { - $this->logger->notice('Transaction Service::Verifying Transaction...'.$tx_ref); + $this->logger->notice('Transaction Service::Verifying Transaction...' . $tx_ref); TransactionVerificationEventHandler::startRecording(); $response = $this->request( null, 'GET', - self::ENDPOINT.'/verify_by_reference?tx_ref='.$tx_ref, + self::ENDPOINT . '/verify_by_reference?tx_ref=' . $tx_ref, ); TransactionVerificationEventHandler::setResponseTime(); return $response; @@ -80,7 +81,7 @@ public function refund(string $trasanctionId): \stdClass $response = $this->request( null, 'GET', - self::ENDPOINT."/{$trasanctionId}/refund", + self::ENDPOINT . "/{$trasanctionId}/refund", ); TransactionVerificationEventHandler::setResponseTime(); return $response; @@ -122,8 +123,11 @@ public function getRefundInfo(string $trasanctionId): \stdClass /** * @throws ClientExceptionInterface */ - public function getTransactionFee(string $amount, string $currency = 'NGN', string $payment_type = 'card'): \stdClass - { + public function getTransactionFee( + string $amount, + string $currency = 'NGN', + string $payment_type = 'card' + ): \stdClass { if (! $amount) { $msg = 'Please pass a valid amount'; $this->logger->warning($msg); @@ -151,7 +155,7 @@ public function getTransactionFee(string $amount, string $currency = 'NGN', stri $response = $this->request( null, 'GET', - self::ENDPOINT."/fee?{$query}", + self::ENDPOINT . "/fee?{$query}", ); TransactionVerificationEventHandler::setResponseTime(); return $response; @@ -168,7 +172,7 @@ public function resendFailedHooks(string $transactionId): \stdClass $response = $this->request( null, 'GET', - self::ENDPOINT."/{$transactionId}/resend-hook", + self::ENDPOINT . "/{$transactionId}/resend-hook", ); TransactionVerificationEventHandler::setResponseTime(); return $response; @@ -180,12 +184,14 @@ public function resendFailedHooks(string $transactionId): \stdClass public function retrieveTimeline(string $transactionId): \stdClass { $this->checkTransactionId($transactionId); - $this->logger->notice("Transaction Service::Retrieving Transaction Timeline: TransactionId => {$transactionId}"); + $this->logger->notice( + "Transaction Service::Retrieving Transaction Timeline: TransactionId => {$transactionId}" + ); TransactionVerificationEventHandler::startRecording(); $response = $this->request( null, 'GET', - self::ENDPOINT."/{$transactionId}/timeline", + self::ENDPOINT . "/{$transactionId}/timeline", ); TransactionVerificationEventHandler::setResponseTime(); return $response; @@ -203,12 +209,12 @@ public function validate(string $otp, string $flw_ref): \stdClass ] ); - $this->logger->notice('Transaction Service::Validating Transaction ...'.$logData); + $this->logger->notice('Transaction Service::Validating Transaction ...' . $logData); $data = [ 'otp' => $otp, 'flw_ref' => $flw_ref, -// "type" => "card" //default would be card + // "type" => "card" //default would be card ]; return $this->request( diff --git a/src/Service/Transfer.php b/src/Service/Transfer.php index 7c3d39c..efffb46 100644 --- a/src/Service/Transfer.php +++ b/src/Service/Transfer.php @@ -17,6 +17,7 @@ class Transfer extends Service implements Payment { use Charge; + public const TYPE = 'transfers'; private TransferEventHandler $eventHandler; private string $name = 'transfers'; @@ -24,19 +25,19 @@ class Transfer extends Service implements Payment 'amount', 'currency', ]; private array $requiredParamsRate = [ - 'amount', 'destination_currency'. 'source_currency', + 'amount', 'destination_currency' . 'source_currency', ]; public function __construct(?ConfigInterface $config = null) { parent::__construct($config); $endpoint = 'transfers'; - $this->url = $this->baseUrl.'/'.$endpoint; + $this->url = $this->baseUrl . '/' . $endpoint; $this->eventHandler = new TransferEventHandler($config); } /** - * @param Payload $payload + * @param Payload $payload * @return array * @throws ClientExceptionInterface */ @@ -51,7 +52,7 @@ public function initiate(Payload $payload): array } /** - * @param Payload $payload + * @param Payload $payload * @return array * @throws ClientExceptionInterface */ @@ -87,7 +88,7 @@ private function handleInitiationResponse(stdClass $data): array 'bank_code' => $root->bank_code, 'full_name' => $root->full_name, 'currency' => $root->currency, -// 'debit_currency' => $root->debit_currency, + // 'debit_currency' => $root->debit_currency, 'reference' => $root->reference, 'amount' => $root->amount, 'status' => $root->status, @@ -101,7 +102,7 @@ public function save(callable $callback): void } /** - * @param string|null $transactionId + * @param string|null $transactionId * @return stdClass * retry a previously failed transfer. * @@ -112,21 +113,22 @@ public function retry(?string $transactionId): stdClass $this->checkTransactionId($transactionId); $this->logger->notice("Transfer Service::Retrieving Settlement [$transactionId]."); $this->eventHandler::startRecording(); - $response = $this->request(null, 'POST', $this->name."/$transactionId/retries"); + $response = $this->request(null, 'POST', $this->name . "/$transactionId/retries"); $this->eventHandler::setResponseTime(); return $response; } /** - * @param Payload $payload + * @param Payload $payload * @return stdClass * @throws ClientExceptionInterface */ public function createBulk(Payload $payload): stdClass { if (! $payload->has('bulk_data')) { - $this->logger->error('Transfer Service::Bulk Payload is empty. Pass a filled array'); - throw new InvalidArgumentException('Transfer Service::Bulk Payload is currently empty. Pass a filled array'); + $msg = 'Bulk Payload is empty. Pass a filled array'; + $this->logger->error('Transfer Service::' . $msg); + throw new InvalidArgumentException('Transfer Service::' . $msg); } $body = $payload->toArray(); @@ -139,7 +141,7 @@ public function createBulk(Payload $payload): stdClass } /** - * @param string $id + * @param string $id * @return stdClass * @throws ClientExceptionInterface */ @@ -147,7 +149,7 @@ public function get(string $id): stdClass { $this->logger->notice("Transfer Service::Retrieving Transfer id:($id)"); $this->eventHandler::startRecording(); - $response = $this->request(null, 'GET', $this->name."/$id"); + $response = $this->request(null, 'GET', $this->name . "/$id"); $this->eventHandler::setResponseTime(); return $response; } @@ -166,7 +168,7 @@ public function getAll(): stdClass } /** - * @param array $params + * @param array $params * @return stdClass * @throws ClientExceptionInterface */ @@ -174,8 +176,9 @@ public function getFee(array $params = []): stdClass { foreach ($this->requiredParamsFee as $param) { if (! array_key_exists($param, $params)) { - $this->logger->error("Transfer Service::the following param is required to get transfer fee: $param"); - throw new InvalidArgumentException("Transfer Service::the following param is required to get transfer fee: $param"); + $msg = "the following param is required to get transfer fee: $param"; + $this->logger->error("Transfer Service::$msg"); + throw new InvalidArgumentException("Transfer Service::$msg"); } } @@ -188,7 +191,7 @@ public function getFee(array $params = []): stdClass } /** - * @param string $id + * @param string $id * @return stdClass * @throws ClientExceptionInterface */ @@ -203,7 +206,7 @@ public function getRetry(string $id): stdClass } /** - * @param string $batch_id + * @param string $batch_id * @return stdClass * @throws ClientExceptionInterface */ @@ -218,7 +221,7 @@ public function getBulk(string $batch_id): stdClass } /** - * @param array $params + * @param array $params * @return stdClass * @throws ClientExceptionInterface */ @@ -226,8 +229,9 @@ public function getRates(array $params): stdClass { foreach ($this->requiredParamsRate as $param) { if (! array_key_exists($param, $params)) { - $this->logger->error("Transfer Service::the following param is required to get transfer rate: $param"); - throw new InvalidArgumentException("Transfer Service::the following param is required to get transfer rate: $param"); + $msg = "the following param is required to get transfer rate: $param"; + $this->logger->error("Transfer Service::$msg"); + throw new InvalidArgumentException("Transfer Service::$msg"); } } diff --git a/src/Service/Ussd.php b/src/Service/Ussd.php index af6c027..bd082e3 100644 --- a/src/Service/Ussd.php +++ b/src/Service/Ussd.php @@ -46,12 +46,12 @@ public function __construct(?ConfigInterface $config = null) parent::__construct($config); $endpoint = $this->getEndpoint(); - $this->url = $this->baseUrl.'/'.$endpoint.'?type='; + $this->url = $this->baseUrl . '/' . $endpoint . '?type='; $this->eventHandler = new UssdEventHandler($config); } /** - * @param Payload $payload + * @param Payload $payload * @return array * @throws ClientExceptionInterface */ @@ -62,7 +62,7 @@ public function initiate(Payload $payload): array } /** - * @param Payload $payload + * @param Payload $payload * @return array * @throws ClientExceptionInterface */ @@ -87,8 +87,9 @@ public function charge(Payload $payload): array $bank = $otherData['account_bank']; if (! array_key_exists($bank, $this->supported_banks)) { - $this->logger->error('USSD Service: We do not support your bank. please kindly use another. '); - throw new \InvalidArgumentException('USSD Service: We do not support your bank. please kindly use another. '); + $msg = 'We do not support your bank. please kindly use another. '; + $this->logger->error('USSD Service:' . $msg); + throw new \InvalidArgumentException('USSD Service:' . $msg); } $payload = $payload->toArray(); @@ -114,8 +115,8 @@ public function save(callable $callback): void } /** - * @param \stdClass $response - * @param array $payload + * @param \stdClass $response + * @param array $payload * @return array * @throws \Exception */ diff --git a/src/Service/VirtualAccount.php b/src/Service/VirtualAccount.php index 1d643a8..9442241 100644 --- a/src/Service/VirtualAccount.php +++ b/src/Service/VirtualAccount.php @@ -11,6 +11,7 @@ class VirtualAccount extends Service { use EventTracker; + private string $name = 'virtual-account-numbers'; public function __construct(?ConfigInterface $config = null) { @@ -26,8 +27,9 @@ public function create(array $payload): \stdClass //check email and bvn are in payload if (! isset($payload['email']) || ! isset($payload['bvn'])) { - $this->logger->error('VirtualAccount Service::The required parameter email or bvn is not present in payload'); - throw new \InvalidArgumentException('The required parameter email or bvn is not present in payload'); + $msg = 'The required parameter email or bvn is not present in payload'; + $this->logger->error('VirtualAccount Service::' . $msg); + throw new \InvalidArgumentException($msg); } $this->logger->notice('VirtualAccount Service::Payload Confirmed.'); @@ -49,8 +51,9 @@ public function createBulk(array $payload): \stdClass $this->logger->notice('VirtualAccount Service::Creating Bulk Virtual Accounts.'); //check accounts and email are in payload if (! isset($payload['accounts']) || ! isset($payload['email'])) { - $this->logger->error('VirtualAccount Service::The required parameter accounts or email is not present in payload'); - throw new \InvalidArgumentException('The required parameter accounts or email is not present in payload'); + $msg = 'The required parameter accounts or email is not present in payload'; + $this->logger->error('VirtualAccount Service::' . $msg); + throw new \InvalidArgumentException($msg); } $this->logger->notice('VirtualAccount Service:: Payload Confirmed [Bulk].'); @@ -92,8 +95,9 @@ public function update(array $payload): \stdClass { //check email and bvn are in payload if (! isset($payload['order_ref']) || ! isset($payload['bvn'])) { - $this->logger->error('VirtualAccount Service::The required parameter order_ref or bvn is not present in payload'); - throw new \InvalidArgumentException('The required parameter order_ref or bvn is not present in payload'); + $msg = 'The required parameter order_ref or bvn is not present in payload'; + $this->logger->error('VirtualAccount Service::' . $msg); + throw new \InvalidArgumentException($msg); } $order_ref = $payload['order_ref']; diff --git a/src/Service/VirtualCard.php b/src/Service/VirtualCard.php index 42e43b4..76097b9 100644 --- a/src/Service/VirtualCard.php +++ b/src/Service/VirtualCard.php @@ -13,8 +13,20 @@ class VirtualCard extends Service { use EventTracker; + private string $name = 'virtual-cards'; - private array $requiredParams = [ 'currency', 'amount', 'first_name', 'last_name', 'date_of_birth','email', 'phone', 'title', 'gender' ]; + private array $requiredParams = [ + 'currency', + 'amount', + 'first_name', + 'last_name', + 'date_of_birth', + 'email', + 'phone', + 'title', + 'gender' + ]; + private array $requiredParamsFund = ['debit_currency','amount']; public function __construct(?ConfigInterface $config = null) { @@ -25,8 +37,9 @@ public function confirmPayload(Payload $payload): array { foreach ($this->requiredParams as $param) { if (! $payload->has($param)) { - $this->logger->error("VirtualCard Service::The required parameter {$param} is not present in payload"); - throw new InvalidArgumentException("The required parameter {$param} is not present in payload"); + $msg = "The required parameter {$param} is not present in payload"; + $this->logger->error("VirtualCard Service::$msg"); + throw new InvalidArgumentException($msg); } } @@ -54,7 +67,7 @@ public function get(string $id): \stdClass { $this->logger->notice("VirtualCard Service::Retrieving Virtual Card [{$id}]."); self::startRecording(); - $response = $this->request(null, 'GET', $this->name."/{$id}"); + $response = $this->request(null, 'GET', $this->name . "/{$id}"); self::setResponseTime(); return $response; } @@ -78,14 +91,15 @@ public function fund(string $id, array $data): \stdClass { foreach ($this->requiredParamsFund as $param) { if (! array_key_exists($param, $data)) { - $this->logger->error("Misc Service::The following parameter is missing to check balance history: {$param}"); - throw new \InvalidArgumentException("The following parameter is missing to check balance history: {$param}"); + $msg = "The following parameter is missing to check balance history: {$param}"; + $this->logger->error("Misc Service::$msg"); + throw new \InvalidArgumentException($msg); } } $this->logger->notice("VirtualCard Service::Funding Virtual Card [{$id}]."); self::startRecording(); - $response = $this->request($data, 'POST', $this->name."/{$id}/fund"); + $response = $this->request($data, 'POST', $this->name . "/{$id}/fund"); self::setResponseTime(); return $response; } @@ -97,7 +111,7 @@ public function withdraw(string $id, string $amount = '0'): \stdClass { $this->logger->notice("VirtualCard Service::Withdrawing from Virtual Card [{$id}]."); self::startRecording(); - $response = $this->request([ 'amount' => $amount ], 'POST', $this->name."/{$id}/withdraw"); + $response = $this->request([ 'amount' => $amount ], 'POST', $this->name . "/{$id}/withdraw"); self::setResponseTime(); return $response; } @@ -109,7 +123,7 @@ public function block(string $id): \stdClass { $this->logger->notice("VirtualCard Service::Blocking Virtual Card [{$id}]."); self::startRecording(); - $response = $this->request(null, 'PUT', $this->name."/{$id}/status/block"); + $response = $this->request(null, 'PUT', $this->name . "/{$id}/status/block"); self::setResponseTime(); return $response; } @@ -121,7 +135,7 @@ public function unblock(string $id): \stdClass { $this->logger->notice("VirtualCard Service::Unblocking Virtual Card [{$id}]."); self::startRecording(); - $response = $this->request(null, 'PUT', $this->name."/{$id}/status/unblock"); + $response = $this->request(null, 'PUT', $this->name . "/{$id}/status/unblock"); self::setResponseTime(); return $response; } @@ -133,7 +147,7 @@ public function terminate(string $id): \stdClass { $this->logger->notice("VirtualCard Service::Terminating Virtual Card [{$id}]."); self::startRecording(); - $response = $this->request(null, 'PUT', $this->name."/{$id}/terminate"); + $response = $this->request(null, 'PUT', $this->name . "/{$id}/terminate"); self::setResponseTime(); return $response; } @@ -146,7 +160,7 @@ public function getTransactions(string $id, array $options = ['index' => 0, 'siz $query = http_build_query($options); $this->logger->notice("VirtualCard Service::Retrieving transaction for Virtual Card [{$id}]."); self::startRecording(); - $response = $this->request(null, 'GET', $this->name."/{$id}/transactions?{$query}"); + $response = $this->request(null, 'GET', $this->name . "/{$id}/transactions?{$query}"); self::setResponseTime(); return $response; } diff --git a/src/Traits/ApiOperations/Delete.php b/src/Traits/ApiOperations/Delete.php index 584a3f7..1040c11 100644 --- a/src/Traits/ApiOperations/Delete.php +++ b/src/Traits/ApiOperations/Delete.php @@ -10,7 +10,7 @@ trait Delete { - public function deleteURL(ConfigInterface $config, string $url): string + public function deleteURL(ConfigInterface $config, string $url): string { $response = (new Http($config))->request(null, 'DELETE', $url); diff --git a/src/Traits/ApiOperations/Get.php b/src/Traits/ApiOperations/Get.php index 77f98f4..89dd415 100644 --- a/src/Traits/ApiOperations/Get.php +++ b/src/Traits/ApiOperations/Get.php @@ -13,8 +13,8 @@ trait Get { /** - * @param ConfigInterface $config - * @param string $url + * @param ConfigInterface $config + * @param string $url * @return stdClass * @throws ClientExceptionInterface * @throws ApiException diff --git a/src/Traits/ApiOperations/Post.php b/src/Traits/ApiOperations/Post.php index 931574d..d9b0215 100644 --- a/src/Traits/ApiOperations/Post.php +++ b/src/Traits/ApiOperations/Post.php @@ -12,7 +12,7 @@ trait Post { /** * @param ConfigInterface $config - * @param array $data + * @param array $data * * @return string * @throws ClientExceptionInterface diff --git a/src/Traits/ApiOperations/Put.php b/src/Traits/ApiOperations/Put.php index aef4f06..65d9f7b 100644 --- a/src/Traits/ApiOperations/Put.php +++ b/src/Traits/ApiOperations/Put.php @@ -12,7 +12,7 @@ trait Put { /** * @param ConfigInterface $config - * @param array $data + * @param array $data * * @return string * @throws ClientExceptionInterface diff --git a/src/Traits/PayloadOperations/Prepare.php b/src/Traits/PayloadOperations/Prepare.php index 754a2f2..f265f0e 100644 --- a/src/Traits/PayloadOperations/Prepare.php +++ b/src/Traits/PayloadOperations/Prepare.php @@ -16,11 +16,7 @@ trait Prepare public function createReferenceNumber(): self { $this->logger->notice('Generating Reference Number....'); - if ($this->overrideTransactionReference) { - $this->txref = $this->transactionPrefix; - } else { - $this->txref = uniqid($this->transactionPrefix); - } + $this->txref = uniqid($this->transactionPrefix); $this->logger->notice('Generated Reference Number....' . $this->txref); return $this; } diff --git a/src/Traits/Setup/Configure.php b/src/Traits/Setup/Configure.php index e95aa0f..981fea9 100644 --- a/src/Traits/Setup/Configure.php +++ b/src/Traits/Setup/Configure.php @@ -6,21 +6,38 @@ use Flutterwave\Contract\ConfigInterface; use Flutterwave\Helper\Config; +use Flutterwave\Config\ForkConfig; trait Configure { public static function bootstrap(?ConfigInterface $config = null): void { if (\is_null($config)) { - require __DIR__.'/../../../setup.php'; - $config = Config::setUp( - getenv(Config::SECRET_KEY), - getenv(Config::PUBLIC_KEY), - getenv(Config::ENCRYPTION_KEY), - getenv(Config::ENV) - ); + include __DIR__ . '/../../../setup.php'; + + if ('composer' === $flutterwave_installation) { + $config = Config::setUp( + $keys[Config::SECRET_KEY], + $keys[Config::PUBLIC_KEY], + $keys[Config::ENCRYPTION_KEY], + $keys[Config::ENV] + ); + } + + if ('manual' === $flutterwave_installation) { + $config = ForkConfig::setUp( + $keys[ForkConfig::SECRET_KEY], + $keys[ForkConfig::PUBLIC_KEY], + $keys[ForkConfig::ENCRYPTION_KEY], + $keys[ForkConfig::ENV] + ); + } + } + + if (\is_null(self::$config)) { + self::$config = $config; } - self::$config = $config; - self::$methods = require __DIR__ . '/../../Util/methods.php'; + + self::$methods = include __DIR__ . '/../../Util/methods.php'; } } diff --git a/src/Util/methods.php b/src/Util/methods.php index 0a656a2..fede22b 100644 --- a/src/Util/methods.php +++ b/src/Util/methods.php @@ -16,6 +16,7 @@ use Flutterwave\Service\TokenizedCharge; use Flutterwave\Service\Transfer; use Flutterwave\Service\Ussd; + //use Flutterwave\Service\PayPal; //use Flutterwave\Service\Remita; //use Flutterwave\Service\VoucherPayment; From 7149d42cedfee2bc27d4a0cc3353bcb53a299130 Mon Sep 17 00:00:00 2001 From: Abraham Olaobaju <129767063+Abraham-Flutterwave@users.noreply.github.com> Date: Mon, 5 Jun 2023 02:57:26 +0000 Subject: [PATCH 48/70] update: setup script check .env files in forked or downloaded projects --- setup.php | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/setup.php b/setup.php index b94f612..1c5b813 100644 --- a/setup.php +++ b/setup.php @@ -3,7 +3,15 @@ use Flutterwave\Helper; use Dotenv\Dotenv; -$dotenv = Dotenv::createImmutable(__DIR__."/../../../"); +$flutterwave_installation = 'composer'; + +if( !file_exists( '.env' )) { + $dotenv = Dotenv::createImmutable(__DIR__."/../../../"); # on the event that the package is install via composer. +} else { + $flutterwave_installation = "manual"; + $dotenv = Dotenv::createImmutable(__DIR__); # on the event that the package is forked or donwload directly from Github. +} + $dotenv->safeLoad(); //check if the current version of php is compatible @@ -13,14 +21,14 @@ exit; } -// check for required key in SERVER super global +// check for required key in ENV super global $flutterwaveKeys = ["SECRET_KEY","PUBLIC_KEY","ENV", "ENCRYPTION_KEY"]; asort($flutterwaveKeys); try{ foreach($flutterwaveKeys as $key) { - if(!array_key_exists($key, $_SERVER)) + if( empty( $_ENV[ $key ] ) ) { throw new InvalidArgumentException("$key environment variable missing."); } @@ -31,4 +39,11 @@ echo "
Kindly create a .env in the project root and add the required environment variables."; exit; -} \ No newline at end of file +} + +$keys = [ + 'SECRET_KEY' => $_ENV['SECRET_KEY'], + 'PUBLIC_KEY' => $_ENV['PUBLIC_KEY'], + 'ENV' => $_ENV['ENV'], + 'ENCRYPTION_KEY' => $_ENV['ENCRYPTION_KEY'] +]; \ No newline at end of file From 1778f58e3652af3d77c3ba017f4ebc23cd6afdde Mon Sep 17 00:00:00 2001 From: Abraham Olaobaju <129767063+Abraham-Flutterwave@users.noreply.github.com> Date: Mon, 5 Jun 2023 03:06:32 +0000 Subject: [PATCH 49/70] Security and Performance Update: checkout process and callback --- paymentForm.php | 29 +++---- processPayment.php | 208 ++++++--------------------------------------- 2 files changed, 40 insertions(+), 197 deletions(-) diff --git a/paymentForm.php b/paymentForm.php index 5bd99ab..34bb9d5 100644 --- a/paymentForm.php +++ b/paymentForm.php @@ -24,31 +24,28 @@
- - - + + - - - - - - - - + + + + + + - + - + - + - + - +
diff --git a/processPayment.php b/processPayment.php index a5da1a5..622ad36 100644 --- a/processPayment.php +++ b/processPayment.php @@ -2,196 +2,42 @@ declare(strict_types=1); +# if vendor file is not present, notify developer to run composer install. require __DIR__.'/vendor/autoload.php'; -session_start(); - -use Flutterwave\EventHandlers\EventHandlerInterface; +use Flutterwave\Controller\PaymentController; +use Flutterwave\EventHandlers\ModalEventHandler as PaymentHandler; use Flutterwave\Flutterwave; +use Flutterwave\Library\Modal; -Flutterwave::bootstrap(); - -$URL = (isset($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; -$getData = $_GET; -$postData = $_POST; -$publicKey = $_SERVER['PUBLIC_KEY']; -$secretKey = $_SERVER['SECRET_KEY']; -if (isset($postData['successurl']) && isset($postData['failureurl'])) { - $success_url = $postData['successurl']; - $failure_url = $postData['failureurl']; -} - -$env = $_SERVER['ENV']; - -if (isset($postData['amount'])) { - $_SESSION['publicKey'] = $publicKey; - $_SESSION['secretKey'] = $secretKey; - $_SESSION['env'] = $env; - $_SESSION['successurl'] = $success_url ?? null; - $_SESSION['failureurl'] = $failure_url ?? null; - $_SESSION['currency'] = $postData['currency']; - $_SESSION['amount'] = $postData['amount']; -} - -$prefix = 'RV'; // Change this to the name of your business or app -$overrideRef = false; - -// Uncomment here to enforce the useage of your own ref else a ref will be generated for you automatically -if (isset($postData['ref'])) { - $prefix = $postData['ref']; - $overrideRef = true; -} - -$payment = new Flutterwave($prefix, $overrideRef); +# start a session. +session_start(); -function getURL($url, $data = []): string -{ - $urlArr = explode('?', $url); - $params = array_merge($_GET, $data); - $new_query_string = http_build_query($params) . '&' . $urlArr[1]; - return $urlArr[0] . '?' . $new_query_string; +try { + Flutterwave::bootstrap(); + $customHandler = new PaymentHandler(); + $client = new Flutterwave(); + $modalType = Modal::POPUP; // Modal::POPUP or Modal::STANDARD + $controller = new PaymentController( $client, $customHandler, $modalType ); +} catch(\Exception $e ) { + echo $e->getMessage(); } -// This is where you set how you want to handle the transaction at different stages -class myEventHandler implements EventHandlerInterface -{ - /** - * This is called when the Rave class is initialized - * */ - public function onInit($initializationData): void - { - // Save the transaction to your DB. - } - - /** - * This is called only when a transaction is successful - * */ - public function onSuccessful($transactionData): void - { - // Get the transaction from your DB using the transaction reference (txref) - // Check if you have previously given value for the transaction. If you have, redirect to your successpage else, continue - // Comfirm that the transaction is successful - // Confirm that the chargecode is 00 or 0 - // Confirm that the currency on your db transaction is equal to the returned currency - // Confirm that the db transaction amount is equal to the returned amount - // Update the db transaction record (includeing parameters that didn't exist before the transaction is completed. for audit purpose) - // Give value for the transaction - // Update the transaction to note that you have given value for the transaction - // You can also redirect to your success page from here - if ($transactionData->status === 'successful') { - if ($transactionData->currency === $_SESSION['currency'] && $transactionData->amount === $_SESSION['amount']) { - if ($_SESSION['publicKey']) { - header('Location: ' . getURL($_SESSION['successurl'], ['event' => 'successful'])); - $_SESSION = []; - session_destroy(); - } - } else { - if ($_SESSION['publicKey']) { - header('Location: ' . getURL($_SESSION['failureurl'], ['event' => 'suspicious'])); - $_SESSION = []; - session_destroy(); - } - } - } else { - $this->onFailure($transactionData); - } - } - - /** - * This is called only when a transaction failed - * */ - public function onFailure($transactionData): void - { - // Get the transaction from your DB using the transaction reference (txref) - // Update the db transaction record (includeing parameters that didn't exist before the transaction is completed. for audit purpose) - // You can also redirect to your failure page from here - if ($_SESSION['publicKey']) { - header('Location: ' . getURL($_SESSION['failureurl'], ['event' => 'failed'])); - $_SESSION = []; - session_destroy(); - } - } - - /** - * This is called when a transaction is requeryed from the payment gateway - * */ - public function onRequery($transactionReference): void - { - // Do something, anything! - } - - /** - * This is called a transaction requery returns with an error - * */ - public function onRequeryError($requeryResponse): void - { - echo 'the transaction was not found'; - } - - /** - * This is called when a transaction is canceled by the user - * */ - public function onCancel($transactionReference): void - { - // Do something, anything! - // Note: Something's a payment can be successful, before a user clicks the cancel button so proceed with caution - if ($_SESSION['publicKey']) { - header('Location: ' . getURL($_SESSION['failureurl'], ['event' => 'canceled'])); - $_SESSION = []; - session_destroy(); - } - } - - /** - * This is called when a transaction doesn't return with a success or a failure response. This can be a timedout transaction on the Rave server or an abandoned transaction by the customer. - * */ - public function onTimeout($transactionReference, $data): void - { - // Get the transaction from your DB using the transaction reference (txref) - // Queue it for requery. Preferably using a queue system. The requery should be about 15 minutes after. - // Ask the customer to contact your support, and you should escalate this issue to the flutterwave support team. Send this as an email and as a notification on the page. just incase the page timesout or disconnects - if ($_SESSION['publicKey']) { - header('Location: ' . getURL($_SESSION['failureurl'], ['event' => 'timedout'])); - $_SESSION = []; - session_destroy(); - } +if ($_SERVER["REQUEST_METHOD"] === "POST") { + $request = $_REQUEST; + $request['redirect_url'] = $_SERVER['HTTP_ORIGIN'] . $_SERVER['REQUEST_URI']; + try { + $controller->process( $request ); + } catch(\Exception $e) { + echo $e->getMessage(); } } -if (isset($postData['amount'])) { - // Make payment - $payment - ->eventHandler(new myEventHandler()) - ->setAmount($postData['amount']) - ->setPaymentOptions($postData['payment_options']) // value can be a card, account or both - ->setDescription($postData['description']) - ->setLogo($postData['logo']) - ->setTitle($postData['title']) - ->setCountry($postData['country']) - ->setCurrency($postData['currency']) - ->setEmail($postData['email']) - ->setFirstname($postData['firstname']) - ->setLastname($postData['lastname']) - ->setPhoneNumber($postData['phonenumber']) - ->setPayButtonText($postData['pay_button_text']) - ->setRedirectUrl($URL) - // ->setMetaData(array('metaname' => 'SomeDataName', 'metavalue' => 'SomeValue')) // can be called multiple times. Uncomment this to add meta datas - // ->setMetaData(array('metaname' => 'SomeOtherDataName', 'metavalue' => 'SomeOtherValue')) // can be called multiple times. Uncomment this to add meta datas - ->initialize(); +$request = $_GET; +# Confirming Payment. +if(isset($request['tx_ref'])) { + $controller->callback( $request ); } else { - if (isset($getData['cancelled'])) { - // Handle canceled payments - $payment - ->eventHandler(new myEventHandler()) - ->paymentCanceled($getData['cancel_ref']); - } elseif (isset($getData['tx_ref'])) { - // Handle completed payments - $payment->logger->notice('Payment completed. Now requerying payment.'); - $payment - ->eventHandler(new myEventHandler()) - ->requeryTransaction($getData['transaction_id']); - } else { - $payment->logger->warning('Stop!!! Please pass the txref parameter!'); - echo 'Stop!!! Please pass the txref parameter!'; - } + } +exit(); From 2a243f65d5e5c7a88702b33877287d7cc90aecf7 Mon Sep 17 00:00:00 2001 From: Abraham Olaobaju <129767063+Abraham-Flutterwave@users.noreply.github.com> Date: Mon, 5 Jun 2023 03:06:53 +0000 Subject: [PATCH 50/70] updated examples --- examples/card.php | 4 ++-- examples/preauth.php | 6 +++--- examples/tokenized.php | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/card.php b/examples/card.php index 653926c..3141857 100644 --- a/examples/card.php +++ b/examples/card.php @@ -41,8 +41,8 @@ $customerObj = $cardpayment->customer->create([ "full_name" => "Olaobaju Abraham", - "email" => "olaobajua@gmail.com", - "phone" => "+2349067985861" + "email" => "ol3746ydgsbc@gmail.com", + "phone" => "+2349035462461" ]); $data['customer'] = $customerObj; diff --git a/examples/preauth.php b/examples/preauth.php index 63eaea1..9c5e55a 100644 --- a/examples/preauth.php +++ b/examples/preauth.php @@ -39,9 +39,9 @@ $data['redirectUrl'] = "http://{$_SERVER['HTTP_HOST']}/examples/endpoint/verify.php?tx_ref={$data['tx_ref']}"; $customerObj = $preauthpayment->customer->create([ - "full_name" => "Olaobaju Jesulayomi Abraham", - "email" => "olaobajua@gmail.com", - "phone" => "+2349067985861" + "full_name" => "Jack Logan Hugh", + "email" => "Jhughck@gmail.com", + "phone" => "+2349062919861" ]); $data['customer'] = $customerObj; diff --git a/examples/tokenized.php b/examples/tokenized.php index 0d9ab61..9b4b182 100644 --- a/examples/tokenized.php +++ b/examples/tokenized.php @@ -27,8 +27,8 @@ $customerObj = $tokenpayment->customer->create([ "full_name" => "Olaobaju Jesulayomi Abraham", - "email" => "olaobajua@gmail.com", - "phone" => "+2349067985861" + "email" => "olr75756uruf@gmail.com", + "phone" => "+2349067263131" ]); $data['customer'] = $customerObj; From 0d588628f316183dda4115c74b2ddb5d4324b690 Mon Sep 17 00:00:00 2001 From: Abraham Olaobaju <129767063+Abraham-Flutterwave@users.noreply.github.com> Date: Mon, 5 Jun 2023 03:07:18 +0000 Subject: [PATCH 51/70] updated dependecies --- composer.json | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index a67fe18..a2012a4 100644 --- a/composer.json +++ b/composer.json @@ -18,9 +18,11 @@ "vlucas/phpdotenv": "^2.5 || ^3.0 || ^5.0", "ext-json": "*", "ext-curl": "*", + "ext-openssl": "*", "guzzlehttp/guzzle": "^7.5", "psr/http-client": "^1.0", - "php-http/guzzle7-adapter": "^1.0" + "php-http/guzzle7-adapter": "^1.0", + "composer/ca-bundle": "^1.3" }, "require-dev": { "phpunit/phpunit": ">=6.0", @@ -28,7 +30,11 @@ "symfony/var-dumper": "5.4.13", "phpstan/phpstan": "^1.9", "pestphp/pest": "^1.22", - "nunomaduro/phpinsights": "^2.6" + "nunomaduro/phpinsights": "^2.6", + "eloquent/liberator": "^3.0", + "squizlabs/php_codesniffer": "3.*", + "dg/bypass-finals": "^1.4", + "phpbench/phpbench": "^1.2" }, "license": "MIT", "authors": [ @@ -49,6 +55,18 @@ ], "php-insight-fix": [ "vendor/bin/phpinsights fix src" + ], + "phpcs": [ + "./vendor/bin/phpcs" + ], + "phpcbf": [ + "./vendor/bin/phpcbf " + ], + "test": [ + "./vendor/bin/pest" + ], + "pest-filter": [ + "./vendor/bin/pest --filter" ] } } From 28ce94529f1ae79639d4643835ce56a101dc6bd7 Mon Sep 17 00:00:00 2001 From: Abraham Olaobaju <129767063+Abraham-Flutterwave@users.noreply.github.com> Date: Mon, 5 Jun 2023 03:07:51 +0000 Subject: [PATCH 52/70] update: README.md --- README.md | 298 +++++++++++++++--------------------------------------- 1 file changed, 81 insertions(+), 217 deletions(-) diff --git a/README.md b/README.md index e445555..b1db0e5 100644 --- a/README.md +++ b/README.md @@ -40,34 +40,37 @@ Available features include: ## Requirements 1. Flutterwave for business [API Keys](https://developer.flutterwave.com/docs/integration-guides/authentication) -2. Acceptable PHP versions: >= 5.4.0 +2. Acceptable PHP versions: >= 7.4.0. for older versions of PHP use the [Legacy Branch]( https://github.com/Flutterwave/PHP-v3/tree/legacy ) ## Installation -The vendor folder is committed into the project to allow easy installation for those who do not have composer installed. -It is recommended to update the project dependencies using: +### Installation via Composer. +To install the package via Composer, run the following command. ```shell -$ composer require flutterwavedev/flutterwave-v3 +composer require flutterwavedev/flutterwave-v3 ``` ## Initialization -Create a .env file and follow the format of the .env.example file -Save your PUBLIC_KEY, SECRET_KEY, ENV in the .env file +Create a .env file and follow the format of the `.env.example` file +Save your PUBLIC_KEY, SECRET_KEY, ENV in the `.env` file -```env - -PUBLIC_KEY="****YOUR**PUBLIC**KEY****" // can be gotten from the dashboard -SECRET_KEY="****YOUR**SECRET**KEY****" // can be gotten from the dashboard -ENCRYPTION_KEY="Encryption key" -ENV="development/production" +```bash +cp .env.example .env +``` +Your `.env` file should look this. +```env +PUBLIC_KEY=FLWSECK_TEST-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-X +SECRET_KEY=FLWPUBK_TEST-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-X +ENCRYPTION_KEY=FLWSECK_XXXXXXXXXXXXXXXX +ENV='staging/production' ``` @@ -75,226 +78,87 @@ ENV="development/production" ## Usage -### Card Charge -This is used to facilitate card transactions. +### Render Payment Modal -Edit the `paymentForm.php` and `processPayment.php` files to suit your purpose. Both files are well documented. +The SDK provides two easy methods of making collections via the famous payment modal. [Learn more](#) -Simply redirect to the `paymentForm.php` file on your browser to process a payment. +1. [Flutterwave Inline]( https://developer.flutterwave.com/docs/collecting-payments/inline ) +2. [Flutterwave Standard]( https://developer.flutterwave.com/docs/collecting-payments/standard ) -In this implementation, we are expecting a form encoded POST request to this script. -The request will contain the following parameters. - -- payment_method `Can be card, account, both` -- description `Your transaction description` -- logo `Your logo url` -- title `Your transaction title` -- country `Your transaction country` -- currency `Your transaction currency` -- email `Your customer's email` -- firstname `Your customer's first name` -- lastname `Your customer's last name` -- phonenumber `Your customer's phonenumber` -- pay_button_text `The payment button text you prefer` -- ref `Your transaction reference. It must be unique per transaction. By default, the Rave class generates a unique transaction reference for each transaction. Pass this parameter only if you uncommented the related section in the script below.` +### Get Started -```php -status === 'successful') { - if ($transactionData->currency == $_SESSION['currency'] && $transactionData->amount == $_SESSION['amount']) { - - if ($_SESSION['publicKey']) { - header('Location: ' . getURL($_SESSION['successurl'], array('event' => 'successful'))); - $_SESSION = array(); - session_destroy(); - } - } else { - if ($_SESSION['publicKey']) { - header('Location: ' . getURL($_SESSION['failureurl'], array('event' => 'suspicious'))); - $_SESSION = array(); - session_destroy(); - } - } - } else { - $this->onFailure($transactionData); - } - } +declare(strict_types=1); - /** - * This is called only when a transaction failed - * */ - function onFailure($transactionData) { - // Get the transaction from your DB using the transaction reference (txref) - // Update the db transaction record (includeing parameters that didn't exist before the transaction is completed. for audit purpose) - // You can also redirect to your failure page from here - if ($_SESSION['publicKey']) { - header('Location: ' . getURL($_SESSION['failureurl'], array('event' => 'failed'))); - $_SESSION = array(); - session_destroy(); - } - } +# if vendor file is not present, notify developer to run composer install. +require __DIR__.'/vendor/autoload.php'; - /** - * This is called when a transaction is requeryed from the payment gateway - * */ - function onRequery($transactionReference) { - // Do something, anything! - } +use Flutterwave\Controller\PaymentController; +use Flutterwave\EventHandlers\ModalEventHandler as PaymentHandler; +use Flutterwave\Flutterwave; +use Flutterwave\Library\Modal; - /** - * This is called a transaction requery returns with an error - * */ - function onRequeryError($requeryResponse) { - echo 'the transaction was not found'; - } +# start a session. +session_start(); - /** - * This is called when a transaction is canceled by the user - * */ - function onCancel($transactionReference) { - // Do something, anything! - // Note: Somethings a payment can be successful, before a user clicks the cancel button so proceed with caution - if ($_SESSION['publicKey']) { - header('Location: ' . getURL($_SESSION['failureurl'], array('event' => 'canceled'))); - $_SESSION = array(); - session_destroy(); - } - } +try { + Flutterwave::bootstrap(); + $customHandler = new PaymentHandler(); + $client = new Flutterwave(); + $modalType = Modal::POPUP; // Modal::POPUP or Modal::STANDARD + $controller = new PaymentController( $client, $customHandler, $modalType ); +} catch(\Exception $e ) { + echo $e->getMessage(); +} - /** - * This is called when a transaction doesn't return with a success or a failure response. This can be a timedout transaction on the Rave server or an abandoned transaction by the customer. - * */ - function onTimeout($transactionReference, $data) { - // Get the transaction from your DB using the transaction reference (txref) - // Queue it for requery. Preferably using a queue system. The requery should be about 15 minutes after. - // Ask the customer to contact your support and you should escalate this issue to the flutterwave support team. Send this as an email and as a notification on the page. just incase the page timesout or disconnects - if ($_SESSION['publicKey']) { - header('Location: ' . getURL($_SESSION['failureurl'], array('event' => 'timedout'))); - $_SESSION = array(); - session_destroy(); - } +if ($_SERVER["REQUEST_METHOD"] === "POST") { + $request = $_REQUEST; + $request['redirect_url'] = $_SERVER['HTTP_ORIGIN'] . $_SERVER['REQUEST_URI']; + try { + $controller->process( $request ); + } catch(\Exception $e) { + echo $e->getMessage(); } } -if (isset($postData['amount'])) { - // Make payment - $payment - ->eventHandler(new myEventHandler) - ->setAmount($postData['amount']) - ->setPaymentOptions($postData['payment_options']) // value can be card, account or both - ->setDescription($postData['description']) - ->setLogo($postData['logo']) - ->setTitle($postData['title']) - ->setCountry($postData['country']) - ->setCurrency($postData['currency']) - ->setEmail($postData['email']) - ->setFirstname($postData['firstname']) - ->setLastname($postData['lastname']) - ->setPhoneNumber($postData['phonenumber']) - ->setPayButtonText($postData['pay_button_text']) - ->setRedirectUrl($URL) - // ->setMetaData(array('metaname' => 'SomeDataName', 'metavalue' => 'SomeValue')) // can be called multiple times. Uncomment this to add meta datas - // ->setMetaData(array('metaname' => 'SomeOtherDataName', 'metavalue' => 'SomeOtherValue')) // can be called multiple times. Uncomment this to add meta datas - ->initialize(); +$request = $_GET; +# Confirming Payment. +if(isset($request['tx_ref'])) { + $controller->callback( $request ); } else { - if (isset($getData['cancelled'])) { - // Handle canceled payments - $payment - ->eventHandler(new myEventHandler) - ->paymentCanceled($getData['cancel_ref']); - } elseif (isset($getData['tx_ref'])) { - // Handle completed payments - $payment->logger->notice('Payment completed. Now requerying payment.'); - $payment - ->eventHandler(new myEventHandler) - ->requeryTransaction($getData['transaction_id']); - } else { - $payment->logger->warning('Stop!!! Please pass the txref parameter!'); - echo 'Stop!!! Please pass the txref parameter!'; - } + } +exit(); + ```
@@ -304,15 +168,15 @@ Create a .env file and add the bootstrap method first before initiating a charge use \Flutterwave\Flutterwave; use \Flutterwave\Helper\Config; # normal configuration -Flutterwave::bootstrap(); # this will use the default configuration +Flutterwave::bootstrap(); # this will use the default configuration set in .env # for a custom configuration # your config must implement Flutterwave\Contract\ConfigInterface $myConfig = Config::setUp( - getenv(Config::SECRET_KEY), - getenv(Config::PUBLIC_KEY), - getenv(Config::ENCRYPTION_KEY), - getenv(Config::ENV) + 'FLWSECK_TEST-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-X', + 'FLWPUBK_TEST-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-X', + 'FLWSECK_XXXXXXXXXXXXXXXX', + 'staging' ); Flutterwave::bootstrap($myConfig); ``` @@ -413,8 +277,8 @@ $data = [ $cardpayment = \Flutterwave\Flutterwave::create("card"); $customerObj = $cardpayment->customer->create([ "full_name" => "Olaobaju Abraham", - "email" => "olaobajua@gmail.com", - "phone" => "+2349067985861" + "email" => "ola2fhahfj@gmail.com", + "phone" => "+234900154861" ]); $data['customer'] = $customerObj; $payload = $cardpayment->payload->create($data); @@ -529,8 +393,8 @@ $data = [ $service = new Transfer(); $customerObj = $service->customer->create([ "full_name" => "Olaobaju Abraham", - "email" => "olaobajua@gmail.com", - "phone" => "+2349067985861" + "email" => "38djsdjfjc954@gmail.com", + "phone" => "+234900085861" ]); $data['customer'] = $customerObj; $payload = $service->payload->create($data); @@ -730,8 +594,8 @@ $data['redirectUrl'] = "http://{$_SERVER['HTTP_HOST']}/examples/endpoint/verify. $customerObj = $tokenpayment->customer->create([ "full_name" => "Olaobaju Jesulayomi Abraham", - "email" => "olaobajua@gmail.com", - "phone" => "+2349067985861" + "email" => "ola3785yfhf@gmail.com", + "phone" => "+2349062947561" ]); $data['customer'] = $customerObj; $tokenpayment = \Flutterwave\Flutterwave::create("tokenize"); From ce45a1e5748d02353f00ae718fca442ef98de071 Mon Sep 17 00:00:00 2001 From: Abraham Olaobaju <129767063+Abraham-Flutterwave@users.noreply.github.com> Date: Tue, 6 Jun 2023 07:55:47 +0000 Subject: [PATCH 53/70] update: change-review workflow --- .github/workflows/change-review.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/change-review.yml b/.github/workflows/change-review.yml index 35b0f4c..c16863f 100644 --- a/.github/workflows/change-review.yml +++ b/.github/workflows/change-review.yml @@ -39,10 +39,11 @@ jobs: - name: 'Create env file' run: | touch .env - echo PUBLIC_KEY=${{ secrets.PUBLIC_KEY }} >> .env - echo SECRET_KEY=${{ secrets.SECRET_KEY }} >> .env - echo ENCRYPTION_KEY=${{ secrets.ENCRYPTION_KEY }} >> .env - echo ENV=${{ secrets.ENV }} >> .env + echo PUBLIC_KEY="$PUBLIC_KEY" >> .env + echo SECRET_KEY="$SECRET_KEY" >> .env + echo ENCRYPTION_KEY="$ENCRYPTION_KEY" >> .env + echo ENV="$ENV" >> .env + ls ${{ github.workspace }} - name: Cache Composer packages id: composer-cache From 90312f335a4dfe09f7c13af71d98ea95ca2dc83a Mon Sep 17 00:00:00 2001 From: Abraham Olaobaju <129767063+Abraham-Flutterwave@users.noreply.github.com> Date: Tue, 6 Jun 2023 10:56:42 +0000 Subject: [PATCH 54/70] update: change-review workflow tests should use specified .env file --- .github/workflows/change-review.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/change-review.yml b/.github/workflows/change-review.yml index c16863f..5ca29a5 100644 --- a/.github/workflows/change-review.yml +++ b/.github/workflows/change-review.yml @@ -39,9 +39,9 @@ jobs: - name: 'Create env file' run: | touch .env - echo PUBLIC_KEY="$PUBLIC_KEY" >> .env - echo SECRET_KEY="$SECRET_KEY" >> .env - echo ENCRYPTION_KEY="$ENCRYPTION_KEY" >> .env + echo PUBLIC_KEY="$PUBLIC_KEY" > .env + echo SECRET_KEY="$SECRET_KEY" > .env + echo ENCRYPTION_KEY="$ENCRYPTION_KEY" > .env echo ENV="$ENV" >> .env ls ${{ github.workspace }} From 115a905202fa4d80c79ff79a01851e569e9ee5dc Mon Sep 17 00:00:00 2001 From: Abraham Olaobaju <129767063+Abraham-Flutterwave@users.noreply.github.com> Date: Fri, 14 Jul 2023 16:57:27 +0100 Subject: [PATCH 55/70] add expiry pwbt test. --- tests/Unit/Service/BankTransferTest.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/Unit/Service/BankTransferTest.php b/tests/Unit/Service/BankTransferTest.php index 80160a5..559a9b5 100644 --- a/tests/Unit/Service/BankTransferTest.php +++ b/tests/Unit/Service/BankTransferTest.php @@ -37,4 +37,28 @@ public function testAuthModeReturnBankTransfer() $result = $btpayment->initiate($payload); $this->assertSame(AuthMode::BANKTRANSFER, $result['mode']); } + + + public function testExpiryOption() + { + $data = [ + "amount" => 2000, + "currency" => Currency::NGN, + "tx_ref" => uniqid().time(), + "redirectUrl" => "https://google.com", + "expires" => 3600 + ]; + + $btpayment = Flutterwave::create("bank-transfer"); + $customerObj = $btpayment->customer->create([ + "full_name" => "Olaobaju Jesulayomi Abraham", + "email" => "developers@flutterwavego.com", + "phone" => "+2349067985011" + ]); + + $data['customer'] = $customerObj; + $payload = $btpayment->payload->create($data); + $result = $btpayment->initiate($payload); + $this->assertTrue(isset($result['account_expiration'])); + } } \ No newline at end of file From 1b2a1bf5ff3f8c05857340a615c59b1faa653001 Mon Sep 17 00:00:00 2001 From: Abraham Olaobaju <129767063+Abraham-Flutterwave@users.noreply.github.com> Date: Fri, 14 Jul 2023 16:59:25 +0100 Subject: [PATCH 56/70] update change-review workflow --- .github/workflows/change-review.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/change-review.yml b/.github/workflows/change-review.yml index 5ca29a5..c16863f 100644 --- a/.github/workflows/change-review.yml +++ b/.github/workflows/change-review.yml @@ -39,9 +39,9 @@ jobs: - name: 'Create env file' run: | touch .env - echo PUBLIC_KEY="$PUBLIC_KEY" > .env - echo SECRET_KEY="$SECRET_KEY" > .env - echo ENCRYPTION_KEY="$ENCRYPTION_KEY" > .env + echo PUBLIC_KEY="$PUBLIC_KEY" >> .env + echo SECRET_KEY="$SECRET_KEY" >> .env + echo ENCRYPTION_KEY="$ENCRYPTION_KEY" >> .env echo ENV="$ENV" >> .env ls ${{ github.workspace }} From 270562884b1f58db22ec2e3f12247b23fe51893c Mon Sep 17 00:00:00 2001 From: Abraham Olaobaju <129767063+Abraham-Flutterwave@users.noreply.github.com> Date: Fri, 14 Jul 2023 17:02:18 +0100 Subject: [PATCH 57/70] update change-review workflow --- .github/workflows/change-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/change-review.yml b/.github/workflows/change-review.yml index c16863f..8df4368 100644 --- a/.github/workflows/change-review.yml +++ b/.github/workflows/change-review.yml @@ -43,7 +43,7 @@ jobs: echo SECRET_KEY="$SECRET_KEY" >> .env echo ENCRYPTION_KEY="$ENCRYPTION_KEY" >> .env echo ENV="$ENV" >> .env - ls ${{ github.workspace }} + ls -a ${{ github.workspace }} - name: Cache Composer packages id: composer-cache From 4c73858a9d2d555e1180afb13d6a926b37e33fa2 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Mon, 17 Jul 2023 10:08:19 +0100 Subject: [PATCH 58/70] update applepay test --- tests/Unit/Service/ApplePayTest.php | 105 ++++++++++++++-------------- 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/tests/Unit/Service/ApplePayTest.php b/tests/Unit/Service/ApplePayTest.php index 6c2b6d4..db72ced 100644 --- a/tests/Unit/Service/ApplePayTest.php +++ b/tests/Unit/Service/ApplePayTest.php @@ -8,57 +8,56 @@ class ApplePayTest extends TestCase { -// protected function setUp(): void -// { -// \Flutterwave\Flutterwave::bootstrap(); -// } -// -// public function testAuthModeReturnRedirect() -// { -// $data = [ -// "amount" => 2000, -// "currency" => Currency::NGN, -// "tx_ref" => uniqid().time(), -// "redirectUrl" => "https://example.com" -// ]; -// -// $applepayment = \Flutterwave\Flutterwave::create("apple"); -// $customerObj = $applepayment->customer->create([ -// "full_name" => "Olaobaju Jesulayomi Abraham", -// "email" => "vicomma@gmail.com", -// "phone" => "+2349067985861" -// ]); -// -// $data['customer'] = $customerObj; -// $payload = $applepayment->payload->create($data); -// $result = $applepayment->initiate($payload); -// -// $this->assertSame(AuthMode::REDIRECT, $result['mode']); -// } -// -// public function testInvalidParams() -// { -// $data = [ -// "amount" => 2000, -// "currency" => Currency::NGN, -// "tx_ref" => uniqid().time(), -// "redirectUrl" => "https://example.com" -// ]; -// -// $applepayment = \Flutterwave\Flutterwave::create("apple"); -// //no customer object; -// $this->expectException(\InvalidArgumentException::class); -// $payload = $applepayment->payload->create($data); -// $result = $applepayment->initiate($payload); -// } -// -// public function testEmptyParamsPassed() -// { -// $data = []; -// $applepayment = \Flutterwave\Flutterwave::create("apple"); -// $this->expectException(\InvalidArgumentException::class); -// $payload = $applepayment->payload->create($data); -// $result = $applepayment->initiate($payload); -// -// } + protected function setUp(): void + { + \Flutterwave\Flutterwave::bootstrap(); + } + + public function testAuthModeReturnRedirect() + { + $data = [ + "amount" => 2000, + "currency" => Currency::NGN, + "tx_ref" => uniqid().time(), + "redirectUrl" => "https://example.com" + ]; + + $applepayment = \Flutterwave\Flutterwave::create("apple"); + $customerObj = $applepayment->customer->create([ + "full_name" => "Olaobaju Jesulayomi Abraham", + "email" => "vicomma@gmail.com", + "phone" => "+2349060085861" + ]); + + $data['customer'] = $customerObj; + $payload = $applepayment->payload->create($data); + $result = $applepayment->initiate($payload); + + $this->assertSame(AuthMode::REDIRECT, $result['mode']); + } + + public function testInvalidParams() + { + $data = [ + "amount" => 2000, + "currency" => Currency::NGN, + "tx_ref" => uniqid().time(), + "redirectUrl" => "https://example.com" + ]; + + $applepayment = \Flutterwave\Flutterwave::create("apple"); + $this->expectException(\InvalidArgumentException::class); + $payload = $applepayment->payload->create($data); + $result = $applepayment->initiate($payload); + } + + public function testEmptyParamsPassed() + { + $data = []; + $applepayment = \Flutterwave\Flutterwave::create("apple"); + $this->expectException(\InvalidArgumentException::class); + $payload = $applepayment->payload->create($data); + $result = $applepayment->initiate($payload); + + } } \ No newline at end of file From 092e6eaa9184f0c5a8188edc7d72799a5c17763b Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Mon, 17 Jul 2023 11:34:31 +0100 Subject: [PATCH 59/70] update change-review workflow --- .github/workflows/change-review.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/change-review.yml b/.github/workflows/change-review.yml index 8df4368..ef8d523 100644 --- a/.github/workflows/change-review.yml +++ b/.github/workflows/change-review.yml @@ -36,15 +36,6 @@ jobs: - name: Validate composer.json and composer.lock run: composer validate --strict - - name: 'Create env file' - run: | - touch .env - echo PUBLIC_KEY="$PUBLIC_KEY" >> .env - echo SECRET_KEY="$SECRET_KEY" >> .env - echo ENCRYPTION_KEY="$ENCRYPTION_KEY" >> .env - echo ENV="$ENV" >> .env - ls -a ${{ github.workspace }} - - name: Cache Composer packages id: composer-cache uses: actions/cache@v3 @@ -57,6 +48,15 @@ jobs: - name: Install dependencies run: composer install --prefer-dist --no-progress + - name: 'Create env file' + run: | + touch .env + echo PUBLIC_KEY="$PUBLIC_KEY" >> .env + echo SECRET_KEY="$SECRET_KEY" >> .env + echo ENCRYPTION_KEY="$ENCRYPTION_KEY" >> .env + echo ENV="$ENV" >> .env + ls -a ${{ github.workspace }} + - name: run unit tests and coverage scan run: ./vendor/bin/pest --coverage --min=20 --coverage-clover ./coverage.xml From e137dc9cc0d7b574586874831eca274caaaebb55 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Mon, 17 Jul 2023 11:50:15 +0100 Subject: [PATCH 60/70] update change-review workflow create .env workflow step --- .github/workflows/change-review.yml | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/.github/workflows/change-review.yml b/.github/workflows/change-review.yml index ef8d523..75f2d18 100644 --- a/.github/workflows/change-review.yml +++ b/.github/workflows/change-review.yml @@ -48,14 +48,18 @@ jobs: - name: Install dependencies run: composer install --prefer-dist --no-progress - - name: 'Create env file' - run: | - touch .env - echo PUBLIC_KEY="$PUBLIC_KEY" >> .env - echo SECRET_KEY="$SECRET_KEY" >> .env - echo ENCRYPTION_KEY="$ENCRYPTION_KEY" >> .env - echo ENV="$ENV" >> .env - ls -a ${{ github.workspace }} + - name: Make envfile + uses: SpicyPizza/create-envfile@v2.0 + with: + envkey_PUBLIC_KEY: ${{ secrets.PUBLIC_KEY }} + envkey_SECRET_KEY: ${{ secrets.SECRET_KEY }} + envkey_ENCRYPTION_KEY: ${{ secrets.ENCRYPTION_KEY }} + envkey_ENV: ${{ secrets.ENV }} + some_other_variable: foobar + directory: ${{ github.workspace }} + file_name: .env + fail_on_empty: false + sort_keys: false - name: run unit tests and coverage scan run: ./vendor/bin/pest --coverage --min=20 --coverage-clover ./coverage.xml From c14aef353dc482e37562d0b91fb7df30b5c1e637 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Mon, 17 Jul 2023 12:09:26 +0100 Subject: [PATCH 61/70] update change-review workflow create .env workflow step --- .github/workflows/change-review.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/change-review.yml b/.github/workflows/change-review.yml index 75f2d18..0ac4e21 100644 --- a/.github/workflows/change-review.yml +++ b/.github/workflows/change-review.yml @@ -56,7 +56,6 @@ jobs: envkey_ENCRYPTION_KEY: ${{ secrets.ENCRYPTION_KEY }} envkey_ENV: ${{ secrets.ENV }} some_other_variable: foobar - directory: ${{ github.workspace }} file_name: .env fail_on_empty: false sort_keys: false From deee8c0adb46db89249426efe47ad61641f0aac3 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Mon, 17 Jul 2023 12:15:27 +0100 Subject: [PATCH 62/70] update change-review workflow create .env workflow step --- .github/workflows/change-review.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/change-review.yml b/.github/workflows/change-review.yml index 0ac4e21..e07b832 100644 --- a/.github/workflows/change-review.yml +++ b/.github/workflows/change-review.yml @@ -51,14 +51,13 @@ jobs: - name: Make envfile uses: SpicyPizza/create-envfile@v2.0 with: + file_name: .env + fail_on_empty: false + sort_keys: false envkey_PUBLIC_KEY: ${{ secrets.PUBLIC_KEY }} envkey_SECRET_KEY: ${{ secrets.SECRET_KEY }} envkey_ENCRYPTION_KEY: ${{ secrets.ENCRYPTION_KEY }} envkey_ENV: ${{ secrets.ENV }} - some_other_variable: foobar - file_name: .env - fail_on_empty: false - sort_keys: false - name: run unit tests and coverage scan run: ./vendor/bin/pest --coverage --min=20 --coverage-clover ./coverage.xml From 9a3fff88ccb4c580ef545220c8b674f19fffb852 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Mon, 17 Jul 2023 13:28:18 +0100 Subject: [PATCH 63/70] update change-review workflow create .env workflow step --- .github/workflows/change-review.yml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/.github/workflows/change-review.yml b/.github/workflows/change-review.yml index e07b832..2dc7be7 100644 --- a/.github/workflows/change-review.yml +++ b/.github/workflows/change-review.yml @@ -48,16 +48,14 @@ jobs: - name: Install dependencies run: composer install --prefer-dist --no-progress - - name: Make envfile - uses: SpicyPizza/create-envfile@v2.0 - with: - file_name: .env - fail_on_empty: false - sort_keys: false - envkey_PUBLIC_KEY: ${{ secrets.PUBLIC_KEY }} - envkey_SECRET_KEY: ${{ secrets.SECRET_KEY }} - envkey_ENCRYPTION_KEY: ${{ secrets.ENCRYPTION_KEY }} - envkey_ENV: ${{ secrets.ENV }} + - name: 'Create env file' + run: | + touch .env + echo PUBLIC_KEY=${PUBLIC_KEY} >> .env + echo SECRET_KEY=${SECRET_KEY} >> .env + echo ENCRYPTION_KEY=${ENCRYPTION_KEY} >> .env + echo ENV=${ENV} >> .env + ls -a ${{ github.workspace }} - name: run unit tests and coverage scan run: ./vendor/bin/pest --coverage --min=20 --coverage-clover ./coverage.xml From 92a651617c0c4517552bc6c60b106f7bb44282f3 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Fri, 21 Jul 2023 12:01:36 +0100 Subject: [PATCH 64/70] feat: GooglePay --- src/EventHandlers/GooglePayEventHandler.php | 71 ++++++++++++++++++ src/Service/GooglePay.php | 79 +++++++++++++++++++++ src/Util/methods.php | 2 + tests/Unit/Service/GooglePayTest.php | 38 ++++++++++ 4 files changed, 190 insertions(+) create mode 100644 src/EventHandlers/GooglePayEventHandler.php create mode 100644 src/Service/GooglePay.php create mode 100644 tests/Unit/Service/GooglePayTest.php diff --git a/src/EventHandlers/GooglePayEventHandler.php b/src/EventHandlers/GooglePayEventHandler.php new file mode 100644 index 0000000..f68cd03 --- /dev/null +++ b/src/EventHandlers/GooglePayEventHandler.php @@ -0,0 +1,71 @@ +data->id; + $tx_ref = $response->data->tx_ref; + $data['data_to_save'] = [ + 'transactionId' => $transactionId, + 'tx_ref' => $tx_ref, + ]; + $data['mode'] = $response->data->meta->authorization->mode; + } + + $data['dev_instruction'] = 'Redirect the user to the auth link for validation. verfiy via the verify endpoint.'; + $data['url'] = $response->data->meta->authorization->redirect; + + if (is_array($resource) && ! empty($resource)) { + $logger = $resource['logger']; + $logger->notice('Apple Method Event::Apple Authorization Mode: ' . $data['mode'] ?? 'redirect'); + } + + return $data; + } +} \ No newline at end of file diff --git a/src/Service/GooglePay.php b/src/Service/GooglePay.php new file mode 100644 index 0000000..2868f5c --- /dev/null +++ b/src/Service/GooglePay.php @@ -0,0 +1,79 @@ +getEndpoint(); + $this->url = $this->baseUrl . '/' . $endpoint . '?type='; + $this->eventHandler = new GooglePayEventHandler($config); + } + + /** + * @return array + * + * @throws GuzzleException + */ + public function initiate(Payload $payload): array + { + return $this->charge($payload); + } + + /** + * @param Payload $payload + * @return array + * + * @throws ClientExceptionInterface + */ + public function charge(Payload $payload): array + { + $this->logger->notice('Google Service::Started Charging Process ...'); + + $payload = $payload->toArray(); + + //request payload + $body = $payload; + + unset($body['country']); + unset($body['address']); + + $this->eventHandler::startRecording(); + $request = $this->request($body, 'POST', self::TYPE); + $this->eventHandler::setResponseTime(); + return $this->handleAuthState($request, $body); + } + + public function save(callable $callback): void + { + // TODO: Implement save() method. + } + + /** + * @param array $payload + * + * @return array + */ + private function handleAuthState(stdClass $response, array $payload): array + { + return $this->eventHandler->onAuthorization($response, ['logger' => $this->logger]); + } +} \ No newline at end of file diff --git a/src/Util/methods.php b/src/Util/methods.php index fede22b..1133bb2 100644 --- a/src/Util/methods.php +++ b/src/Util/methods.php @@ -16,6 +16,7 @@ use Flutterwave\Service\TokenizedCharge; use Flutterwave\Service\Transfer; use Flutterwave\Service\Ussd; +use Flutterwave\Service\GooglePay; //use Flutterwave\Service\PayPal; //use Flutterwave\Service\Remita; @@ -36,6 +37,7 @@ 'tokenize' => TokenizedCharge::class, 'transfer' => Transfer::class, 'ussd' => Ussd::class, + 'google' => GooglePay::class // "paypal" => PayPal::class, // "remita" => Remita::class, // "voucher" => VoucherPayment::class, diff --git a/tests/Unit/Service/GooglePayTest.php b/tests/Unit/Service/GooglePayTest.php new file mode 100644 index 0000000..d9e269a --- /dev/null +++ b/tests/Unit/Service/GooglePayTest.php @@ -0,0 +1,38 @@ + 2000, + "currency" => Currency::NGN, + "tx_ref" => uniqid().time(), + "redirectUrl" => "https://example.com" + ]; + + $googlepayment = \Flutterwave\Flutterwave::create("google"); + $customerObj = $googlepayment->customer->create([ + "full_name" => "Olaobaju Jesulayomi Abraham", + "email" => "vicomma@gmail.com", + "phone" => "+2349060085861" + ]); + + $data['customer'] = $customerObj; + $payload = $googlepayment->payload->create($data); + $result = $googlepayment->initiate($payload); + + $this->assertSame(AuthMode::REDIRECT, $result['mode']); + } +} \ No newline at end of file From f606366cebeb93ec4b1d05fd2495acf3b54ccca1 Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Fri, 21 Jul 2023 20:00:57 +0100 Subject: [PATCH 65/70] feat: Enaira --- README.md | 27 ++++++++ src/EventHandlers/EnairaEventHandler.php | 78 +++++++++++++++++++++++ src/Service/Enaira.php | 81 ++++++++++++++++++++++++ src/Util/methods.php | 4 +- tests/Unit/Service/EnairaTest.php | 39 ++++++++++++ 5 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 src/EventHandlers/EnairaEventHandler.php create mode 100644 src/Service/Enaira.php create mode 100644 tests/Unit/Service/EnairaTest.php diff --git a/README.md b/README.md index b1db0e5..67b1a87 100644 --- a/README.md +++ b/README.md @@ -573,6 +573,33 @@ $response = $service->create($payload); ```
+### Enaira + +```php +use Flutterwave\Util\Currency; + +$data = [ + "amount" => 2000, + "is_token" => 1, + "currency" => Currency::NGN, + "tx_ref" => uniqid().time(), + "redirectUrl" => "https://example.com" +]; + +$payment = \Flutterwave\Flutterwave::create("enaira"); +$customerObj = $payment->customer->create([ + "full_name" => "Olaobaju Jesulayomi Abraham", + "email" => "developers@flutterwavego.com", + "phone" => "+2349060085861" +]); + +$data['customer'] = $customerObj; +$payload = $payment->payload->create($data); +$result = $payment->initiate($payload); +``` + +
+ ### Tokenized Charge Once the charge and validation process is complete for the first charge on the card, you can make use of the token for subsequent charges. diff --git a/src/EventHandlers/EnairaEventHandler.php b/src/EventHandlers/EnairaEventHandler.php new file mode 100644 index 0000000..6ef5b38 --- /dev/null +++ b/src/EventHandlers/EnairaEventHandler.php @@ -0,0 +1,78 @@ +data->id; + $tx_ref = $response->data->tx_ref; + $data['data_to_save'] = [ + 'transactionId' => $transactionId, + 'tx_ref' => $tx_ref, + ]; + $data['mode'] = $response->data->meta->authorization->mode; + + switch ($data['mode']) { + case AuthMode::REDIRECT: + $data['dev_instruction'] = 'Redirect the user to the auth link for validation'; + $data['url'] = $response->meta->authorization->redirect; + break; + case AuthMode::VALIDATE: + $data['dev_instruction'] = "To complete the charge, call the validate endpoint and pass the token (OTP generated from the user's speed wallet)."; + $data['instruction'] = $response->meta->validate_instructions; + break; + } + } + + if (is_array($resource) && ! empty($resource)) { + $logger = $resource['logger']; + $logger->notice('Enaira Method Event::Enaira Authorization Mode: ' . $data['mode'] ?? 'redirect'); + } + + return $data; + } +} \ No newline at end of file diff --git a/src/Service/Enaira.php b/src/Service/Enaira.php new file mode 100644 index 0000000..5fd17fe --- /dev/null +++ b/src/Service/Enaira.php @@ -0,0 +1,81 @@ +getEndpoint(); + $this->url = $this->baseUrl . '/' . $endpoint . '?type='; + $this->eventHandler = new ApplePayEventHandler($config); + } + + /** + * @return array + * + * @throws GuzzleException + */ + public function initiate(Payload $payload): array + { + return $this->charge($payload); + } + + /** + * @param Payload $payload + * @return array + * + * @throws ClientExceptionInterface + */ + public function charge(Payload $payload): array + { + $this->logger->notice('Enaira Service::Started Charging Process ...'); + + if($payload->has('is_qr') || $payload->has('is_token')) { + dd($payload); + } + + $payload = $payload->toArray(); + +// dd($payload); + + //request payload + $body = $payload; + + ApplePayEventHandler::startRecording(); + $request = $this->request($body, 'POST', self::TYPE); + ApplePayEventHandler::setResponseTime(); + return $this->handleAuthState($request, $body); + } + + public function save(callable $callback): void + { + // TODO: Implement save() method. + } + + /** + * @param array $payload + * + * @return array + */ + private function handleAuthState(stdClass $response, array $payload): array + { + return $this->eventHandler->onAuthorization($response, ['logger' => $this->logger]); + } +} \ No newline at end of file diff --git a/src/Util/methods.php b/src/Util/methods.php index 1133bb2..8ef122d 100644 --- a/src/Util/methods.php +++ b/src/Util/methods.php @@ -17,6 +17,7 @@ use Flutterwave\Service\Transfer; use Flutterwave\Service\Ussd; use Flutterwave\Service\GooglePay; +use Flutterwave\Service\Enaira; //use Flutterwave\Service\PayPal; //use Flutterwave\Service\Remita; @@ -37,7 +38,8 @@ 'tokenize' => TokenizedCharge::class, 'transfer' => Transfer::class, 'ussd' => Ussd::class, - 'google' => GooglePay::class + 'google' => GooglePay::class, + 'enaira' => Enaira::class // "paypal" => PayPal::class, // "remita" => Remita::class, // "voucher" => VoucherPayment::class, diff --git a/tests/Unit/Service/EnairaTest.php b/tests/Unit/Service/EnairaTest.php new file mode 100644 index 0000000..77ecc05 --- /dev/null +++ b/tests/Unit/Service/EnairaTest.php @@ -0,0 +1,39 @@ + 2000, + "is_token" => 1, + "currency" => Currency::NGN, + "tx_ref" => uniqid().time(), + "redirectUrl" => "https://example.com" + ]; + + $payment = \Flutterwave\Flutterwave::create("enaira"); + $customerObj = $payment->customer->create([ + "full_name" => "Olaobaju Jesulayomi Abraham", + "email" => "olaobaju@gmail.com", + "phone" => "+2349067985861" + ]); + + $data['customer'] = $customerObj; + $payload = $payment->payload->create($data); + $result = $payment->initiate($payload); + $this->assertSame(AuthMode::REDIRECT, $result['mode']); + } +} \ No newline at end of file From 8b95e154ac891c6f9bbbaa0e20b9f17690db4c6f Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Fri, 21 Jul 2023 20:10:48 +0100 Subject: [PATCH 66/70] update: enaira test --- src/Service/Enaira.php | 6 ------ tests/Unit/Service/EnairaTest.php | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Service/Enaira.php b/src/Service/Enaira.php index 5fd17fe..3b928ad 100644 --- a/src/Service/Enaira.php +++ b/src/Service/Enaira.php @@ -47,14 +47,8 @@ public function charge(Payload $payload): array { $this->logger->notice('Enaira Service::Started Charging Process ...'); - if($payload->has('is_qr') || $payload->has('is_token')) { - dd($payload); - } - $payload = $payload->toArray(); -// dd($payload); - //request payload $body = $payload; diff --git a/tests/Unit/Service/EnairaTest.php b/tests/Unit/Service/EnairaTest.php index 77ecc05..3129783 100644 --- a/tests/Unit/Service/EnairaTest.php +++ b/tests/Unit/Service/EnairaTest.php @@ -26,7 +26,7 @@ public function testAuthModeReturnRedirect() $payment = \Flutterwave\Flutterwave::create("enaira"); $customerObj = $payment->customer->create([ - "full_name" => "Olaobaju Jesulayomi Abraham", + "full_name" => "Flutterwave Developers", "email" => "olaobaju@gmail.com", "phone" => "+2349067985861" ]); From 0a96bdb402bfd74d8bc4996308792b747bdd89ef Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Fri, 21 Jul 2023 20:12:53 +0100 Subject: [PATCH 67/70] update GooglePay EventHandler --- src/EventHandlers/GooglePayEventHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EventHandlers/GooglePayEventHandler.php b/src/EventHandlers/GooglePayEventHandler.php index f68cd03..d481232 100644 --- a/src/EventHandlers/GooglePayEventHandler.php +++ b/src/EventHandlers/GooglePayEventHandler.php @@ -63,7 +63,7 @@ public function onAuthorization(\stdClass $response, ?array $resource = null): a if (is_array($resource) && ! empty($resource)) { $logger = $resource['logger']; - $logger->notice('Apple Method Event::Apple Authorization Mode: ' . $data['mode'] ?? 'redirect'); + $logger->notice('Google Method Event::Apple Authorization Mode: ' . $data['mode'] ?? 'redirect'); } return $data; From e0d488f7310c5a02816637c84b72dcab4e8a59de Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Sat, 22 Jul 2023 01:56:49 +0100 Subject: [PATCH 68/70] feat: FawryPay --- src/EventHandlers/FawryEventHandler.php | 68 +++++++++++++++++++++ src/Service/Fawry.php | 81 +++++++++++++++++++++++++ src/Util/Currency.php | 1 + src/Util/methods.php | 4 +- tests/Unit/Service/FawryTest.php | 40 ++++++++++++ 5 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 src/EventHandlers/FawryEventHandler.php create mode 100644 src/Service/Fawry.php create mode 100644 tests/Unit/Service/FawryTest.php diff --git a/src/EventHandlers/FawryEventHandler.php b/src/EventHandlers/FawryEventHandler.php new file mode 100644 index 0000000..a4a40d5 --- /dev/null +++ b/src/EventHandlers/FawryEventHandler.php @@ -0,0 +1,68 @@ +data->id; + $tx_ref = $response->data->tx_ref; + $data['data_to_save'] = [ + 'transactionId' => $transactionId, + 'tx_ref' => $tx_ref, + ]; + $data['mode'] = $response->data->meta->authorization->mode; + } + + $data['dev_instruction'] = 'Redirect the user to the auth link for validation. verfiy via the verify endpoint.'; + + if (is_array($resource) && ! empty($resource)) { + $logger = $resource['logger']; + $logger->notice('Fawry Method Event::Fawry Authorization Mode: ' . $data['mode'] ?? 'fawry_pay'); + } + + return $data; + } +} \ No newline at end of file diff --git a/src/Service/Fawry.php b/src/Service/Fawry.php new file mode 100644 index 0000000..0eaad3f --- /dev/null +++ b/src/Service/Fawry.php @@ -0,0 +1,81 @@ +getEndpoint(); + $this->url = $this->baseUrl . '/' . $endpoint . '?type='; + $this->eventHandler = new GooglePayEventHandler($config); + } + + /** + * @return array + * + * @throws GuzzleException + */ + public function initiate(Payload $payload): array + { + return $this->charge($payload); + } + + /** + * @param Payload $payload + * @return array + * + * @throws ClientExceptionInterface + */ + public function charge(Payload $payload): array + { + $this->logger->notice('Google Service::Started Charging Process ...'); + + $payload = $payload->toArray(); + + if($payload['currency'] !== 'EGP') { + throw new \InvalidArgumentException("Invalid currency. This transaction is only allowed for EGP"); + } + + //request payload + $body = $payload; + + unset($body['country']); + unset($body['address']); + + $this->eventHandler::startRecording(); + $request = $this->request($body, 'POST', self::TYPE); + $this->eventHandler::setResponseTime(); + return $this->handleAuthState($request, $body); + } + + public function save(callable $callback): void + { + // TODO: Implement save() method. + } + + /** + * @param array $payload + * + * @return array + */ + private function handleAuthState(stdClass $response, array $payload): array + { + return $this->eventHandler->onAuthorization($response, ['logger' => $this->logger]); + } +} \ No newline at end of file diff --git a/src/Util/Currency.php b/src/Util/Currency.php index 23eb0f3..06d7aa3 100644 --- a/src/Util/Currency.php +++ b/src/Util/Currency.php @@ -18,4 +18,5 @@ class Currency public const RWF = 'RWF'; public const XAF = 'XAF'; public const XOF = 'XOF'; + public const EGP = 'EGP'; } diff --git a/src/Util/methods.php b/src/Util/methods.php index 8ef122d..3e5fd20 100644 --- a/src/Util/methods.php +++ b/src/Util/methods.php @@ -18,6 +18,7 @@ use Flutterwave\Service\Ussd; use Flutterwave\Service\GooglePay; use Flutterwave\Service\Enaira; +use Flutterwave\Service\Fawry; //use Flutterwave\Service\PayPal; //use Flutterwave\Service\Remita; @@ -39,7 +40,8 @@ 'transfer' => Transfer::class, 'ussd' => Ussd::class, 'google' => GooglePay::class, - 'enaira' => Enaira::class + 'enaira' => Enaira::class, + 'fawry' => Fawry::class // "paypal" => PayPal::class, // "remita" => Remita::class, // "voucher" => VoucherPayment::class, diff --git a/tests/Unit/Service/FawryTest.php b/tests/Unit/Service/FawryTest.php new file mode 100644 index 0000000..6f68a67 --- /dev/null +++ b/tests/Unit/Service/FawryTest.php @@ -0,0 +1,40 @@ + 2000, + "currency" => Currency::EGP, + "tx_ref" => uniqid().time(), + "redirectUrl" => "https://example.com" + ]; + + $payment = \Flutterwave\Flutterwave::create("fawry"); + $customerObj = $payment->customer->create([ + "full_name" => "Olaobaju Jesulayomi Abraham", + "email" => "vicomma@gmail.com", + "phone" => "+2349060085861" + ]); + + $data['customer'] = $customerObj; + $payload = $payment->payload->create($data); + $result = $payment->initiate($payload); + + $this->assertSame('fawry_pay', $result['mode']); + } + +} \ No newline at end of file From 3dc88e51564ba50a158dfb01e88c19759bfee2be Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Mon, 24 Jul 2023 06:42:43 +0100 Subject: [PATCH 69/70] feat: TZS momo --- src/EventHandlers/MomoEventHandler.php | 1 + src/Service/MobileMoney.php | 3 ++- tests/Unit/Service/MomoTest.php | 26 ++++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/EventHandlers/MomoEventHandler.php b/src/EventHandlers/MomoEventHandler.php index bdf3e5b..1695701 100644 --- a/src/EventHandlers/MomoEventHandler.php +++ b/src/EventHandlers/MomoEventHandler.php @@ -96,6 +96,7 @@ public function onAuthorization(\stdClass $response, ?array $resource = null): a $data['data_to_save'] = [ 'transactionId' => $transactionId, 'tx_ref' => $tx_ref, + 'status' => $response->data->status ]; } diff --git a/src/Service/MobileMoney.php b/src/Service/MobileMoney.php index 6e05d64..a546bc8 100644 --- a/src/Service/MobileMoney.php +++ b/src/Service/MobileMoney.php @@ -23,12 +23,14 @@ class MobileMoney extends Service implements Payment Currency::UGX => 'mobile_money_uganda', Currency::XAF => 'mobile_money_franco', Currency::ZMW => 'mobile_money_zambia', + Currency::TZS => 'mobile_money_tanzania' ]; private array $networks = [ 'GH' => ['MTN','VODOFONE','TIGO'], 'UG' => ['MTN', 'AIRTEL'], 'ZM' => ['MTN', 'ZAMTEL'], + 'Tz' => ['AIRTEL', 'TIGO', 'HALOPESA', 'VODOFONE' ] ]; private array $supported_countries_franco = [ @@ -89,7 +91,6 @@ public function charge(Payload $payload): array MomoEventHandler::startRecording(); $request = $this->request($body, 'POST', $type); MomoEventHandler::setResponseTime(); - return $this->handleAuthState($request, $body); } diff --git a/tests/Unit/Service/MomoTest.php b/tests/Unit/Service/MomoTest.php index 3b9c95b..0afd9ab 100644 --- a/tests/Unit/Service/MomoTest.php +++ b/tests/Unit/Service/MomoTest.php @@ -42,6 +42,32 @@ public function testAuthModeRwandaRedirect(){ $this->assertSame(AuthMode::REDIRECT,$result['mode']); } + + public function testInitiateTanzaniaRedirect(){ + $data = [ + "amount" => 2000, + "currency" => Currency::TZS, + "tx_ref" => uniqid().time(), + "redirectUrl" => null, + "additionalData" => [ + "network" => "VODAFONE", + ] + ]; + + $momopayment = \Flutterwave\Flutterwave::create("momo"); + $customerObj = $momopayment->customer->create([ + "full_name" => "Abiodun Abrahams", + "email" => "developers@flutterwavego.com", + "phone" => "+2349067982061" + ]); + + $data['customer'] = $customerObj; + + $payload = $momopayment->payload->create($data); + $result = $momopayment->initiate($payload); + $this->assertSame('pending',$result['data_to_save']['status']); + } + public function testAuthModeGhanaRedirect(){ $data = [ "amount" => 2000, From b4256b4317f08a25936e1384ca8b6f323444583c Mon Sep 17 00:00:00 2001 From: Olaobaju Abraham Date: Mon, 24 Jul 2023 07:45:29 +0100 Subject: [PATCH 70/70] update: BankAccount Service and test --- src/EventHandlers/AccountEventHandler.php | 7 +++-- src/Service/AccountPayment.php | 25 +++++++++++----- src/Service/AchPayment.php | 8 +++--- src/Util/Currency.php | 1 + tests/Unit/Service/AccountTest.php | 35 +++++++++++++++++++---- 5 files changed, 57 insertions(+), 19 deletions(-) diff --git a/src/EventHandlers/AccountEventHandler.php b/src/EventHandlers/AccountEventHandler.php index 9b13804..30b957c 100644 --- a/src/EventHandlers/AccountEventHandler.php +++ b/src/EventHandlers/AccountEventHandler.php @@ -91,7 +91,8 @@ public function onTimeout($transactionReference, $data): void * */ public function onAuthorization(\stdClass $response, ?array $resource = null): array { - $mode = $response->meta->authorization->mode; + + $mode = $response->data->meta->authorization->mode; if (property_exists($response, 'data')) { $transactionId = $response->data->id; @@ -109,7 +110,7 @@ public function onAuthorization(\stdClass $response, ?array $resource = null): a break; case 'redirect': $data['dev_instruction'] = 'Redirect the user to the auth link for validation'; - $data['url'] = $response->meta->authorization->redirect; + $data['url'] = $response->data->meta->authorization->redirect; break; case 'avs': throw new \Exception('AVS is currently not available via the SDK. please call the endpoint directly.'); @@ -120,7 +121,7 @@ public function onAuthorization(\stdClass $response, ?array $resource = null): a if (property_exists($response->data, 'processor_response')) { $data['instruction'] = $response->data->processor_response; } else { - $data['instruction'] = $response->meta->authorization->validate_instructions; + $data['instruction'] = $response->data->meta->authorization->validate_instructions; } $data['validate'] = true; diff --git a/src/Service/AccountPayment.php b/src/Service/AccountPayment.php index b0a5558..1748883 100644 --- a/src/Service/AccountPayment.php +++ b/src/Service/AccountPayment.php @@ -10,6 +10,7 @@ use Flutterwave\EventHandlers\AccountEventHandler; use Flutterwave\Entities\Payload; use Flutterwave\Traits\Group\Charge; +use Flutterwave\Util\Currency; use GuzzleHttp\Exception\GuzzleException; use InvalidArgumentException; use Psr\Http\Client\ClientExceptionInterface; @@ -20,13 +21,14 @@ class AccountPayment extends Service implements Payment use Charge; public const ENDPOINT = 'charge'; - public const DEBIT_NG = 'debit_ng_account'; - public const DEBIT_UK = 'debit_uk_account'; + public const DEBIT_NG = 'mono'; + public const DEBIT_UK = 'account-ach-uk'; public const TYPE = 'account'; protected array $accounts = [ - 'NG' => self::DEBIT_NG, - 'UK' => self::DEBIT_UK, - ]; + Currency::NGN => self::DEBIT_NG, + Currency::GBP => self::DEBIT_UK, + Currency::EUR => self::DEBIT_UK + ]; protected string $country = 'NG'; private AccountEventHandler $eventHandler; @@ -55,6 +57,12 @@ public function setCountry(string $country): void */ public function initiate(Payload $payload): array { + if($payload->has('currency') && !key_exists($payload->get('currency'), $this->accounts)) { + $msg = 'Account Service: The Currency passed is not supported. kindy pass NGN, GBP or EUR.'; + $this->logger->info($msg); + throw new InvalidArgumentException($msg); + } + if ($this->checkPayloadIsValid($payload, 'account_details')) { return $this->charge($payload); } @@ -73,14 +81,17 @@ public function charge(Payload $payload): array { $this->logger->notice('Account Service::Charging Account ...'); - $this->checkSpecialCasesParams($payload); + if($payload->has('currency') && $payload->get('currency') === Currency::NGN ) { + $this->checkSpecialCasesParams($payload); + } + $payload = $payload->toArray(self::TYPE); //request payload $body = $payload; //check which country was passed. - $account = $this->accounts[$payload['country']]; + $account = $this->accounts[$payload['currency']]; unset($body['country']); unset($body['address']); diff --git a/src/Service/AchPayment.php b/src/Service/AchPayment.php index 924a8b8..653b0e2 100644 --- a/src/Service/AchPayment.php +++ b/src/Service/AchPayment.php @@ -10,6 +10,7 @@ use Flutterwave\EventHandlers\AchEventHandler; use Flutterwave\Entities\Payload; use Flutterwave\Traits\Group\Charge; +use Flutterwave\Util\Currency; use GuzzleHttp\Exception\GuzzleException; use stdClass; @@ -18,12 +19,11 @@ class AchPayment extends Service implements Payment use Charge; public const TYPE = 'ach_payment'; - public const USD = 'USD'; - public const ZAR = 'ZAR'; + protected string $country = 'US'; protected array $currency = [ - self::USD => 'US', - self::ZAR => 'ZA', + Currency::USD => 'US', + Currency::ZAR => 'ZA', ]; private AchEventHandler $eventHandler; diff --git a/src/Util/Currency.php b/src/Util/Currency.php index 06d7aa3..21977f1 100644 --- a/src/Util/Currency.php +++ b/src/Util/Currency.php @@ -19,4 +19,5 @@ class Currency public const XAF = 'XAF'; public const XOF = 'XOF'; public const EGP = 'EGP'; + public const GBP = 'GBP'; } diff --git a/tests/Unit/Service/AccountTest.php b/tests/Unit/Service/AccountTest.php index c820970..ed31cbd 100644 --- a/tests/Unit/Service/AccountTest.php +++ b/tests/Unit/Service/AccountTest.php @@ -15,7 +15,7 @@ protected function setUp(): void Flutterwave::bootstrap(); } - public function testAuthModeReturn() + public function testNgnAuthModeReturn() { //currently returning "Sorry, we could not connect to your bank"; @@ -41,11 +41,8 @@ public function testAuthModeReturn() $data['customer'] = $customerObj; $payload = $accountpayment->payload->create($data); - $this->expectException(\Exception::class); $result = $accountpayment->initiate($payload); - - //check mode returned is either OTP or Redirect -// $this->assertTrue($result['mode'] === AuthMode::OTP || $result['mode'] === AuthMode::REDIRECT ); + $this->assertTrue( $result['mode'] === AuthMode::REDIRECT ); } public function testInvalidParam() @@ -69,4 +66,32 @@ public function testInvalidParam() $this->expectException(\InvalidArgumentException::class); $result = $accountpayment->initiate($payload); } + + public function testUKBankAccountAuthMode() { + $data = [ + "amount" => 2000, + "currency" => Currency::NGN, + "tx_ref" => uniqid().time(), + "additionalData" => [ + "account_details" => [ + "account_bank" => "044", + "account_number" => "0690000034", + "country" => "UK" //or EU + ] + ], + ]; + + $accountpayment = \Flutterwave\Flutterwave::create("account"); + $customerObj = $accountpayment->customer->create([ + "full_name" => "Jake Jesulayomi Ola", + "email" => "developers@flutterwavego.com", + "phone" => "+2349067985861" + ]); + + $data['customer'] = $customerObj; + $payload = $accountpayment->payload->create($data); + $result = $accountpayment->initiate($payload); + + $this->assertTrue( $result['mode'] === AuthMode::REDIRECT ); + } } \ No newline at end of file