diff --git a/CHANGELOG.md b/CHANGELOG.md index d608355d..684b0f0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,14 @@ # Changelog -## Latest Version +## Latest Version - v10.1.1 (10/10/2023) +#### Enhancements: +- [GP-API] Add a new alternative payment method, ALIPAY +- [GP-ECOM] Limit what card types to accept for payment or storage (HPP & API) + * https://developer.globalpay.com/hpp/card-blocking + * https://developer.globalpay.com/api/card-blocking + +## v10.1.0 (09/21/2023) #### Enhancements: - [Verifone] P400: added initial Meet-In-The-Cloud connectivity support for this device - [GP-API]: Upload Merchant Documentation - https://developer.globalpay.com/api/merchants diff --git a/metadata.xml b/metadata.xml index 06751711..95afb276 100644 --- a/metadata.xml +++ b/metadata.xml @@ -1,3 +1,3 @@ - 10.1.0 + 10.1.1 \ No newline at end of file diff --git a/src/Builders/AuthorizationBuilder.php b/src/Builders/AuthorizationBuilder.php index 384e5969..3663c6e3 100644 --- a/src/Builders/AuthorizationBuilder.php +++ b/src/Builders/AuthorizationBuilder.php @@ -3,8 +3,8 @@ namespace GlobalPayments\Api\Builders; use GlobalPayments\Api\ServicesContainer; -use GlobalPayments\Api\Entities\{ - Address, +use GlobalPayments\Api\Entities\{Address, + BlockedCardType, Customer, AutoSubstantiation, EcommerceInfo, @@ -16,25 +16,24 @@ DccRateData, DecisionManager, Transaction}; -use GlobalPayments\Api\Entities\Enums\{ - AddressType, +use GlobalPayments\Api\Entities\Enums\{AddressType, AliasAction, BNPLShippingMethod, EmvFallbackCondition, EmvLastChipRead, InquiryType, FraudFilterMode, + MerchantCategory, PaymentMethodUsageMode, PhoneNumberType, RemittanceReferenceType, RecurringSequence, RecurringType, TransactionModifier, - TransactionType -}; + TransactionType}; use GlobalPayments\Api\PaymentMethods\{BankPayment, BNPL, EBTCardData, GiftCard, TransactionReference}; use GlobalPayments\Api\PaymentMethods\Interfaces\IPaymentMethod; -use GlobalPayments\Api\Entities\Exceptions\ArgumentException; +use GlobalPayments\Api\Entities\Exceptions\{ArgumentException,BuilderException}; class AuthorizationBuilder extends TransactionBuilder { @@ -506,6 +505,11 @@ class AuthorizationBuilder extends TransactionBuilder /** @var boolean */ public $maskedDataResponse; + public BlockedCardType $cardTypesBlocking; + + /** @var MerchantCategory */ + public string $merchantCategory; + /** * {@inheritdoc} * @@ -1512,4 +1516,25 @@ public function withMaskedDataResponse($value) return $this; } + + public function withBlockedCardType(BlockedCardType $cardTypesBlocking) : AuthorizationBuilder + { + $vars = get_object_vars($cardTypesBlocking); + if (empty(array_filter($vars))) { + $array = explode('\\', get_class($cardTypesBlocking)); + throw new BuilderException(sprintf('No properties set on the %s object', end($array))); + } + $this->cardTypesBlocking = $cardTypesBlocking; + + return $this; + } + + /** + * @param MerchantCategory $merchantCategory + */ + public function withMerchantCategory($merchantCategory) : AuthorizationBuilder + { + $this->merchantCategory = $merchantCategory; + return $this; + } } diff --git a/src/Builders/RequestBuilder/GpApi/GpApiAuthorizationRequestBuilder.php b/src/Builders/RequestBuilder/GpApi/GpApiAuthorizationRequestBuilder.php index 55bd16b5..e7601635 100644 --- a/src/Builders/RequestBuilder/GpApi/GpApiAuthorizationRequestBuilder.php +++ b/src/Builders/RequestBuilder/GpApi/GpApiAuthorizationRequestBuilder.php @@ -251,6 +251,7 @@ private function createFromAuthorizationBuilder($builder, GpApiConfig $config) $requestBody['convenience_amount'] = StringUtils::toNumeric($builder->convenienceAmount); $requestBody['cashback_amount'] = StringUtils::toNumeric($builder->cashBackAmount); $requestBody['ip_address'] = $builder->customerIpAddress; + $requestBody['merchant_category'] = $builder->merchantCategory ?? null; $requestBody['payment_method'] = $this->createPaymentMethodParam($builder, $config); $requestBody['risk_assessment'] = !empty($builder->fraudFilter) ? [$this->mapFraudManagement()] : null; if (!empty($builder->paymentLinkId)) { diff --git a/src/Builders/RequestBuilder/GpEcom/GpEcomAuthorizationRequestBuilder.php b/src/Builders/RequestBuilder/GpEcom/GpEcomAuthorizationRequestBuilder.php index 3183a71f..f1661acb 100644 --- a/src/Builders/RequestBuilder/GpEcom/GpEcomAuthorizationRequestBuilder.php +++ b/src/Builders/RequestBuilder/GpEcom/GpEcomAuthorizationRequestBuilder.php @@ -5,6 +5,7 @@ use DOMDocument; use GlobalPayments\Api\Builders\AuthorizationBuilder; use GlobalPayments\Api\Builders\BaseBuilder; +use GlobalPayments\Api\Entities\BlockedCardType; use GlobalPayments\Api\Entities\Enums\AlternativePaymentType; use GlobalPayments\Api\Entities\Enums\CvnPresenceIndicator; use GlobalPayments\Api\Entities\Enums\DccProcessor; @@ -247,6 +248,23 @@ public function buildRequest(BaseBuilder $builder, $config) $this->maskedValues = ProtectSensitiveData::hideValue('card.cvn.number', $card->cvn ?? ''); } $request->appendChild($cardElement); + if (!empty($builder->cardTypesBlocking)) { + $cardTypes = $builder->cardTypesBlocking; + $cardTypeBlock = $xml->createElement("blockcard"); + if (isset($cardTypes->commercialcredit)) { + $cardTypeBlock->appendChild($xml->createElement("commercialcredit", $cardTypes->commercialcredit)); + } + if (isset($cardTypes->commercialdebit)) { + $cardTypeBlock->appendChild($xml->createElement("commercialdebit", $cardTypes->commercialdebit)); + } + if (isset($cardTypes->consumercredit)) { + $cardTypeBlock->appendChild($xml->createElement("consumercredit", $cardTypes->consumercredit)); + } + if (isset($cardTypes->consumerdebit)) { + $cardTypeBlock->appendChild($xml->createElement("consumerdebit", $cardTypes->consumerdebit)); + } + $request->appendChild($cardTypeBlock); + } } // issueno $hash = ''; diff --git a/src/Entities/BlockedCardType.php b/src/Entities/BlockedCardType.php new file mode 100644 index 00000000..a0e886e7 --- /dev/null +++ b/src/Entities/BlockedCardType.php @@ -0,0 +1,11 @@ + */ + public array $blockCardTypes; + /** * Instantiates a new `HostedPaymentData` object. * @@ -136,5 +140,6 @@ class HostedPaymentData public function __construct() { $this->supplementaryData = []; + $this->blockCardTypes = []; } } diff --git a/src/Gateways/GpEcomConnector.php b/src/Gateways/GpEcomConnector.php index ff79420b..07499732 100644 --- a/src/Gateways/GpEcomConnector.php +++ b/src/Gateways/GpEcomConnector.php @@ -222,6 +222,7 @@ public function serializeRequest(AuthorizationBuilder $builder) if ($builder->amount !== null) { $this->setSerializeData('AMOUNT', $amount); } + $this->setSerializeData('CURRENCY', $builder->currency); $this->setSerializeData('TIMESTAMP', $timestamp); @@ -301,9 +302,12 @@ public function serializeRequest(AuthorizationBuilder $builder) $this->setSerializeData('HPP_TX_STATUS_URL', $hostedPaymentData->transactionStatusUrl); } if (!empty($hostedPaymentData->presetPaymentMethods)) { - $this->setSerializeData('PM_METHODS', implode( '|', $hostedPaymentData->presetPaymentMethods)); + $this->setSerializeData('PM_METHODS', implode('|', $hostedPaymentData->presetPaymentMethods)); } // end APMs Fields + if (!empty($hostedPaymentData->blockCardTypes)) { + $this->setSerializeData('BLOCK_CARD_TYPE', implode('|', $hostedPaymentData->blockCardTypes)); + } } elseif (isset($builder->customerId)) { $this->setSerializeData('CUST_NUM', $builder->customerId); } diff --git a/src/Mapping/GpApiMapping.php b/src/Mapping/GpApiMapping.php index d95dc188..9a9cb98e 100644 --- a/src/Mapping/GpApiMapping.php +++ b/src/Mapping/GpApiMapping.php @@ -875,7 +875,14 @@ public static function mapResponseAPM($response) $paymentMethodApm = $response->payment_method->apm; $apm->redirectUrl = !empty($response->payment_method->redirect_url) ? $response->payment_method->redirect_url : ($paymentMethodApm->redirect_url ?? null); - $apm->providerName = $paymentMethodApm->provider; + if (is_string($paymentMethodApm->provider)) { + $apm->providerName = $paymentMethodApm->provider; + } elseif (is_object($paymentMethodApm->provider)) { + $apm->providerName = strtolower($paymentMethodApm->provider->name) ?? null; + $apm->providerReference = $paymentMethodApm->provider->merchant_identifier ?? null; + $apm->timeCreatedReference = $paymentMethodApm->provider->time_created_reference ?? null; + } + $apm->accountHolderName = $paymentMethodApm->provider_payer_name ?? null; $apm->ack = $paymentMethodApm->ack ?? null; $apm->sessionToken = !empty($paymentMethodApm->session_token) ? $paymentMethodApm->session_token : null; diff --git a/test/Integration/Gateways/GpApiConnector/GpApiApmTest.php b/test/Integration/Gateways/GpApiConnector/GpApiApmTest.php index 43ef5960..a307d036 100644 --- a/test/Integration/Gateways/GpApiConnector/GpApiApmTest.php +++ b/test/Integration/Gateways/GpApiConnector/GpApiApmTest.php @@ -8,9 +8,12 @@ use GlobalPayments\Api\Entities\Enums\AddressType; use GlobalPayments\Api\Entities\Enums\AlternativePaymentType; use GlobalPayments\Api\Entities\Enums\Channel; +use GlobalPayments\Api\Entities\Enums\MerchantCategory; use GlobalPayments\Api\Entities\Enums\PaymentMethodType; use GlobalPayments\Api\Entities\Enums\PhoneNumberType; use GlobalPayments\Api\Entities\Enums\TransactionStatus; +use GlobalPayments\Api\Entities\Exceptions\BuilderException; +use GlobalPayments\Api\Entities\Exceptions\GatewayException; use GlobalPayments\Api\Entities\OrderDetails; use GlobalPayments\Api\Entities\Reporting\SearchCriteria; use GlobalPayments\Api\Entities\Reporting\TransactionSummary; @@ -373,4 +376,151 @@ public function testAPMPendingTransaction() $this->assertNotNull($response->alternativePaymentResponse->redirectUrl); $this->assertEquals(AlternativePaymentType::TEST_PAY, $response->alternativePaymentResponse->providerName); } + + public function testAlipay() + { + $paymentMethod = new AlternativePaymentMethod(AlternativePaymentType::ALIPAY); + $paymentMethod->returnUrl = 'https://example.com/returnUrl'; + $paymentMethod->statusUpdateUrl = 'https://example.com/statusUrl'; + $paymentMethod->country = 'US'; + $paymentMethod->accountHolderName = 'Jane Doe'; + + $response = $paymentMethod->charge(19.99) + ->withCurrency('HKD') + ->withMerchantCategory(MerchantCategory::OTHER) + ->execute(); + + $this->assertNotNull($response); + $this->assertEquals('SUCCESS', $response->responseCode); + $this->assertEquals(TransactionStatus::INITIATED, $response->responseMessage); + $this->assertNotNull($response->alternativePaymentResponse->redirectUrl); + $this->assertEquals(AlternativePaymentType::ALIPAY, $response->alternativePaymentResponse->providerName); + } + + public function testAlipay_MissingReturnUrl() + { + $paymentMethod = new AlternativePaymentMethod(AlternativePaymentType::ALIPAY); + $paymentMethod->statusUpdateUrl = 'https://example.com/statusUrl'; + $paymentMethod->country = 'US'; + $paymentMethod->accountHolderName = 'Jane Doe'; + + $exceptionCaught = false; + try { + $paymentMethod->charge(19.99) + ->withCurrency('HKD') + ->withMerchantCategory(MerchantCategory::OTHER) + ->execute(); + } catch (BuilderException $e) { + $exceptionCaught = true; + $this->assertEquals('returnUrl cannot be null for this transaction type.', $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } + + public function testAlipay_MissingStatusUrl() + { + $paymentMethod = new AlternativePaymentMethod(AlternativePaymentType::ALIPAY); + $paymentMethod->returnUrl = 'https://example.com/returnUrl'; + $paymentMethod->country = 'US'; + $paymentMethod->accountHolderName = 'Jane Doe'; + + $exceptionCaught = false; + try { + $paymentMethod->charge(19.99) + ->withCurrency('HKD') + ->withMerchantCategory(MerchantCategory::OTHER) + ->execute(); + } catch (BuilderException $e) { + $exceptionCaught = true; + $this->assertEquals('statusUpdateUrl cannot be null for this transaction type.', $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } + + public function testAlipay_MissingCountry() + { + $paymentMethod = new AlternativePaymentMethod(AlternativePaymentType::ALIPAY); + $paymentMethod->returnUrl = 'https://example.com/returnUrl'; + $paymentMethod->statusUpdateUrl = 'https://example.com/statusUrl'; + $paymentMethod->accountHolderName = 'Jane Doe'; + + $exceptionCaught = false; + try { + $paymentMethod->charge(19.99) + ->withCurrency('HKD') + ->withMerchantCategory(MerchantCategory::OTHER) + ->execute(); + } catch (BuilderException $e) { + $exceptionCaught = true; + $this->assertEquals('country cannot be null for this transaction type.', $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } + + public function testAlipay_MissingAccountHolderName() + { + $paymentMethod = new AlternativePaymentMethod(AlternativePaymentType::ALIPAY); + $paymentMethod->returnUrl = 'https://example.com/returnUrl'; + $paymentMethod->statusUpdateUrl = 'https://example.com/statusUrl'; + $paymentMethod->country = 'US'; + + $exceptionCaught = false; + try { + $paymentMethod->charge(19.99) + ->withCurrency('HKD') + ->withMerchantCategory(MerchantCategory::OTHER) + ->execute(); + } catch (BuilderException $e) { + $exceptionCaught = true; + $this->assertEquals('accountHolderName cannot be null for this transaction type.', $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } + + public function testAlipay_MissingCurrency() + { + $paymentMethod = new AlternativePaymentMethod(AlternativePaymentType::ALIPAY); + $paymentMethod->returnUrl = 'https://example.com/returnUrl'; + $paymentMethod->statusUpdateUrl = 'https://example.com/statusUrl'; + $paymentMethod->country = 'US'; + $paymentMethod->accountHolderName = 'Jane Doe'; + + $exceptionCaught = false; + try { + $paymentMethod->charge(19.99) + ->withMerchantCategory(MerchantCategory::OTHER) + ->execute(); + } catch (BuilderException $e) { + $exceptionCaught = true; + $this->assertEquals('currency cannot be null for this transaction type.', $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } + + public function testAlipay_MissingMerchantCategory() + { + $paymentMethod = new AlternativePaymentMethod(AlternativePaymentType::ALIPAY); + $paymentMethod->returnUrl = 'https://example.com/returnUrl'; + $paymentMethod->statusUpdateUrl = 'https://example.com/statusUrl'; + $paymentMethod->country = 'US'; + $paymentMethod->accountHolderName = 'Jane Doe'; + + $exceptionCaught = false; + try { + $paymentMethod->charge(19.99) + ->withCurrency('HKD') + ->execute(); + } catch (GatewayException $e) { + $exceptionCaught = true; + $this->assertEquals('Status Code: MANDATORY_DATA_MISSING - Request expects the following fields merchant_category', $e->getMessage()); + $this->assertEquals('40005', $e->responseCode); + } finally { + $this->assertTrue($exceptionCaught); + } + } } \ No newline at end of file diff --git a/test/Integration/Gateways/GpEcomConnector/CreditTest.php b/test/Integration/Gateways/GpEcomConnector/CreditTest.php index db243b57..8b228c26 100644 --- a/test/Integration/Gateways/GpEcomConnector/CreditTest.php +++ b/test/Integration/Gateways/GpEcomConnector/CreditTest.php @@ -2,6 +2,7 @@ namespace GlobalPayments\Api\Tests\Integration\Gateways\GpEcomConnector; +use GlobalPayments\Api\Entities\BlockedCardType; use GlobalPayments\Api\Entities\Exceptions\GatewayException; use GlobalPayments\Api\PaymentMethods\CreditCardData; use GlobalPayments\Api\Services\CreditService; @@ -313,4 +314,19 @@ public function testCreditAuthorizationSupplementaryData() $this->assertNotNull($capture); $this->assertEquals('00', $capture->responseCode, $capture->responseMessage); } + + public function testCardBlockingPaymentRequest() + { + $cardTypesBlocked = new BlockedCardType(); + $cardTypesBlocked->commercialdebit = true; + $cardTypesBlocked->consumerdebit = true; + + $authorization = $this->card->authorize(14) + ->withCurrency('USD') + ->withBlockedCardType($cardTypesBlocked) + ->execute(); + + $this->assertNotNull($authorization); + $this->assertEquals('00', $authorization->responseCode); + } } diff --git a/test/Integration/Gateways/GpEcomConnector/Hpp/GpEcomHppClient.php b/test/Integration/Gateways/GpEcomConnector/Hpp/GpEcomHppClient.php index f9b58a90..4a516c76 100644 --- a/test/Integration/Gateways/GpEcomConnector/Hpp/GpEcomHppClient.php +++ b/test/Integration/Gateways/GpEcomConnector/Hpp/GpEcomHppClient.php @@ -2,6 +2,7 @@ namespace GlobalPayments\Api\Tests\Integration\Gateways\GpEcomConnector\Hpp; use GlobalPayments\Api\Entities\AlternativePaymentResponse; +use GlobalPayments\Api\Entities\BlockedCardType; use GlobalPayments\Api\Entities\Enums\AlternativePaymentType; use GlobalPayments\Api\Entities\Enums\HostedPaymentMethods; use GlobalPayments\Api\Entities\Enums\ShaHashType; @@ -167,6 +168,16 @@ public function sendRequest($jsonData, $hppVersion = '') //handle fraud management $this->addFraudManagementInfo($gatewayRequest, $orderId); + if (!empty($this->getValue('BLOCK_CARD_TYPE'))) { + $cardTypes = explode("|", $this->getValue('BLOCK_CARD_TYPE')); + $cardTypesBlocking = new BlockedCardType(); + foreach ($cardTypes as $cardType) { + if (property_exists($cardTypesBlocking, $cardType)) { + $cardTypesBlocking->{$cardType} = true; + } + } + $gatewayRequest->withBlockedCardType($cardTypesBlocking); + } if ($card instanceof BankPayment) { $this->addRemittanceRef($gatewayRequest); diff --git a/test/Integration/Gateways/GpEcomConnector/HppTest.php b/test/Integration/Gateways/GpEcomConnector/HppTest.php index f6419cd5..805b1dc2 100644 --- a/test/Integration/Gateways/GpEcomConnector/HppTest.php +++ b/test/Integration/Gateways/GpEcomConnector/HppTest.php @@ -3,27 +3,29 @@ namespace GlobalPayments\Api\Tests\Integration\Gateways\GpEcomConnector; use GlobalPayments\Api\Entities\Address; +use GlobalPayments\Api\Entities\Enums\AddressType; use GlobalPayments\Api\Entities\Enums\AlternativePaymentType; use GlobalPayments\Api\Entities\Enums\BankPaymentStatus; +use GlobalPayments\Api\Entities\Enums\BlockCardType; +use GlobalPayments\Api\Entities\Enums\ChallengeRequestIndicator; +use GlobalPayments\Api\Entities\Enums\FraudFilterMode; +use GlobalPayments\Api\Entities\Enums\GatewayProvider; use GlobalPayments\Api\Entities\Enums\HostedPaymentMethods; +use GlobalPayments\Api\Entities\Enums\HppVersion; +use GlobalPayments\Api\Entities\Enums\RecurringSequence; +use GlobalPayments\Api\Entities\Enums\RecurringType; +use GlobalPayments\Api\Entities\Enums\RemittanceReferenceType; use GlobalPayments\Api\Entities\Enums\ShaHashType; use GlobalPayments\Api\Entities\Enums\TransactionStatus; use GlobalPayments\Api\Entities\Exceptions\BuilderException; +use GlobalPayments\Api\Entities\Exceptions\GatewayException; use GlobalPayments\Api\Entities\FraudRuleCollection; -use GlobalPayments\Api\PaymentMethods\BankPayment; -use GlobalPayments\Api\Services\HostedService; -use GlobalPayments\Api\HostedPaymentConfig; use GlobalPayments\Api\Entities\HostedPaymentData; -use GlobalPayments\Api\Entities\Enums\HppVersion; -use GlobalPayments\Api\Entities\Enums\RecurringSequence; -use GlobalPayments\Api\Entities\Enums\RecurringType; -use GlobalPayments\Api\Entities\Enums\AddressType; -use GlobalPayments\Api\Entities\Enums\FraudFilterMode; -use GlobalPayments\Api\Entities\Enums\GatewayProvider; +use GlobalPayments\Api\HostedPaymentConfig; +use GlobalPayments\Api\PaymentMethods\BankPayment; use GlobalPayments\Api\ServiceConfigs\Gateways\GpEcomConfig; +use GlobalPayments\Api\Services\HostedService; use GlobalPayments\Api\Tests\Integration\Gateways\GpEcomConnector\Hpp\GpEcomHppClient; -use GlobalPayments\Api\Entities\Enums\RemittanceReferenceType; -use GlobalPayments\Api\Entities\Enums\ChallengeRequestIndicator; use PHPUnit\Framework\TestCase; use RecursiveArrayIterator; use RecursiveIteratorIterator; @@ -40,7 +42,7 @@ class HppTest extends TestCase '' ]; - public function setup() : void + public function setup(): void { // billing address $this->billingAddress = new Address(); @@ -94,11 +96,11 @@ public function testCreditAuth() $service = new HostedService($config); $json = $service->authorize(1) - ->withCurrency("EUR") - ->withCustomerId("123456") - ->withAddress($address) - ->serialize(); - + ->withCurrency("EUR") + ->withCustomerId("123456") + ->withAddress($address) + ->serialize(); + $this->assertNotNull($json); $response = $client->sendRequest($json, $hppVersion); @@ -132,10 +134,10 @@ public function testCreditSale() $service = new HostedService($config); $json = $service->charge(1) - ->withCurrency("EUR") - ->withCustomerId("123456") - ->withAddress($address) - ->serialize(); + ->withCurrency("EUR") + ->withCustomerId("123456") + ->withAddress($address) + ->serialize(); $this->assertNotNull($json); $response = $client->sendRequest($json, $hppVersion); @@ -173,10 +175,10 @@ public function testCreditVerify() $service = new HostedService($config); $json = $service->verify() - ->withCurrency("EUR") - ->withCustomerId("123456") - ->withAddress($address) - ->serialize(); + ->withCurrency("EUR") + ->withCustomerId("123456") + ->withAddress($address) + ->serialize(); $this->assertNotNull($json); $response = $client->sendRequest($json, $hppVersion); @@ -256,9 +258,9 @@ public function testCardStorageCreatePayer() $service = new HostedService($config); $json = $service->charge(15) - ->withCurrency("EUR") - ->withHostedPaymentData($hostedPaymentData) - ->serialize(); + ->withCurrency("EUR") + ->withHostedPaymentData($hostedPaymentData) + ->serialize(); $this->assertNotNull($json); @@ -299,9 +301,9 @@ public function testCardStorageDisplayStoredCard() $service = new HostedService($config); $json = $service->charge(15) - ->withCurrency("EUR") - ->withHostedPaymentData($hostedPaymentData) - ->serialize(); + ->withCurrency("EUR") + ->withHostedPaymentData($hostedPaymentData) + ->serialize(); $this->assertNotNull($json); @@ -336,9 +338,9 @@ public function testContinuousAuthorityRequest() $service = new HostedService($config); $json = $service->charge(15) - ->withCurrency("EUR") - ->withRecurringInfo(RecurringType::FIXED, RecurringSequence::FIRST) - ->serialize(); + ->withCurrency("EUR") + ->withRecurringInfo(RecurringType::FIXED, RecurringSequence::FIRST) + ->serialize(); $this->assertNotNull($json); @@ -374,15 +376,15 @@ public function testEnableDynamicCurrencyConversionRequest() //serialize the request $json = $service->Charge(19) - ->withCurrency("EUR") - ->withTimestamp("20170725154824") - ->withOrderId('GTI5Yxb0SumL_TkDMCAxQA') - ->serialize(); - + ->withCurrency("EUR") + ->withTimestamp("20170725154824") + ->withOrderId('GTI5Yxb0SumL_TkDMCAxQA') + ->serialize(); + $this->assertNotNull($json); $this->assertEquals('{"MERCHANT_ID":"MerchantId","ACCOUNT":"internet","ORDER_ID":"GTI5Yxb0SumL_TkDMCAxQA","AMOUNT":"1900","CURRENCY":"EUR","TIMESTAMP":"20170725154824","AUTO_SETTLE_FLAG":"1","DCC_ENABLE":"1","HPP_LANG":"GB","MERCHANT_RESPONSE_URL":"http:\/\/requestb.in\/10q2bjb1","HPP_VERSION":"2","SHA1HASH":"448d742db89b05ce97152beb55157c904f3839cc"}', $json); } - + public function testDisableDynamicCurrencyConversionRequest() { //set config for DCC @@ -404,13 +406,13 @@ public function testDisableDynamicCurrencyConversionRequest() //serialize the request $json = $service->Charge(19) - ->withCurrency("EUR") - ->withTimestamp("20170725154824") - ->withOrderId('GTI5Yxb0SumL_TkDMCAxQA') - ->serialize(); - + ->withCurrency("EUR") + ->withTimestamp("20170725154824") + ->withOrderId('GTI5Yxb0SumL_TkDMCAxQA') + ->serialize(); + $this->assertNotNull($json); - $this->assertEquals($json, '{"MERCHANT_ID":"MerchantId","ACCOUNT":"internet","ORDER_ID":"GTI5Yxb0SumL_TkDMCAxQA","AMOUNT":"1900","CURRENCY":"EUR","TIMESTAMP":"20170725154824","AUTO_SETTLE_FLAG":"1","DCC_ENABLE":"0","HPP_LANG":"GB","MERCHANT_RESPONSE_URL":"http:\/\/requestb.in\/10q2bjb1","HPP_VERSION":"2","SHA1HASH":"448d742db89b05ce97152beb55157c904f3839cc"}'); + $this->assertEquals($json, '{"MERCHANT_ID":"MerchantId","ACCOUNT":"internet","ORDER_ID":"GTI5Yxb0SumL_TkDMCAxQA","AMOUNT":"1900","CURRENCY":"EUR","TIMESTAMP":"20170725154824","AUTO_SETTLE_FLAG":"1","DCC_ENABLE":"0","HPP_LANG":"GB","MERCHANT_RESPONSE_URL":"http:\/\/requestb.in\/10q2bjb1","HPP_VERSION":"2","SHA1HASH":"448d742db89b05ce97152beb55157c904f3839cc"}'); } /* 11. FraudManagementRequest */ @@ -431,7 +433,7 @@ public function testFraudManagementRequest() $service = new HostedService($config); $client = new GpEcomHppClient("secret"); - + // data to be passed to the HPP along with transaction level settings $hostedPaymentData = new HostedPaymentData(); $hostedPaymentData->customerNumber = "E8953893489"; // display the save card tick box @@ -439,13 +441,13 @@ public function testFraudManagementRequest() //serialize the request $json = $service->charge(19) - ->withCurrency("EUR") - ->withAddress($this->billingAddress, AddressType::BILLING) - ->withAddress($this->shippingAddress, AddressType::SHIPPING) - ->withClientTransactionId("Car Part HV") // varref - ->withCustomerIpAddress("123.123.123.123") - ->withHostedPaymentData($hostedPaymentData) - ->serialize(); + ->withCurrency("EUR") + ->withAddress($this->billingAddress, AddressType::BILLING) + ->withAddress($this->shippingAddress, AddressType::SHIPPING) + ->withClientTransactionId("Car Part HV") // varref + ->withCustomerIpAddress("123.123.123.123") + ->withHostedPaymentData($hostedPaymentData) + ->serialize(); $this->assertNotNull($json); @@ -535,10 +537,10 @@ public function testBasicAuthHppVersion1() $client = new GpEcomHppClient("secret"); $json = $service->authorize(19.99) - ->withCurrency("EUR") - ->withTimeStamp("20170725154824") - ->WithOrderId("GTI5Yxb0SumL_TkDMCAxQA") - ->serialize(); + ->withCurrency("EUR") + ->withTimeStamp("20170725154824") + ->WithOrderId("GTI5Yxb0SumL_TkDMCAxQA") + ->serialize(); $expectedJson = '{"MERCHANT_ID":"TWVyY2hhbnRJZA==","ACCOUNT":"aW50ZXJuZXQ=","ORDER_ID":"R1RJNVl4YjBTdW1MX1RrRE1DQXhRQQ==","AMOUNT":"MTk5OQ==","CURRENCY":"RVVS","TIMESTAMP":"MjAxNzA3MjUxNTQ4MjQ=","AUTO_SETTLE_FLAG":"MA==","HPP_LANG":"R0I=","MERCHANT_RESPONSE_URL":"aHR0cHM6Ly93d3cuZXhhbXBsZS5jb20vcmVzcG9uc2U=","HPP_VERSION":"MQ==","HPP_POST_DIMENSIONS":"aHR0cHM6Ly93d3cuZXhhbXBsZS5jb20=","HPP_POST_RESPONSE":"aHR0cHM6Ly93d3cuZXhhbXBsZS5jb20=","SHA1HASH":"MDYxNjA5Zjg1YThlMDE5MWRjN2Y0ODdmODI3OGU3MTg5OGEyZWUyZA=="}'; $this->assertEquals($json, $expectedJson); @@ -561,10 +563,10 @@ public function testBasicAuthHppVersion2() $client = new GpEcomHppClient("secret"); $json = $service->authorize(19.99) - ->withCurrency("EUR") - ->withTimeStamp("20170725154824") - ->WithOrderId("GTI5Yxb0SumL_TkDMCAxQA") - ->serialize(); + ->withCurrency("EUR") + ->withTimeStamp("20170725154824") + ->WithOrderId("GTI5Yxb0SumL_TkDMCAxQA") + ->serialize(); $expectedJson = '{"MERCHANT_ID":"MerchantId","ACCOUNT":"internet","ORDER_ID":"GTI5Yxb0SumL_TkDMCAxQA","AMOUNT":"1999","CURRENCY":"EUR","TIMESTAMP":"20170725154824","AUTO_SETTLE_FLAG":"0","HPP_LANG":"GB","MERCHANT_RESPONSE_URL":"https:\/\/www.example.com\/response","HPP_VERSION":"2","SHA1HASH":"061609f85a8e0191dc7f487f8278e71898a2ee2d"}'; $this->assertEquals($json, $expectedJson); @@ -587,10 +589,10 @@ public function testBasicSale() $client = new GpEcomHppClient("secret"); $json = $service->charge(19.99) - ->withCurrency("EUR") - ->withTimeStamp("20170725154824") - ->WithOrderId("GTI5Yxb0SumL_TkDMCAxQA") - ->serialize(); + ->withCurrency("EUR") + ->withTimeStamp("20170725154824") + ->WithOrderId("GTI5Yxb0SumL_TkDMCAxQA") + ->serialize(); $expectedJson = '{"MERCHANT_ID":"MerchantId","ACCOUNT":"internet","ORDER_ID":"GTI5Yxb0SumL_TkDMCAxQA","AMOUNT":"1999","CURRENCY":"EUR","TIMESTAMP":"20170725154824","AUTO_SETTLE_FLAG":"1","HPP_LANG":"GB","MERCHANT_RESPONSE_URL":"https:\/\/www.example.com\/response","HPP_VERSION":"2","SHA1HASH":"061609f85a8e0191dc7f487f8278e71898a2ee2d"}'; $this->assertEquals($json, $expectedJson); @@ -619,13 +621,13 @@ public function testBasicHostedPaymentDataHppVersion1() $hostedPaymentData->productId = 'a0b38df5-b23c-4d82-88fe-2e9c47438972-b23c-4d82-88f'; $json = $service->charge(19.99) - ->withCurrency("EUR") - ->withTimeStamp("20170725154824") - ->WithOrderId("GTI5Yxb0SumL_TkDMCAxQA") - ->WithHostedPaymentData($hostedPaymentData) - ->WithDescription("Mobile Channel") - ->WithClientTransactionId("My Legal Entity") - ->serialize(); + ->withCurrency("EUR") + ->withTimeStamp("20170725154824") + ->WithOrderId("GTI5Yxb0SumL_TkDMCAxQA") + ->WithHostedPaymentData($hostedPaymentData) + ->WithDescription("Mobile Channel") + ->WithClientTransactionId("My Legal Entity") + ->serialize(); $expectedJson = '{"MERCHANT_ID":"TWVyY2hhbnRJZA==","ACCOUNT":"aW50ZXJuZXQ=","ORDER_ID":"R1RJNVl4YjBTdW1MX1RrRE1DQXhRQQ==","AMOUNT":"MTk5OQ==","CURRENCY":"RVVS","TIMESTAMP":"MjAxNzA3MjUxNTQ4MjQ=","AUTO_SETTLE_FLAG":"MQ==","COMMENT1":"TW9iaWxlIENoYW5uZWw=","CUST_NUM":"YTAyODc3NGYtYmVmZi00N2JjLWJkNmUtZWQ3ZTA0ZjVkNzU4YTAyODc3NGYtYnRlZmE=","OFFER_SAVE_CARD":"MQ==","PAYER_EXIST":"MA==","PROD_ID":"YTBiMzhkZjUtYjIzYy00ZDgyLTg4ZmUtMmU5YzQ3NDM4OTcyLWIyM2MtNGQ4Mi04OGY=","VAR_REF":"TXkgTGVnYWwgRW50aXR5","HPP_LANG":"R0I=","MERCHANT_RESPONSE_URL":"aHR0cHM6Ly93d3cuZXhhbXBsZS5jb20vcmVzcG9uc2U=","HPP_VERSION":"MQ==","SHA1HASH":"NzExNmM0OTgyNjM2N2M2NTEzZWZkYzBjYzgxZTI0M2I4MDk1ZDc4Zg=="}'; $this->assertEquals($json, $expectedJson); @@ -654,13 +656,13 @@ public function testBasicHostedPaymentDataHppVersion2() $hostedPaymentData->productId = 'a0b38df5-b23c-4d82-88fe-2e9c47438972-b23c-4d82-88f'; $json = $service->charge(19.99) - ->withCurrency("EUR") - ->withTimeStamp("20170725154824") - ->WithOrderId("GTI5Yxb0SumL_TkDMCAxQA") - ->WithHostedPaymentData($hostedPaymentData) - ->WithDescription("Mobile Channel") - ->WithClientTransactionId("My Legal Entity") - ->serialize(); + ->withCurrency("EUR") + ->withTimeStamp("20170725154824") + ->WithOrderId("GTI5Yxb0SumL_TkDMCAxQA") + ->WithHostedPaymentData($hostedPaymentData) + ->WithDescription("Mobile Channel") + ->WithClientTransactionId("My Legal Entity") + ->serialize(); $expectedJson = '{"MERCHANT_ID":"MerchantId","ACCOUNT":"internet","ORDER_ID":"GTI5Yxb0SumL_TkDMCAxQA","AMOUNT":"1999","CURRENCY":"EUR","TIMESTAMP":"20170725154824","AUTO_SETTLE_FLAG":"1","COMMENT1":"Mobile Channel","CUST_NUM":"a028774f-beff-47bc-bd6e-ed7e04f5d758a028774f-btefa","OFFER_SAVE_CARD":"1","PAYER_EXIST":"0","PROD_ID":"a0b38df5-b23c-4d82-88fe-2e9c47438972-b23c-4d82-88f","VAR_REF":"My Legal Entity","HPP_LANG":"GB","MERCHANT_RESPONSE_URL":"https:\/\/www.example.com\/response","HPP_VERSION":"2","SHA1HASH":"7116c49826367c6513efdc0cc81e243b8095d78f"}'; $this->assertEquals($json, $expectedJson); @@ -689,11 +691,11 @@ public function testParseResponse() $service = new HostedService($config); $json = $service->authorize(1) - ->withCurrency("EUR") - ->withCustomerId("123456") - ->withAddress($address) - ->serialize(); - + ->withCurrency("EUR") + ->withCustomerId("123456") + ->withAddress($address) + ->serialize(); + $this->assertNotNull($json); $response = $client->sendRequest($json, $hppVersion); @@ -714,7 +716,7 @@ public function testParseResponse() } } - public function testHostedPaymentDataSupplementaryDataSerialize() + public function testHostedPaymentDataSupplementaryDataSerialize() { $config = new GpEcomConfig(); $config->merchantId = "MerchantId"; @@ -750,7 +752,8 @@ public function testHostedPaymentDataSupplementaryDataSerialize() $this->assertEquals($json, $expectedJson); } - public function testSupplementaryDataWithOneValueSerialized() { + public function testSupplementaryDataWithOneValueSerialized() + { $config = new GpEcomConfig(); $config->merchantId = "MerchantId"; $config->accountId = "internet"; @@ -785,7 +788,7 @@ public function testSupplementaryDataWithOneValueSerialized() { $this->assertEquals($json, $expectedJson); } - public function testSupplementaryDataWithTwoValuesSerialized() + public function testSupplementaryDataWithTwoValuesSerialized() { $config = new GpEcomConfig(); $config->merchantId = "MerchantId"; @@ -852,6 +855,84 @@ public function testNetherlandsAntillesCountry() $this->assertEquals('530', $response['HPP_BILLING_COUNTRY']); } + public function testCardBlockingPayment() + { + $config = new GpEcomConfig(); + $config->merchantId = "heartlandgpsandbox"; + $config->accountId = "hpp"; + $config->sharedSecret = "secret"; + $config->serviceUrl = "https://pay.sandbox.realexpayments.com/pay"; + + $config->hostedPaymentConfig = new HostedPaymentConfig(); + $config->hostedPaymentConfig->version = HppVersion::VERSION_2; + + $service = new HostedService($config); + + $hostedPaymentData = new HostedPaymentData(); + $hostedPaymentData->customerCountry = 'DE'; + $hostedPaymentData->customerFirstName = 'James'; + $hostedPaymentData->customerLastName = 'Mason'; + $hostedPaymentData->merchantResponseUrl = 'https://www.example.com/returnUrl'; + $hostedPaymentData->transactionStatusUrl = 'https://www.example.com/statusUrl'; + $blockCardTypes = [BlockCardType::COMMERCIAL_CREDIT, BlockCardType::COMMERCIAL_DEBIT]; + $hostedPaymentData->blockCardTypes = $blockCardTypes; + + $json = $service->charge(10.01) + ->withCurrency("EUR") + ->withHostedPaymentData($hostedPaymentData) + ->serialize(); + $response = json_decode($json, true); + $this->assertEquals(implode('|', $blockCardTypes), $response['BLOCK_CARD_TYPE']); + + $client = new GpEcomHppClient("secret"); + $response = $client->sendRequest($json, $config->hostedPaymentConfig->version); + $parsedResponse = $service->parseResponse($response); + + $this->assertEquals("00", $parsedResponse->responseCode); + } + + public function testCardBlockingPayment_AllCardTypes() + { + $config = new GpEcomConfig(); + $config->merchantId = "heartlandgpsandbox"; + $config->accountId = "hpp"; + $config->sharedSecret = "secret"; + $config->serviceUrl = "https://pay.sandbox.realexpayments.com/pay"; + + $config->hostedPaymentConfig = new HostedPaymentConfig(); + $config->hostedPaymentConfig->version = HppVersion::VERSION_2; + + $service = new HostedService($config); + + $hostedPaymentData = new HostedPaymentData(); + $hostedPaymentData->customerCountry = 'DE'; + $hostedPaymentData->customerFirstName = 'James'; + $hostedPaymentData->customerLastName = 'Mason'; + $hostedPaymentData->merchantResponseUrl = 'https://www.example.com/returnUrl'; + $hostedPaymentData->transactionStatusUrl = 'https://www.example.com/statusUrl'; + $blockCardTypes = [BlockCardType::CONSUMER_CREDIT, BlockCardType::CONSUMER_DEBIT, BlockCardType::COMMERCIAL_CREDIT, BlockCardType::COMMERCIAL_DEBIT]; + $hostedPaymentData->blockCardTypes = $blockCardTypes; + + $json = $service->charge(10.01) + ->withCurrency("EUR") + ->withHostedPaymentData($hostedPaymentData) + ->serialize(); + $response = json_decode($json, true); + $this->assertEquals(implode('|', $blockCardTypes), $response['BLOCK_CARD_TYPE']); + + $client = new GpEcomHppClient("secret"); + + $exceptionCaught = false; + try { + $client->sendRequest($json, $config->hostedPaymentConfig->version); + } catch (GatewayException $e) { + $exceptionCaught = true; + $this->assertEquals('Unexpected Gateway Response: 561 - All card types are blocked, invalid request', $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } + /** * We can set multiple APMs/LPMs on $presetPaymentMethods, but our HppClient for testing will treat only the first * entry from the list as an example for our unit test, in this case will be "sofort" diff --git a/test/Integration/Gateways/GpEcomConnector/HppTestCase.php b/test/Integration/Gateways/GpEcomConnector/HppTestCase.php index 1569aa07..7d145996 100644 --- a/test/Integration/Gateways/GpEcomConnector/HppTestCase.php +++ b/test/Integration/Gateways/GpEcomConnector/HppTestCase.php @@ -151,7 +151,7 @@ public function testCardStorageDisplayStoredCardsResponse() // TODO: grab the response JSON from the client-side for example: //sample response JSON: - $responseJson = array("MERCHANT_ID" => "MerchantId", "ACCOUNT" => "internet", "ORDER_ID" => "GTI5Yxb0SumL_TkDMCAxQA", "AMOUNT" => "1999", "TIMESTAMP" => "20170725154824", "SHA1HASH" => "843680654f377bfa845387fdbace35acc9d95778", "RESULT" => "00", "AUTHCODE" => "12345", "CARD_PAYMENT_BUTTON" => "Place Order", "AVSADDRESSRESULT" => "M", "AVSPOSTCODERESULT" => "M", "BATCHID" => "445196", "MESSAGE" => "[ test system ] Authorised", "PASREF" => "15011597872195765", "CVNRESULT" => "M", "HPP_FRAUDFILTER_RESULT" => "PASS", "HPP_CHOSEN_PMT_REF" => "099efeb4-eda2-4fd7-a04d-29647bb6c51d", "HPP_EDITED_PMT_REF" => "037bd26a-c76b-4ee4-8063-376d8858f23d", "HPP_DELETED_PMT_REF" => "3db4c72c-cd95-4743-8070-f17e2b56b642"); + $responseJson = array("MERCHANT_ID" => "MerchantId", "ACCOUNT" => "internet", "MERCHANT_RESPONSE_URL" => "http://requestb.in/10q2bjb1" ,"ORDER_ID" => "GTI5Yxb0SumL_TkDMCAxQA", "AMOUNT" => "1999", "TIMESTAMP" => "20170725154824", "SHA1HASH" => "843680654f377bfa845387fdbace35acc9d95778", "RESULT" => "00", "AUTHCODE" => "12345", "CARD_PAYMENT_BUTTON" => "Place Order", "AVSADDRESSRESULT" => "M", "AVSPOSTCODERESULT" => "M", "BATCHID" => "445196", "MESSAGE" => "[ test system ] Authorised", "PASREF" => "15011597872195765", "CVNRESULT" => "M", "HPP_FRAUDFILTER_RESULT" => "PASS", "HPP_CHOSEN_PMT_REF" => "099efeb4-eda2-4fd7-a04d-29647bb6c51d", "HPP_EDITED_PMT_REF" => "037bd26a-c76b-4ee4-8063-376d8858f23d", "HPP_DELETED_PMT_REF" => "3db4c72c-cd95-4743-8070-f17e2b56b642"); $parsedResponse = $service->parseResponse(json_encode($responseJson)); $responseCode = $parsedResponse->responseCode; // 00 @@ -183,7 +183,7 @@ public function testFraudManagementResponse() // TODO: grab the response JSON from the client-side for example: //sample response JSON: - $responseJson = array("MERCHANT_ID" => "MerchantId", "ACCOUNT" => "internet", "ORDER_ID" => "GTI5Yxb0SumL_TkDMCAxQA", "AMOUNT" => "1999", "TIMESTAMP" => "20170725154824", "SHA1HASH" => "843680654f377bfa845387fdbace35acc9d95778", "RESULT" => "00", "AUTHCODE" => "12345", "CARD_PAYMENT_BUTTON" => "Place Order", "AVSADDRESSRESULT" => "M", "AVSPOSTCODERESULT" => "M", "BATCHID" => "445196", "MESSAGE" => "[ test system ] Authorised", "PASREF" => "15011597872195765", "CVNRESULT" => "M", "HPP_FRAUDFILTER_RESULT" => "HOLD", "HPP_FRAUDFILTER_RULE_56257838-4590-4227-b946-11e061fb15fe" => "HOLD", "HPP_FRAUDFILTER_RULE_cf609cf9-9e5a-4700-ac69-8aa09c119305" => "PASS"); + $responseJson = array("MERCHANT_ID" => "MerchantId", "ACCOUNT" => "internet","MERCHANT_RESPONSE_URL" => "http://requestb.in/10q2bjb1", "ORDER_ID" => "GTI5Yxb0SumL_TkDMCAxQA", "AMOUNT" => "1999", "TIMESTAMP" => "20170725154824", "SHA1HASH" => "843680654f377bfa845387fdbace35acc9d95778", "RESULT" => "00", "AUTHCODE" => "12345", "CARD_PAYMENT_BUTTON" => "Place Order", "AVSADDRESSRESULT" => "M", "AVSPOSTCODERESULT" => "M", "BATCHID" => "445196", "MESSAGE" => "[ test system ] Authorised", "PASREF" => "15011597872195765", "CVNRESULT" => "M", "HPP_FRAUDFILTER_RESULT" => "HOLD", "HPP_FRAUDFILTER_RULE_56257838-4590-4227-b946-11e061fb15fe" => "HOLD", "HPP_FRAUDFILTER_RULE_cf609cf9-9e5a-4700-ac69-8aa09c119305" => "PASS"); $parsedResponse = $service->parseResponse(json_encode($responseJson)); $responseCode = $parsedResponse->responseCode; // 00