diff --git a/CHANGELOG.md b/CHANGELOG.md index c32706db..843fbe96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ ## Latest version #### Enhancements: +- GP-API: Add mapping for some missing fields on response 3DS2 initiate step +- GP-ECOM: Add missing optional fields HPP_CUSTOMER_PHONENUMBER_HOME and HPP_CUSTOMER_PHONENUMBER_WORK +- Update Open Banking endpoints + +## v4.0.3 (06/28/2022) +#### Enhancements: - Add autoloader standalone - Add end-to-end example for GP-API with HF and 3DS2 - Refacto on the folder structure in examples @@ -25,6 +31,7 @@ - GP-ECOM/GP-API: Structure refacto - Upgrade to min PHP 7.1 - GP-API: Add example with Google Pay +- GP-API: Add Dynamic Descriptor for authorize and charge ## v3.1.1 (05/17/2022) #### Enhancements: diff --git a/examples/gp-ecom/hpp/get-json.php b/examples/gp-ecom/hpp/get-json.php index 04994312..2b5ccb2b 100644 --- a/examples/gp-ecom/hpp/get-json.php +++ b/examples/gp-ecom/hpp/get-json.php @@ -12,6 +12,7 @@ use GlobalPayments\Api\Entities\Enums\HppVersion; use GlobalPayments\Api\Entities\Exceptions\ApiException; use GlobalPayments\Api\Services\HostedService; +use GlobalPayments\Api\Entities\Enums\PhoneNumberType; // configure client, request and HPP settings $config = new GpEcomConfig(); @@ -74,6 +75,8 @@ ->withHostedPaymentData($hostedPaymentData) ->withAddress($billingAddress, AddressType::BILLING) ->withAddress($shippingAddress, AddressType::SHIPPING) + ->withPhoneNumber('44', '124 445 556', PhoneNumberType::WORK) + ->withPhoneNumber('44', '124 444 333', PhoneNumberType::HOME) ->withRemittanceReference(RemittanceReferenceType::TEXT, 'Nike Bounce Shoes') ->serialize(); //with this, we can pass our json to the client side diff --git a/metadata.xml b/metadata.xml index 1133cdc8..402d4051 100644 --- a/metadata.xml +++ b/metadata.xml @@ -1,3 +1,3 @@ - 4.0.3 + 4.0.4 \ No newline at end of file diff --git a/src/Entities/Enums/ServiceEndpoints.php b/src/Entities/Enums/ServiceEndpoints.php index 4b8a6905..0924280f 100644 --- a/src/Entities/Enums/ServiceEndpoints.php +++ b/src/Entities/Enums/ServiceEndpoints.php @@ -26,6 +26,6 @@ class ServiceEndpoints extends Enum 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/ucp"; - const OPEN_BANKING_TEST = 'https://beta.sandbox.globalpay-ecommerce.com/openbanking'; - const OPEN_BANKING_PRODUCTION = 'https://beta.globalpay-ecommerce.com/openbanking'; + const OPEN_BANKING_TEST = 'https://api.sandbox.globalpay-ecommerce.com/openbanking'; + const OPEN_BANKING_PRODUCTION = 'https://api.globalpay-ecommerce.com/openbanking'; } diff --git a/src/Entities/ThreeDSecure.php b/src/Entities/ThreeDSecure.php index a57a69d8..304228c0 100644 --- a/src/Entities/ThreeDSecure.php +++ b/src/Entities/ThreeDSecure.php @@ -358,6 +358,20 @@ public function setVersion($version) */ public $liabilityShift; + /** + * Reference Number assigned by the ACS. + * + * @var string + */ + public $acsReferenceNumber; + + /** + * The reference created by the 3DSecure provider to identify the specific authentication attempt. + * + * @var string + */ + public $providerServerTransRef; + public function __construct() { $this->paymentDataType = '3DSecure'; @@ -414,6 +428,8 @@ public function merge(ThreeDSecure $secureEcom) $this->exemptStatus = $this->mergeValue($this->exemptStatus, $secureEcom->exemptStatus); $this->exemptReason = $this->mergeValue($this->exemptStatus, $secureEcom->exemptReason); $this->liabilityShift = $this->mergeValue($this->liabilityShift, $secureEcom->liabilityShift); + $this->acsReferenceNumber = $this->mergeValue($this->acsReferenceNumber, $secureEcom->acsReferenceNumber); + $this->providerServerTransRef = $this->mergeValue($this->providerServerTransRef, $secureEcom->providerServerTransRef); } } diff --git a/src/Gateways/GpEcomConnector.php b/src/Gateways/GpEcomConnector.php index feb13982..105ab270 100644 --- a/src/Gateways/GpEcomConnector.php +++ b/src/Gateways/GpEcomConnector.php @@ -28,6 +28,7 @@ use GlobalPayments\Api\Entities\Enums\Secure3dVersion; use GlobalPayments\Api\Builders\Secure3dBuilder; use GlobalPayments\Api\Entities\Exceptions\ApiException; +use GlobalPayments\Api\Utils\StringUtils; class GpEcomConnector extends XmlGateway implements IPaymentGateway, IRecurringService, ISecure3dProvider { @@ -377,6 +378,18 @@ public function serializeRequest(AuthorizationBuilder $builder) ); } + if (!empty($builder->homePhone)) { + $this->setSerializeData('HPP_CUSTOMER_PHONENUMBER_HOME', + StringUtils::validateToNumber($builder->homePhone->countryCode) . '|' . + StringUtils::validateToNumber($builder->homePhone->number)); + } + + if (!empty($builder->workPhone)) { + $this->setSerializeData('HPP_CUSTOMER_PHONENUMBER_WORK', + StringUtils::validateToNumber($builder->workPhone->countryCode) . '|' . + StringUtils::validateToNumber($builder->workPhone->number)); + } + $this->setSerializeData('VAR_REF', $builder->clientTransactionId); $this->setSerializeData('HPP_LANG', $this->hostedPaymentConfig->language); $this->setSerializeData('MERCHANT_RESPONSE_URL', $this->hostedPaymentConfig->responseUrl); diff --git a/src/Mapping/GpApiMapping.php b/src/Mapping/GpApiMapping.php index c96dc20d..90bb92ec 100644 --- a/src/Mapping/GpApiMapping.php +++ b/src/Mapping/GpApiMapping.php @@ -468,8 +468,8 @@ public static function mapResponseSecure3D($response) { $transaction = new Transaction(); $threeDSecure = new ThreeDSecure(); - $threeDSecure->serverTransactionId = !empty($response->id) ? $response->id : - (!empty($response->three_ds->server_trans_ref) ? $response->three_ds->server_trans_ref : null); + $threeDSecure->serverTransactionId = $response->id; + if (!empty($response->three_ds->message_version)) { $messageVersion = $response->three_ds->message_version; switch (substr($messageVersion, 0, 2)) { @@ -499,6 +499,8 @@ public static function mapResponseSecure3D($response) $threeDSecure->eci = !empty($response->three_ds->eci) ? $response->three_ds->eci : null; $threeDSecure->acsInfoIndicator = !empty($response->three_ds->acs_info_indicator) ? $response->three_ds->acs_info_indicator : null; + $threeDSecure->acsReferenceNumber = $response->three_ds->acs_reference_number ?? null; + $threeDSecure->providerServerTransRef = $response->three_ds->server_trans_ref ?? null; $threeDSecure->challengeMandated = !empty($response->three_ds->challenge_status) ? ($response->three_ds->challenge_status == 'MANDATED') : false; $threeDSecure->payerAuthenticationRequest = !empty($response->three_ds->method_data->encoded_method_data) ? diff --git a/test/Integration/Gateways/GpApiConnector/CreditCardPresentTest.php b/test/Integration/Gateways/GpApiConnector/CreditCardPresentTest.php index d20f44a2..3a7ce87d 100644 --- a/test/Integration/Gateways/GpApiConnector/CreditCardPresentTest.php +++ b/test/Integration/Gateways/GpApiConnector/CreditCardPresentTest.php @@ -632,8 +632,6 @@ public function testIncrementalAuth() $this->assertEquals(TransactionStatus::PREAUTHORIZED, $transaction->responseMessage); $this->assertEquals(60, $transaction->authorizedAmount); - - $capture = $transaction->capture()->execute(); $this->assertNotNull($capture); @@ -641,6 +639,118 @@ public function testIncrementalAuth() $this->assertEquals(TransactionStatus::CAPTURED, $capture->responseMessage); } + public function testIncrementalAuth_WithoutCurrencyAndLodgingData() + { + $card = $this->initCreditCardData(); + + $transaction = $card->authorize(50) + ->withCurrency($this->currency) + ->execute(); + + $this->assertNotNull($transaction); + $this->assertEquals('SUCCESS', $transaction->responseCode); + $this->assertEquals(TransactionStatus::PREAUTHORIZED, $transaction->responseMessage); + + $transaction = $transaction->additionalAuth(10) + ->execute(); + + $this->assertNotNull($transaction); + $this->assertEquals('SUCCESS', $transaction->responseCode); + $this->assertEquals(TransactionStatus::PREAUTHORIZED, $transaction->responseMessage); + $this->assertEquals(60, $transaction->authorizedAmount); + } + + public function testIncrementalAuth_ZeroAmount() + { + $card = $this->initCreditCardData(); + + $transaction = $card->authorize(50) + ->withCurrency($this->currency) + ->execute(); + + $this->assertNotNull($transaction); + $this->assertEquals('SUCCESS', $transaction->responseCode); + $this->assertEquals(TransactionStatus::PREAUTHORIZED, $transaction->responseMessage); + + $transaction = $transaction->additionalAuth(0) + ->execute(); + + $this->assertNotNull($transaction); + $this->assertEquals('SUCCESS', $transaction->responseCode); + $this->assertEquals(TransactionStatus::PREAUTHORIZED, $transaction->responseMessage); + $this->assertEquals(50, $transaction->authorizedAmount); + } + + public function testIncrementalAuth_ChargeTransaction() + { + $card = $this->initCreditCardData(); + + $charge = $card->charge(50) + ->withCurrency($this->currency) + ->execute(); + + $this->assertNotNull($charge); + $this->assertEquals('SUCCESS', $charge->responseCode); + $this->assertEquals(TransactionStatus::CAPTURED, $charge->responseMessage); + + $exceptionCaught = false; + try { + $charge->additionalAuth(10) + ->execute(); + } catch (GatewayException $e) { + $exceptionCaught = true; + $this->assertEquals('40290', $e->responseCode); + $this->assertContains('Status Code: INVALID_ACTION - Cannot PROCESS Incremental Authorization over a transaction that does not have a status of PREAUTHORIZED.', $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } + + public function testIncrementalAuth_WithoutAmount() + { + $card = $this->initCreditCardData(); + + $transaction = $card->authorize(50) + ->withCurrency($this->currency) + ->execute(); + + $this->assertNotNull($transaction); + $this->assertEquals('SUCCESS', $transaction->responseCode); + $this->assertEquals(TransactionStatus::PREAUTHORIZED, $transaction->responseMessage); + + $exceptionCaught = false; + try { + $transaction->additionalAuth() + ->withCurrency($this->currency) + ->execute(); + } catch (GatewayException $e) { + $exceptionCaught = true; + $this->assertEquals('40005', $e->responseCode); + $this->assertContains('Status Code: MANDATORY_DATA_MISSING - Request expects the following fields [amount]', $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } + + public function testIncrementalAuth_TransactionNotFound() + { + $transaction = new Transaction(); + $transaction->transactionId = GenerationUtils::getGuid(); + + $exceptionCaught = false; + try { + $transaction->additionalAuth() + ->withCurrency($this->currency) + ->execute(); + } catch (GatewayException $e) { + $exceptionCaught = true; + $this->assertEquals('40008', $e->responseCode); + $this->assertContains(sprintf('Status Code: RESOURCE_NOT_FOUND - Transaction %s not found at this location.', $transaction->transactionId), $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } + private function initCreditCardData() { $card = new CreditCardData(); diff --git a/test/Integration/Gateways/GpApiConnector/GpApi3DSecureTest.php b/test/Integration/Gateways/GpApiConnector/GpApi3DSecureTest.php index b2ff1046..7cd40a45 100644 --- a/test/Integration/Gateways/GpApiConnector/GpApi3DSecureTest.php +++ b/test/Integration/Gateways/GpApiConnector/GpApi3DSecureTest.php @@ -743,14 +743,18 @@ public function testFrictionlessFullCycle_v2_WithMobileSdk() ->withOrderTransactionType(OrderTransactionType::GOODS_SERVICE_PURCHASE) ->withMobileData($mobileData) ->execute(); + $this->assertNotNull($initAuth); $this->assertEquals(Secure3dStatus::SUCCESS_AUTHENTICATED, $initAuth->status); $this->assertNotNull($initAuth->issuerAcsUrl); $this->assertNotNull($initAuth->payerAuthenticationRequest); $this->assertNotNull($initAuth->acsTransactionId); + $this->assertNotNull($initAuth->providerServerTransRef); + $this->assertNotNull($initAuth->acsReferenceNumber); $this->assertEquals("05", $initAuth->eci); $this->assertEquals("2.2.0", $initAuth->messageVersion); + $secureEcom = Secure3dService::getAuthenticationData() ->withServerTransactionId($secureEcom->serverTransactionId) ->execute(); diff --git a/test/Integration/Gateways/GpEcomConnector/OpenBankingTest.php b/test/Integration/Gateways/GpEcomConnector/OpenBankingTest.php index f1d59c86..504f865b 100644 --- a/test/Integration/Gateways/GpEcomConnector/OpenBankingTest.php +++ b/test/Integration/Gateways/GpEcomConnector/OpenBankingTest.php @@ -59,6 +59,10 @@ public function testFasterPaymentsCharge() $this->assertNotNull($response); $this->assertEquals(1, $response->totalRecordCount); $this->assertEquals($trn->bankPaymentResponse->id, $response->result[0]->transactionId); + $this->assertNull($response->result[0]->bankPaymentResponse->iban); + $this->assertNull($response->result[0]->bankPaymentResponse->sortCode); + $this->assertNull($response->result[0]->bankPaymentResponse->accountNumber); + $this->assertNull($response->result[0]->bankPaymentResponse->accountName); } public function testSEPACharge() @@ -73,6 +77,17 @@ public function testSEPACharge() $this->assertOpenBankingResponse($trn); // fwrite(STDERR, print_r($trn->bankPaymentResponse->redirectUrl, TRUE)); + sleep(2); + $response = ReportingService::bankPaymentDetail($trn->bankPaymentResponse->id) + ->execute(); + + $this->assertNotNull($response); + $this->assertEquals(1, $response->totalRecordCount); + $this->assertEquals($trn->bankPaymentResponse->id, $response->result[0]->transactionId); + $this->assertNull($response->result[0]->bankPaymentResponse->iban); + $this->assertNull($response->result[0]->bankPaymentResponse->sortCode); + $this->assertNull($response->result[0]->bankPaymentResponse->accountNumber); + $this->assertNull($response->result[0]->bankPaymentResponse->accountName); } public function testBankPaymentList() @@ -417,6 +432,24 @@ public function testSEPACharge_InvalidCurrency() } } + public function testSEPACharge_CADCurrency() + { + $bankPayment = $this->sepaConfig(); + + $exceptionCaught = false; + try { + $bankPayment->charge($this->amount) + ->withCurrency("CAD") + ->withRemittanceReference(RemittanceReferenceType::TEXT, 'Nike Bounce Shoes') + ->execute(); + } catch (GatewayException $e) { + $exceptionCaught = true; + $this->assertEquals('Status Code: 400 - payment.scheme cannot be null ', $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } + private function fasterPaymentsConfig() { $bankPayment = new BankPayment();