diff --git a/.docker/.gitpod.Dockerfile b/.docker/.gitpod.Dockerfile
new file mode 100644
index 0000000..1c3bd34
--- /dev/null
+++ b/.docker/.gitpod.Dockerfile
@@ -0,0 +1,3 @@
+FROM gitpod/workspace-full
+
+RUN sudo install-packages php-xdebug
\ No newline at end of file
diff --git a/.github/workflows/change-review.yml b/.github/workflows/change-review.yml
index 2dc7be7..8d3895c 100644
--- a/.github/workflows/change-review.yml
+++ b/.github/workflows/change-review.yml
@@ -14,7 +14,7 @@ jobs:
strategy:
fail-fast: true
matrix:
- php: [7.4, 8.1, 8.2]
+ php: [7.4, 8.1, 8.2, 8.3]
env:
XDEBUG_MODE: coverage
@@ -48,17 +48,13 @@ 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
+ env:
+ PUBLIC_KEY: ${{ secrets.PUBLIC_KEY }}
+ SECRET_KEY: ${{ secrets.SECRET_KEY }}
+ ENCRYPTION_KEY: ${{ secrets.ENCRYPTION_KEY }}
+ ENV: ${{ secrets.ENV }}
- name: Upload to Codecov
uses: codecov/codecov-action@v2
diff --git a/.gitpod.yml b/.gitpod.yml
new file mode 100644
index 0000000..485aafb
--- /dev/null
+++ b/.gitpod.yml
@@ -0,0 +1,15 @@
+# This configuration file was automatically generated by Gitpod.
+# Please adjust to your needs (see https://www.gitpod.io/docs/introduction/learn-gitpod/gitpod-yaml)
+# and commit this file to your remote git repository to share the goodness with others.
+
+# Learn more from ready-to-use templates: https://www.gitpod.io/docs/introduction/getting-started/quickstart
+
+image:
+ file: .docker/.gitpod.Dockerfile
+
+tasks:
+ - init: make
+
+vscode:
+ extensions:
+ - felixfbecker.php-debug
diff --git a/Makefile b/Makefile
index 0fa8af9..4db333a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,15 @@
.PHONY: init
-test:
+check:
@echo "Installing dependencies..."
@composer install
@echo "Installing dependencies... Done"
@./vendor/bin/pest --coverage --min=0 --coverage-clover ./coverage.xml
+test:
+ @./vendor/bin/pest --coverage --min=0 --coverage-clover ./coverage.xml
+
+debug:
+ XDEBUG_MODE=coverage ./vendor/bin/pest --coverage --coverage-html .log
+
+
diff --git a/examples/card.php b/examples/card.php
index 3141857..0f7ade0 100644
--- a/examples/card.php
+++ b/examples/card.php
@@ -4,7 +4,26 @@
use Flutterwave\Util\AuthMode;
use Flutterwave\Util\Currency;
-\Flutterwave\Flutterwave::bootstrap();
+use Flutterwave\Config\ForkConfig;
+use Dotenv\Dotenv;
+// custom config.
+
+if(!file_exists( '.env' )) {
+ $dotenv = Dotenv::createImmutable(__DIR__."/../");
+} else {
+ $dotenv = Dotenv::createImmutable(__DIR__."/");
+}
+
+$dotenv->safeLoad();
+
+$config = ForkConfig::setUp(
+ $_ENV['SECRET_KEY'],
+ $_ENV['PUBLIC_KEY'],
+ $_ENV['ENV'],
+ $_ENV['ENCRYPTION_KEY']
+);
+
+\Flutterwave\Flutterwave::bootstrap($config);
try {
@@ -48,6 +67,8 @@
$data['customer'] = $customerObj;
$payload = $cardpayment->payload->create($data);
+
+
if(!empty($_REQUEST))
{
$request = $_REQUEST;
@@ -59,7 +80,7 @@
if(isset($request['make'])){
$result = $cardpayment->initiate($payload);
-
+ dd($cardpayment);
if($result['mode'] === AuthMode::PIN){
$instruction = $result['instruction'];
require __DIR__."/view/form/pin.php";
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index fc42dbe..86240f3 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -19,6 +19,12 @@
./src
+
+ ./vendor
+ ./vendor
+ ./vendor
+ tests/bootstrap.php
+
diff --git a/processPayment.php b/processPayment.php
index 622ad36..0946145 100644
--- a/processPayment.php
+++ b/processPayment.php
@@ -9,15 +9,33 @@
use Flutterwave\EventHandlers\ModalEventHandler as PaymentHandler;
use Flutterwave\Flutterwave;
use Flutterwave\Library\Modal;
+use \Flutterwave\Config\ForkConfig;
-# start a session.
+// start a session.
session_start();
+// Define custom config.
+// $myConfig = ForkConfig::setUp(
+// 'FLWSECK_TEST-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-X', //Secret key
+// 'FLWPUBK_TEST-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-X', // Public key
+// 'FLWSECK_TESTXXXXXXXXXXX', //Encryption key
+// 'staging' //Environment Variable
+// );
+
+// uncomment the block if you just want to pass the keys with a specific configuration.
+// $_ENV['SECRET_KEY'] = "FLWSECK_TEST-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-X";
+// $_ENV['PUBLIC_KEY'] = "FLWPUBK_TEST-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-X";
+// $_ENV['ENCRYPTION_KEY'] = "FLWSECK_TESTXXXXXXXXXXXX";
+// $_ENV['ENV'] = "staging";
+
+// controller default
+$controller = null;
+
try {
- Flutterwave::bootstrap();
+ Flutterwave::bootstrap(); // create a .env or Flutterwave::bootstrap($myConfig)
$customHandler = new PaymentHandler();
$client = new Flutterwave();
- $modalType = Modal::POPUP; // Modal::POPUP or Modal::STANDARD
+ $modalType = Modal::STANDARD; // Modal::POPUP or Modal::STANDARD
$controller = new PaymentController( $client, $customHandler, $modalType );
} catch(\Exception $e ) {
echo $e->getMessage();
diff --git a/setup.php b/setup.php
index 1c5b813..88934ec 100644
--- a/setup.php
+++ b/setup.php
@@ -5,7 +5,7 @@
$flutterwave_installation = 'composer';
-if( !file_exists( '.env' )) {
+if( !file_exists( '.env' ) && !is_dir('vendor')) {
$dotenv = Dotenv::createImmutable(__DIR__."/../../../"); # on the event that the package is install via composer.
} else {
$flutterwave_installation = "manual";
@@ -17,7 +17,12 @@
//check if the current version of php is compatible
if(!Helper\CheckCompatibility::isCompatible())
{
- echo "Flutterwave: This SDK only support php version ". Helper\CheckCompatibility::MINIMUM_COMPATIBILITY. " or greater.";
+ if (PHP_SAPI === 'cli') {
+ echo "❌ Flutterwave: This SDK only support php version ". Helper\CheckCompatibility::MINIMUM_COMPATIBILITY. " or greater.";
+ } else {
+ echo "Flutterwave: This SDK only support php version ". Helper\CheckCompatibility::MINIMUM_COMPATIBILITY. " or greater.";
+ }
+
exit;
}
@@ -28,22 +33,27 @@
try{
foreach($flutterwaveKeys as $key)
{
- if( empty( $_ENV[ $key ] ) )
+ if(empty($_ENV[ $key ]) && empty(\getenv($key)))
{
throw new InvalidArgumentException("$key environment variable missing.");
}
}
}catch(\Exception $e)
{
- echo "Flutterwave sdk: " .$e->getMessage()."
";
+ if (PHP_SAPI === 'cli') {
+ echo "❌❌Flutterwave sdk: " .$e->getMessage();
+ echo "Kindly create a .env in the project root and add the required environment variables. ❌". PHP_EOL;
+ } else {
+ echo "Flutterwave sdk: " .$e->getMessage()."
";
+ echo "
Kindly create a .env
in the project root and add the required environment variables.";
+ }
- echo "
Kindly create a .env
in the project root and add the required environment variables.";
exit;
}
$keys = [
- 'SECRET_KEY' => $_ENV['SECRET_KEY'],
- 'PUBLIC_KEY' => $_ENV['PUBLIC_KEY'],
- 'ENV' => $_ENV['ENV'],
- 'ENCRYPTION_KEY' => $_ENV['ENCRYPTION_KEY']
+ 'SECRET_KEY' => $_ENV['SECRET_KEY'] ?? \getenv('SECRET_KEY'),
+ 'PUBLIC_KEY' => $_ENV['PUBLIC_KEY'] ?? \getenv('PUBLIC_KEY'),
+ 'ENV' => $_ENV['ENV'] ?? \getenv('ENV'),
+ 'ENCRYPTION_KEY' => $_ENV['ENCRYPTION_KEY'] ?? \getenv('ENCRYPTION_KEY')
];
\ No newline at end of file
diff --git a/src/Config/AbstractConfig.php b/src/Config/AbstractConfig.php
index 6a34aad..63a9cc7 100644
--- a/src/Config/AbstractConfig.php
+++ b/src/Config/AbstractConfig.php
@@ -43,7 +43,11 @@ protected function __construct(string $secret_key, string $public_key, string $e
[
'base_uri' => EnvVariables::BASE_URL,
'timeout' => 60,
- RequestOptions::VERIFY => \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath()
+ 'headers' => ['User-Agent' => sprintf(
+ 'FlutterwavePHP/%d', EnvVariables::SDK_VERSION
+ )],
+ RequestOptions::VERIFY =>
+ \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath()
]
);
diff --git a/src/Contract/ControllerInterface.php b/src/Contract/ControllerInterface.php
new file mode 100644
index 0000000..6cb9c2e
--- /dev/null
+++ b/src/Contract/ControllerInterface.php
@@ -0,0 +1,18 @@
+meta->authorization->mode;
+
+ $mode = $resource['mode'] ?? $response->meta->authorization->mode;
if (property_exists($response, 'data')) {
$transactionId = $response->data->id;
@@ -124,6 +125,12 @@ public function onAuthorization(\stdClass $response, ?array $resource = null): a
$data['instruction'] = $response->data->processor_response;
$data['validate'] = true;
break;
+ default:
+ $data['data_to_save']['status'] = $response->data->status;
+ $data['data_to_save']['amount'] = $response->data->amount;
+ $data['data_to_save']['currency'] = $response->data->currency;
+ $data['data_to_save']['customer_name'] = $response->data->customer->name;
+ $data['data_to_save']['customer_email'] = $response->data->customer->email;
}
$data['mode'] = $mode;
diff --git a/src/Helper/EnvVariables.php b/src/Helper/EnvVariables.php
index 1806271..f70babe 100644
--- a/src/Helper/EnvVariables.php
+++ b/src/Helper/EnvVariables.php
@@ -7,6 +7,7 @@
class EnvVariables
{
public const VERSION = 'v3';
+ public const SDK_VERSION = '1.0.7';
public const BASE_URL = 'https://api.flutterwave.com/' . self::VERSION;
public const TIME_OUT = 30;
}
diff --git a/src/HttpAdapter/CurlClient.php b/src/HttpAdapter/CurlClient.php
index 8fd34a5..bcd9ce6 100644
--- a/src/HttpAdapter/CurlClient.php
+++ b/src/HttpAdapter/CurlClient.php
@@ -1,6 +1,6 @@
logger->notice('Bill Payment Service::Retrieving Top Categories.');
+ self::startRecording();
+ $response = $this->request(null, 'GET', "top-".$this->name);
+ self::setResponseTime();
+ return $response;
+ }
+
+ /**
+ * Retrieve items under a specific biller code.
+ */
+ public function getBillerItems(string $biller_code = null): \stdClass
+ {
+ if(is_null($biller_code)) {
+ $msg = "The required parameter" . $biller_code . " is not present in payload";
+ $this->logger->error("Bill Payment Service::$msg");
+ throw new \InvalidArgumentException("Bill Payment Service:$msg");
+ }
+
+ $this->logger->notice('Bill Payment Service::Retrieving items under biller '. $biller_code);
+ self::startRecording();
+ $response = $this->request(null, 'GET', sprintf('billers/%s/items', $biller_code));
+ self::setResponseTime();
+ return $response;
+ }
+
/**
* @throws ClientExceptionInterface
+ * @deprecated Use `validateCustomerInfo()` instead.
*/
public function validateService(string $item_code): \stdClass
{
@@ -47,6 +85,30 @@ public function validateService(string $item_code): \stdClass
return $response;
}
+ public function validateCustomerInfo(\Flutterwave\Payload $payload): \stdClass
+ {
+ $payload = $payload->toArray();
+
+ foreach (['biller_code', 'customer', 'item_code'] as $param) {
+ if (! array_key_exists($param, $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");
+ }
+ }
+
+ $code = $payload['biller_code'];
+ $customer = $payload['customer'];
+ $customer = $customer[0] == '+' ? substr($customer, 1) : $customer;
+ $item_code = $payload['item_code'];
+
+ $this->logger->notice('Bill Payment Service::Retrieving all Plans.');
+ self::startRecording();
+ $response = $this->request(null, 'GET', sprintf("bill-items/{$item_code}/validate?code=%s&customer=%s", $code, $customer));
+ self::setResponseTime();
+ return $response;
+ }
+
/**
* @throws ClientExceptionInterface
*/
@@ -55,7 +117,7 @@ public function createPayment(\Flutterwave\Payload $payload): \stdClass
$payload = $payload->toArray();
foreach ($this->requiredParams as $param) {
if (! array_key_exists($param, $payload)) {
- $msg = '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");
}
@@ -63,9 +125,12 @@ public function createPayment(\Flutterwave\Payload $payload): \stdClass
$body = $payload;
+ $biller_code = $payload['biller_code'];
+ $item_code = $payload['item_code'];
+
$this->logger->notice('Bill Payment Service::Creating a Bill Payment.');
self::startRecording();
- $response = $this->request($body, 'POST', 'bills');
+ $response = $this->request($body, 'POST', sprintf('billers/%s/items/%s/payment', $biller_code, $item_code));
$this->logger->notice('Bill Payment Service::Created a Bill Payment Successfully.');
self::setResponseTime();
return $response;
diff --git a/src/Service/CardPayment.php b/src/Service/CardPayment.php
index 0bbf487..faadfb4 100644
--- a/src/Service/CardPayment.php
+++ b/src/Service/CardPayment.php
@@ -131,6 +131,20 @@ public function encryption(string $params): string
*/
public function handleAuthState(\stdClass $response, $payload): array
{
+ // dd($response);
+ if(property_exists( $response, 'data' ) && property_exists( $response->data, 'status' ) && $response->data->status === 'successful') {
+ return [
+ 'card_info' => $response->data->card,
+ 'transaction_id' => $response->data->id,
+ 'reference' => $response->data->tx_ref,
+ 'amount' => $response->data->amount,
+ 'mode' => $response->data->auth_model,
+ 'currency' => $response->data->currency,
+ 'customer' => $response->data->customer,
+ 'fraud_status' => $response->data->fraud_status
+ ];
+ }
+
$mode = $response->meta->authorization->mode;
if ($mode === 'pin') {
$data = $this->eventHandler->onAuthorization($response, ['logger' => $this->logger]);
diff --git a/src/Service/PayoutSubaccount.php b/src/Service/PayoutSubaccount.php
index e63dcaf..493019d 100644
--- a/src/Service/PayoutSubaccount.php
+++ b/src/Service/PayoutSubaccount.php
@@ -8,20 +8,20 @@
use Flutterwave\EventHandlers\PayoutSubaccoutEventHandler;
use Flutterwave\Payload;
use Psr\Http\Client\ClientExceptionInterface;
+use Flutterwave\EventHandlers\EventTracker;
use stdClass;
class PayoutSubaccount extends Service
{
+ use EventTracker;
private string $name = 'payout-subaccounts';
private array $requiredParams = [ 'email', 'mobilenumber','country' ];
- private PayoutSubaccoutEventHandler $eventHandler;
public function __construct(?ConfigInterface $config = null)
{
parent::__construct($config);
$endpoint = $this->name;
$this->url = $this->baseUrl . '/' . $endpoint;
- $this->eventHandler = new PayoutSubaccoutEventHandler();
}
public function confirmPayload(Payload $payload): array
@@ -51,9 +51,9 @@ public function create(Payload $payload): stdClass
$this->logger->notice('PSA Service::Creating new Payout Subaccount.');
$body = $this->confirmPayload($payload);
$this->logger->notice('PSA Service::Payload Confirmed.');
- $this->eventHandler::startRecording();
+ self::startRecording();
$response = $this->request($body, 'POST');
- $this->eventHandler::setResponseTime();
+ self::setResponseTime();
return $response;
}
@@ -62,9 +62,9 @@ public function create(Payload $payload): stdClass
*/
public function list(): stdClass
{
- $this->eventHandler::startRecording();
+ self::startRecording();
$response = $this->request(null, 'GET');
- $this->eventHandler::setResponseTime();
+ self::setResponseTime();
return $response;
}
@@ -73,9 +73,9 @@ public function list(): stdClass
*/
public function get(string $account_reference): \stdClass
{
- $this->eventHandler::startRecording();
+ self::startRecording();
$response = $this->request(null, 'GET', "/$account_reference");
- $this->eventHandler::setResponseTime();
+ self::setResponseTime();
return $response;
}
@@ -90,9 +90,9 @@ public function update(string $account_reference, Payload $payload): \stdClass
throw new \InvalidArgumentException($msg);
}
- $this->eventHandler::startRecording();
+ self::startRecording();
$response = $this->request($payload->toArray(), 'PUT', "/{$account_reference}");
- $this->eventHandler::setResponseTime();
+ self::setResponseTime();
return $response;
}
@@ -101,9 +101,9 @@ public function update(string $account_reference, Payload $payload): \stdClass
*/
public function fetchTransactions(string $account_reference): \stdClass
{
- $this->eventHandler::startRecording();
+ self::startRecording();
$response = $this->request(null, 'GET', "/{$account_reference}/transactions");
- $this->eventHandler::setResponseTime();
+ self::setResponseTime();
return $response;
}
@@ -112,9 +112,9 @@ public function fetchTransactions(string $account_reference): \stdClass
*/
public function fetchAvailableBalance(string $account_reference, string $currency = 'NGN'): \stdClass
{
- $this->eventHandler::startRecording();
+ self::startRecording();
$response = $this->request(null, 'GET', "/{$account_reference}/balances?currency={$currency}");
- $this->eventHandler::setResponseTime();
+ self::setResponseTime();
return $response;
}
@@ -123,9 +123,9 @@ public function fetchAvailableBalance(string $account_reference, string $currenc
*/
public function fetchStaticVirtualAccounts(string $account_reference, string $currency = 'NGN'): stdClass
{
- $this->eventHandler::startRecording();
+ self::startRecording();
$response = $this->request(null, 'GET', "/{$account_reference}/static-account?currency={$currency}");
- $this->eventHandler::setResponseTime();
+ self::setResponseTime();
return $response;
}
}
diff --git a/src/Service/Transactions.php b/src/Service/Transactions.php
index ea40d0e..155b20d 100644
--- a/src/Service/Transactions.php
+++ b/src/Service/Transactions.php
@@ -5,12 +5,13 @@
namespace Flutterwave\Service;
use Flutterwave\Contract\ConfigInterface;
-use Flutterwave\EventHandlers\TransactionVerificationEventHandler;
+use Flutterwave\EventHandlers\EventTracker;
use Flutterwave\Traits\ApiOperations\Post;
use Psr\Http\Client\ClientExceptionInterface;
class Transactions extends Service
{
+ use EventTracker;
use Post;
public const ENDPOINT = 'transactions';
@@ -26,14 +27,12 @@ class Transactions extends Service
private array $payment_type = [
'card','debit_ng_account','mobilemoney','bank_transfer', 'ach_payment',
];
- private TransactionVerificationEventHandler $eventHandler;
public function __construct(?ConfigInterface $config = null)
{
parent::__construct($config);
- $this->baseUrl = $this->config::BASE_URL;
$this->end_point = Transactions::ENDPOINT;
- $this->eventHandler = new TransactionVerificationEventHandler();
+
}
/**
@@ -43,13 +42,13 @@ public function verify(string $transactionId): \stdClass
{
$this->checkTransactionId($transactionId);
$this->logger->notice('Transaction Service::Verifying Transaction...' . $transactionId);
- TransactionVerificationEventHandler::startRecording();
+ self::startRecording();
$response = $this->request(
null,
'GET',
self::ENDPOINT . "/{$transactionId}/verify",
);
- TransactionVerificationEventHandler::setResponseTime();
+ self::setResponseTime();
return $response;
}
@@ -60,13 +59,13 @@ public function verify(string $transactionId): \stdClass
public function verifyWithTxref(string $tx_ref): \stdClass
{
$this->logger->notice('Transaction Service::Verifying Transaction...' . $tx_ref);
- TransactionVerificationEventHandler::startRecording();
+ self::startRecording();
$response = $this->request(
null,
'GET',
self::ENDPOINT . '/verify_by_reference?tx_ref=' . $tx_ref,
);
- TransactionVerificationEventHandler::setResponseTime();
+ self::setResponseTime();
return $response;
}
@@ -77,13 +76,13 @@ public function refund(string $trasanctionId): \stdClass
{
$this->checkTransactionId($trasanctionId);
$this->logger->notice("Transaction Service::Refunding Transaction...{$trasanctionId}");
- TransactionVerificationEventHandler::startRecording();
+ self::startRecording();
$response = $this->request(
null,
'GET',
self::ENDPOINT . "/{$trasanctionId}/refund",
);
- TransactionVerificationEventHandler::setResponseTime();
+ self::setResponseTime();
return $response;
}
@@ -93,13 +92,13 @@ public function refund(string $trasanctionId): \stdClass
public function getAllTransactions(): \stdClass
{
$this->logger->notice('Transaction Service::Retrieving all Transaction for Merchant');
- TransactionVerificationEventHandler::startRecording();
+ self::startRecording();
$response = $this->request(
null,
'GET',
self::ENDPOINT,
);
- TransactionVerificationEventHandler::setResponseTime();
+ self::setResponseTime();
return $response;
}
@@ -110,13 +109,13 @@ public function getRefundInfo(string $trasanctionId): \stdClass
{
$this->checkTransactionId($trasanctionId);
$this->logger->notice("Transaction Service::Retrieving refund:Transactionid => {$trasanctionId}");
- TransactionVerificationEventHandler::startRecording();
+ self::startRecording();
$response = $this->request(
null,
'GET',
"refunds/{$trasanctionId}",
);
- TransactionVerificationEventHandler::setResponseTime();
+ self::setResponseTime();
return $response;
}
@@ -151,13 +150,13 @@ public function getTransactionFee(
$logData = json_encode($data);
$this->logger->notice("Transaction Service::Retrieving Transaction Fee: Util => {$logData}");
- TransactionVerificationEventHandler::startRecording();
+ self::startRecording();
$response = $this->request(
null,
'GET',
self::ENDPOINT . "/fee?{$query}",
);
- TransactionVerificationEventHandler::setResponseTime();
+ self::setResponseTime();
return $response;
}
@@ -168,13 +167,13 @@ public function resendFailedHooks(string $transactionId): \stdClass
{
$this->checkTransactionId($transactionId);
$this->logger->notice("Transaction Service::Resending Transaction Webhook: TransactionId => {$transactionId}");
- TransactionVerificationEventHandler::startRecording();
+ self::startRecording();
$response = $this->request(
null,
- 'GET',
+ 'POST',
self::ENDPOINT . "/{$transactionId}/resend-hook",
);
- TransactionVerificationEventHandler::setResponseTime();
+ self::setResponseTime();
return $response;
}
@@ -187,13 +186,13 @@ public function retrieveTimeline(string $transactionId): \stdClass
$this->logger->notice(
"Transaction Service::Retrieving Transaction Timeline: TransactionId => {$transactionId}"
);
- TransactionVerificationEventHandler::startRecording();
+ self::startRecording();
$response = $this->request(
null,
'GET',
- self::ENDPOINT . "/{$transactionId}/timeline",
+ self::ENDPOINT . "/{$transactionId}/events",
);
- TransactionVerificationEventHandler::setResponseTime();
+ self::setResponseTime();
return $response;
}
diff --git a/src/Traits/Setup/Configure.php b/src/Traits/Setup/Configure.php
index 981fea9..dcc7cf1 100644
--- a/src/Traits/Setup/Configure.php
+++ b/src/Traits/Setup/Configure.php
@@ -6,21 +6,22 @@
use Flutterwave\Contract\ConfigInterface;
use Flutterwave\Helper\Config;
+use Flutterwave\Config\PackageConfig;
use Flutterwave\Config\ForkConfig;
trait Configure
{
public static function bootstrap(?ConfigInterface $config = null): void
{
- if (\is_null($config)) {
+ if (\is_null($config) && \is_null(self::$config)) {
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]
+ $config = PackageConfig::setUp(
+ $keys[PackageConfig::SECRET_KEY],
+ $keys[PackageConfig::PUBLIC_KEY],
+ $keys[PackageConfig::ENCRYPTION_KEY],
+ $keys[PackageConfig::ENV]
);
}
@@ -34,7 +35,7 @@ public static function bootstrap(?ConfigInterface $config = null): void
}
}
- if (\is_null(self::$config)) {
+ if (\is_null(self::$config) && !\is_null($config)) {
self::$config = $config;
}
diff --git a/tests/Resources/Card/test_cards.php b/tests/Resources/Card/test_cards.php
new file mode 100644
index 0000000..72f8e8e
--- /dev/null
+++ b/tests/Resources/Card/test_cards.php
@@ -0,0 +1,77 @@
+ "5531886652142950",
+ "cvv" => "564",
+ "expiry_month" => "09",
+ "expiry_year" => "32"
+ ];
+
+ const MSTR_CARD_PIN_TWO = [
+ "card_number" => "5399838383838381",
+ "cvv" => "470",
+ "expiry_month" => "10",
+ "expiry_year" => "31"
+ ];
+
+ const MSTR_3DS = [
+ "card_number" => "5438898014560229",
+ "cvv" => "564",
+ "expiry_month" => "10",
+ "expiry_year" => "31"
+ ];
+
+ const VISA_3DS = [
+ "card_number" => "4187427415564246",
+ "cvv" => "828",
+ "expiry_month" => "09",
+ "expiry_year" => "32"
+ ];
+
+ const VISA_3DS_TWO = [
+ "card_number" => "4242424242424242",
+ "cvv" => "812",
+ "expiry_month" => "01",
+ "expiry_year" => "31"
+ ];
+
+ const VISA_3DS_THREE = [
+ "card_number" => "4751763236699647",
+ "cvv" => "812",
+ "expiry_month" => "09",
+ "expiry_year" => "35"
+ ];
+
+ const VERVE_NOAUTH = [
+ "card_number" => "5061460410120223210",
+ "cvv" => "780",
+ "expiry_month" => "12",
+ "expiry_year" => "31"
+ ];
+
+ const VERVE_PIN = [
+ "card_number" => "5061460166976054667",
+ "cvv" => "780",
+ "expiry_month" => "10",
+ "expiry_year" => "22"
+ ];
+
+ const AVS = [
+ "card_number" => "4556052704172643",
+ "cvv" => "899",
+ "expiry_month" => "09",
+ "expiry_year" => "32"
+ ];
+
+ const PREATH = [
+ "card_number" => "5377283645077450",
+ "cvv" => "789",
+ "expiry_month" => "09",
+ "expiry_year" => "31"
+ ];
+}
\ No newline at end of file
diff --git a/tests/Unit/Service/CheckoutTest.php b/tests/Unit/Checkout/CheckoutTest.php
similarity index 77%
rename from tests/Unit/Service/CheckoutTest.php
rename to tests/Unit/Checkout/CheckoutTest.php
index f8680ac..1f2aac7 100644
--- a/tests/Unit/Service/CheckoutTest.php
+++ b/tests/Unit/Checkout/CheckoutTest.php
@@ -1,6 +1,6 @@
'FLW_TEST|' . random_int( 10, 2000) . '|' . uniqid('aMx') ],
+ [
+ "tx_ref" => 'FLW_TEST|' . random_int(10, 2000) . '|' . uniqid('aMx')
+ ],
new ModalEventHandler(),
ForkConfig::setUp(
- $_ENV['SECRET_KEY'],
- $_ENV['PUBLIC_KEY'],
- $_ENV['ENCRYPTION_KEY'],
- $_ENV['ENV']
+ $_ENV['SECRET_KEY'] ?? \getenv('SECRET_KEY'),
+ $_ENV['PUBLIC_KEY'] ?? \getenv('PUBLIC_KEY'),
+ $_ENV['ENCRYPTION_KEY'] ?? \getenv('ENCRYPTION_KEY'),
+ $_ENV['ENV'] ?? \getenv('ENV')
),
[
'amount' => 3000,
@@ -100,10 +116,10 @@ public function checkoutProvider() {
[ "tx_ref" => 'FLW_TEST|' . random_int( 10, 2000) . '|' . uniqid('mAx') ],
new ModalEventHandler(),
ForkConfig::setUp(
- $_ENV['SECRET_KEY'],
- $_ENV['PUBLIC_KEY'],
- $_ENV['ENCRYPTION_KEY'],
- $_ENV['ENV']
+ $_ENV['SECRET_KEY'] ?? \getenv('SECRET_KEY'),
+ $_ENV['PUBLIC_KEY'] ?? \getenv('PUBLIC_KEY'),
+ $_ENV['ENCRYPTION_KEY'] ?? \getenv('ENCRYPTION_KEY'),
+ $_ENV['ENV'] ?? \getenv('ENV')
),
[
'amount' => 1500,
diff --git a/tests/Unit/Service/CardTest.php b/tests/Unit/Service/CardTest.php
index 93c9b5a..ed77e5b 100644
--- a/tests/Unit/Service/CardTest.php
+++ b/tests/Unit/Service/CardTest.php
@@ -8,6 +8,7 @@
use PHPUnit\Framework\TestCase;
use Flutterwave\Util\Currency;
use Flutterwave\Test\Resources\Setup\Config;
+use Test_Cards;
class CardTest extends TestCase
{
@@ -32,12 +33,7 @@ public function testAuthModeReturnPin()
],
"preauthorize" => false,
"payment_plan" => null,
- "card_details" => [
- "card_number" => "5531886652142950",
- "cvv" => "564",
- "expiry_month" => "09",
- "expiry_year" => "32"
- ]
+ "card_details" => Test_Cards::MSTR_CARD_PIN_TWO
],
];
@@ -47,6 +43,7 @@ public function testAuthModeReturnPin()
"email" => "ol868gjdfjua@gmail.com",
"phone" => "+2349067985861"
]);
+
$data['customer'] = $customerObj;
$payload = $cardpayment->payload->create($data);
$result = $cardpayment->initiate($payload);
@@ -93,12 +90,7 @@ public function testAuthModeReturnRedirect()
],
"preauthorize" => false,
"payment_plan" => null,
- "card_details" => [
- "card_number" => "5531886652142950",
- "cvv" => "564",
- "expiry_month" => "09",
- "expiry_year" => "32"
- ]
+ "card_details" => Test_Cards::MSTR_CARD_PIN_ONE
],
];
@@ -155,8 +147,42 @@ public function testAuthModeReturnRedirect()
// $this->assertSame(AuthMode::AVS, $result['mode']);
// }
+ public function testPreuthCard()
+ {
+ $data = [
+ "amount" => 2000,
+ "currency" => Currency::NGN,
+ "tx_ref" => "TEST-".uniqid().time(),
+ "redirectUrl" => "https://www.example.com",
+ "additionalData" => [
+ "subaccounts" => [
+ ["id" => "RSA_345983858845935893"]
+ ],
+ "meta" => [
+ "unique_id" => uniqid().uniqid()
+ ],
+ "preauthorize" => false,
+ "payment_plan" => null,
+ "card_details" => Test_Cards::PREATH
+ ],
+ ];
+
+ $cardpayment = Flutterwave::create("card");
+ $customerObj = $cardpayment->customer->create([
+ "full_name" => "Olaobaju Abraham",
+ "email" => "ol868gjdfjua@gmail.com",
+ "phone" => "+2349062985861"
+ ]);
+ $data['customer'] = $customerObj;
+ $payload = $cardpayment->payload->create($data);
+ $result = $cardpayment->initiate($payload);
+
+ $this->assertTrue(!empty($result['url']));
+ }
+
public function testAuthModelReturnNoauth()
{
$this->assertTrue(true);
}
+
}
\ No newline at end of file
diff --git a/tests/Unit/Service/MomoTest.php b/tests/Unit/Service/MomoTest.php
index 0afd9ab..d57137b 100644
--- a/tests/Unit/Service/MomoTest.php
+++ b/tests/Unit/Service/MomoTest.php
@@ -66,6 +66,8 @@ public function testInitiateTanzaniaRedirect(){
$payload = $momopayment->payload->create($data);
$result = $momopayment->initiate($payload);
$this->assertSame('pending',$result['data_to_save']['status']);
+
+ return $data['tx_ref'];
}
public function testAuthModeGhanaRedirect(){
diff --git a/tests/Unit/Service/TransactionTest.php b/tests/Unit/Service/TransactionTest.php
index f8e8ebe..f6ba683 100644
--- a/tests/Unit/Service/TransactionTest.php
+++ b/tests/Unit/Service/TransactionTest.php
@@ -2,9 +2,65 @@
namespace Unit\Service;
+use Flutterwave\Service\Transactions;
use PHPUnit\Framework\TestCase;
class TransactionTest extends TestCase
{
+ public Transactions $service;
+ protected function setUp(): void
+ {
+ $this->service = new Transactions();
+ }
+
+ /**
+ * @depends Unit\Service\MomoTest::testInitiateTanzaniaRedirect
+ */
+ public function testVerifyingTransaction(string $tx_ref)
+ {
+ $result = $this->service->verifyWithTxref($tx_ref);
+ $data = $result->data;
+ $this->assertSame($data->customer->email, "developers@flutterwavego.com");
+ return [ "id" => $data->id, "amount" => $data->amount, "currency" => $data->currency ];
+ }
+
+ /**
+ * @depends testVerifyingTransaction
+ */
+ public function testVerifyingTransactionWithId(array $data)
+ {
+ $tx_id = $data['id'];
+
+ $result = $this->service->verify($tx_id);
+ $data = $result->data;
+ $this->assertSame($data->customer->email, "developers@flutterwavego.com");
+ }
+
+ /**
+ * @depends testVerifyingTransaction
+ */
+ public function testResendingFailedHooks( array $data )
+ {
+ sleep(6);
+ $tx_id = $data['id'];
+ $result = $this->service->resendFailedHooks($tx_id);
+ $this->assertTrue( $result->status === "success" && $result->data === "hook sent");
+ }
+
+ /**
+ * @depends testVerifyingTransaction
+ */
+ public function testRetrievingTimeline( array $data )
+ {
+ $tx_id = $data['id'];
+ $result = $this->service->retrieveTimeline($tx_id);
+ $this->assertTrue( $result->status === "success" && $result->message === "Transaction events fetched");
+ }
+
+ // public function testValidateCharge( string $flw_ref )
+ // {
+ // $result = $this->service->validate("3310", $flw_ref);
+ // dd($result);
+ // }
}
\ No newline at end of file
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index a0eed40..de73edc 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -1,4 +1,5 @@