From fe796c5b8ccac435c554410eda439d8fda4e1f00 Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Mon, 4 May 2020 11:06:48 +0300 Subject: [PATCH 01/23] add post method for tokenV2 --- .../PaymentsV4/Services/HTTPClient.php | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/PayU/PaymentsApi/PaymentsV4/Services/HTTPClient.php b/src/PayU/PaymentsApi/PaymentsV4/Services/HTTPClient.php index be8fde10..2253795a 100644 --- a/src/PayU/PaymentsApi/PaymentsV4/Services/HTTPClient.php +++ b/src/PayU/PaymentsApi/PaymentsV4/Services/HTTPClient.php @@ -100,4 +100,35 @@ public function buildRequestHeaders($merchantCode, $orderDate, $signature) 'Content-Type: application/json;charset=utf-8' ]; } + + /** + * @param $url + * @param array $postParams + * @return string + * @throws ConnectionException + */ + public function postTokenCreationRequest($url, array $postParams) + { + curl_setopt_array( + $this->handler, + array( + CURLOPT_URL => $url, + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => http_build_query($postParams), + CURLOPT_HTTPHEADER => array('Content-Type: application/x-www-form-urlencoded') + ) + ); + + $result = curl_exec($this->handler); + if (curl_errno($this->handler) > 0) { + throw new ConnectionException( + sprintf( + 'Curl error "%s" when accessing url: "%s"', + curl_error($this->handler), + $url + ) + ); + } + return $result; + } } From 1e0b0bb43c02ce143c748fc64e7d06a84c2c8b44 Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Mon, 4 May 2020 13:50:28 +0300 Subject: [PATCH 02/23] add tokenV2 scripts --- .../createTokenForRecurrentPaymentV4.php | 217 ++++++++++++++++++ examplesV4/tokenPayment.php | 201 ++++++++++++++++ 2 files changed, 418 insertions(+) create mode 100644 examplesV4/createTokenForRecurrentPaymentV4.php create mode 100644 examplesV4/tokenPayment.php diff --git a/examplesV4/createTokenForRecurrentPaymentV4.php b/examplesV4/createTokenForRecurrentPaymentV4.php new file mode 100644 index 00000000..6071414b --- /dev/null +++ b/examplesV4/createTokenForRecurrentPaymentV4.php @@ -0,0 +1,217 @@ +withBackRef('http://path/to/your/returnUrlScript') + ->withOrderRef($merchantOrderRef) + //->withOrderRef('MerchantOrderRef') + ->withCurrency('RON') + ->withOrderDate(gmdate('Y-m-d\TH:i:sP')) + ->withOrderTimeout(1000) + ->withPayMethod('CCVISAMC'); + +/** + * Create new product + */ +$product = new Product(); + +/** + * Setup the product params + * + * Full params available in the documentation + */ +$product->withCode('PCODE01') + ->withName('PNAME01') + ->withPrice(100.0) + ->withVAT(24.0) + ->withQuantity(1); + +/** + * Add the product to the order + */ +$order->addProduct($product); + +/** + * Create another product + */ +$product = new Product(); + +/** + * Setup the product params + * + * Full params available in the documentation + */ +$product->withCode('PCODE02') + ->withName('PNAME02') + ->withPrice(200.0) + ->withVAT(24.0) + ->withQuantity(1); + +/** + * Add the second product to the same order + */ +$order->addProduct($product); + +/** + * Create new billing address + */ +$billing = new Billing(); + +/** + * Setup the billing address params + * + * Full params available in the documentation + */ +$billing->withAddressLine1('Address1') + ->withAddressLine2('Address2') + ->withCity('City') + ->withCountryCode('RO') + ->withEmail('john.doe@mail.com') + ->withFirstName('FirstName') + ->withLastName('LastName') + ->withPhoneNumber('40123456789') + ->withIdentityCardNumber('111222'); + +/** + * Create new delivery address + * + * If you want to have the same delivery as billing, skip these two steps + * and pass the Billing $billing object to the request twice + */ +$delivery = new Delivery(); + +/** + * Setup the delivery address params + * + * Full params available in the documentation + */ +$delivery->withAddressLine1('Address1') + ->withAddressLine2('Address2') + ->withCity('City') + ->withCountryCode('RO') + ->withEmail('john.doe@mail.com') + ->withFirstName('FirstName') + ->withLastName('LastName') + ->withPhoneNumber('40123456789'); + +/** + * Create new Card with params: + * + * Credit Card Number + * Credit Card Expiration Month + * Credit Card Expiration Year + * Credit Card CVV (Security Code) + * Credit Card Owner + */ +$card = new Card( + '4111111111111111', + '01', + date("Y", strtotime("+1 year")), + 123, + 'Card Owner Name' +); + +/** + * tokenize card for further token payments + */ +$card->enableTokenCreation(); + +/** + * Create new Request with params: + * + * Config object + * Order object + * Billing object + * Delivery (or Billing object again, if you want to have the delivery address the same as the billing address) + * User object + */ +$request = new Request($cfg, $order, $billing, $delivery, $user, PaymentsV4::API_VERSION_V4); + +/** + * Add the Credit Card to the Request + */ +$request->setCard($card); + +/** + * Create new API Client, passing the Config object as parameter + */ +$client = new Client($cfg); + +/** + * Will throw different Exceptions on errors + */ +try { + /** + * Sends the Request to ALU and returns a Response + * + * See documentation for Response params + */ + $response = $client->pay($request); + + /** + * In case of 3DS enrolled cards, PayU will return the URL_3DS that contains a unique url for each + * transaction. The merchant must redirect the browser to this url to allow user to authenticate. + * After the authentication process ends the user will be redirected to BACK_REF url + * with payment result in a HTTP POST request + */ + if ($response->isThreeDs()) { + header("Location:" . $response->getThreeDsUrl()); + die(); + } + + echo $response->getStatus() . ' ' . $response->getReturnCode() . ' ' . $response->getReturnMessage(); + echo('Token response data: '); + echo $response->getTokenCode() . ' ' . $response->getTokenMessage() . ' Token:' . $response->getTokenHash(); +} catch (ClientException $exception) { + echo $exception->getErrorMessage(); +} diff --git a/examplesV4/tokenPayment.php b/examplesV4/tokenPayment.php new file mode 100644 index 00000000..7dc6ff8b --- /dev/null +++ b/examplesV4/tokenPayment.php @@ -0,0 +1,201 @@ +withBackRef('http://path/to/your/returnUrlScript') + ->withOrderRef($merchantOrderRef) + //->withOrderRef('MerchantOrderRef') + ->withCurrency('RON') + ->withOrderDate(gmdate('Y-m-d\TH:i:sP')) + ->withOrderTimeout(1000) + ->withPayMethod('CCVISAMC'); + +/** + * Create new product + */ +$product = new Product(); + +/** + * Setup the product params + * + * Full params available in the documentation + */ +$product->withCode('PCODE01') + ->withName('PNAME01') + ->withPrice(100.0) + ->withVAT(24.0) + ->withQuantity(1); + +/** + * Add the product to the order + */ +$order->addProduct($product); + +/** + * Create another product + */ +$product = new Product(); + +/** + * Setup the product params + * + * Full params available in the documentation + */ +$product->withCode('PCODE02') + ->withName('PNAME02') + ->withPrice(200.0) + ->withVAT(24.0) + ->withQuantity(1); + +/** + * Add the second product to the same order + */ +$order->addProduct($product); + +/** + * Create new billing address + */ +$billing = new Billing(); + +/** + * Setup the billing address params + * + * Full params available in the documentation + */ +$billing->withAddressLine1('Address1') + ->withAddressLine2('Address2') + ->withCity('City') + ->withCountryCode('RO') + ->withEmail('john.doe@mail.com') + ->withFirstName('FirstName') + ->withLastName('LastName') + ->withPhoneNumber('40123456789') + ->withIdentityCardNumber('111222'); + +/** + * Create new delivery address + * + * If you want to have the same delivery as billing, skip these two steps + * and pass the Billing $billing object to the request twice + */ +$delivery = new Delivery(); + +/** + * Setup the delivery address params + * + * Full params available in the documentation + */ +$delivery->withAddressLine1('Address1') + ->withAddressLine2('Address2') + ->withCity('City') + ->withCountryCode('RO') + ->withEmail('john.doe@mail.com') + ->withFirstName('FirstName') + ->withLastName('LastName') + ->withPhoneNumber('40123456789'); + +/** + * Create new CardToken with params: + * + * Token + */ +$cardToken = new CardToken("9964cc6183134b2b796bcead87aa14ab"); + +/** + * Create new Request with params: + * + * Config object + * Order object + * Billing object + * Delivery (or Billing object again, if you want to have the delivery address the same as the billing address) + * User object + */ +$request = new Request($cfg, $order, $billing, $delivery, $user, PaymentsV4::API_VERSION_V4); + +/** + * Add the Card Token to the Request + */ +$request->setCardToken($cardToken); + +/** + * Create new API Client, passing the Config object as parameter + */ +$client = new Client($cfg); + +/** + * Will throw different Exceptions on errors + */ +try { + /** + * Sends the Request to ALU and returns a Response + * + * See documentation for Response params + */ + + $response = $client->pay($request); + + /** + * In case of 3DS enrolled cards, PayU will return the URL_3DS that contains a unique url for each + * transaction. The merchant must redirect the browser to this url to allow user to authenticate. + * After the authentication process ends the user will be redirected to BACK_REF url + * with payment result in a HTTP POST request + */ + if ($response->isThreeDs()) { + header("Location:" . $response->getThreeDsUrl()); + die(); + } + + echo $response->getReturnMessage() . ' ' . $response->getRefno(); +} catch (ClientException $exception) { + echo $exception->getErrorMessage(); +} From 04ea3e23efb712295d408c2dda9e60949dd2f875 Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Mon, 4 May 2020 13:52:14 +0300 Subject: [PATCH 03/23] remove comments --- examplesV4/createTokenForRecurrentPaymentV4.php | 11 ++--------- examplesV4/tokenPayment.php | 12 ++---------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/examplesV4/createTokenForRecurrentPaymentV4.php b/examplesV4/createTokenForRecurrentPaymentV4.php index 6071414b..093b2f10 100644 --- a/examplesV4/createTokenForRecurrentPaymentV4.php +++ b/examplesV4/createTokenForRecurrentPaymentV4.php @@ -24,8 +24,7 @@ * Secret Key - Your PayU Secret Key * Platform - RO | RU | UA | TR | HU */ -//todo modify merchantCode back to MERCHANT_CODE -$cfg = new MerchantConfig('PAYU_2', 'SECRET_KEY', 'RO'); +$cfg = new MerchantConfig('MERCHANT_CODE', 'SECRET_KEY', 'RO'); /** * Create user with params: * @@ -46,15 +45,9 @@ * * Full params available in the documentation */ -/** - * todo remove $merchantOrderRef when pushing to master - * also date format has been modified - */ -$merchantOrderRef = strval(rand(1000, 9999)); $order->withBackRef('http://path/to/your/returnUrlScript') - ->withOrderRef($merchantOrderRef) - //->withOrderRef('MerchantOrderRef') + ->withOrderRef('MerchantOrderRef') ->withCurrency('RON') ->withOrderDate(gmdate('Y-m-d\TH:i:sP')) ->withOrderTimeout(1000) diff --git a/examplesV4/tokenPayment.php b/examplesV4/tokenPayment.php index 7dc6ff8b..13ffb803 100644 --- a/examplesV4/tokenPayment.php +++ b/examplesV4/tokenPayment.php @@ -24,8 +24,7 @@ * Secret Key - Your PayU Secret Key * Platform - RO | RU | UA | TR | HU */ -//todo modify merchantCode back to MERCHANT_CODE -$cfg = new MerchantConfig('PAYU_2', 'SECRET_KEY', 'RO'); +$cfg = new MerchantConfig('MERCHANT_CODE', 'SECRET_KEY', 'RO'); /** * Create user with params: @@ -46,15 +45,8 @@ * * Full params available in the documentation */ -/** - * todo remove $merchantOrderRef when pushing to master - * also date format has been modified - */ - -$merchantOrderRef = strval(rand(1000, 9999)); $order->withBackRef('http://path/to/your/returnUrlScript') - ->withOrderRef($merchantOrderRef) - //->withOrderRef('MerchantOrderRef') + ->withOrderRef('MerchantOrderRef') ->withCurrency('RON') ->withOrderDate(gmdate('Y-m-d\TH:i:sP')) ->withOrderTimeout(1000) From fb2c98cec589a3fbd4a9bcdd6fc88eafc41543fd Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Mon, 4 May 2020 13:55:13 +0300 Subject: [PATCH 04/23] add GenerateTokenSignature function --- .../PaymentsV4/Services/HashService.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/PayU/PaymentsApi/PaymentsV4/Services/HashService.php b/src/PayU/PaymentsApi/PaymentsV4/Services/HashService.php index 20c66104..df3b25c9 100644 --- a/src/PayU/PaymentsApi/PaymentsV4/Services/HashService.php +++ b/src/PayU/PaymentsApi/PaymentsV4/Services/HashService.php @@ -26,4 +26,22 @@ public function generateSignature($merchantConfig, $orderDate, $jsonRequest) return hash_hmac("sha256", $stringToBeHashed, $merchantConfig->getSecretKey()); } + + /** + * @param array $requestArray + * @param string $secretKey + * @return string + */ + public function generateTokenSignature($requestArray, $secretKey) + { + ksort($requestArray); + $stringToBeHashed = ''; + foreach ($requestArray as $key => $val) { + if ($key !== 'timestamp') + $stringToBeHashed = $stringToBeHashed . $val; + } + $stringToBeHashed = $stringToBeHashed . $requestArray['timestamp']; + + return hash_hmac("sha256", $stringToBeHashed, $secretKey); + } } From 592b92a14821d51d44327d508a85023ed87b1d63 Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Mon, 4 May 2020 13:55:36 +0300 Subject: [PATCH 05/23] add post method for tokenV2 --- .../PaymentsV4/Services/HTTPClient.php | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/PayU/PaymentsApi/PaymentsV4/Services/HTTPClient.php b/src/PayU/PaymentsApi/PaymentsV4/Services/HTTPClient.php index 2253795a..44c010f8 100644 --- a/src/PayU/PaymentsApi/PaymentsV4/Services/HTTPClient.php +++ b/src/PayU/PaymentsApi/PaymentsV4/Services/HTTPClient.php @@ -102,19 +102,26 @@ public function buildRequestHeaders($merchantCode, $orderDate, $signature) } /** - * @param $url - * @param array $postParams + * @param string $url + * @param array $requestBody + * @param string $secretKey * @return string * @throws ConnectionException */ - public function postTokenCreationRequest($url, array $postParams) - { + public function postTokenCreationRequest( + $url, + $requestBody, + $secretKey + ) { + $signature = $this->hashService->generateTokenSignature($requestBody, $secretKey); + $requestBody['signature'] = $signature; + curl_setopt_array( $this->handler, array( CURLOPT_URL => $url, CURLOPT_POST => true, - CURLOPT_POSTFIELDS => http_build_query($postParams), + CURLOPT_POSTFIELDS => http_build_query($requestBody), CURLOPT_HTTPHEADER => array('Content-Type: application/x-www-form-urlencoded') ) ); From 2086ccb3d371e3b4556c84c22b889625109b7c12 Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Mon, 4 May 2020 13:56:35 +0300 Subject: [PATCH 06/23] add buildTokenRequestBody method --- .../PaymentsV4/Services/RequestBuilder.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/PayU/PaymentsApi/PaymentsV4/Services/RequestBuilder.php b/src/PayU/PaymentsApi/PaymentsV4/Services/RequestBuilder.php index 222cb39d..2824a011 100644 --- a/src/PayU/PaymentsApi/PaymentsV4/Services/RequestBuilder.php +++ b/src/PayU/PaymentsApi/PaymentsV4/Services/RequestBuilder.php @@ -3,6 +3,7 @@ namespace PayU\PaymentsApi\PaymentsV4\Services; +use DateTime; use PayU\Alu\Product; use PayU\Alu\Request; use PayU\PaymentsApi\PaymentsV4\Entities\ApplePayToken; @@ -288,4 +289,21 @@ private function getFlightSegmentsArray($request) return $flightSegmentsArray; } + + /** + * @param string $merchantCode + * @param int $payuPaymentReference + * @return array + * @throws \Exception + */ + public function buildTokenRequestBody($merchantCode, $payuPaymentReference) + { + $date = new DateTime(); + + return [ + 'merchant' => $merchantCode, + 'refNo' => $payuPaymentReference, + 'timestamp' => strval($date->getTimestamp()) + ]; + } } From f528e5e7bc9298c7d7abd489bf37d2d07cdea64f Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Mon, 4 May 2020 13:57:13 +0300 Subject: [PATCH 07/23] add parseTokenJsonResponse method --- .../PaymentsV4/Services/ResponseParser.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/PayU/PaymentsApi/PaymentsV4/Services/ResponseParser.php b/src/PayU/PaymentsApi/PaymentsV4/Services/ResponseParser.php index a4291dc7..86be6be3 100644 --- a/src/PayU/PaymentsApi/PaymentsV4/Services/ResponseParser.php +++ b/src/PayU/PaymentsApi/PaymentsV4/Services/ResponseParser.php @@ -42,4 +42,20 @@ private function createArray($jsonResponse) { return $this->aluResponseMapper->processResponse($jsonResponse); } + + /** + * @param string $jsonResponse + * @return AuthorizationResponse + * @throws AuthorizationResponseException + */ + public function parseTokenJsonResponse($jsonResponse) + { + $responseArray = json_decode($jsonResponse, true); + + if (is_array($responseArray)) { + return new AuthorizationResponse($responseArray); + } + + throw new AuthorizationResponseException('Could not decode Json response'); + } } From f1067fb12ec32c957dfb6a7c5901e358558b224b Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Mon, 4 May 2020 13:57:54 +0300 Subject: [PATCH 08/23] add buildTokenResponse method --- .../PaymentsV4/Services/ResponseBuilder.php | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/PayU/PaymentsApi/PaymentsV4/Services/ResponseBuilder.php b/src/PayU/PaymentsApi/PaymentsV4/Services/ResponseBuilder.php index b9e51d02..c5c04b47 100644 --- a/src/PayU/PaymentsApi/PaymentsV4/Services/ResponseBuilder.php +++ b/src/PayU/PaymentsApi/PaymentsV4/Services/ResponseBuilder.php @@ -98,4 +98,24 @@ private function getResponseWireAccount($account) return $responseWireAccount; } + + /** + * @param AuthorizationResponse $authorizationResponse + * @param Response $response + * @return Response + */ + public function buildTokenResponse( + AuthorizationResponse $authorizationResponse, + Response $response + ) { + $responseArray = $authorizationResponse->getResponse(); + + if ($responseArray["meta"]["status"]["code"] === 0) { + $response->setTokenHash($responseArray["response"]["token"]); + } + $response->setTokenCode($responseArray["meta"]["status"]["code"]); + $response->setTokenMessage($responseArray["meta"]["status"]["message"]); + + return $response; + } } From db185a974e3071e4477baab731eabff3e3312010 Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Mon, 4 May 2020 13:58:28 +0300 Subject: [PATCH 09/23] add tokenCode si tokenMessage params to Alu/Response --- src/PayU/Alu/Response.php | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/PayU/Alu/Response.php b/src/PayU/Alu/Response.php index 5413cdf8..bf42d3d7 100644 --- a/src/PayU/Alu/Response.php +++ b/src/PayU/Alu/Response.php @@ -119,6 +119,44 @@ class Response */ private $type; + /** @var int */ + private $tokenCode; + + /** @var string */ + private $tokenMessage; + + /** + * @return int + */ + public function getTokenCode() + { + return $this->tokenCode; + } + + /** + * @param int $tokenCode + */ + public function setTokenCode($tokenCode) + { + $this->tokenCode = $tokenCode; + } + + /** + * @return string + */ + public function getTokenMessage() + { + return $this->tokenMessage; + } + + /** + * @param string $tokenMessage + */ + public function setTokenMessage($tokenMessage) + { + $this->tokenMessage = $tokenMessage; + } + /** * @param string $type */ From 0074ea1f42235205ac34ea8dfe2b0a1461496f58 Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Mon, 4 May 2020 13:59:16 +0300 Subject: [PATCH 10/23] add tokenV2 flow --- .../PaymentsApi/PaymentsV4/PaymentsV4.php | 85 ++++++++++++++++--- 1 file changed, 74 insertions(+), 11 deletions(-) diff --git a/src/PayU/PaymentsApi/PaymentsV4/PaymentsV4.php b/src/PayU/PaymentsApi/PaymentsV4/PaymentsV4.php index 03522ae8..b271e93c 100644 --- a/src/PayU/PaymentsApi/PaymentsV4/PaymentsV4.php +++ b/src/PayU/PaymentsApi/PaymentsV4/PaymentsV4.php @@ -3,6 +3,7 @@ namespace PayU\PaymentsApi\PaymentsV4; use PayU\Alu\Request; +use PayU\Alu\Response; use PayU\PaymentsApi\Exceptions\AuthorizationException; use PayU\PaymentsApi\Interfaces\AuthorizationPaymentsApiClient; use PayU\PaymentsApi\PaymentsV4\Exceptions\ConnectionException; @@ -16,6 +17,8 @@ class PaymentsV4 implements AuthorizationPaymentsApiClient { const PAYMENTS_API_AUTHORIZE_PATH = '/api/v4/payments/authorize'; + const BASE_CREATE_TOKEN_PATH = '/order/token/v2/merchantToken'; + const API_VERSION_V4 = 'v4'; /** @@ -38,6 +41,15 @@ class PaymentsV4 implements AuthorizationPaymentsApiClient */ private $responseBuilder; + /** @var array */ + private $platformHostname = [ + 'ro' => 'https://secure.payu.ro', + 'ru' => 'https://secure.payu.ru', + 'ua' => 'https://secure.payu.ua', + 'hu' => 'https://secure.payu.hu', + 'tr' => 'https://secure.payu.com.tr', + ]; + /** * PaymentsV4 constructor. * @throws AuthorizationException @@ -57,19 +69,25 @@ public function __construct() */ private function getPaymentsUrl($country) { - $platformHostname = [ - 'ro' => 'https://secure.payu.ro', - 'ru' => 'https://secure.payu.ru', - 'ua' => 'https://secure.payu.ua', - 'hu' => 'https://secure.payu.hu', - 'tr' => 'https://secure.payu.com.tr', - ]; - - if (!isset($platformHostname[$country])) { + if (!isset($this->platformHostname[$country])) { throw new AuthorizationException('Invalid platform'); } - return $platformHostname[$country] . self::PAYMENTS_API_AUTHORIZE_PATH; + return $this->platformHostname[$country] . self::PAYMENTS_API_AUTHORIZE_PATH; + } + + /** + * @param string $country + * @return string + * @throws AuthorizationException + */ + private function getTokenUrl($country) + { + if (!isset($this->platformHostname[$country])) { + throw new AuthorizationException('Invalid platform'); + } + + return $this->platformHostname[$country] . self::BASE_CREATE_TOKEN_PATH; } /** @@ -100,6 +118,51 @@ public function authorize(Request $request) throw new AuthorizationException($e->getMessage(), $e->getCode(), $e); } - return $this->responseBuilder->buildResponse($authorizationResponse); + $response = $this->responseBuilder->buildResponse($authorizationResponse); + + if (($response->getCode() === 200 || $response->getCode() === 202) + && $request->getCard() !== null + && $request->getCard()->isEnableTokenCreation() + ) { + return $this->makeTokenCreationRequest($request, $response); + } + + return $response; + } + + /** + * @param Request $request + * @param Response $response + * @return Response + * @throws AuthorizationException + */ + private function makeTokenCreationRequest(Request $request, Response $response) + { + try { + $tokenRequest = $this->requestBuilder->buildTokenRequestBody( + $request->getMerchantConfig()->getMerchantCode(), + $response->getRefno() + ); + } catch (\Exception $e) { + throw new AuthorizationException($e->getMessage(), $e->getCode(), $e); + } + + try { + $responseJson = $this->httpClient->postTokenCreationRequest( + $this->getTokenUrl($request->getMerchantConfig()->getPlatform()), + $tokenRequest, + $request->getMerchantConfig()->getSecretKey() + ); + } catch (ConnectionException $e) { + throw new AuthorizationException($e->getMessage(), $e->getCode(), $e); + } + + try { + $authorizationResponse = $this->responseParser->parseTokenJsonResponse($responseJson); + } catch (AuthorizationResponseException $e) { + throw new AuthorizationException($e->getMessage(), $e->getCode(), $e); + } + + return $this->responseBuilder->buildTokenResponse($authorizationResponse, $response); } } From 10aa1e47cf3257cb70c33c82494d754a21364ac4 Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Mon, 4 May 2020 14:00:37 +0300 Subject: [PATCH 11/23] reformat code --- src/PayU/PaymentsApi/PaymentsV4/Services/HashService.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PayU/PaymentsApi/PaymentsV4/Services/HashService.php b/src/PayU/PaymentsApi/PaymentsV4/Services/HashService.php index df3b25c9..8b791c5b 100644 --- a/src/PayU/PaymentsApi/PaymentsV4/Services/HashService.php +++ b/src/PayU/PaymentsApi/PaymentsV4/Services/HashService.php @@ -37,8 +37,9 @@ public function generateTokenSignature($requestArray, $secretKey) ksort($requestArray); $stringToBeHashed = ''; foreach ($requestArray as $key => $val) { - if ($key !== 'timestamp') + if ($key !== 'timestamp') { $stringToBeHashed = $stringToBeHashed . $val; + } } $stringToBeHashed = $stringToBeHashed . $requestArray['timestamp']; From 71644c2de715e12af9d63f43e01b35bef66e0536 Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Mon, 4 May 2020 14:18:37 +0300 Subject: [PATCH 12/23] add example script for token creation and payment --- examplesV4/tokenCreationAndPaymentExample.php | 222 ++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 examplesV4/tokenCreationAndPaymentExample.php diff --git a/examplesV4/tokenCreationAndPaymentExample.php b/examplesV4/tokenCreationAndPaymentExample.php new file mode 100644 index 00000000..ca75dc12 --- /dev/null +++ b/examplesV4/tokenCreationAndPaymentExample.php @@ -0,0 +1,222 @@ +withBackRef('http://path/to/your/returnUrlScript') + ->withOrderRef('MerchantOrderRef') + ->withCurrency('RON') + ->withOrderDate(gmdate('Y-m-d\TH:i:sP')) + ->withOrderTimeout(1000) + ->withPayMethod('CCVISAMC'); + +/** + * Create new product + */ +$product = new Product(); + +/** + * Setup the product params + * + * Full params available in the documentation + */ +$product->withCode('PCODE01') + ->withName('PNAME01') + ->withPrice(100.0) + ->withVAT(24.0) + ->withQuantity(1); + +/** + * Add the product to the order + */ +$order->addProduct($product); + +/** + * Create another product + */ +$product = new Product(); + +/** + * Setup the product params + * + * Full params available in the documentation + */ +$product->withCode('PCODE02') + ->withName('PNAME02') + ->withPrice(200.0) + ->withVAT(24.0) + ->withQuantity(1); + +/** + * Add the second product to the same order + */ +$order->addProduct($product); + +/** + * Create new billing address + */ +$billing = new Billing(); + +/** + * Setup the billing address params + * + * Full params available in the documentation + */ +$billing->withAddressLine1('Address1') + ->withAddressLine2('Address2') + ->withCity('City') + ->withCountryCode('RO') + ->withEmail('john.doe@mail.com') + ->withFirstName('FirstName') + ->withLastName('LastName') + ->withPhoneNumber('40123456789') + ->withIdentityCardNumber('111222'); + +/** + * Create new delivery address + * + * If you want to have the same delivery as billing, skip these two steps + * and pass the Billing $billing object to the request twice + */ +$delivery = new Delivery(); + +/** + * Setup the delivery address params + * + * Full params available in the documentation + */ +$delivery->withAddressLine1('Address1') + ->withAddressLine2('Address2') + ->withCity('City') + ->withCountryCode('RO') + ->withEmail('john.doe@mail.com') + ->withFirstName('FirstName') + ->withLastName('LastName') + ->withPhoneNumber('40123456789'); + +/** + * Create new Card with params: + * + * Credit Card Number + * Credit Card Expiration Month + * Credit Card Expiration Year + * Credit Card CVV (Security Code) + * Credit Card Owner + */ +$card = new Card( + '4111111111111111', + '01', + date("Y", strtotime("+1 year")), + 123, + 'Card Owner Name' +); + +/** + * tokenize card for further token payments + */ +$card->enableTokenCreation(); + +/** + * Create new Request with params: + * + * Config object + * Order object + * Billing object + * Delivery (or Billing object again, if you want to have the delivery address the same as the billing address) + * User object + */ +$request = new Request($cfg, $order, $billing, $delivery, $user, PaymentsV4::API_VERSION_V4); +$requestWithToken = new Request($cfg, $order, $billing, $delivery, $user, PaymentsV4::API_VERSION_V4); +$requestWithToken->getOrder()->withOrderRef('TokenOrderRef'); +/** + * Add the Credit Card to the Request + */ +$request->setCard($card); + +/** + * Create new API Client, passing the Config object as parameter + */ +$client = new Client($cfg); + +/** + * Will throw different Exceptions on errors + */ +try { + /** + * Sends the Request to ALU and returns a Response + * + * See documentation for Response params + */ + $response = $client->pay($request); + + /** + * In case of 3DS enrolled cards, PayU will return the URL_3DS that contains a unique url for each + * transaction. The merchant must redirect the browser to this url to allow user to authenticate. + * After the authentication process ends the user will be redirected to BACK_REF url + * with payment result in a HTTP POST request + */ + if ($response->isThreeDs()) { + header("Location:" . $response->getThreeDsUrl()); + die(); + } + + echo $response->getStatus() . ' ' . $response->getReturnCode() . ' ' . $response->getReturnMessage() . "\n"; + echo('Token response data: '); + echo $response->getTokenCode() . ' ' . $response->getTokenMessage() . ' Token:' . $response->getTokenHash() . "\n"; + + if ($response->getTokenCode() == 0 && $response->getTokenHash() !== ''){ + $cardToken = new CardToken($response->getTokenHash()); + $requestWithToken->setCardToken($cardToken); + + $response = $client->pay($requestWithToken); + + echo $response->getStatus() . ' ' . $response->getReturnCode() . ' ' . $response->getReturnMessage() . "\n"; + } + +} catch (ClientException $exception) { + echo $exception->getErrorMessage(); +} From ed4e536635af8178803e3c04bf304f2acbf1a0a4 Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Mon, 4 May 2020 14:34:44 +0300 Subject: [PATCH 13/23] add test for token signature generation --- .../PaymentsV4/Services/HashServiceTest.php | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/PayU/PaymentsApi/PaymentsV4/Services/HashServiceTest.php b/tests/PayU/PaymentsApi/PaymentsV4/Services/HashServiceTest.php index 2c2ea8db..0f9122af 100644 --- a/tests/PayU/PaymentsApi/PaymentsV4/Services/HashServiceTest.php +++ b/tests/PayU/PaymentsApi/PaymentsV4/Services/HashServiceTest.php @@ -80,6 +80,22 @@ public function generateSignatureProvider() ); } + public function generateTokenSignatureProvider() + { + return [ + [ + [ + 'merchant' => 'CC921', + 'refNo' => 12039391, + 'timestamp' => 1428045257 + ], + 'secretKey' => 'SECRET_KEY', + 'expectedHash' => 'c211b9fc82bc10fb9d104ba3c756bbb0e61eddb3bd26303b9e4109f271c7059e' + ] + + ]; + } + /** * @dataProvider generateSignatureProvider */ @@ -101,4 +117,16 @@ public function testGenerateSignature($orderDate, $jsonRequest, $expectedHash) $this->hashService->generateSignature($this->merchantConfigMock, $orderDate, $jsonRequest) ); } + + /** + * @dataProvider generateTokenSignatureProvider + */ + public function testGenerateTokenSignature($requestArray, $secretKey, $expectedHash) + { + // Then + $this->assertEquals( + $expectedHash, + $this->hashService->generateTokenSignature($requestArray, $secretKey) + ); + } } From dd16b0a98e4b2a1d05335b7232e132c9bb837dd3 Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Mon, 4 May 2020 15:09:35 +0300 Subject: [PATCH 14/23] test buildTokenResponse method --- .../Services/ResponseBuilderTest.php | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 tests/PayU/PaymentsApi/PaymentsV4/Services/ResponseBuilderTest.php diff --git a/tests/PayU/PaymentsApi/PaymentsV4/Services/ResponseBuilderTest.php b/tests/PayU/PaymentsApi/PaymentsV4/Services/ResponseBuilderTest.php new file mode 100644 index 00000000..da9f2413 --- /dev/null +++ b/tests/PayU/PaymentsApi/PaymentsV4/Services/ResponseBuilderTest.php @@ -0,0 +1,94 @@ +responseBuilder = new ResponseBuilder(); + } + + private function createSuccessResponseArray() + { + return [ + 'meta' => [ + 'status' => [ + "code" => 0, + "message" => "success" + ], + 'response' => [ + "httpCode" => 200, + "httpMessage" => "200 OK" + ], + 'version' => 'v2' + ], + 'response' => [ + "token" => "b7e5d8649c9e2e75726b59c56c29e91d", + "cardUniqueIdentifier" => "e9fc5107db302fa8373efbedf55a1614b5a3125ee59fe274e7dc802930d68f6d" + ] + ]; + } + + private function createErrorResponseArray() + { + return [ + 'meta' => [ + 'status' => [ + "code" => 400, + "message" => "No order with reference number: 120393911" + ], + 'response' => [ + "httpCode" => 400, + "httpMessage" => "400 Bad Request" + ], + 'version' => 'v2' + ], + 'error' => [ + "code" => 400, + "message" => "No order with reference number: 120393911" + ] + ]; + } + + public function testBuildTokenResponseWithSuccessResponse() + { + // Given + $authorizationResponse = new AuthorizationResponse($this->createSuccessResponseArray()); + $expectedResponse = new Response(); + $expectedResponse->setTokenCode(0); + $expectedResponse->setTokenMessage('success'); + $expectedResponse->setTokenHash('b7e5d8649c9e2e75726b59c56c29e91d'); + + // Then + $this->assertEquals( + $expectedResponse, + $this->responseBuilder->buildTokenResponse($authorizationResponse, new Response()) + ); + } + + public function testBuildTokenResponseWithErrorResponse() + { + // Given + $authorizationResponse = new AuthorizationResponse($this->createErrorResponseArray()); + $expectedResponse = new Response(); + $expectedResponse->setTokenCode(400); + $expectedResponse->setTokenMessage('No order with reference number: 120393911'); + + // Then + $this->assertEquals( + $expectedResponse, + $this->responseBuilder->buildTokenResponse($authorizationResponse, new Response()) + ); + } +} From 2fd27ceb81685e2c415e3fda74a4763b113ad070 Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Mon, 4 May 2020 15:11:46 +0300 Subject: [PATCH 15/23] remove Examples/basicExampleV4.php --- examples/basicExampleV4.php | 213 ------------------------------------ 1 file changed, 213 deletions(-) delete mode 100644 examples/basicExampleV4.php diff --git a/examples/basicExampleV4.php b/examples/basicExampleV4.php deleted file mode 100644 index 388a3c52..00000000 --- a/examples/basicExampleV4.php +++ /dev/null @@ -1,213 +0,0 @@ -withBackRef('http://path/to/your/returnUrlScript') - ->withOrderRef($merchantOrderRef) - //->withOrderRef('MerchantOrderRef') - ->withCurrency('RON') - ->withOrderDate(gmdate('Y-m-d\TH:i:sP')) - ->withOrderTimeout(1000) - ->withPayMethod('CCVISAMC'); - -/** - * Create new product - */ -$product = new Product(); - -/** - * Setup the product params - * - * Full params available in the documentation - */ -$product->withCode('PCODE01') - ->withName('PNAME01') - ->withPrice(100.0) - ->withVAT(24.0) - ->withQuantity(1); - -/** - * Add the product to the order - */ -$order->addProduct($product); - -/** - * Create another product - */ -$product = new Product(); - -/** - * Setup the product params - * - * Full params available in the documentation - */ -$product->withCode('PCODE02') - ->withName('PNAME02') - ->withPrice(200.0) - ->withVAT(24.0) - ->withQuantity(1); - -/** - * Add the second product to the same order - */ -$order->addProduct($product); - -/** - * Create new billing address - */ -$billing = new Billing(); - -/** - * Setup the billing address params - * - * Full params available in the documentation - */ -$billing->withAddressLine1('Address1') - ->withAddressLine2('Address2') - ->withCity('City') - ->withCountryCode('RO') - ->withEmail('john.doe@mail.com') - ->withFirstName('FirstName') - ->withLastName('LastName') - ->withPhoneNumber('40123456789') - ->withIdentityCardNumber('111222'); - - -/** - * Create new delivery address - * - * If you want to have the same delivery as billing, skip these two steps - * and pass the Billing $billing object to the request twice - */ -$delivery = new Delivery(); - -/** - * Setup the delivery address params - * - * Full params available in the documentation - */ -$delivery->withAddressLine1('Address1') - ->withAddressLine2('Address2') - ->withCity('City') - ->withCountryCode('RO') - ->withEmail('john.doe@mail.com') - ->withFirstName('FirstName') - ->withLastName('LastName') - ->withPhoneNumber('40123456789'); - -/** - * Create new Card with params: - * - * Credit Card Number - * Credit Card Expiration Month - * Credit Card Expiration Year - * Credit Card CVV (Security Code) - * Credit Card Owner - */ -$card = new Card('4111111111111111', '01', '2026', '123', 'Card Owner Name'); - -/** - * Create new Request with params: - * - * Config object - * Order object - * Billing object - * Delivery (or Billing object again, if you want to have the delivery address the same as the billing address) - * User object - */ -$request = new Request($cfg, $order, $billing, $delivery, $user, PaymentsV4::API_VERSION_V4); -//$request = new Request($cfg, $order, $billing, $delivery, $user); - -/** - * Add the Credit Card to the Request - */ -$request->setCard($card); - -/** - * Create new API Client, passing the Config object as parameter - */ -$client = new Client($cfg); - -/** - * Will throw different Exceptions on errors - */ -try { - /** - * Sends the Request to ALU and returns a Response - * - * See documentation for Response params - */ - $response = $client->pay($request); - - /** - * In case of 3DS enrolled cards, PayU will return the URL_3DS that contains a unique url for each - * transaction. The merchant must redirect the browser to this url to allow user to authenticate. - * After the authentication process ends the user will be redirected to BACK_REF url - * with payment result in a HTTP POST request - */ - if ($response->isThreeDs()) { - header("Location:" . $response->getThreeDsUrl()); - die(); - } - - echo $response->getCode() - . ' ' . $response->getStatus() - . ' ' . $response->getReturnCode() - . ' ' . $response->getReturnMessage(); -} catch (ConnectionException $exception) { - echo $exception->getMessage(); -} catch (ClientException $exception) { - echo $exception->getErrorMessage(); -} From cfd59ad94d5070640e4970816c0d9a747b6dcdd8 Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Mon, 4 May 2020 15:12:03 +0300 Subject: [PATCH 16/23] reformat code --- examplesV4/tokenCreationAndPaymentExample.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examplesV4/tokenCreationAndPaymentExample.php b/examplesV4/tokenCreationAndPaymentExample.php index ca75dc12..fde673a9 100644 --- a/examplesV4/tokenCreationAndPaymentExample.php +++ b/examplesV4/tokenCreationAndPaymentExample.php @@ -208,7 +208,7 @@ echo('Token response data: '); echo $response->getTokenCode() . ' ' . $response->getTokenMessage() . ' Token:' . $response->getTokenHash() . "\n"; - if ($response->getTokenCode() == 0 && $response->getTokenHash() !== ''){ + if ($response->getTokenCode() == 0 && $response->getTokenHash() !== '') { $cardToken = new CardToken($response->getTokenHash()); $requestWithToken->setCardToken($cardToken); @@ -216,7 +216,6 @@ echo $response->getStatus() . ' ' . $response->getReturnCode() . ' ' . $response->getReturnMessage() . "\n"; } - } catch (ClientException $exception) { echo $exception->getErrorMessage(); } From f8f4256f039efaa58418fd218ba57f8a6e6f5430 Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Mon, 4 May 2020 16:45:51 +0300 Subject: [PATCH 17/23] test tokenV2 flow --- .../PaymentsApi/PaymentsV4/PaymentsV4Test.php | 212 +++++++++++++++++- 1 file changed, 207 insertions(+), 5 deletions(-) diff --git a/tests/PayU/PaymentsApi/PaymentsV4/PaymentsV4Test.php b/tests/PayU/PaymentsApi/PaymentsV4/PaymentsV4Test.php index d2be2590..7804d12a 100644 --- a/tests/PayU/PaymentsApi/PaymentsV4/PaymentsV4Test.php +++ b/tests/PayU/PaymentsApi/PaymentsV4/PaymentsV4Test.php @@ -56,22 +56,22 @@ public function setUp() { $this->mockRequestBuilder = $this->getMockBuilder(RequestBuilder::class) ->disableOriginalConstructor() - ->setMethods(array('buildAuthorizationRequest')) + ->setMethods(array('buildAuthorizationRequest', 'buildTokenRequestBody')) ->getMock(); $this->mockResponseParser = $this->getMockBuilder(ResponseParser::class) ->disableOriginalConstructor() - ->setMethods(array('parseJsonResponse')) + ->setMethods(array('parseJsonResponse', 'parseTokenJsonResponse')) ->getMock(); $this->mockResponseBuilder = $this->getMockBuilder(ResponseBuilder::class) ->disableOriginalConstructor() - ->setMethods(array('buildResponse')) + ->setMethods(array('buildResponse', 'buildTokenResponse')) ->getMock(); $this->mockHttpClient = $this->getMockBuilder(HTTPClient::class) ->disableOriginalConstructor() - ->setMethods(array('post')) + ->setMethods(array('post', 'postTokenCreationRequest')) ->getMock(); $this->paymentsV4 = new PaymentsV4(); @@ -103,7 +103,7 @@ private function addMockObjectsToPaymentsV4() */ private function createAluRequest() { - $cfg = new MerchantConfig('PAYU_2', 'SECRET_KEY', 'RO'); + $cfg = new MerchantConfig('MERCHANT_CODE', 'SECRET_KEY', 'RO'); $user = new User('127.0.0.1'); @@ -167,6 +167,74 @@ private function createAluRequest() return $request; } + + private function createAluRequestWithTokenCreation() + { + $cfg = new MerchantConfig('MERCHANT_CODE', 'SECRET_KEY', 'RO'); + + $user = new User('127.0.0.1'); + + $order = new Order(); + + $order->withBackRef('http://path/to/your/returnUrlScript') + ->withOrderRef(self::MERCHANT_PAYMENT_REFERENCE) + ->withCurrency('RON') + ->withOrderDate(self::ORDER_DATE) + ->withOrderTimeout(1000) + ->withPayMethod('CCVISAMC'); + + $product = new Product(); + $product->withCode('PCODE01') + ->withName('PNAME01') + ->withPrice(100.0) + ->withVAT(24.0) + ->withQuantity(1); + + $order->addProduct($product); + + $product = new Product(); + $product->withCode('PCODE02') + ->withName('PNAME02') + ->withPrice(200.0) + ->withVAT(24.0) + ->withQuantity(1); + + $order->addProduct($product); + + $billing = new Billing(); + + $billing->withAddressLine1('Address1') + ->withAddressLine2('Address2') + ->withCity('City') + ->withCountryCode('RO') + ->withEmail('john.doe@mail.com') + ->withFirstName('FirstName') + ->withLastName('LastName') + ->withPhoneNumber('40123456789') + ->withIdentityCardNumber('111222') + ->withIdentityCardType(null); + + $delivery = new Delivery(); + $delivery->withAddressLine1('Address1') + ->withAddressLine2('Address2') + ->withCity('City') + ->withCountryCode('RO') + ->withEmail('john.doe@mail.com') + ->withFirstName('FirstName') + ->withLastName('LastName') + ->withPhoneNumber('40123456789'); + + + $card = new Card('4111111111111111', '01', '2026', 123, 'Card Owner Name'); + $card->enableTokenCreation(); + + $request = new Request($cfg, $order, $billing, $delivery, $user, PaymentsV4::API_VERSION_V4); + + $request->setCard($card); + + return $request; + } + private function createJsonRequest() { $requestArray = [ @@ -302,6 +370,57 @@ private function createAluResponse() return $response; } + private function createTokenRequestArray() + { + return [ + 'merchant' => 'MERCHANT_CODE', + 'refNo' => self::PAYU_PAYMENT_REFERENCE, + 'timestamp' => '1428045257' + ]; + } + + private function createTokenJsonResponse() + { + return '{ + "meta":{ + "status":{ + "code":0, + "message":"success" + }, + "response":{ + "httpCode":200, + "httpMessage":"200 OK" + }, + "version":"v2" + }, + "response":{ + "token":"b7e5d8649c9e2e75726b59c56c29e91d", + "cardUniqueIdentifier":"e9fc5107db302fa8373efbedf55a1614b5a3125ee59fe274e7dc802930d68f6d" + } + '; + } + + private function createTokenArrayResponse() + { + return [ + 'meta' => [ + 'status' => [ + "code" => 0, + "message" => "success" + ], + 'response' => [ + "httpCode" => 200, + "httpMessage" => "200 OK" + ], + 'version' => 'v2' + ], + 'response' => [ + "token" => "b7e5d8649c9e2e75726b59c56c29e91d", + "cardUniqueIdentifier" => "e9fc5107db302fa8373efbedf55a1614b5a3125ee59fe274e7dc802930d68f6d" + ] + ]; + } + public function testAuthorize() { // Given @@ -414,4 +533,87 @@ public function testResponseParserThrowsAuthorizationResponseException() $this->paymentsV4->authorize($aluRequest); } + + public function testAuthorizeWithCreateToken() + { + // Given + $aluRequest = $this->createAluRequestWithTokenCreation(); + $jsonRequest = $this->createJsonRequest(); + $jsonResponse = $this->createJsonResponse(); + $arrayResponse = $this->createArrayResponse(); + $aluResponse = $this->createAluResponse(); + + $tokenRequest = $this->createTokenRequestArray(); + $tokenJsonResponse = $this->createTokenJsonResponse(); + $tokenArrayResponse = $this->createTokenArrayResponse(); + $aluResponseToken = $this->createAluResponse(); + + $aluResponseToken->setTokenCode(0); + $aluResponseToken->setTokenMessage('success'); + $aluResponseToken->setTokenHash('b7e5d8649c9e2e75726b59c56c29e91d'); + + // When + $this->addMockObjectsToPaymentsV4(); + + $this->mockRequestBuilder->expects($this->once()) + ->method('buildAuthorizationRequest') + ->with($aluRequest) + ->willReturn($jsonRequest); + + $this->mockHttpClient->expects($this->once()) + ->method('post') + ->with( + self::PAYMENTS_URL . PaymentsV4::PAYMENTS_API_AUTHORIZE_PATH, + $aluRequest->getMerchantConfig(), + self::ORDER_DATE, + $jsonRequest + ) + ->willReturn($jsonResponse); + + $authorizationResponse = new AuthorizationResponse($arrayResponse); + + $this->mockResponseParser->expects($this->once()) + ->method('parseJsonResponse') + ->with($jsonResponse) + ->willReturn($authorizationResponse); + + $this->mockResponseBuilder->expects($this->once()) + ->method('buildResponse') + ->with($authorizationResponse) + ->willReturn($aluResponse); + + // Begin token flow + + $this->mockRequestBuilder->expects($this->once()) + ->method('buildTokenRequestBody') + ->with($aluRequest->getMerchantConfig()->getMerchantCode(), $aluResponse->getRefno()) + ->willReturn($tokenRequest); + + $this->mockHttpClient->expects($this->once()) + ->method('postTokenCreationRequest') + ->with( + self::PAYMENTS_URL . PaymentsV4::BASE_CREATE_TOKEN_PATH, + $tokenRequest, + $aluRequest->getMerchantConfig()->getSecretKey() + ) + ->willReturn($tokenJsonResponse); + + $authorizationTokenResponse = new AuthorizationResponse($tokenArrayResponse); + + $this->mockResponseParser->expects($this->once()) + ->method('parseTokenJsonResponse') + ->with($tokenJsonResponse) + ->willReturn($authorizationTokenResponse); + + $this->mockResponseBuilder->expects($this->once()) + ->method('buildTokenResponse') + ->with($authorizationTokenResponse, $aluResponse) + ->willReturn($aluResponseToken); + + $actualResponse = $this->paymentsV4->authorize($aluRequest); + + // Then + $this->assertInstanceOf(Response::class, $actualResponse); + $this->assertEquals($aluResponseToken, $actualResponse); + } } From 6d00fe479f9bdbaab15fcb759b43aab5097144c6 Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Mon, 4 May 2020 17:05:18 +0300 Subject: [PATCH 18/23] add exception test --- .../PaymentsApi/PaymentsV4/PaymentsV4Test.php | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/tests/PayU/PaymentsApi/PaymentsV4/PaymentsV4Test.php b/tests/PayU/PaymentsApi/PaymentsV4/PaymentsV4Test.php index 7804d12a..93eaf17a 100644 --- a/tests/PayU/PaymentsApi/PaymentsV4/PaymentsV4Test.php +++ b/tests/PayU/PaymentsApi/PaymentsV4/PaymentsV4Test.php @@ -2,6 +2,7 @@ namespace PayU\PaymentsApi\PaymentsV4; +use Exception; use PayU\Alu\Billing; use PayU\Alu\Card; use PayU\Alu\Delivery; @@ -616,4 +617,57 @@ public function testAuthorizeWithCreateToken() $this->assertInstanceOf(Response::class, $actualResponse); $this->assertEquals($aluResponseToken, $actualResponse); } + + /** + * @expectedException \PayU\PaymentsApi\Exceptions\AuthorizationException + */ + public function testRequestBuilderThrowsException() + { + // Given + $aluRequest = $this->createAluRequestWithTokenCreation(); + $jsonRequest = $this->createJsonRequest(); + $jsonResponse = $this->createJsonResponse(); + $arrayResponse = $this->createArrayResponse(); + $aluResponse = $this->createAluResponse(); + + // When + $this->addMockObjectsToPaymentsV4(); + + $this->mockRequestBuilder->expects($this->once()) + ->method('buildAuthorizationRequest') + ->with($aluRequest) + ->willReturn($jsonRequest); + + $this->mockHttpClient->expects($this->once()) + ->method('post') + ->with( + self::PAYMENTS_URL . PaymentsV4::PAYMENTS_API_AUTHORIZE_PATH, + $aluRequest->getMerchantConfig(), + self::ORDER_DATE, + $jsonRequest + ) + ->willReturn($jsonResponse); + + $authorizationResponse = new AuthorizationResponse($arrayResponse); + + $this->mockResponseParser->expects($this->once()) + ->method('parseJsonResponse') + ->with($jsonResponse) + ->willReturn($authorizationResponse); + + $this->mockResponseBuilder->expects($this->once()) + ->method('buildResponse') + ->with($authorizationResponse) + ->willReturn($aluResponse); + + // Begin token flow + + $this->mockRequestBuilder->expects($this->once()) + ->method('buildTokenRequestBody') + ->with($aluRequest->getMerchantConfig()->getMerchantCode(), $aluResponse->getRefno()) + ->willThrowException(new Exception()); + + // Then + $this->paymentsV4->authorize($aluRequest); + } } From 12de3b269979c001876d29b8dc324c6f9f13338f Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Tue, 23 Jun 2020 15:43:25 +0300 Subject: [PATCH 19/23] remove unused countries --- src/PayU/PaymentsApi/PaymentsV4/PaymentsV4.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/PayU/PaymentsApi/PaymentsV4/PaymentsV4.php b/src/PayU/PaymentsApi/PaymentsV4/PaymentsV4.php index b271e93c..e4817d56 100644 --- a/src/PayU/PaymentsApi/PaymentsV4/PaymentsV4.php +++ b/src/PayU/PaymentsApi/PaymentsV4/PaymentsV4.php @@ -45,8 +45,6 @@ class PaymentsV4 implements AuthorizationPaymentsApiClient private $platformHostname = [ 'ro' => 'https://secure.payu.ro', 'ru' => 'https://secure.payu.ru', - 'ua' => 'https://secure.payu.ua', - 'hu' => 'https://secure.payu.hu', 'tr' => 'https://secure.payu.com.tr', ]; From 6de2f0dd07f5a7ec82bde40316dfe118f0c54c67 Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Tue, 23 Jun 2020 16:28:05 +0300 Subject: [PATCH 20/23] * move creation of $requestWithToken after receiving the token * rename the 2 $response instances to $initialPaymentResponse and $tokenPaymentResponse * create Alu/TokenResponseData.php and use it in Response.php * --- .../createTokenForRecurrentPaymentV4.php | 4 +- examplesV4/tokenCreationAndPaymentExample.php | 36 +++++++++++----- src/PayU/Alu/Response.php | 35 ++++----------- src/PayU/Alu/TokenResponseData.php | 43 +++++++++++++++++++ .../PaymentsV4/Services/ResponseBuilder.php | 9 +++- .../PaymentsApi/PaymentsV4/PaymentsV4Test.php | 5 ++- .../Services/ResponseBuilderTest.php | 12 ++++-- 7 files changed, 97 insertions(+), 47 deletions(-) create mode 100644 src/PayU/Alu/TokenResponseData.php diff --git a/examplesV4/createTokenForRecurrentPaymentV4.php b/examplesV4/createTokenForRecurrentPaymentV4.php index 093b2f10..ebeb39ba 100644 --- a/examplesV4/createTokenForRecurrentPaymentV4.php +++ b/examplesV4/createTokenForRecurrentPaymentV4.php @@ -204,7 +204,9 @@ echo $response->getStatus() . ' ' . $response->getReturnCode() . ' ' . $response->getReturnMessage(); echo('Token response data: '); - echo $response->getTokenCode() . ' ' . $response->getTokenMessage() . ' Token:' . $response->getTokenHash(); + echo $response->getTokenResponseData()->getTokenCode() . ' ' . + $response->getTokenResponseData()->getTokenMessage() . + ' Token:' . $response->getTokenHash(); } catch (ClientException $exception) { echo $exception->getErrorMessage(); } diff --git a/examplesV4/tokenCreationAndPaymentExample.php b/examplesV4/tokenCreationAndPaymentExample.php index fde673a9..404b90f7 100644 --- a/examplesV4/tokenCreationAndPaymentExample.php +++ b/examplesV4/tokenCreationAndPaymentExample.php @@ -170,8 +170,6 @@ * User object */ $request = new Request($cfg, $order, $billing, $delivery, $user, PaymentsV4::API_VERSION_V4); -$requestWithToken = new Request($cfg, $order, $billing, $delivery, $user, PaymentsV4::API_VERSION_V4); -$requestWithToken->getOrder()->withOrderRef('TokenOrderRef'); /** * Add the Credit Card to the Request */ @@ -191,7 +189,7 @@ * * See documentation for Response params */ - $response = $client->pay($request); + $initialPaymentResponse = $client->pay($request); /** * In case of 3DS enrolled cards, PayU will return the URL_3DS that contains a unique url for each @@ -199,22 +197,38 @@ * After the authentication process ends the user will be redirected to BACK_REF url * with payment result in a HTTP POST request */ - if ($response->isThreeDs()) { - header("Location:" . $response->getThreeDsUrl()); + if ($initialPaymentResponse->isThreeDs()) { + header("Location:" . $initialPaymentResponse->getThreeDsUrl()); die(); } - echo $response->getStatus() . ' ' . $response->getReturnCode() . ' ' . $response->getReturnMessage() . "\n"; + echo $initialPaymentResponse->getStatus() . ' ' . + $initialPaymentResponse->getReturnCode() . ' ' . + $initialPaymentResponse->getReturnMessage() . + "\n"; + echo('Token response data: '); - echo $response->getTokenCode() . ' ' . $response->getTokenMessage() . ' Token:' . $response->getTokenHash() . "\n"; + echo $initialPaymentResponse->getTokenResponseData()->getTokenCode() . ' ' . + $initialPaymentResponse->getTokenResponseData()->getTokenMessage() . + ' Token:' . $initialPaymentResponse->getTokenHash() . + "\n"; + + if ($initialPaymentResponse->getTokenResponseData()->getTokenCode() == 0 && $initialPaymentResponse->getTokenHash() !== '') { + $cardToken = new CardToken($initialPaymentResponse->getTokenHash()); - if ($response->getTokenCode() == 0 && $response->getTokenHash() !== '') { - $cardToken = new CardToken($response->getTokenHash()); + // Create a new request using the token received + $requestWithToken = new Request($cfg, $order, $billing, $delivery, $user, PaymentsV4::API_VERSION_V4); + $requestWithToken->getOrder()->withOrderRef(4444); $requestWithToken->setCardToken($cardToken); - $response = $client->pay($requestWithToken); + $tokenPaymentResponse = $client->pay($requestWithToken); - echo $response->getStatus() . ' ' . $response->getReturnCode() . ' ' . $response->getReturnMessage() . "\n"; + echo $tokenPaymentResponse->getStatus() . ' ' . + $tokenPaymentResponse->getReturnCode() . ' ' . + $tokenPaymentResponse->getReturnMessage() . + "\n"; + } else { + echo "No token received"; } } catch (ClientException $exception) { echo $exception->getErrorMessage(); diff --git a/src/PayU/Alu/Response.php b/src/PayU/Alu/Response.php index bf42d3d7..d5662c4b 100644 --- a/src/PayU/Alu/Response.php +++ b/src/PayU/Alu/Response.php @@ -119,42 +119,23 @@ class Response */ private $type; - /** @var int */ - private $tokenCode; - - /** @var string */ - private $tokenMessage; - - /** - * @return int - */ - public function getTokenCode() - { - return $this->tokenCode; - } + /** @var TokenResponseData */ + private $tokenResponseData; /** - * @param int $tokenCode - */ - public function setTokenCode($tokenCode) - { - $this->tokenCode = $tokenCode; - } - - /** - * @return string + * @return TokenResponseData */ - public function getTokenMessage() + public function getTokenResponseData() { - return $this->tokenMessage; + return $this->tokenResponseData; } /** - * @param string $tokenMessage + * @param TokenResponseData $tokenResponseData */ - public function setTokenMessage($tokenMessage) + public function setTokenResponseData($tokenResponseData) { - $this->tokenMessage = $tokenMessage; + $this->tokenResponseData = $tokenResponseData; } /** diff --git a/src/PayU/Alu/TokenResponseData.php b/src/PayU/Alu/TokenResponseData.php new file mode 100644 index 00000000..615768fc --- /dev/null +++ b/src/PayU/Alu/TokenResponseData.php @@ -0,0 +1,43 @@ +tokenCode = $tokenCode; + $this->tokenMessage = $tokenMessage; + } + + /** + * @return int + */ + public function getTokenCode() + { + return $this->tokenCode; + } + + /** + * @return string + */ + public function getTokenMessage() + { + return $this->tokenMessage; + } +} diff --git a/src/PayU/PaymentsApi/PaymentsV4/Services/ResponseBuilder.php b/src/PayU/PaymentsApi/PaymentsV4/Services/ResponseBuilder.php index c5c04b47..4a709883 100644 --- a/src/PayU/PaymentsApi/PaymentsV4/Services/ResponseBuilder.php +++ b/src/PayU/PaymentsApi/PaymentsV4/Services/ResponseBuilder.php @@ -5,6 +5,7 @@ use PayU\Alu\Response; use PayU\Alu\ResponseWireAccount; +use PayU\Alu\TokenResponseData; use PayU\PaymentsApi\PaymentsV4\Entities\AuthorizationResponse; class ResponseBuilder @@ -113,8 +114,12 @@ public function buildTokenResponse( if ($responseArray["meta"]["status"]["code"] === 0) { $response->setTokenHash($responseArray["response"]["token"]); } - $response->setTokenCode($responseArray["meta"]["status"]["code"]); - $response->setTokenMessage($responseArray["meta"]["status"]["message"]); + + $responseTokenData = new TokenResponseData( + $responseArray["meta"]["status"]["code"], + $responseArray["meta"]["status"]["message"] + ); + $response->setTokenResponseData($responseTokenData); return $response; } diff --git a/tests/PayU/PaymentsApi/PaymentsV4/PaymentsV4Test.php b/tests/PayU/PaymentsApi/PaymentsV4/PaymentsV4Test.php index 93eaf17a..1853f889 100644 --- a/tests/PayU/PaymentsApi/PaymentsV4/PaymentsV4Test.php +++ b/tests/PayU/PaymentsApi/PaymentsV4/PaymentsV4Test.php @@ -11,6 +11,7 @@ use PayU\Alu\Product; use PayU\Alu\Request; use PayU\Alu\Response; +use PayU\Alu\TokenResponseData; use PayU\Alu\User; use PayU\PaymentsApi\PaymentsV4\Entities\AuthorizationResponse; use PayU\PaymentsApi\PaymentsV4\Exceptions\AuthorizationResponseException; @@ -549,8 +550,8 @@ public function testAuthorizeWithCreateToken() $tokenArrayResponse = $this->createTokenArrayResponse(); $aluResponseToken = $this->createAluResponse(); - $aluResponseToken->setTokenCode(0); - $aluResponseToken->setTokenMessage('success'); + $tokenResponseData = new TokenResponseData(0, 'success'); + $aluResponseToken->setTokenResponseData($tokenResponseData); $aluResponseToken->setTokenHash('b7e5d8649c9e2e75726b59c56c29e91d'); // When diff --git a/tests/PayU/PaymentsApi/PaymentsV4/Services/ResponseBuilderTest.php b/tests/PayU/PaymentsApi/PaymentsV4/Services/ResponseBuilderTest.php index da9f2413..55c41786 100644 --- a/tests/PayU/PaymentsApi/PaymentsV4/Services/ResponseBuilderTest.php +++ b/tests/PayU/PaymentsApi/PaymentsV4/Services/ResponseBuilderTest.php @@ -4,6 +4,7 @@ namespace PayU\PaymentsApi\PaymentsV4\Services; use PayU\Alu\Response; +use PayU\Alu\TokenResponseData; use PayU\PaymentsApi\PaymentsV4\Entities\AuthorizationResponse; use PHPUnit\Framework\TestCase; @@ -66,8 +67,8 @@ public function testBuildTokenResponseWithSuccessResponse() // Given $authorizationResponse = new AuthorizationResponse($this->createSuccessResponseArray()); $expectedResponse = new Response(); - $expectedResponse->setTokenCode(0); - $expectedResponse->setTokenMessage('success'); + $tokenResponseData = new TokenResponseData(0, 'success'); + $expectedResponse->setTokenResponseData($tokenResponseData); $expectedResponse->setTokenHash('b7e5d8649c9e2e75726b59c56c29e91d'); // Then @@ -82,8 +83,11 @@ public function testBuildTokenResponseWithErrorResponse() // Given $authorizationResponse = new AuthorizationResponse($this->createErrorResponseArray()); $expectedResponse = new Response(); - $expectedResponse->setTokenCode(400); - $expectedResponse->setTokenMessage('No order with reference number: 120393911'); + $tokenResponseData = new TokenResponseData( + 400, + 'No order with reference number: 120393911' + ); + $expectedResponse->setTokenResponseData($tokenResponseData); // Then $this->assertEquals( From 448a1c0ffb6eb1ef7569bb12bc7e92bda5773a22 Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Tue, 23 Jun 2020 16:40:32 +0300 Subject: [PATCH 21/23] treat the authorization failed case where no token creation request is made --- examplesV4/createTokenForRecurrentPaymentV4.php | 8 +++++++- examplesV4/tokenCreationAndPaymentExample.php | 9 +++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/examplesV4/createTokenForRecurrentPaymentV4.php b/examplesV4/createTokenForRecurrentPaymentV4.php index ebeb39ba..e0dc8c5c 100644 --- a/examplesV4/createTokenForRecurrentPaymentV4.php +++ b/examplesV4/createTokenForRecurrentPaymentV4.php @@ -202,7 +202,13 @@ die(); } - echo $response->getStatus() . ' ' . $response->getReturnCode() . ' ' . $response->getReturnMessage(); + echo $response->getStatus() . ' ' . $response->getReturnCode() . ' ' . $response->getReturnMessage() . "\n"; + + if ($response->getTokenResponseData() === null) { + echo 'Could not make token request because authorization failed.' . "\n"; + die(); + } + echo('Token response data: '); echo $response->getTokenResponseData()->getTokenCode() . ' ' . $response->getTokenResponseData()->getTokenMessage() . diff --git a/examplesV4/tokenCreationAndPaymentExample.php b/examplesV4/tokenCreationAndPaymentExample.php index 404b90f7..968dca0c 100644 --- a/examplesV4/tokenCreationAndPaymentExample.php +++ b/examplesV4/tokenCreationAndPaymentExample.php @@ -207,7 +207,12 @@ $initialPaymentResponse->getReturnMessage() . "\n"; - echo('Token response data: '); + if ($initialPaymentResponse->getTokenResponseData() === null) { + echo 'Could not make token request because authorization failed.' . "\n"; + die(); + } + + echo 'Token response data: '; echo $initialPaymentResponse->getTokenResponseData()->getTokenCode() . ' ' . $initialPaymentResponse->getTokenResponseData()->getTokenMessage() . ' Token:' . $initialPaymentResponse->getTokenHash() . @@ -218,7 +223,7 @@ // Create a new request using the token received $requestWithToken = new Request($cfg, $order, $billing, $delivery, $user, PaymentsV4::API_VERSION_V4); - $requestWithToken->getOrder()->withOrderRef(4444); + $requestWithToken->getOrder()->withOrderRef('TokenOrderRef'); $requestWithToken->setCardToken($cardToken); $tokenPaymentResponse = $client->pay($requestWithToken); From b653ea3643b55c71a13a194ee32a584dc80b2e28 Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Tue, 23 Jun 2020 17:02:17 +0300 Subject: [PATCH 22/23] reformat code --- examplesV4/tokenCreationAndPaymentExample.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/examplesV4/tokenCreationAndPaymentExample.php b/examplesV4/tokenCreationAndPaymentExample.php index 968dca0c..39699c91 100644 --- a/examplesV4/tokenCreationAndPaymentExample.php +++ b/examplesV4/tokenCreationAndPaymentExample.php @@ -218,11 +218,21 @@ ' Token:' . $initialPaymentResponse->getTokenHash() . "\n"; - if ($initialPaymentResponse->getTokenResponseData()->getTokenCode() == 0 && $initialPaymentResponse->getTokenHash() !== '') { + if ( + $initialPaymentResponse->getTokenResponseData()->getTokenCode() == 0 && + $initialPaymentResponse->getTokenHash() !== '' + ) { $cardToken = new CardToken($initialPaymentResponse->getTokenHash()); // Create a new request using the token received - $requestWithToken = new Request($cfg, $order, $billing, $delivery, $user, PaymentsV4::API_VERSION_V4); + $requestWithToken = new Request( + $cfg, + $order, + $billing, + $delivery, + $user, + PaymentsV4::API_VERSION_V4 + ); $requestWithToken->getOrder()->withOrderRef('TokenOrderRef'); $requestWithToken->setCardToken($cardToken); From b6e1b4c9f2f9488147570276b1b4c55dc81d87a9 Mon Sep 17 00:00:00 2001 From: spopawdodo Date: Tue, 23 Jun 2020 17:09:16 +0300 Subject: [PATCH 23/23] reformat code --- examplesV4/tokenCreationAndPaymentExample.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examplesV4/tokenCreationAndPaymentExample.php b/examplesV4/tokenCreationAndPaymentExample.php index 39699c91..2e4310a2 100644 --- a/examplesV4/tokenCreationAndPaymentExample.php +++ b/examplesV4/tokenCreationAndPaymentExample.php @@ -218,8 +218,7 @@ ' Token:' . $initialPaymentResponse->getTokenHash() . "\n"; - if ( - $initialPaymentResponse->getTokenResponseData()->getTokenCode() == 0 && + if ($initialPaymentResponse->getTokenResponseData()->getTokenCode() == 0 && $initialPaymentResponse->getTokenHash() !== '' ) { $cardToken = new CardToken($initialPaymentResponse->getTokenHash());