From 82b423442f18956f03ee6e507a9897452775fcd9 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 6 Jul 2021 20:02:47 +1000 Subject: [PATCH] Token Billing with PayFast. --- app/PaymentDrivers/PayFast/CreditCard.php | 8 +- app/PaymentDrivers/PayFast/Token.php | 178 ++++++++++++++++++++ app/PaymentDrivers/PayFastPaymentDriver.php | 5 +- tests/Unit/CentConversionTest.php | 67 ++++++++ 4 files changed, 252 insertions(+), 6 deletions(-) create mode 100644 app/PaymentDrivers/PayFast/Token.php create mode 100644 tests/Unit/CentConversionTest.php diff --git a/app/PaymentDrivers/PayFast/CreditCard.php b/app/PaymentDrivers/PayFast/CreditCard.php index fd99322a84fd..ea5caebb56de 100644 --- a/app/PaymentDrivers/PayFast/CreditCard.php +++ b/app/PaymentDrivers/PayFast/CreditCard.php @@ -15,14 +15,16 @@ namespace App\PaymentDrivers\PayFast; use App\Exceptions\PaymentFailed; use App\Jobs\Mail\PaymentFailureMailer; use App\Jobs\Util\SystemLogger; +use App\Models\ClientGatewayToken; use App\Models\GatewayType; use App\Models\Payment; +use App\Models\PaymentHash; use App\Models\PaymentType; use App\Models\SystemLog; use App\PaymentDrivers\PayFastPaymentDriver; -use Illuminate\Support\Str; -use Illuminate\Support\Facades\Cache; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Cache; +use Illuminate\Support\Str; class CreditCard { @@ -159,8 +161,6 @@ class CreditCard } - - public function paymentView($data) { diff --git a/app/PaymentDrivers/PayFast/Token.php b/app/PaymentDrivers/PayFast/Token.php new file mode 100644 index 000000000000..05daa204d2ff --- /dev/null +++ b/app/PaymentDrivers/PayFast/Token.php @@ -0,0 +1,178 @@ +payfast = $payfast; + } + + // Attributes + // merchant-id + // integer, 8 char | REQUIRED + // Header, the Merchant ID as given by the PayFast system. + // version + // string | REQUIRED + // Header, the PayFast API version (i.e. v1). + // timestamp + // ISO-8601 date and time | REQUIRED + // Header, the current timestamp (YYYY-MM-DDTHH:MM:SS[+HH:MM]). + // signature + // string | REQUIRED + // Header, MD5 hash of the alphabetised submitted header and body variables, as well as the passphrase. Characters must be in lower case. + // amount + // integer | REQUIRED + // Body, the amount which the buyer must pay, in cents (ZAR), no decimals. + // item_name + // string, 100 char | REQUIRED + // Body, the name of the item being charged for. + // item_description + // string, 255 char | OPTIONAL + // Body, the description of the item being charged for. + // itn + // boolean | OPTIONAL + // Body, specify whether an ITN must be sent for the tokenization payment (true by default). + // m_payment_id + // string, 100 char | OPTIONAL + // Body, unique payment ID on the merchant’s system. + // cc_cvv + // numeric | OPTIONAL + + + public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash) + { + + $amount = array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total; + $amount = round(($amount * pow(10, $this->payfast->client->currency()->precision)),0); + + $header =[ + 'merchant-id' => $this->payfast->company_gateway->getConfigField('merchantId'), + 'timestamp' => now()->format('c'), + 'version' => 'v1', + ]; + + $body = [ + 'amount' => $amount, + 'item_name' => 'purchase', + 'item_description' => ctrans('texts.invoices') . ': ' . collect($payment_hash->invoices())->pluck('invoice_number'), + 'm_payment_id' => $payment_hash->hash, + 'passphrase' => $this->payfast->company_gateway->getConfigField('passphrase'), + ]; + + $header['signature'] = $this->payfast->genSig(array_merge($header, $body)); + + $result = $this->send($header, $body, $cgt->token); + + nlog($result); + + // /*Refactor and push to BaseDriver*/ + // if ($data['response'] != null && $data['response']->getMessages()->getResultCode() == 'Ok') { + + // $response = $data['response']; + + // $this->storePayment($payment_hash, $data); + + // $vars = [ + // 'invoices' => $payment_hash->invoices(), + // 'amount' => $amount, + // ]; + + // $logger_message = [ + // 'server_response' => $response->getTransactionResponse()->getTransId(), + // 'data' => $this->formatGatewayResponse($data, $vars), + // ]; + + // SystemLogger::dispatch($logger_message, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::TYPE_AUTHORIZE, $this->authorize->client, $this->authorize->client->company); + + // return true; + // } else { + + // $vars = [ + // 'invoices' => $payment_hash->invoices(), + // 'amount' => $amount, + // ]; + + // $logger_message = [ + // 'server_response' => $response->getTransactionResponse()->getTransId(), + // 'data' => $this->formatGatewayResponse($data, $vars), + // ]; + + // PaymentFailureMailer::dispatch($this->authorize->client, $response->getTransactionResponse()->getTransId(), $this->authorize->client->company, $amount); + + // SystemLogger::dispatch($logger_message, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_AUTHORIZE, $this->authorize->client, $this->authorize->client->company); + + // return false; + // } + } + + private function genSig($data) + { + $fields = []; + + ksort($data); + + foreach($data as $key => $value) + { + if (!empty($data[$key])) { + $fields[$key] = $data[$key]; + } + } + + return md5(http_build_query($fields)); + } + + private function send($headers, $body, $token) + { + $client = new \GuzzleHttp\Client( + [ + 'headers' => $headers, + ]); + + try { + $response = $client->post("https://api.payfast.co.za/subscriptions/{$token}/adhoc",[ + RequestOptions::JSON => ['body' => $body], RequestOptions::ALLOW_REDIRECTS => false + ]); + + return json_decode($response->getBody(),true); + } + catch(\Exception $e) + { + + nlog($e->getMessage()); + + } + } +} + diff --git a/app/PaymentDrivers/PayFastPaymentDriver.php b/app/PaymentDrivers/PayFastPaymentDriver.php index 1ba03887ff2a..b6ec14e1c32d 100644 --- a/app/PaymentDrivers/PayFastPaymentDriver.php +++ b/app/PaymentDrivers/PayFastPaymentDriver.php @@ -17,10 +17,11 @@ use App\Models\Payment; use App\Models\PaymentHash; use App\Models\SystemLog; use App\PaymentDrivers\PayFast\CreditCard; +use App\PaymentDrivers\PayFast\Token; use App\Utils\Traits\MakesHash; -use \PayFastPayment; use Illuminate\Http\Request; use Illuminate\Support\Facades\Cache; +use \PayFastPayment; class PayFastPaymentDriver extends BaseDriver { @@ -120,7 +121,7 @@ class PayFastPaymentDriver extends BaseDriver public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash) { - return $this->payment_method->yourTokenBillingImplmentation(); //this is your custom implementation from here + return (new Token($this))->tokenBilling($cgt, $payment_hash); } // public function generateSignature($data, $passPhrase = null) diff --git a/tests/Unit/CentConversionTest.php b/tests/Unit/CentConversionTest.php new file mode 100644 index 000000000000..4823f6c788a1 --- /dev/null +++ b/tests/Unit/CentConversionTest.php @@ -0,0 +1,67 @@ +assertEquals(1020, $amount); + + $amount = 2; + $amount = round(($amount * pow(10, $precision)),0); + + $this->assertEquals(200, $amount); + + $amount = 2.12; + $amount = round(($amount * pow(10, $precision)),0); + + $this->assertEquals(212, $amount); + } + + + public function testBcMathWay() + { + + $amount = 64.99; + $amount = bcmul($amount, 100); + + $this->assertEquals(6499, $amount); + + $amount = 2; + $amount = bcmul($amount, 100); + + $this->assertEquals(200, $amount); + + $amount = 2.12; + $amount = bcmul($amount, 100); + + $this->assertEquals(212, $amount); + } +}