diff --git a/CHANGELOG.md b/CHANGELOG.md index b47afd38..6a43aceb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,18 @@ #### Enhancements: -- Set global merchant country configuration where required +- Update GP-API to 2021-03-22 version +- 3DS Status Mapping - Missed Mapping and Revise some mappings +- Update ACS simulator for 3DS2 to use values from initiate response for the form fields name required in the POST redirect +- Change position of fields: "source", "preference", "message_version" need to exist in the "three_ds" sub-object in the 3DS2 initiate call +- Remove "/detokenize" endpoint from GP-API +- Update GP-API production endpoint + +## v2.2.13 (04/29/2021) + +#### Enhancements: + +- Set global merchant country configuration where required for GP-API - Add GP-API 3DS new tests - Add additional GP-API 3DS mappings - Add additional GP-API transaction summary mappings @@ -17,6 +28,7 @@ - Add GP-API actions report - Add GP-API reauthorization functionality - Add GP-API EBT new tests +- Add Exemption Optimization service for GP-ECOM #### Bug Fixes: diff --git a/src/Entities/Enums/ServiceEndpoints.php b/src/Entities/Enums/ServiceEndpoints.php index 141ad65c..195b58d6 100644 --- a/src/Entities/Enums/ServiceEndpoints.php +++ b/src/Entities/Enums/ServiceEndpoints.php @@ -25,5 +25,5 @@ class ServiceEndpoints extends Enum const PROPAY_PRODUCTION = "https://epay.propay.com/API/PropayAPI.aspx"; const PROPAY_PRODUCTION_CANADIAN = "https://www.propaycanada.ca/API/PropayAPI.aspx"; const GP_API_TEST = "https://apis.sandbox.globalpay.com/ucp"; - const GP_API_PRODUCTION = "https://apis.globalpay.com"; + const GP_API_PRODUCTION = "https://apis.globalpay.com/ucp"; } diff --git a/src/Entities/GpApi/GpApiManagementRequestBuilder.php b/src/Entities/GpApi/GpApiManagementRequestBuilder.php index dd82fc6f..690178ef 100644 --- a/src/Entities/GpApi/GpApiManagementRequestBuilder.php +++ b/src/Entities/GpApi/GpApiManagementRequestBuilder.php @@ -35,10 +35,6 @@ public function buildRequest(BaseBuilder $builder, $config) { $payload = []; switch ($builder->transactionType) { - case TransactionType::DETOKENIZE: - $endpoint = GpApiRequest::PAYMENT_METHODS_ENDPOINT . '/' . $builder->paymentMethod->token . '/detokenize'; - $verb = 'POST'; - break; case TransactionType::TOKEN_DELETE: $endpoint = GpApiRequest::PAYMENT_METHODS_ENDPOINT . '/' . $builder->paymentMethod->token; $verb = 'DELETE'; diff --git a/src/Entities/GpApi/GpApiReportRequestBuilder.php b/src/Entities/GpApi/GpApiReportRequestBuilder.php index 07a9616e..3caf4ceb 100644 --- a/src/Entities/GpApi/GpApiReportRequestBuilder.php +++ b/src/Entities/GpApi/GpApiReportRequestBuilder.php @@ -136,6 +136,8 @@ public function buildRequest(BaseBuilder $builder, $config) $builder->searchBuilder->fromTimeLastUpdated->format('Y-m-d') : null, 'to_time_last_updated' => !empty($builder->searchBuilder->toTimeLastUpdated) ? $builder->searchBuilder->toTimeLastUpdated->format('Y-m-d') : null, + 'id' => !empty($builder->searchBuilder->storedPaymentMethodId) ? + $builder->searchBuilder->storedPaymentMethodId : null ]; break; case ReportType::STORED_PAYMENT_METHOD_DETAIL: diff --git a/src/Entities/GpApi/GpApiSecure3DRequestBuilder.php b/src/Entities/GpApi/GpApiSecure3DRequestBuilder.php index cacd1ed4..1e045677 100644 --- a/src/Entities/GpApi/GpApiSecure3DRequestBuilder.php +++ b/src/Entities/GpApi/GpApiSecure3DRequestBuilder.php @@ -98,9 +98,12 @@ private function verifyEnrolled(Secure3dBuilder $builder, GpApiConfig $config) private function initiateAuthenticationData(Secure3dBuilder $builder, GpApiConfig $config) { $threeDS = []; - $threeDS['preference'] = $builder->challengeRequestIndicator; + $threeDS['three_ds'] = [ + 'source' => (string) $builder->authenticationSource, + 'preference' => $builder->challengeRequestIndicator, + 'message_version' => $builder->messageVersion + ]; $threeDS['method_url_completion_status'] = (string) $builder->methodUrlCompletion; - $threeDS['source'] = (string) $builder->authenticationSource; $threeDS['merchant_contact_url'] = 'https://enp4qhvjseljg.x.pipedream.net/'; // @TODO $order = [ 'time_created_reference' => !empty($builder->orderCreateDate) ? @@ -118,7 +121,7 @@ private function initiateAuthenticationData(Secure3dBuilder $builder, GpApiConfi 'shipping_name_matches_cardholder_name' => $builder->getShippingNameMatchesCardHolderName(), 'preorder_indicator' => (string) $builder->preOrderIndicator, 'preorder_availability_date' => !empty($builder->preOrderAvailabilityDate) ? - $builder->preOrderAvailabilityDate->format('Y-m-d') : null, + (new \DateTime($builder->preOrderAvailabilityDate))->format('Y-m-d') : null, 'reorder_indicator' => (string) $builder->reorderIndicator, 'transaction_type' => $builder->orderTransactionType ]; @@ -140,12 +143,12 @@ private function initiateAuthenticationData(Secure3dBuilder $builder, GpApiConfi 'reference' => $builder->customerAccountId, 'account_age' => (string) $builder->accountAgeIndicator, 'account_creation_date' => !empty($builder->accountCreateDate) ? - $builder->accountCreateDate->format('Y-m-d') : null, + (new \DateTime($builder->accountCreateDate))->format('Y-m-d') : null, 'account_change_date' => !empty($builder->accountChangeDate) ? - $builder->accountChangeDate->format('Y-m-d') : null, + (new \DateTime($builder->accountChangeDate))->format('Y-m-d') : null, 'account_change_indicator' => (string) $builder->accountChangeIndicator, 'account_password_change_date' => !empty($builder->passwordChangeDate) ? - $builder->passwordChangeDate->format('Y-m-d') : null, + (new \DateTime($builder->passwordChangeDate))->format('Y-m-d') : null, 'account_password_change_indicator' => (string) $builder->passwordChangeIndicator, 'home_phone' => [ 'country_code' => $builder->homeCountryCode, @@ -156,7 +159,7 @@ private function initiateAuthenticationData(Secure3dBuilder $builder, GpApiConfi 'subscriber_number' => $builder->workNumber ], 'payment_account_creation_date' => !empty($builder->paymentAccountCreateDate) ? - $builder->paymentAccountCreateDate->format('Y-m-d') : null, + (new \DateTime($builder->paymentAccountCreateDate))->format('Y-m-d') : null, 'payment_account_age_indicator' => (string) $builder->paymentAgeIndicator, 'suspicious_account_activity' => $builder->previousSuspiciousActivity, 'purchases_last_6months_count' => $builder->numberOfPurchasesInLastSixMonths, @@ -164,7 +167,7 @@ private function initiateAuthenticationData(Secure3dBuilder $builder, GpApiConfi 'transaction_last_year_count' => $builder->numberOfTransactionsInLastYear, 'provision_attempt_last_24hours_count' => $builder->numberOfAddCardAttemptsInLast24Hours, 'shipping_address_time_created_reference' => !empty($builder->shippingAddressCreateDate) ? - $builder->shippingAddressCreateDate->format('Y-m-d') : null, + (new \DateTime($builder->shippingAddressCreateDate))->format('Y-m-d') : null, 'shipping_address_creation_indicator' => (string) $builder->shippingAddressUsageIndicator ]; @@ -172,7 +175,7 @@ private function initiateAuthenticationData(Secure3dBuilder $builder, GpApiConfi 'authentication_method' => (string) $builder->priorAuthenticationMethod, 'acs_transaction_reference' => $builder->priorAuthenticationTransactionId, 'authentication_timestamp' => !empty($builder->priorAuthenticationTimestamp) ? - $builder->priorAuthenticationTimestamp->format('Y-m-d\TH:i:s.u\Z') : null, + (new \DateTime($builder->priorAuthenticationTimestamp))->format('Y-m-d\TH:i:s.u\Z') : null, 'authentication_data' => $builder->priorAuthenticationData ]; @@ -185,9 +188,10 @@ private function initiateAuthenticationData(Secure3dBuilder $builder, GpApiConfi $threeDS['payer_login_data'] = [ 'authentication_data' => $builder->customerAuthenticationData, 'authentication_timestamp' => !empty($builder->customerAuthenticationTimestamp) ? - $builder->customerAuthenticationTimestamp->format('Y-m-d\TH:i:s.u\Z') : null, + (new \DateTime($builder->customerAuthenticationTimestamp))->format('Y-m-d\TH:i:s.u\Z') : null, 'authentication_type' => (string) $builder->customerAuthenticationMethod ]; + if (!empty($builder->browserData)) { $threeDS['browser_data'] = [ 'accept_header' => $builder->browserData->acceptHeader, diff --git a/src/Entities/Reporting/SearchCriteria.php b/src/Entities/Reporting/SearchCriteria.php index 683de86d..52776c9d 100644 --- a/src/Entities/Reporting/SearchCriteria.php +++ b/src/Entities/Reporting/SearchCriteria.php @@ -58,7 +58,8 @@ class SearchCriteria extends Enum const CARDHOLDER_NAME = 'name'; const DEPOSIT_ID = 'depositId'; const FROM_TIME_LAST_UPDATED = 'fromTimeLastUpdated'; - const TO_TIME_LAST_UPDATED = 'fromTimeLastUpdated'; + const TO_TIME_LAST_UPDATED = 'toTimeLastUpdated'; + const STORED_PAYMENT_METHOD_ID = 'storedPaymentMethodId'; const STORED_PAYMENT_METHOD_STATUS = 'storedPaymentMethodStatus'; const ACTION_TYPE = 'actionType'; const ACTION_ID = 'actionId'; diff --git a/src/Gateways/GpApiConnector.php b/src/Gateways/GpApiConnector.php index db7fcf87..fa013df6 100644 --- a/src/Gateways/GpApiConnector.php +++ b/src/Gateways/GpApiConnector.php @@ -25,7 +25,7 @@ class GpApiConnector extends RestGateway implements IPaymentGateway, ISecure3dProvider { - const GP_API_VERSION = '2020-12-22'; + const GP_API_VERSION = '2021-03-22'; const IDEMPOTENCY_HEADER = 'x-gp-idempotency'; /** * @var $gpApiConfig GpApiConfig @@ -222,16 +222,25 @@ public function signIn() $this->accessToken = $response->getToken(); $this->headers['Authorization'] = sprintf('Bearer %s', $this->accessToken); - if (empty($accessTokenInfo)) { + if (!$accessTokenInfo instanceof AccessTokenInfo) { $accessTokenInfo = new AccessTokenInfo(); } - $accessTokenInfo->accessToken = $response->getToken(); - $accessTokenInfo->dataAccountName = $response->getDataAccountName(); - $accessTokenInfo->tokenizationAccountName = $response->getTokenizationAccountName(); - $accessTokenInfo->transactionProcessingAccountName = $response->getTransactionProcessingAccountName(); - $accessTokenInfo->disputeManagementAccountName = $response->getDisputeManagementAccountName(); + if (empty($accessTokenInfo->accessToken)) { + $accessTokenInfo->accessToken = $response->getToken(); + } + if (empty($accessTokenInfo->dataAccountName)) { + $accessTokenInfo->dataAccountName = $response->getDataAccountName(); + } + if (empty($accessTokenInfo->tokenizationAccountName)) { + $accessTokenInfo->tokenizationAccountName = $response->getTokenizationAccountName(); + } + if (empty($accessTokenInfo->transactionProcessingAccountName)) { + $accessTokenInfo->transactionProcessingAccountName = $response->getTransactionProcessingAccountName(); + } + if (empty($accessTokenInfo->disputeManagementAccountName)) { + $accessTokenInfo->disputeManagementAccountName = $response->getDisputeManagementAccountName(); + } $this->gpApiConfig->accessTokenInfo = $accessTokenInfo; - } /** diff --git a/src/Gateways/RestGateway.php b/src/Gateways/RestGateway.php index d2f9265b..23d8d4e5 100644 --- a/src/Gateways/RestGateway.php +++ b/src/Gateways/RestGateway.php @@ -47,6 +47,9 @@ protected function doTransaction( if (!in_array($response->statusCode, [200, 204])) { $parsed = json_decode($response->rawResponse); $error = isset($parsed->error) ? $parsed->error : $parsed; + if (empty($error)) { + throw new GatewayException(sprintf('Status Code: %s', $response->statusCode)); + } if ($this->isGpApi()) { $gatewayException = new GatewayException( sprintf( diff --git a/src/Services/HostedService.php b/src/Services/HostedService.php index 43415f67..44044238 100644 --- a/src/Services/HostedService.php +++ b/src/Services/HostedService.php @@ -129,7 +129,11 @@ public function parseResponse($response, $encoded = false) $ref->transactionId = $transactionId; $trans = new Transaction(); - $trans->authorizedAmount = $response["AMOUNT"]; + + if (isset($response["AMOUNT"])) { + $trans->authorizedAmount = $response["AMOUNT"]; + } + $trans->cvnResponseCode = $response["CVNRESULT"]; $trans->responseCode = $result; $trans->responseMessage = $message; diff --git a/test/Integration/Gateways/GpApiConnector/CreditCardNotPresentTest.php b/test/Integration/Gateways/GpApiConnector/CreditCardNotPresentTest.php index d13b7059..920a0742 100644 --- a/test/Integration/Gateways/GpApiConnector/CreditCardNotPresentTest.php +++ b/test/Integration/Gateways/GpApiConnector/CreditCardNotPresentTest.php @@ -423,38 +423,6 @@ public function testCardTokenization() $this->assertEquals('ACTIVE', $response->responseMessage); } - public function testCardTokenizationThenPayingWithToken_UsageModeSingle() - { - // process an auto-capture authorization - $response = $this->card->tokenize() - ->withPaymentMethodUsageMode(PaymentMethodUsageMode::SINGLE) - ->execute(); - $tokenId = $response->token; - - $tokenizedCard = new CreditCardData(); - $tokenizedCard->token = $tokenId; - $tokenizedCard->cardHolderName = "James Mason"; - - $detokenizedCard = $tokenizedCard->detokenize(); - $this->assertNotNull($detokenizedCard); - $this->assertEquals($this->card->number, $detokenizedCard->cardNumber); - $this->assertEquals($this->card->cvn, $detokenizedCard->cvnResponseCode); - - $response = $tokenizedCard->charge(10) - ->withCurrency("USD") - ->execute(); - - $this->assertNotNull($response); - $this->assertEquals('SUCCESS', $response->responseCode); - $this->assertEquals(TransactionStatus::CAPTURED, $response->responseMessage); - - $detokenizedCard = $tokenizedCard->detokenize(); - - $this->assertNotNull($detokenizedCard); - $this->assertEquals($this->card->number, $detokenizedCard->cardNumber); - $this->assertNull($detokenizedCard->cvnResponseCode); - } - public function testCardTokenizationThenPayingWithToken_SingleToMultiUse() { // process an auto-capture authorization @@ -611,35 +579,6 @@ public function testVerifyTokenizedPaymentMethod_WrongID() } } - public function testDetokenizePaymentMethodWithIdempotencyKey() - { - try { - // process an auto-capture authorization - $response = $this->card->tokenize() - ->execute(); - - } catch (ApiException $e) { - $this->fail('Credit Card Tokenization failed ' . $e->getMessage()); - } - $tokenizedCard = new CreditCardData(); - $tokenizedCard->token = $response->token; - - $detokenizedCard = (new ManagementBuilder(TransactionType::DETOKENIZE, $tokenizedCard)) - ->withIdempotencyKey($this->idempotencyKey) - ->execute(); - - $this->assertNotNull($response); - $this->assertEquals($this->card->number, $detokenizedCard->cardNumber); - $this->assertEquals($this->card->expMonth, $detokenizedCard->cardExpMonth); - - try { - $tokenizedCard->detokenize(); - } catch (GatewayException $e) { - $this->assertEquals('40039', $e->responseCode); - $this->assertContains('Idempotency Key seen before', $e->getMessage()); - } - } - public function testCreditVerifyx() { $response = $this->card->verify() @@ -663,44 +602,6 @@ public function testCreditVerifyWithIdempotencyKey() $this->assertEquals('VERIFIED', $response->responseMessage); } - public function testCardTokenizationThenCardDetokenization() - { - try { - // process an auto-capture authorization - $response = $this->card->tokenize() - ->execute(); - - } catch (ApiException $e) { - $this->fail('Credit Card Tokenization failed ' . $e->getMessage()); - } - - $tokenId = $response->token; - - $tokenizedCard = new CreditCardData(); - $tokenizedCard->token = $tokenId; - - try { - $response = $tokenizedCard->detokenize(); - } catch (ApiException $e) { - $this->fail('Credit Card detokenization failed ' . $e->getMessage()); - } - - $this->assertEquals('SUCCESS', $response->responseCode); - } - - public function testCardDetokenization_WrongId() - { - $tokenizedCard = new CreditCardData(); - $tokenizedCard->token = "PMT_" . GenerationUtils::getGuid(); - - try { - $tokenizedCard->detokenize(); - } catch (ApiException $e) { - $this->assertEquals('40116', $e->responseCode); - $this->assertEquals('Status Code: RESOURCE_NOT_FOUND - payment_method ' . $tokenizedCard->token . ' not found at this location.', $e->getMessage()); - } - } - public function testCardTokenizationThenDeletion() { // process an auto-capture authorization diff --git a/test/Integration/Gateways/GpApiConnector/CreditCardPresentTest.php b/test/Integration/Gateways/GpApiConnector/CreditCardPresentTest.php index 6715c247..8834714a 100644 --- a/test/Integration/Gateways/GpApiConnector/CreditCardPresentTest.php +++ b/test/Integration/Gateways/GpApiConnector/CreditCardPresentTest.php @@ -511,9 +511,15 @@ public function testReauthorizedAnExistingTransaction() $transaction = new Transaction(); $transaction->transactionId = $result->transactionId; - $response = $transaction->reauthorized($result->amount)->execute(); + $reverse = $transaction->reverse()->execute(); + + $this->assertNotNull($reverse); + $this->assertEquals('SUCCESS', $reverse->responseCode); + $this->assertEquals(TransactionStatus::REVERSED, $reverse->responseMessage); + + $response = $reverse->reauthorized()->execute(); $this->assertNotNull($response); $this->assertEquals('SUCCESS', $response->responseCode); - $this->assertEquals(TransactionStatus::CAPTURED, $response->responseMessage); + $this->assertEquals(TransactionStatus::PREAUTHORIZED, $response->responseMessage); } } \ No newline at end of file diff --git a/test/Integration/Gateways/GpApiConnector/GpApi3DS1Test.php b/test/Integration/Gateways/GpApiConnector/GpApi3DS1Test.php index f7782c85..120ac226 100644 --- a/test/Integration/Gateways/GpApiConnector/GpApi3DS1Test.php +++ b/test/Integration/Gateways/GpApiConnector/GpApi3DS1Test.php @@ -264,13 +264,14 @@ public function testCardHolderEnrolled_PostResult() $authClient->setGatewayProvider($this->gatewayProvider); $authResponse = $authClient->authenticate_v1($secureEcom); $this->assertTrue($authResponse->getStatus()); + $this->assertNotEmpty($authResponse->getMerchantData()); $secureEcom = Secure3dService::getAuthenticationData() - ->withServerTransactionId($secureEcom->serverTransactionId) + ->withServerTransactionId($authResponse->getMerchantData()) ->withPayerAuthenticationResponse($authResponse->getAuthResponse()) ->execute(); - $this->assertEquals('AUTHENTICATION_SUCCESSFUL', $secureEcom->status); + $this->assertEquals('SUCCESS_AUTHENTICATED', $secureEcom->status); $this->assertTrue($secureEcom->challengeMandated); $this->assertNotNull($secureEcom->issuerAcsUrl); $this->assertNotNull($secureEcom->payerAuthenticationRequest); @@ -295,14 +296,15 @@ public function testCardHolderEnrolled_PostResult_WithIdempotencyKey() $authClient->setGatewayProvider($this->gatewayProvider); $authResponse = $authClient->authenticate_v1($secureEcom); $this->assertTrue($authResponse->getStatus()); + $this->assertNotEmpty($authResponse->getMerchantData()); $secureEcom = Secure3dService::getAuthenticationData() - ->withServerTransactionId($secureEcom->serverTransactionId) + ->withServerTransactionId($authResponse->getMerchantData()) ->withPayerAuthenticationResponse($authResponse->getAuthResponse()) ->withIdempotencyKey($idempotencyKey) ->execute(); - $this->assertEquals('AUTHENTICATION_SUCCESSFUL', $secureEcom->status); + $this->assertEquals('SUCCESS_AUTHENTICATED', $secureEcom->status); $this->assertTrue($secureEcom->challengeMandated); $this->assertNotNull($secureEcom->issuerAcsUrl); $this->assertNotNull($secureEcom->payerAuthenticationRequest); diff --git a/test/Integration/Gateways/GpApiConnector/GpApi3DS2Test.php b/test/Integration/Gateways/GpApiConnector/GpApi3DS2Test.php index 2d521acf..753f4552 100644 --- a/test/Integration/Gateways/GpApiConnector/GpApi3DS2Test.php +++ b/test/Integration/Gateways/GpApiConnector/GpApi3DS2Test.php @@ -177,13 +177,13 @@ public function testFullCycle_v2_FrictionlessFailed() ->execute(); $this->assertNotNull($initAuth); - $this->assertEquals('FAILED', $initAuth->status); + $this->assertEquals('NOT_AUTHENTICATED', $initAuth->status); $secureEcom = Secure3dService::getAuthenticationData() ->withServerTransactionId($secureEcom->serverTransactionId) ->execute(); $this->card->threeDSecure = $initAuth; - $this->assertEquals('FAILED', $secureEcom->status); + $this->assertEquals('NOT_AUTHENTICATED', $secureEcom->status); $response = $this->card->charge($this->amount)->withCurrency($this->currency)->execute(); $this->assertNotNull($response); @@ -270,9 +270,10 @@ public function testFullCycle_CardHolderEnrolled_ChallengeRequired_v2() $authClient->setGatewayProvider($this->gatewayProvider); $authResponse = $authClient->authenticate_v2($initAuth); $this->assertTrue($authResponse->getStatus()); + $this->assertNotEmpty($authResponse->getMerchantData()); $secureEcom = Secure3dService::getAuthenticationData() - ->withServerTransactionId($initAuth->serverTransactionId) + ->withServerTransactionId($authResponse->getMerchantData()) ->execute(); $this->card->threeDSecure = $secureEcom; @@ -595,9 +596,10 @@ public function testCardHolderChallengeRequired_PostResult() $authClient->setGatewayProvider($this->gatewayProvider); $authResponse = $authClient->authenticate_v2($initAuth); $this->assertTrue($authResponse->getStatus()); + $this->assertNotEmpty($authResponse->getMerchantData()); $secureEcom = Secure3dService::getAuthenticationData() - ->withServerTransactionId($secureEcom->serverTransactionId) + ->withServerTransactionId($authResponse->getMerchantData()) ->execute(); $this->assertEquals('SUCCESS_AUTHENTICATED', $secureEcom->status); @@ -637,9 +639,10 @@ public function testCardHolderChallengeRequired_PostResult_WithIdempotencyKey() $authClient->setGatewayProvider($this->gatewayProvider); $authResponse = $authClient->authenticate_v2($initAuth); $this->assertTrue($authResponse->getStatus()); + $this->assertNotEmpty($authResponse->getMerchantData()); $secureEcom = Secure3dService::getAuthenticationData() - ->withServerTransactionId($secureEcom->serverTransactionId) + ->withServerTransactionId($authResponse->getMerchantData()) ->withIdempotencyKey($idempotencyKey) ->execute(); diff --git a/test/Integration/Gateways/GpApiConnector/GpApi3DSecureTest.php b/test/Integration/Gateways/GpApiConnector/GpApi3DSecureTest.php index 82169522..fcd1c4a2 100644 --- a/test/Integration/Gateways/GpApiConnector/GpApi3DSecureTest.php +++ b/test/Integration/Gateways/GpApiConnector/GpApi3DSecureTest.php @@ -118,13 +118,14 @@ public function testCardHolderEnrolled_ChallengeRequired_AuthenticationSuccessfu $authClient->setGatewayProvider($this->gatewayProvider); $authResponse = $authClient->authenticate_v1($secureEcom); $this->assertTrue($authResponse->getStatus()); + $this->assertNotEmpty($authResponse->getMerchantData()); $secureEcom = Secure3dService::getAuthenticationData() - ->withServerTransactionId($secureEcom->serverTransactionId) + ->withServerTransactionId($authResponse->getMerchantData()) ->withPayerAuthenticationResponse($authResponse->getAuthResponse()) ->execute(); $this->card->threeDSecure = $secureEcom; - $this->assertEquals('AUTHENTICATION_SUCCESSFUL', $secureEcom->status); + $this->assertEquals('SUCCESS_AUTHENTICATED', $secureEcom->status); $response = $this->card->charge($this->amount)->withCurrency($this->currency)->execute(); $this->assertNotNull($response); @@ -155,13 +156,14 @@ public function testCardHolderEnrolled_ChallengeRequired_AuthenticationSuccessfu $authClient->setGatewayProvider($this->gatewayProvider); $authResponse = $authClient->authenticate_v1($secureEcom); $this->assertTrue($authResponse->getStatus()); + $this->assertNotEmpty($authResponse->getMerchantData()); $secureEcom = Secure3dService::getAuthenticationData() - ->withServerTransactionId($secureEcom->serverTransactionId) + ->withServerTransactionId($authResponse->getMerchantData()) ->withPayerAuthenticationResponse($authResponse->getAuthResponse()) ->execute(); $tokenizedCard->threeDSecure = $secureEcom; - $this->assertEquals('AUTHENTICATION_SUCCESSFUL', $secureEcom->status); + $this->assertEquals('SUCCESS_AUTHENTICATED', $secureEcom->status); $response = $tokenizedCard->charge($this->amount)->withCurrency($this->currency)->execute(); $this->assertNotNull($response); @@ -191,9 +193,10 @@ public function testCardHolderEnrolled_ChallengeRequired_AuthenticationFailed_v1 $authClient->setGatewayProvider($this->gatewayProvider); $authResponse = $authClient->authenticate_v1($secureEcom); $this->assertTrue($authResponse->getStatus()); + $this->assertNotEmpty($authResponse->getMerchantData()); $secureEcom = Secure3dService::getAuthenticationData() - ->withServerTransactionId($secureEcom->serverTransactionId) + ->withServerTransactionId($authResponse->getMerchantData()) ->withPayerAuthenticationResponse($authResponse->getAuthResponse()) ->execute(); $this->card->threeDSecure = $secureEcom; @@ -221,11 +224,12 @@ public function testCardHolderEnrolled_ChallengeRequired_AuthenticationFailed_v1 $authClient->setGatewayProvider($this->gatewayProvider); $authResponse = $authClient->authenticate_v1($secureEcom); $this->assertTrue($authResponse->getStatus()); + $this->assertNotEmpty($authResponse->getMerchantData()); $exceptionCaught = false; try { Secure3dService::getAuthenticationData() - ->withServerTransactionId($secureEcom->serverTransactionId) + ->withServerTransactionId($authResponse->getMerchantData()) ->withPayerAuthenticationResponse(GenerationUtils::getGuid()) ->execute(); } catch (ApiException $e) { @@ -391,9 +395,10 @@ public function testCardHolderEnrolled_ChallengeRequired_v2($cardNumber, $status $authClient->setGatewayProvider($this->gatewayProvider); $authResponse = $authClient->authenticate_v2($initAuth); $this->assertTrue($authResponse->getStatus()); + $this->assertNotEmpty($authResponse->getMerchantData()); $secureEcom = Secure3dService::getAuthenticationData() - ->withServerTransactionId($initAuth->serverTransactionId) + ->withServerTransactionId($authResponse->getMerchantData()) ->execute(); $this->card->threeDSecure = $secureEcom; @@ -440,18 +445,11 @@ public function testChallengeRequired_GetResultFailed_v2() $this->assertNotNull($initAuth->issuerAcsUrl); $this->assertNotNull($initAuth->challengeValue); - $exceptionCaught = false; - try { - Secure3dService::getAuthenticationData() + $secureEcom = Secure3dService::getAuthenticationData() ->withServerTransactionId($initAuth->serverTransactionId) ->execute(); - } catch (ApiException $e) { - $exceptionCaught = true; - $this->assertEquals('50012', $e->responseCode); - $this->assertEquals('Status Code: INVALID_REQUEST_DATA - Undefined element in Message before PARes', $e->getMessage()); - } finally { - $this->assertTrue($exceptionCaught); - } + $this->assertEquals('NOT_ENROLLED', $secureEcom->enrolled); + $this->assertEquals('CHALLENGE_REQUIRED', $secureEcom->status); } /** @@ -585,14 +583,16 @@ public function testCardHolderEnrolled_ChallengeRequired_v2_DuplicateAcsRequest( $authClient->setGatewayProvider($this->gatewayProvider); $authResponse = $authClient->authenticate_v2($initAuth); $this->assertTrue($authResponse->getStatus()); + $this->assertNotEmpty($authResponse->getMerchantData()); $authClient2 = new ThreeDSecureAcsClient($secureEcom->issuerAcsUrl); $authClient2->setGatewayProvider($this->gatewayProvider); $authResponse2 = $authClient2->authenticate_v2($initAuth); $this->assertTrue($authResponse2->getStatus()); + $this->assertNotEmpty($authResponse2->getMerchantData()); $secureEcom = Secure3dService::getAuthenticationData() - ->withServerTransactionId($initAuth->serverTransactionId) + ->withServerTransactionId($authResponse2->getMerchantData()) ->execute(); $this->card->threeDSecure = $secureEcom; @@ -615,9 +615,9 @@ public function ChallengeSuccessful3DSV2CardTests() public function ChallengeRequiredFailed3DSV1CardTests() { return [ - 'Acs Client result code 5' => [5, 'AUTHENTICATION_COULD_NOT_BE_PERFORMED'], - 'Acs Client result code 7' => [7, 'FAILED'], - 'Acs Client result code 9' => [9, 'AUTHENTICATION_FAILED'] + 'Acs Client result code 5' => [5, 'FAILED'], + 'Acs Client result code 7' => [7, 'SUCCESS_ATTEMPT_MADE'], + 'Acs Client result code 9' => [9, 'NOT_AUTHENTICATED'] ]; } @@ -634,12 +634,12 @@ public function FrictionlessSuccessful3DSV2CardTests() public function FrictionlessFailed3DSV2CardTests() { return [ - 'Frictionless failed 1' => [GpApi3DSTestCards::CARD_AUTH_ATTEMPTED_BUT_NOT_SUCCESSFUL_V2_1, 'NOT_AUTHENTICATED'], - 'Frictionless failed 2' => [GpApi3DSTestCards::CARD_AUTH_FAILED_V2_1, 'FAILED'], + 'Frictionless failed 1' => [GpApi3DSTestCards::CARD_AUTH_ATTEMPTED_BUT_NOT_SUCCESSFUL_V2_1, 'SUCCESS_ATTEMPT_MADE'], + 'Frictionless failed 2' => [GpApi3DSTestCards::CARD_AUTH_FAILED_V2_1, 'NOT_AUTHENTICATED'], 'Frictionless failed 3' => [GpApi3DSTestCards::CARD_AUTH_ISSUER_REJECTED_V2_1, 'FAILED'], 'Frictionless failed 4' => [GpApi3DSTestCards::CARD_AUTH_COULD_NOT_BE_PREFORMED_V2_1, 'FAILED'], - 'Frictionless failed 5' => [GpApi3DSTestCards::CARD_AUTH_ATTEMPTED_BUT_NOT_SUCCESSFUL_V2_2, 'NOT_AUTHENTICATED'], - 'Frictionless failed 6' => [GpApi3DSTestCards::CARD_AUTH_FAILED_V2_2, 'FAILED'], + 'Frictionless failed 5' => [GpApi3DSTestCards::CARD_AUTH_ATTEMPTED_BUT_NOT_SUCCESSFUL_V2_2, 'SUCCESS_ATTEMPT_MADE'], + 'Frictionless failed 6' => [GpApi3DSTestCards::CARD_AUTH_FAILED_V2_2, 'NOT_AUTHENTICATED'], 'Frictionless failed 7' => [GpApi3DSTestCards::CARD_AUTH_ISSUER_REJECTED_V2_2, 'FAILED'], 'Frictionless failed 8' => [GpApi3DSTestCards::CARD_AUTH_COULD_NOT_BE_PREFORMED_V2_2, 'FAILED'] ]; diff --git a/test/Integration/Gateways/GpApiConnector/ReportingActionsTest.php b/test/Integration/Gateways/GpApiConnector/ReportingActionsTest.php index c37c2263..c9f83bb3 100644 --- a/test/Integration/Gateways/GpApiConnector/ReportingActionsTest.php +++ b/test/Integration/Gateways/GpApiConnector/ReportingActionsTest.php @@ -1,14 +1,16 @@ execute(); $this->assertNotNull($response); - $this->assertInstanceOf( ActionSummary::class, $response); + $this->assertInstanceOf(ActionSummary::class, $response); $this->assertEquals($actionId, $response->id); } + public function testReportActionDetail_RandomId() + { + $actionId = GenerationUtils::getGuid(); + $exceptionCaught = false; + + try { + ReportingService::actionDetail($actionId) + ->execute(); + } catch (ApiException $e) { + $exceptionCaught = true; + $this->assertEquals('40118', $e->responseCode); + $this->assertEquals(sprintf('Status Code: RESOURCE_NOT_FOUND - Actions %s not found at this /ucp/actions/%s', $actionId, $actionId), $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } + public function testFindActions_By_StartDateAndEndDate() { - $startDate = (new \DateTime())->modify('-30 days')->setTime(0,0,0); - $endDate = (new \DateTime())->modify('-3 days')->setTime(0,0,0); + $startDate = (new \DateTime())->modify('-30 days')->setTime(0, 0, 0); + $endDate = (new \DateTime())->modify('-3 days')->setTime(0, 0, 0); $response = ReportingService::findActionsPaged(1, 10) ->orderBy(StoredPaymentMethodSortProperty::TIME_CREATED, SortDirection::ASC) @@ -52,7 +71,9 @@ public function testFindActions_By_StartDateAndEndDate() $this->assertNotNull($response); $this->assertTrue(is_array($response->result)); $actionsList = $response->result; - uasort($actionsList, function($a, $b) {return strcmp(($a->timeCreated)->format('Y-m-d H:i:s'), ($b->timeCreated)->format('Y-m-d H:i:s'));}); + uasort($actionsList, function ($a, $b) { + return strcmp(($a->timeCreated)->format('Y-m-d H:i:s'), ($b->timeCreated)->format('Y-m-d H:i:s')); + }); /** @var ActionSummary $rs */ foreach ($response->result as $index => $rs) { @@ -62,6 +83,34 @@ public function testFindActions_By_StartDateAndEndDate() } } + public function testFindActions_FilterBy_Id() + { + $id = 'ACT_p11JBFXHU9w2linA6IhMf5ccOoR50a'; + $response = ReportingService::findActionsPaged(1, 10) + ->where(SearchCriteria::ACTION_ID, $id) + ->execute(); + + $this->assertNotNull($response); + $this->assertTrue(is_array($response->result)); + + /** @var ActionSummary $rs */ + foreach ($response->result as $index => $rs) { + $this->assertEquals($id, $rs->id); + } + } + + public function testFindActions_FilterBy_RandomId() + { + $id = GenerationUtils::getGuid(); + $response = ReportingService::findActionsPaged(1, 10) + ->where(SearchCriteria::ACTION_ID, $id) + ->execute(); + + $this->assertNotNull($response); + $this->assertTrue(empty($response->result)); + $this->assertEquals(0, count($response->result)); + } + public function testFindActions_FilterBy_Type() { $actionType = 'PREAUTHORIZE'; @@ -78,6 +127,18 @@ public function testFindActions_FilterBy_Type() } } + public function testFindActions_FilterBy_RandomType() + { + $actionType = GenerationUtils::getGuid(); + $response = ReportingService::findActionsPaged(1, 10) + ->where(SearchCriteria::ACTION_TYPE, $actionType) + ->execute(); + + $this->assertNotNull($response); + $this->assertEmpty($response->result); + $this->assertEquals(0, count($response->result)); + } + public function testFindActions_FilterBy_Resource() { $resource = 'TRANSACTIONS'; @@ -109,4 +170,244 @@ public function testFindActions_FilterBy_ResourceStatus() $this->assertEquals($resourceStatus, $rs->resourceStatus); } } + + public function testFindActions_FilterBy_ResourceId() + { + $resourceId = 'ACT_tc888Ub0L0dthnPjOqrjeSnB4JflNF'; + $response = ReportingService::findActionsPaged(1, 10) + ->where(SearchCriteria::RESOURCE_ID, $resourceId) + ->execute(); + + $this->assertNotNull($response); + $this->assertTrue(is_array($response->result)); + $this->assertGreaterThanOrEqual(1, count($response->result)); + + /** @var ActionSummary $rs */ + foreach ($response->result as $index => $rs) { + $this->assertEquals($resourceId, $rs->resourceId); + } + } + + public function testFindActions_FilterBy_RandomResourceId() + { + $resourceId = GenerationUtils::getGuid(); + $response = ReportingService::findActionsPaged(1, 10) + ->where(SearchCriteria::RESOURCE_ID, $resourceId) + ->execute(); + + $this->assertNotNull($response); + $this->assertTrue(is_array($response->result)); + $this->assertEquals(0, count($response->result)); + } + + public function testFindActions_FilterBy_MerchantName() + { + $merchantName = 'Sandbox_merchant_2'; + $response = ReportingService::findActionsPaged(1, 10) + ->where(SearchCriteria::MERCHANT_NAME, $merchantName) + ->execute(); + + $this->assertNotNull($response); + $this->assertTrue(is_array($response->result)); + $this->assertGreaterThanOrEqual(1, count($response->result)); + + /** @var ActionSummary $rs */ + foreach ($response->result as $index => $rs) { + $this->assertEquals($merchantName, $rs->merchantName); + } + } + + public function testFindActions_FilterBy_RandomMerchantName() + { + $merchantName = GenerationUtils::getGuid(); + $exceptionCaught = false; + + try { + ReportingService::findActionsPaged(1, 10) + ->where(SearchCriteria::MERCHANT_NAME, $merchantName) + ->execute(); + } catch (ApiException $e) { + $exceptionCaught = true; + $this->assertEquals('40003', $e->responseCode); + $this->assertEquals('Status Code: ACTION_NOT_AUTHORIZED - Token does not match merchant_name in the request', $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } + + public function testFindActions_FilterBy_AccountName() + { +// $accountName = 'Transaction_Processing'; + $accountName = 'Tokenization'; +// $accountName = 'Settlement Reporting'; +// $accountName = 'Dispute Management'; + $response = ReportingService::findActionsPaged(1, 10) + ->where(SearchCriteria::ACCOUNT_NAME, $accountName) + ->execute(); + + $this->assertNotNull($response); + $this->assertTrue(is_array($response->result)); + $this->assertGreaterThanOrEqual(1, count($response->result)); + + /** @var ActionSummary $rs */ + foreach ($response->result as $index => $rs) { + $this->assertEquals($accountName, $rs->accountName); + } + } + + public function testFindActions_FilterBy_AppName() + { + $appName = 'demo_app'; + $response = ReportingService::findActionsPaged(1, 10) + ->where(SearchCriteria::APP_NAME, $appName) + ->execute(); + + $this->assertNotNull($response); + $this->assertTrue(is_array($response->result)); + $this->assertGreaterThanOrEqual(1, count($response->result)); + + /** @var ActionSummary $rs */ + foreach ($response->result as $index => $rs) { + $this->assertEquals($appName, $rs->appName); + } + } + + public function testFindActions_FilterBy_Version() + { + $version = '2020-04-10'; + $response = ReportingService::findActionsPaged(1, 10) + ->where(SearchCriteria::VERSION, $version) + ->execute(); + + $this->assertNotNull($response); + $this->assertTrue(is_array($response->result)); + $this->assertGreaterThanOrEqual(1, count($response->result)); + + /** @var ActionSummary $rs */ + foreach ($response->result as $index => $rs) { + $this->assertEquals($version, $rs->version); + } + } + + public function testFindActions_FilterBy_WrongVersion() + { + $version = '2020-05-10'; + $response = ReportingService::findActionsPaged(1, 10) + ->where(SearchCriteria::VERSION, $version) + ->execute(); + + $this->assertNotNull($response); + $this->assertTrue(is_array($response->result)); + $this->assertEquals(0, count($response->result)); + } + + public function testFindActions_FilterBy_ResponseCode() + { + $responseCode = 'DECLINED'; + $response = ReportingService::findActionsPaged(1, 10) + ->where(SearchCriteria::RESPONSE_CODE, $responseCode) + ->execute(); + + $this->assertNotNull($response); + $this->assertTrue(is_array($response->result)); + $this->assertGreaterThanOrEqual(1, count($response->result)); + + /** @var ActionSummary $rs */ + foreach ($response->result as $index => $rs) { + $this->assertEquals($responseCode, $rs->responseCode); + } + } + + public function testFindActions_FilterBy_HttpResponseCode() + { + $httpResponseCode = '200'; + $response = ReportingService::findActionsPaged(1, 10) + ->where(SearchCriteria::HTTP_RESPONSE_CODE, $httpResponseCode) + ->execute(); + + $this->assertNotNull($response); + $this->assertTrue(is_array($response->result)); + $this->assertGreaterThanOrEqual(1, count($response->result)); + + /** @var ActionSummary $rs */ + foreach ($response->result as $index => $rs) { + $this->assertEquals($httpResponseCode, $rs->httpResponseCode); + } + } + + public function testFindActions_FilterBy_502_HttpResponseCode() + { + $httpResponseCode = '502'; + $response = ReportingService::findActionsPaged(1, 10) + ->where(SearchCriteria::HTTP_RESPONSE_CODE, $httpResponseCode) + ->execute(); + + $this->assertNotNull($response); + $this->assertTrue(is_array($response->result)); + $this->assertGreaterThanOrEqual(1, count($response->result)); + + /** @var ActionSummary $rs */ + foreach ($response->result as $index => $rs) { + $this->assertEquals($httpResponseCode, $rs->httpResponseCode); + } + } + + public function testFindActions_OrderBy_TimeCreated() + { + $id = 'ACT_p11JBFXHU9w2linA6IhMf5ccOoR50a'; + $response = ReportingService::findActionsPaged(1, 10) + ->orderBy(StoredPaymentMethodSortProperty::TIME_CREATED, SortDirection::ASC) + ->where(SearchCriteria::ACTION_ID, $id) + ->execute(); + + $this->assertNotNull($response); + $this->assertTrue(is_array($response->result)); + + /** @var ActionSummary $rs */ + foreach ($response->result as $index => $rs) { + $this->assertEquals($id, $rs->id); + } + + $responseDesc = ReportingService::findActionsPaged(1, 10) + ->orderBy(StoredPaymentMethodSortProperty::TIME_CREATED, SortDirection::DESC) + ->where(SearchCriteria::ACTION_ID, $id) + ->execute(); + + $this->assertNotNull($responseDesc); + $this->assertTrue(is_array($responseDesc->result)); + + /** @var ActionSummary $rs */ + foreach ($responseDesc->result as $index => $rs) { + $this->assertEquals($id, $rs->id); + } + + $this->assertNotSame($response, $responseDesc); + } + + public function testFindActions_FilterBy_MultipleFilters() + { + $resource = 'TRANSACTIONS'; + $actionType = 'AUTHORIZE'; + $resource_status = 'DECLINED'; + $startDate = (new \DateTime())->modify('-30 days'); + $endDate = (new \DateTime())->modify('-3 days'); + + $response = ReportingService::findActionsPaged(1, 10) + ->where(SearchCriteria::RESOURCE, $resource) + ->andWith(SearchCriteria::ACTION_TYPE, $actionType) + ->andWith(SearchCriteria::RESOURCE_STATUS, $resource_status) + ->andWith(SearchCriteria::START_DATE, $startDate) + ->andWith(SearchCriteria::END_DATE, $endDate) + ->execute(); + + $this->assertNotNull($response); + $this->assertTrue(is_array($response->result)); + + /** @var ActionSummary $rs */ + foreach ($response->result as $index => $rs) { + $this->assertEquals($resource, $rs->resource); + $this->assertEquals($actionType, $rs->type); + $this->assertEquals($resource_status, $rs->resourceStatus); + } + } } \ No newline at end of file diff --git a/test/Integration/Gateways/GpApiConnector/ReportingStoredPaymentMethodsTest.php b/test/Integration/Gateways/GpApiConnector/ReportingStoredPaymentMethodsTest.php index d2ba19c1..689d0a7e 100644 --- a/test/Integration/Gateways/GpApiConnector/ReportingStoredPaymentMethodsTest.php +++ b/test/Integration/Gateways/GpApiConnector/ReportingStoredPaymentMethodsTest.php @@ -4,11 +4,13 @@ use GlobalPayments\Api\Entities\Enums\Environment; use GlobalPayments\Api\Entities\Enums\GpApi\SortDirection; use GlobalPayments\Api\Entities\Enums\GpApi\StoredPaymentMethodSortProperty; +use GlobalPayments\Api\Entities\Exceptions\GatewayException; use GlobalPayments\Api\Entities\Reporting\SearchCriteria; use GlobalPayments\Api\Entities\Reporting\StoredPaymentMethodSummary; use GlobalPayments\Api\ServiceConfigs\Gateways\GpApiConfig; use GlobalPayments\Api\Services\ReportingService; use GlobalPayments\Api\ServicesContainer; +use GlobalPayments\Api\Utils\GenerationUtils; use PHPUnit\Framework\TestCase; class ReportingStoredPaymentMethodsTest extends TestCase @@ -30,8 +32,8 @@ public function setUpConfig() public function testFindStoredPaymentMethod_By_StartDateAndEndDate() { - $startDate = (new \DateTime())->modify('-30 days')->setTime(0,0,0); - $endDate = (new \DateTime())->modify('-3 days')->setTime(0,0,0); + $startDate = (new \DateTime())->modify('-30 days')->setTime(0, 0, 0); + $endDate = (new \DateTime())->modify('-3 days')->setTime(0, 0, 0); $response = ReportingService::findStoredPaymentMethodsPaged(1, 10) ->orderBy(StoredPaymentMethodSortProperty::TIME_CREATED, SortDirection::ASC) @@ -42,7 +44,9 @@ public function testFindStoredPaymentMethod_By_StartDateAndEndDate() $this->assertNotNull($response); $this->assertTrue(is_array($response->result)); $paymentMethodsList = $response->result; - uasort($paymentMethodsList, function($a, $b) {return strcmp(($a->timeCreated)->format('Y-m-d H:i:s'), ($b->timeCreated)->format('Y-m-d H:i:s'));}); + uasort($paymentMethodsList, function ($a, $b) { + return strcmp(($a->timeCreated)->format('Y-m-d H:i:s'), ($b->timeCreated)->format('Y-m-d H:i:s')); + }); /** @var StoredPaymentMethodSummary $rs */ foreach ($response->result as $index => $rs) { @@ -54,8 +58,8 @@ public function testFindStoredPaymentMethod_By_StartDateAndEndDate() public function testFindStoredPaymentMethod_By_LastUpdated() { - $startDate = (new \DateTime())->modify('-30 days')->setTime(0,0,0); - $endDate = (new \DateTime())->modify('-3 days')->setTime(0,0,0); + $startDate = (new \DateTime())->modify('-30 days')->setTime(0, 0, 0); + $endDate = (new \DateTime())->modify('-3 days')->setTime(0, 0, 0); $response = ReportingService::findStoredPaymentMethodsPaged(1, 10) ->orderBy(StoredPaymentMethodSortProperty::TIME_CREATED, SortDirection::ASC) @@ -66,7 +70,52 @@ public function testFindStoredPaymentMethod_By_LastUpdated() $this->assertNotNull($response); $this->assertTrue(is_array($response->result)); $this->assertTrue(count($response->result) > 0); + } + + public function testFindStoredPaymentMethod_By_LastUpdated_CurrentDay() + { + $currentDay = (new \DateTime()); + + $response = ReportingService::findStoredPaymentMethodsPaged(1, 10) + ->orderBy(StoredPaymentMethodSortProperty::TIME_CREATED, SortDirection::ASC) + ->where(SearchCriteria::FROM_TIME_LAST_UPDATED, $currentDay) + ->andWith(SearchCriteria::TO_TIME_LAST_UPDATED, $currentDay) + ->execute(); + + $this->assertNotNull($response); + $this->assertTrue(is_array($response->result)); + $this->assertTrue(count($response->result) > 0); + } + + public function testFindStoredPaymentMethod_By_Id() + { + $paymentMethodId = 'PMT_3ad13ea3-6b43-4d1c-8075-aca4f61182ed'; + $response = ReportingService::findStoredPaymentMethodsPaged(1, 10) + ->orderBy(StoredPaymentMethodSortProperty::TIME_CREATED, SortDirection::ASC) + ->where(SearchCriteria::STORED_PAYMENT_METHOD_ID, $paymentMethodId) + ->execute(); + + $this->assertNotNull($response); + $this->assertTrue(is_array($response->result)); + /** @var StoredPaymentMethodSummary $rs */ + foreach ($response->result as $rs) { + $this->assertEquals($paymentMethodId, $rs->paymentMethodId); + } + } + + public function testFindStoredPaymentMethod_By_RandomId() + { + $paymentMethodId = 'PMT_' . GenerationUtils::getGuid(); + + $response = ReportingService::findStoredPaymentMethodsPaged(1, 10) + ->orderBy(StoredPaymentMethodSortProperty::TIME_CREATED, SortDirection::ASC) + ->where(SearchCriteria::STORED_PAYMENT_METHOD_ID, $paymentMethodId) + ->execute(); + + $this->assertNotNull($response); + $this->assertTrue(is_array($response->result)); + $this->assertCount(0, $response->result); } public function testFindStoredPaymentMethod_By_Status() @@ -86,6 +135,23 @@ public function testFindStoredPaymentMethod_By_Status() } } + public function testFindStoredPaymentMethod_By_Not_Active_Status() + { + $status = 'NOT_ACTIVE'; + $response = ReportingService::findStoredPaymentMethodsPaged(1, 10) + ->orderBy(StoredPaymentMethodSortProperty::TIME_CREATED, SortDirection::ASC) + ->where(SearchCriteria::STORED_PAYMENT_METHOD_STATUS, $status) + ->execute(); + + $this->assertNotNull($response); + $this->assertTrue(is_array($response->result)); + + /** @var StoredPaymentMethodSummary $rs */ + foreach ($response->result as $rs) { + $this->assertEquals($status, $rs->status); + } + } + public function testFindStoredPaymentMethod_By_CardNumberLastFour() { $cardNumberLastFour = '1112'; @@ -103,7 +169,37 @@ public function testFindStoredPaymentMethod_By_CardNumberLastFour() } } - public function testReportDisputeDetail() + public function testFindStoredPaymentMethod_By_CardNumberLastFour0000() + { + $cardNumberLastFour = '0000'; + $response = ReportingService::findStoredPaymentMethodsPaged(1, 10) + ->orderBy(StoredPaymentMethodSortProperty::TIME_CREATED, SortDirection::ASC) + ->where(SearchCriteria::CARD_NUMBER_LAST_FOUR, $cardNumberLastFour) + ->execute(); + + $this->assertNotNull($response); + $this->assertTrue(is_array($response->result)); + $this->assertCount(0, $response->result); + } + + public function testFindStoredPaymentMethod_By_Reference() + { + $reference = '5e3d3885-ceb3-a5ea-015c-945eaa4df8c8'; + $response = ReportingService::findStoredPaymentMethodsPaged(1, 10) + ->orderBy(StoredPaymentMethodSortProperty::TIME_CREATED, SortDirection::ASC) + ->where(SearchCriteria::REFERENCE_NUMBER, $reference) + ->execute(); + + $this->assertNotNull($response); + $this->assertTrue(is_array($response->result)); + + /** @var StoredPaymentMethodSummary $rs */ + foreach ($response->result as $rs) { + $this->assertEquals($reference, $rs->reference); + } + } + + public function testReportStoredPaymentMethodDetail() { $paymentMethodId = 'PMT_37c89e83-0349-4e19-add1-4b60d3c3d3ac'; $response = ReportingService::storedPaymentMethodDetail($paymentMethodId) @@ -113,4 +209,38 @@ public function testReportDisputeDetail() $this->assertInstanceOf(StoredPaymentMethodSummary::class, $response); $this->assertEquals($paymentMethodId, $response->paymentMethodId); } + + public function testReportStoredPaymentMethodDetail_NonExistentId() + { + $paymentMethodId = 'PMT_' . GenerationUtils::getGuid(); + $exceptionCaught = false; + + try { + ReportingService::storedPaymentMethodDetail($paymentMethodId) + ->execute(); + } catch (GatewayException $e) { + $exceptionCaught = true; + $this->assertEquals('40118', $e->responseCode); + $this->assertEquals(sprintf('Status Code: RESOURCE_NOT_FOUND - PAYMENT_METHODS %s not found at this /ucp/payment-methods/%s', $paymentMethodId, $paymentMethodId), $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } + + public function testReportStoredPaymentMethodDetail_RandomId() + { + $paymentMethodId = GenerationUtils::getGuid(); + $exceptionCaught = false; + + try { + ReportingService::storedPaymentMethodDetail($paymentMethodId) + ->execute(); + } catch (GatewayException $e) { + $exceptionCaught = true; + $this->assertEquals('40213', $e->responseCode); + $this->assertEquals(sprintf('Status Code: INVALID_REQUEST_DATA - payment_method.id: %s contains unexpected data', $paymentMethodId), $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } } \ No newline at end of file diff --git a/test/Integration/Gateways/ThreeDSecureAcsClient.php b/test/Integration/Gateways/ThreeDSecureAcsClient.php index 2e89f66c..05e88a9a 100644 --- a/test/Integration/Gateways/ThreeDSecureAcsClient.php +++ b/test/Integration/Gateways/ThreeDSecureAcsClient.php @@ -38,15 +38,14 @@ public function authenticate_v2(ThreeDSecure $secureEcom) switch ($this->gatewayProvider) { case GatewayProvider::GP_API: - array_push($kvps, ['key' => 'creq', 'value' => urlencode($secureEcom->payerAuthenticationRequest)]); - array_push($kvps, ['key' => 'threeDSSessionData', 'value' => urlencode($secureEcom->serverTransactionId)]); + array_push($kvps, ['key' => $secureEcom->messageType, 'value' => urlencode($secureEcom->payerAuthenticationRequest)]); $postData = $this->buildData($kvps); $header = [ "Content-Type: application/x-www-form-urlencoded", "cache-control: no-cache" ]; $verb = 'POST'; - $rawResponse = $this->sendRequest($verb, $postData, $header); + $this->sendRequest($verb, $postData, $header); $kvps = []; array_push($kvps, ['key' => 'get-status-type', 'value' => "true"]); do { @@ -57,7 +56,9 @@ public function authenticate_v2(ThreeDSecure $secureEcom) $rawResponse = $this->sendRequest($verb, '', $header); $kvps = []; - array_push($kvps, ['key' => 'cres', 'value' => urlencode($this->getInputValue($rawResponse, 'cres'))]); + $cres = $this->getInputValue($rawResponse, 'cres'); + array_push($kvps, ['key' => 'cres', 'value' => urlencode($cres)]); + $acsDecodedRS = json_decode(base64_decode($cres), true); $postData = $this->buildData($kvps); $this->serviceUrl = $this->getInputValue($rawResponse, null, 'ResForm'); $rawResponse = $this->sendRequest($verb, $postData, $header); @@ -68,6 +69,9 @@ public function authenticate_v2(ThreeDSecure $secureEcom) $status = !empty($rawResponse->success) ? $rawResponse->success : false; } $rValue->setStatus($status); + if (!empty($acsDecodedRS['threeDSServerTransID'])) { + $rValue->setMerchantData($acsDecodedRS['threeDSServerTransID']); + } break; default: return false; @@ -100,13 +104,14 @@ public function authenticate_v1(ThreeDSecure $secureEcom) array_push($kvps, ['key' => 'MD', 'value' => $this->getInputValue($rawResponse, 'MD')]); $postData = $this->buildData($kvps); $this->serviceUrl = $this->getInputValue($rawResponse, null, 'PAResForm'); - $rawResponse = $this->sendRequest($verb, $postData, $header); + $rawResponse2 = $this->sendRequest($verb, $postData, $header); $rValue = new AcsResponse(); - if ($this->isJson($rawResponse)) { - $rawResponse = json_decode($rawResponse); - $rValue->setStatus(!empty($rawResponse->success) ? $rawResponse->success : false); + if ($this->isJson($rawResponse2)) { + $rawResponse2 = json_decode($rawResponse2); + $rValue->setStatus(!empty($rawResponse2->success) ? $rawResponse2->success : false); $rValue->setAuthResponse($paRes); + $rValue->setMerchantData($this->getInputValue($rawResponse, 'MD')); } break; default: @@ -116,49 +121,6 @@ public function authenticate_v1(ThreeDSecure $secureEcom) return $rValue; } - public function authenticate_2($payerAuthRequest) - { - $kvps = []; - switch ($this->gatewayProvider) - { - case GatewayProvider::GP_API: - array_push($kvps, ['key' => 'challenge_value', 'value' => urlencode($payerAuthRequest)]); - $postData = $this->buildData($kvps); - $header = [ - "Content-Type: application/x-www-form-urlencoded", - "cache-control: no-cache" - ]; - $verb = 'POST'; - $rawResponse = $this->sendRequest($verb, $postData, $header); - $kvps = []; - array_push($kvps, ['key' => 'get-status-type', 'value' => "true"]); - do { - $postData = $this->buildData($kvps); - $rawResponse = $this->sendRequest($verb, $postData, $header); - sleep(5); - } while (trim($rawResponse) == 'IN_PROGRESS'); - $rawResponse = $this->sendRequest($verb, '', $header); - - $kvps = []; - array_push($kvps, ['key' => 'cres', 'value' => urlencode($this->getInputValue($rawResponse, 'cres'))]); - $postData = $this->buildData($kvps); - $this->serviceUrl = $this->getInputValue($rawResponse, null, 'ResForm'); - $rawResponse = $this->sendRequest($verb, $postData, $header); - $rValue = new AcsResponse(); - $status = false; - if ($this->isJson($rawResponse)) { - $rawResponse = json_decode($rawResponse); - $status = !empty($rawResponse->success) ? $rawResponse->success : false; - } - $rValue->setStatus($status); - break; - default: - return false; - } - - return $rValue; - } - /** * @return AcsResponse */ @@ -183,38 +145,6 @@ public function authenticate($payerAuthRequest, $merchantData = '') $rValue->setAuthResponse($this->getInputValue($rawResponse, 'PaRes')); $rValue->setMerchantData($this->getInputValue($rawResponse, 'MD')); break; - case GatewayProvider::GP_API: - array_push($kvps, ['key' => 'challenge_value', 'value' => urlencode($payerAuthRequest)]); - $postData = $this->buildData($kvps); - $header = [ - "Content-Type: application/x-www-form-urlencoded", - "cache-control: no-cache" - ]; - $verb = 'POST'; - $rawResponse = $this->sendRequest($verb, $postData, $header); - - $kvps = []; - array_push($kvps, ['key' => 'TermUrl', 'value' => urlencode($this->getInputValue($rawResponse, 'TermUrl'))]); - array_push($kvps, ['key' => 'MD', 'value' => $this->getInputValue($rawResponse, 'MD')]); - array_push($kvps, ['key' => 'PaReq', 'value' => urlencode($this->getInputValue($rawResponse, 'PaReq'))]); - array_push($kvps, ['key' => 'AuthenticationResultCode', 'value' => "0"]); - $postData = $this->buildData($kvps); - $this->serviceUrl = $this->getInputValue($rawResponse, null, 'PAResFormSim'); - $rawResponse = $this->sendRequest($verb, $postData, $header); - - $kvps = []; - array_push($kvps, ['key' => 'PaRes', 'value' => urlencode($this->getInputValue($rawResponse, 'PaRes'))]); - array_push($kvps, ['key' => 'MD', 'value' => $this->getInputValue($rawResponse, 'MD')]); - $postData = $this->buildData($kvps); - - $this->serviceUrl = $this->getInputValue($rawResponse, null, 'PAResForm'); - $rawResponse = $this->sendRequest($verb, $postData, $header); - $rValue = new AcsResponse(); - if ($this->isJson($rawResponse)) { - $rawResponse = json_decode($rawResponse); - $rValue->setStatus(!empty($rawResponse->success) ? $rawResponse->success : false); - } - break; default: return false; }