diff --git a/src/Builders/Secure3dBuilder.php b/src/Builders/Secure3dBuilder.php index 9e23dd28..eb4c038f 100644 --- a/src/Builders/Secure3dBuilder.php +++ b/src/Builders/Secure3dBuilder.php @@ -2,21 +2,18 @@ namespace GlobalPayments\Api\Builders; +use GlobalPayments\Api\Entities\Enums\DecoupledFlowRequest; +use GlobalPayments\Api\Entities\Enums\WhiteListStatus; use GlobalPayments\Api\ServicesContainer; use GlobalPayments\Api\Entities\Exceptions\ApiException; -use GlobalPayments\Api\Entities\Exceptions\BuilderException; use GlobalPayments\Api\Entities\Exceptions\GatewayException; use GlobalPayments\Api\Entities\Exceptions\ConfigurationException; -use GlobalPayments\Api\Gateways\ISecure3dProvider; -use GlobalPayments\Api\PaymentMethods\CreditCardData; use GlobalPayments\Api\PaymentMethods\Interfaces\IPaymentMethod; use GlobalPayments\Api\PaymentMethods\Interfaces\ISecure3d; -use GlobalPayments\Api\PaymentMethods\RecurringPaymentMethod; use GlobalPayments\Api\Entities\Address; use GlobalPayments\Api\Entities\BrowserData; use GlobalPayments\Api\Entities\MerchantDataCollection; use GlobalPayments\Api\Entities\ThreeDSecure; -use GlobalPayments\Api\Entities\Transaction; use GlobalPayments\Api\Entities\Enums\AddressType; use GlobalPayments\Api\Entities\Enums\AgeIndicator; use GlobalPayments\Api\Entities\Enums\AuthenticationRequestType; @@ -50,7 +47,7 @@ class Secure3dBuilder extends BaseBuilder public $billingAddress; /** @var BrowserData */ public $browserData; - /** @var ChallengeRequestIndicator */ + /** @var ChallengeRequestIndicator */ public $challengeRequestIndicator; /** @var string */ public $currency; @@ -64,6 +61,12 @@ class Secure3dBuilder extends BaseBuilder public $customerAuthenticationTimestamp; /** @var string */ public $customerEmail; + /** @var DecoupledFlowRequest */ + public $decoupledFlowRequest; + /** @var integer */ + public $decoupledFlowTimeout; + /** @var string */ + public $decoupledNotificationUrl; /** @var string */ public $deliveryEmail; /** @var DeliveryTimeFrame */ @@ -170,8 +173,10 @@ class Secure3dBuilder extends BaseBuilder public $transactionType; /** @var TransactionModifier */ public $transactionModifier = TransactionModifier::NONE; - // /** @var Secure3dVersion */ - // public $version; +// /** @var Secure3dVersion */ +// public $version; + /** @var string */ + public $whitelistStatus; /** @var string */ public $workCountryCode; /** @var string */ @@ -191,316 +196,379 @@ public function getAccountAgeIndicator() { return $this->accountAgeIndicator; } + /** @return DateTime */ public function getAccountChangeDate() { return $this->accountChangeDate; } + /** @return DateTime */ public function getAccountCreateDate() { return $this->accountCreateDate; } + /** @return AgeIndicator */ public function getAccountChangeIndicator() { return $this->accountChangeIndicator; } + /** @return bool */ public function isAddressMatchIndicator() { return $this->addressMatchIndicator; } + /** @return string|float */ public function getAmount() { return $this->amount; } + /** @return string */ public function getApplicationId() { return $this->applicationId; } + /** @return AuthenticationSource */ public function getAuthenticationSource() { return $this->authenticationSource; } + /** @return AuthenticationRequestType */ public function getAuthenticationRequestType() { return $this->authenticationRequestType; } + /** @return address */ public function getBillingAddress() { return $this->billingAddress; } + /** @return BrowserData */ public function getBrowserData() { return $this->browserData; } + /** @return string */ public function getChallengeRequestIndicator() { return $this->challengeRequestIndicator; } + /** @return string */ public function getCurrency() { return $this->currency; } + /** @return string */ public function getCustomerAccountId() { return $this->customerAccountId; } + /** @return string */ public function getCustomerAuthenticationData() { return $this->customerAuthenticationData; } + /** @return CustomerAuthenticationMethod */ public function getCustomerAuthenticationMethod() { return $this->customerAuthenticationMethod; } + /** @return DateTime */ public function getCustomerAuthenticationTimestamp() { return $this->customerAuthenticationTimestamp; } + /** @return string */ public function getCustomerEmail() { return $this->customerEmail; } + /** @return string */ public function getDeliveryEmail() { return $this->deliveryEmail; } + /** @return DeliveryTimeFrame */ public function getDeliveryTimeframe() { return $this->deliveryTimeframe; } + /** @return string */ public function getEncodedData() { return $this->encodedData; } + /** @return string */ public function getEphemeralPublicKey() { return $this->ephemeralPublicKey; } + /** @return int */ public function getGiftCardCount() { return $this->giftCardCount; } + /** @return string */ public function getGiftCardCurrency() { return $this->giftCardCurrency; } + /** @return decimal */ public function getGiftCardAmount() { return $this->giftCardAmount; } + /** @return string */ public function getHomeCountryCode() { return $this->homeCountryCode; } + /** @return string */ public function getHomeNumber() { return $this->homeNumber; } + /** @return int */ public function getMaxNumberOfInstallments() { return $this->maxNumberOfInstallments; } + /** @return int */ public function getMaximumTimeout() { return $this->maximumTimeout; } + /** @return MerchantDataCollection */ public function getMerchantData() { return $this->merchantData; } + /** @return MessageCategory */ public function getMessageCategory() { return $this->messageCategory; } + /** @return AuthenticationRequestType */ public function getMerchantInitiatedRequestType() { return $this->merchantInitiatedRequestType; } + /** @return MessageVersion */ public function getMessageVersion() { return $this->messageVersion; } + /** @return MethodUrlCompletion */ public function getMethodUrlCompletion() { return $this->methodUrlCompletion; } + /** @return string */ public function getMobileCountryCode() { return $this->mobileCountryCode; } + /** @return string */ public function getMobileNumber() { return $this->mobileNumber; } + /** @return int */ public function getNumberOfAddCardAttemptsInLast24Hours() { return $this->numberOfAddCardAttemptsInLast24Hours; } + /** @return int */ public function getNumberOfPurchasesInLastSixMonths() { return $this->numberOfPurchasesInLastSixMonths; } + /** @return int */ public function getNumberOfTransactionsInLast24Hours() { return $this->numberOfTransactionsInLast24Hours; } + /** @return int */ public function getNumberOfTransactionsInLastYear() { return $this->numberOfTransactionsInLastYear; } + /** @return DateTime */ public function getOrderCreateDate() { return $this->orderCreateDate; } + /** @return string */ public function getOrderId() { return $this->orderId; } + /** @return OrderTransactionType */ public function getOrderTransactionType() { return $this->orderTransactionType; } + /** @return DateTime */ public function getPasswordChangeDate() { return $this->passwordChangeDate; } + /** @return AgeIndicator */ public function getPasswordChangeIndicator() { return $this->passwordChangeIndicator; } + /** @return DateTime */ public function getPaymentAccountCreateDate() { return $this->paymentAccountCreateDate; } + /** @return AgeIndicator */ public function getPaymentAgeIndicator() { return $this->paymentAgeIndicator; } + /** @return string */ public function getPayerAuthenticationResponse() { return $this->payerAuthenticationResponse; } + /** @return IPaymentMethod */ public function getPaymentMethod() { return $this->paymentMethod; } + /** @return DateTime */ public function getPreOrderAvailabilityDate() { return $this->preOrderAvailabilityDate; } + /** @return PreOrderIndicator */ public function getPreOrderIndicator() { return $this->preOrderIndicator; } + /** @return bool */ public function getPreviousSuspiciousActivity() { return $this->previousSuspiciousActivity; } + /** @return string */ public function getPriorAuthenticationData() { return $this->priorAuthenticationData; } + /** @return PriorAuthenticationMethod */ public function getPriorAuthenticationMethod() { return $this->priorAuthenticationMethod; } + /** @return string */ public function getPriorAuthenticationTransactionId() { return $this->priorAuthenticationTransactionId; } + /** @return DateTime */ public function getPriorAuthenticationTimestamp() { return $this->priorAuthenticationTimestamp; } + /** @return DateTime */ public function getRecurringAuthorizationExpiryDate() { return $this->recurringAuthorizationExpiryDate; } + /** @return int */ public function getRecurringAuthorizationFrequency() { return $this->recurringAuthorizationFrequency; } + /** @return string */ public function getReferenceNumber() { return $this->referenceNumber; } + /** @return ReorderIndicator */ public function getReorderIndicator() { return $this->reorderIndicator; } + /** @return SdkInterface */ public function getSdkInterface() { return $this->sdkInterface; } + /** @return string */ public function getSdkTransactionId() { return $this->sdkTransactionId; } + /** @return array */ public function getSdkUiTypes() { return $this->sdkUiTypes; } + /** @return string */ public function getServerTransactionId() { @@ -509,41 +577,49 @@ public function getServerTransactionId() } return null; } + /** @return Address */ public function getShippingAddress() { return $this->shippingAddress; } + /** @return DateTime */ public function getShippingAddressCreateDate() { return $this->shippingAddressCreateDate; } + /** @return AgeIndicator */ public function getShippingAddressUsageIndicator() { return $this->shippingAddressUsageIndicator; } + /** @return ShippingMethod */ public function getShippingMethod() { return $this->shippingMethod; } + /** @return bool */ public function getShippingNameMatchesCardHolderName() { return $this->shippingNameMatchesCardHolderName; } + /** @return ThreeDSecure */ public function getThreeDSecure() { return $this->threeDSecure; } + /** @return TransactionType */ public function getTransactionType() { return $this->transactionType; } + /** @return Secure3dVersion */ public function getVersion() { @@ -552,11 +628,47 @@ public function getVersion() } return null; } + + /** + * @return DecoupledFlowRequest + */ + public function getDecoupledFlowRequest() + { + return $this->decoupledFlowRequest; + } + + /** + * @return int + */ + public function getDecoupledFlowTimeout() + { + return $this->decoupledFlowTimeout; + } + + /** + * @return string + */ + public function getDecoupledNotificationUrl() + { + return $this->decoupledNotificationUrl; + } + + /** + * @return string + */ + public function getWhitelistStatus() + { + return $this->whitelistStatus; + } + + + /** @return string */ public function getWorkCountryCode() { return $this->workCountryCode; } + /** @return string */ public function getWorkNumber() { @@ -564,10 +676,11 @@ public function getWorkNumber() } // HELPER METHOD FOR THE CONNECTOR + /** @return bool */ public function hasMobileFields() { - return( + return ( !empty($this->applicationId) || $this->ephemeralPublicKey != null || $this->maximumTimeout != null || @@ -578,6 +691,7 @@ public function hasMobileFields() $this->sdkUiTypes != null ); } + /** @return bool */ public function hasPriorAuthenticationData() { @@ -588,6 +702,7 @@ public function hasPriorAuthenticationData() !empty($this->priorAuthenticationData) ); } + /** @return bool */ public function hasRecurringAuthData() { @@ -597,6 +712,7 @@ public function hasRecurringAuthData() $this->recurringAuthorizationExpiryDate != null ); } + /** @return bool */ public function hasPayerLoginData() { @@ -697,7 +813,7 @@ public function withChallengeRequestIndicator($challengeRequestIndicator) $this->challengeRequestIndicator = $challengeRequestIndicator; return $this; } - + /** @return Secure3dBuilder */ public function withCustomerAccountId($customerAccountId) { @@ -740,6 +856,36 @@ public function withCustomerEmail($value) return $this; } + /** + * @param DecoupledFlowRequest + * @return Secure3dBuilder + */ + public function withDecoupledFlowRequest($decoupledFlowRequest) + { + $this->decoupledFlowRequest = $decoupledFlowRequest; + return $this; + } + + /** + * @param $decoupledFlowTimeout + * @return Secure3dBuilder + */ + public function withDecoupledFlowTimeout($decoupledFlowTimeout) + { + $this->decoupledFlowTimeout = $decoupledFlowTimeout; + return $this; + } + + /** + * @param $decoupledNotificationUrl + * @return Secure3dBuilder + */ + public function withDecoupledNotificationUrl($decoupledNotificationUrl) + { + $this->decoupledNotificationUrl = $decoupledNotificationUrl; + return $this; + } + /** @return Secure3dBuilder */ public function withDeliveryEmail($deliveryEmail) { @@ -1110,6 +1256,16 @@ public function withTransactionType($transactionType) return $this; } + /** + * @param WhiteListStatus + * @return Secure3dBuilder + */ + public function withWhitelistStatus($whitelistStatus) + { + $this->whitelistStatus = $whitelistStatus; + return $this; + } + /** @return Secure3dBuilder */ public function withWorkNumber($countryCode, $number) { @@ -1121,7 +1277,7 @@ public function withWorkNumber($countryCode, $number) /** * @throws ApiException * @return ThreeDSecure */ - public function execute($version = Secure3dVersion::ANY) + public function execute($configName = 'default', $version = Secure3dVersion::ANY) { // TODO Get validations working // parent::execute(); @@ -1139,12 +1295,12 @@ public function execute($version = Secure3dVersion::ANY) } // get the provider - $provider = ServicesContainer::instance()->getSecure3d($version); + $provider = ServicesContainer::instance()->getSecure3d($configName, $version); if (!empty($provider)) { $canDowngrade = false; if ($provider->getVersion() === Secure3dVersion::TWO && $version === Secure3dVersion::ANY) { try { - $oneProvider = ServicesContainer::instance()->getSecure3d(Secure3dVersion::ONE); + $oneProvider = ServicesContainer::instance()->getSecure3d($configName, Secure3dVersion::ONE); $canDowngrade = (bool)(!empty($oneProvider)); } catch (ConfigurationException $exc) { // NOT CONFIGURED @@ -1157,7 +1313,7 @@ public function execute($version = Secure3dVersion::ANY) $response = $provider->processSecure3d($this); if (empty($response) && (bool)$canDowngrade) { - return $this->execute(Secure3dVersion::ONE); + return $this->execute($configName, Secure3dVersion::ONE); } } catch (GatewayException $exc) { // check for not enrolled @@ -1166,7 +1322,7 @@ public function execute($version = Secure3dVersion::ANY) return $rvalue; } } elseif ((bool)$canDowngrade && $this->transactionType === TransactionType::VERIFY_ENROLLED) { // check if we can downgrade - return $this->execute(Secure3dVersion::ONE); + return $this->execute($configName, Secure3dVersion::ONE); } else { // throw exception throw $exc; } @@ -1184,10 +1340,10 @@ public function execute($version = Secure3dVersion::ANY) $rvalue->setOrderId($response->orderId); $rvalue->setVersion($provider->getVersion()); } elseif ((bool)$canDowngrade) { - return $this->execute(Secure3dVersion::ONE); + return $this->execute($configName, Secure3dVersion::ONE); } } elseif ((bool)$canDowngrade) { - return $this->execute(Secure3dVersion::ONE); + return $this->execute($configName, Secure3dVersion::ONE); } break; case TransactionType::INITIATE_AUTHENTICATION: diff --git a/src/ConfiguredServices.php b/src/ConfiguredServices.php index 3bd56c00..8060702e 100644 --- a/src/ConfiguredServices.php +++ b/src/ConfiguredServices.php @@ -40,9 +40,9 @@ public function __construct() $this->secure3dProviders = array(); } - protected function getSecure3dProvider(Secure3dVersion $version) + public function getSecure3dProvider($version) { - if (in_array($version, $this->secure3dProviders)) { + if (array_key_exists($version, $this->secure3dProviders)) { return $this->secure3dProviders[$version]; } elseif ($version == Secure3dVersion::ANY) { $provider = $this->secure3dProviders[Secure3dVersion::TWO]; @@ -55,7 +55,7 @@ protected function getSecure3dProvider(Secure3dVersion $version) } } - protected function setSecure3dProvider(Secure3dVersion $version, ISecure3dProvider $provider) + public function setSecure3dProvider($version, $provider) { $this->secure3dProviders[$version] = $provider; } diff --git a/src/Entities/Enums/AuthenticationSource.php b/src/Entities/Enums/AuthenticationSource.php index afe78ef0..c4643bfa 100644 --- a/src/Entities/Enums/AuthenticationSource.php +++ b/src/Entities/Enums/AuthenticationSource.php @@ -9,4 +9,5 @@ class AuthenticationSource extends Enum const BROWSER = "BROWSER"; const STORED_RECURRING = "STORED_RECURRING"; const MOBILE_SDK = "MOBILE_SDK"; + const MERCHANT_INITIATED = "MERCHANT_INITIATED"; } diff --git a/src/Entities/Enums/ChallengeRequestIndicator.php b/src/Entities/Enums/ChallengeRequestIndicator.php index 0d9e7e6e..fb2abbd3 100644 --- a/src/Entities/Enums/ChallengeRequestIndicator.php +++ b/src/Entities/Enums/ChallengeRequestIndicator.php @@ -10,4 +10,9 @@ class ChallengeRequestIndicator extends Enum const NO_CHALLENGE_REQUESTED = "NO_CHALLENGE_REQUESTED"; const CHALLENGE_PREFERRED = "CHALLENGE_PREFERRED"; const CHALLENGE_MANDATED = "CHALLENGE_MANDATED"; + const NO_CHALLENGE_REQUESTED_TRANSACTION_RISK_ANALYSIS_PERFORMED = "NO_CHALLENGE_REQUESTED_TRANSACTION_RISK_ANALYSIS_PERFORMED"; + const NO_CHALLENGE_REQUESTED_DATA_SHARE_ONLY = "NO_CHALLENGE_REQUESTED_DATA_SHARE_ONLY"; + const NO_CHALLENGE_REQUESTED_SCA_ALREADY_PERFORMED = "NO_CHALLENGE_REQUESTED_SCA_ALREADY_PERFORMED"; + const NO_CHALLENGE_REQUESTED_WHITELIST = "NO_CHALLENGE_REQUESTED_WHITELIST"; + const CHALLENGE_REQUESTED_PROMPT_FOR_WHITELIST = "CHALLENGE_REQUESTED_PROMPT_FOR_WHITELIST"; } diff --git a/src/Entities/Enums/DecoupledFlowRequest.php b/src/Entities/Enums/DecoupledFlowRequest.php new file mode 100644 index 00000000..f902ec4a --- /dev/null +++ b/src/Entities/Enums/DecoupledFlowRequest.php @@ -0,0 +1,13 @@ +merchantData->add('currency', $this->currency, false); } + /** + * @var string + */ + public $decoupledResponseIndicator; + /** * @var string */ @@ -136,6 +146,13 @@ public function setCurrency($value) */ public $enrolled; + /** + * The exempt status + * + * @var string + */ + public $exemptStatus; + /** * The URL of the Issuing Bank's ACS * @@ -190,6 +207,11 @@ public function setMerchantData($merchantData) */ public $messageCategory; + /** + * @var string + */ + public $messageExtensionData; + /** * @var string */ @@ -303,6 +325,11 @@ public function setVersion($version) $this->merchantData->add('version', $version, false); } + /** + * @var string + */ + public $whitelistStatus; + /** * Consumer authentication (3DSecure) transaction ID * @@ -337,6 +364,7 @@ public function merge(ThreeDSecure $secureEcom) $this->challengeMandated = $this->mergeValue($this->challengeMandated, $secureEcom->challengeMandated); $this->criticalityIndicator = $this->mergeValue($this->criticalityIndicator, $secureEcom->criticalityIndicator); $this->currency = $this->mergeValue($this->currency, $secureEcom->currency); + $this->decoupledResponseIndicator = $this->mergeValue($this->decoupledResponseIndicator, $secureEcom->decoupledResponseIndicator); $this->directoryServerTransactionId = $this->mergeValue($this->directoryServerTransactionId, $secureEcom->directoryServerTransactionId); $this->directoryServerEndVersion = $this->mergeValue($this->directoryServerEndVersion, $secureEcom->directoryServerEndVersion); $this->directoryServerStartVersion = $this->mergeValue($this->directoryServerStartVersion, $secureEcom->directoryServerStartVersion); @@ -344,6 +372,7 @@ public function merge(ThreeDSecure $secureEcom) $this->enrolled = $this->mergeValue($this->enrolled, $secureEcom->enrolled); $this->issuerAcsUrl = $this->mergeValue($this->issuerAcsUrl, $secureEcom->issuerAcsUrl); $this->messageCategory = $this->mergeValue($this->messageCategory, $secureEcom->messageCategory); + $this->messageExtensionData = $this->mergeValue($this->messageExtensionData, $secureEcom->messageExtensionData); $this->messageExtensionId = $this->mergeValue($this->messageExtensionId, $secureEcom->messageExtensionId); $this->messageExtensionName = $this->mergeValue($this->messageExtensionName, $secureEcom->messageExtensionName); $this->messageVersion = $this->mergeValue($this->messageVersion, $secureEcom->messageVersion); @@ -357,6 +386,7 @@ public function merge(ThreeDSecure $secureEcom) $this->status = $this->mergeValue($this->status, $secureEcom->status); $this->statusReason = $this->mergeValue($this->statusReason, $secureEcom->statusReason); $this->version = $this->mergeValue($this->version, $secureEcom->version); + $this->whitelistStatus = $this->mergeValue($this->whitelistStatus, $secureEcom->whitelistStatus); $this->xid = $this->mergeValue($this->xid, $secureEcom->xid); } } diff --git a/src/Gateways/Gp3DSProvider.php b/src/Gateways/Gp3DSProvider.php index b3ae1067..6369d91b 100644 --- a/src/Gateways/Gp3DSProvider.php +++ b/src/Gateways/Gp3DSProvider.php @@ -110,12 +110,14 @@ public function processSecure3d(Secure3dBuilder $builder) $hash = GenerationUtils::generateHash($this->sharedSecret, implode('.', [$timestamp, $this->merchantId, $hashValue])); $headers['Authorization'] = sprintf('securehash %s', $hash); + $headers["X-GP-Version"] = "2.2.0"; $rawResponse = $this->doTransaction('POST', 'protocol-versions', json_encode($request), null, $headers); return $this->mapResponse($rawResponse); } elseif ($transType === TransactionType::VERIFY_SIGNATURE) { $hash = GenerationUtils::generateHash($this->sharedSecret, implode('.', [$timestamp, $this->merchantId, $builder->getServerTransactionId()])); $headers['Authorization'] = sprintf('securehash %s', $hash); + $headers["X-GP-Version"] = "2.2.0"; $queryValues = []; $queryValues['merchant_id'] = $this->merchantId; @@ -143,6 +145,10 @@ public function processSecure3d(Secure3dBuilder $builder) $request = $this->maybeSetKey($request, 'method_url_completion', $builder->getMethodUrlCompletion()); $request = $this->maybeSetKey($request, 'merchant_contact_url', $this->merchantContactUrl); $request = $this->maybeSetKey($request, 'merchant_initiated_request_type', $builder->getMerchantInitiatedRequestType()); + $request = $this->maybeSetKey($request, 'whitelist_status', $builder->getWhitelistStatus()); + $request = $this->maybeSetKey($request, 'decoupled_flow_request', $builder->getDecoupledFlowRequest()); + $request = $this->maybeSetKey($request, 'decoupled_flow_timeout', $builder->getDecoupledFlowTimeout()); + $request = $this->maybeSetKey($request, 'decoupled_notification_url', $builder->getDecoupledNotificationUrl()); // card details $hashValue = ''; @@ -150,11 +156,11 @@ public function processSecure3d(Secure3dBuilder $builder) if ($paymentMethod instanceof CreditCardData) { $cardData = $paymentMethod; $hashValue = $cardData->number; - + $request['card_detail'] = $this->maybeSetKey($request['card_detail'], 'number', $cardData->number); $request['card_detail'] = $this->maybeSetKey($request['card_detail'], 'scheme', strtoupper($cardData->getCardType())); $request['card_detail'] = $this->maybeSetKey($request['card_detail'], 'expiry_month', $cardData->expMonth); - $request['card_detail'] = $this->maybeSetKey($request['card_detail'], 'expiry_year', + $request['card_detail'] = $this->maybeSetKey($request['card_detail'], 'expiry_year', substr(str_pad($cardData->expYear, 4, '0', STR_PAD_LEFT), 2, 2)); $request['card_detail'] = $this->maybeSetKey($request['card_detail'], 'full_name', $cardData->cardHolderName); @@ -312,7 +318,7 @@ public function processSecure3d(Secure3dBuilder $builder) $request['sdk_information'] = []; $request['sdk_information'] = $this->maybeSetKey($request['sdk_information'], 'application_id', $builder->getApplicationId()); $request['sdk_information'] = $this->maybeSetKey($request['sdk_information'], 'ephemeral_public_key', $builder->getEphemeralPublicKey()); - $request['sdk_information'] = $this->maybeSetKey($request['sdk_information'], 'maximum_timeout', + $request['sdk_information'] = $this->maybeSetKey($request['sdk_information'], 'maximum_timeout', (!empty($builder->getMaximumTimeout())) ? str_pad($builder->getMaximumTimeout(), 2, '0' , STR_PAD_LEFT) : ''); $request['sdk_information'] = $this->maybeSetKey($request['sdk_information'], 'reference_number', $builder->getReferenceNumber()); $request['sdk_information'] = $this->maybeSetKey($request['sdk_information'], 'sdk_trans_id', $builder->getSdkTransactionId()); @@ -328,6 +334,7 @@ public function processSecure3d(Secure3dBuilder $builder) $hash = GenerationUtils::generateHash($this->sharedSecret, implode('.', [$timestamp, $this->merchantId, $hashValue, $secureEcom->serverTransactionId])); $headers['Authorization'] = sprintf('securehash %s', $hash); + $headers["X-GP-Version"] = "2.2.0"; $rawResponse = $this->doTransaction('POST', 'authentications', json_encode($request, JSON_UNESCAPED_SLASHES), null, $headers); return $this->mapResponse($rawResponse); } @@ -360,6 +367,10 @@ private function mapResponse($rawResponse) $secureEcom->authenticationSource = isset($doc['authentication_source']) ? $doc['authentication_source'] : null; $secureEcom->messageCategory = isset($doc['message_category']) ? $doc['message_category'] : null; $secureEcom->messageVersion = isset($doc['message_version']) ? $doc['message_version'] : null; + $secureEcom->acsInfoIndicator = isset($doc['acs_info_indicator']) ? $doc['acs_info_indicator'] : null; + $secureEcom->decoupledResponseIndicator = isset($doc['decoupled_response_indicator']) ? + $doc['decoupled_response_indicator'] : null; + $secureEcom->whitelistStatus = isset($doc['whitelist_status']) ? $doc['whitelist_status'] : null; // challenge mandated if (array_key_exists('challenge_mandated', $doc)) { @@ -382,6 +393,8 @@ private function mapResponse($rawResponse) $secureEcom->criticalityIndicator = isset($doc['message_extension']['criticality_indicator']) ? $doc['message_extension']['criticality_indicator'] : null; + $secureEcom->messageExtensionData = isset($doc['message_extension']['data']) ? + $doc['message_extension']['data'] : null; $secureEcom->messageExtensionId = isset($doc['message_extension']['id']) ? $doc['message_extension']['id'] : null; $secureEcom->messageExtensionName = diff --git a/src/Gateways/RealexConnector.php b/src/Gateways/RealexConnector.php index e38fee2c..5080c8a6 100644 --- a/src/Gateways/RealexConnector.php +++ b/src/Gateways/RealexConnector.php @@ -455,11 +455,18 @@ public function processAuthorization(AuthorizationBuilder $builder) $mpi->appendChild($xml->createElement("cavv", $secureEcom->cavv)); $mpi->appendChild($xml->createElement("xid", $secureEcom->xid)); - if ($secureEcom->directoryServerTransactionId != null || $secureEcom->authenticationValue != null || $secureEcom->messageVersion != null) { + if ( + $secureEcom->directoryServerTransactionId != null || + $secureEcom->authenticationValue != null || + $secureEcom->messageVersion != null + ) { $mpi->appendChild($xml->createElement("ds_trans_id", $secureEcom->directoryServerTransactionId)); $mpi->appendChild($xml->createElement("authentication_value", $secureEcom->authenticationValue)); $mpi->appendChild($xml->createElement("message_version", $secureEcom->messageVersion)); } + if ($secureEcom->exemptStatus != null) { + $mpi->appendChild($xml->createElement("exempt_status", $secureEcom->exemptStatus)); + } $request->appendChild($mpi); } diff --git a/src/ServiceConfigs/Gateways/GpEcomConfig.php b/src/ServiceConfigs/Gateways/GpEcomConfig.php index c0b1fa90..fe7a64c2 100644 --- a/src/ServiceConfigs/Gateways/GpEcomConfig.php +++ b/src/ServiceConfigs/Gateways/GpEcomConfig.php @@ -68,9 +68,9 @@ public function configureContainer($services) { $secure3d2->setMerchantId($gateway->merchantId); $secure3d2->setAccountId($gateway->accountId); $secure3d2->setSharedSecret($gateway->sharedSecret); - $secure3d2->serviceUrl = $gateway->serviceUrl; + $secure3d2->serviceUrl = $this->environment == Environment::TEST ? ServiceEndpoints::THREE_DS_AUTH_TEST : ServiceEndpoints::THREE_DS_AUTH_PRODUCTION; $secure3d2->setMerchantContactUrl($this->merchantContactUrl); - $secure3d2->setMethodNotificationUrl($this->merchantNotificationUrl); + $secure3d2->setMethodNotificationUrl($this->methodNotificationUrl); $secure3d2->setChallengeNotificationUrl($this->challengeNotificationUrl); $secure3d2->timeout = $gateway->timeout; diff --git a/src/ServicesContainer.php b/src/ServicesContainer.php index 1d982bdf..0088c702 100644 --- a/src/ServicesContainer.php +++ b/src/ServicesContainer.php @@ -169,7 +169,7 @@ public function getReportingClient($configName) /** * @return ISecure3dProvider */ - public function getSecure3d($configName, Secure3dVersion $version) + public function getSecure3d($configName, $version) { if (array_key_exists($configName, static::$configurations)) { $provider = static::$configurations[$configName]->getSecure3dProvider($version); diff --git a/test/Integration/Gateways/RealexConnector/Secure3dServiceTests.php b/test/Integration/Gateways/RealexConnector/Secure3dServiceTests.php index d36db6e2..5e31b75c 100644 --- a/test/Integration/Gateways/RealexConnector/Secure3dServiceTests.php +++ b/test/Integration/Gateways/RealexConnector/Secure3dServiceTests.php @@ -2,16 +2,13 @@ namespace GlobalPayments\Api\Tests\Integration\Gateways\RealexConnector; -use GlobalPayments\Api\ServicesConfig; +use GlobalPayments\Api\Entities\Enums\DecoupledFlowRequest; +use GlobalPayments\Api\Entities\Enums\MerchantInitiatedRequestType; +use GlobalPayments\Api\Entities\Enums\WhiteListStatus; use GlobalPayments\Api\ServicesContainer; use GlobalPayments\Api\Entities\MerchantDataCollection; -use GlobalPayments\Api\Entities\ThreeDSecure; -use GlobalPayments\Api\Entities\Transaction; use GlobalPayments\Api\Entities\Enums\Secure3dVersion; -use GlobalPayments\Api\Entities\Exceptions\ApiException; -use GlobalPayments\Api\Entities\Exceptions\BuilderException; use GlobalPayments\Api\PaymentMethods\CreditCardData; -use GlobalPayments\Api\PaymentMethods\DebitTrackData; use GlobalPayments\Api\PaymentMethods\RecurringPaymentMethod; use GlobalPayments\Api\Services\Secure3dService; use GlobalPayments\Api\Tests\Data\TestCards; @@ -35,6 +32,7 @@ use GlobalPayments\Api\Entities\Enums\SdkInterface; use GlobalPayments\Api\Entities\Enums\SdkUiType; use GlobalPayments\Api\Entities\Enums\ChallengeRequestIndicator; +use GlobalPayments\Api\ServiceConfigs\Gateways\GpEcomConfig; class Secure3dServiceTests extends TestCase { @@ -44,9 +42,9 @@ class Secure3dServiceTests extends TestCase private $billingAddress; private $browserData; - public function setup() : void + public function setup() { - ServicesContainer::configure($this->getConfig()); + ServicesContainer::configureService($this->getConfig()); // create card data $this->card = new CreditCardData(); @@ -93,7 +91,7 @@ public function setup() : void protected function getConfig() { - $config = new ServicesConfig(); + $config = new GpEcomConfig(); $config->merchantId = 'myMerchantId'; $config->accountId = 'ecom3ds'; $config->sharedSecret = 'secret'; @@ -115,7 +113,7 @@ public function testFullCycle_v1() $secureEcom = Secure3dService::checkEnrollment($card) ->withAmount(10.01) ->withCurrency('USD') - ->execute(Secure3dVersion::ONE); + ->execute('default', Secure3dVersion::ONE); $this->assertEquals(Secure3dVersion::ONE, $secureEcom->getVersion()); if ($secureEcom->enrolled) { @@ -147,7 +145,7 @@ public function testFullCycle_v1() public function testFullCycle_v2() { $secureEcom = Secure3dService::checkEnrollment($this->card) - ->execute(Secure3dVersion::TWO); + ->execute('default', Secure3dVersion::TWO); $this->assertNotNull($secureEcom); $this->assertNotNull($secureEcom->serverTransactionId); @@ -188,12 +186,61 @@ public function testFullCycle_v2() } } + public function testFullCycle_v2_2() + { + $secureEcom = Secure3dService::checkEnrollment($this->card) + ->execute('default', Secure3dVersion::TWO); + $this->assertNotNull($secureEcom); + $this->assertNotNull($secureEcom->serverTransactionId); + + if ($secureEcom->enrolled) { + $this->assertEquals(Secure3dVersion::TWO, $secureEcom->getVersion()); + + // initiate authentication + $initAuth = Secure3dService::initiateAuthentication($this->card, $secureEcom) + ->withAmount(10.01) + ->withCurrency('USD') + ->withOrderCreateDate(date('Y-m-d H:i:s')) + ->withAddress($this->billingAddress, AddressType::BILLING) + ->withAddress($this->shippingAddress, AddressType::SHIPPING) + ->withBrowserData($this->browserData) + ->withMethodUrlCompletion(MethodUrlCompletion::NO) + ->withChallengeRequestIndicator(ChallengeRequestIndicator::NO_PREFERENCE) + ->withMerchantInitiatedRequestType(MerchantInitiatedRequestType::TOP_UP) +// ->withWhitelistStatus(WhiteListStatus::NOT_WHITELISTED) +// ->withDecoupledFlowRequest(DecoupledFlowRequest::DO_NOT_USE_DECOUPLED) + ->withDecoupledFlowTimeout('9001') + ->withDecoupledNotificationUrl('https://example-value.com') + ->execute(); + $this->assertNotNull($initAuth); + + // get authentication data + $secureEcom = Secure3dService::getAuthenticationData() + ->withServerTransactionId($initAuth->serverTransactionId) + ->execute(); + $this->card->threeDSecure = $secureEcom; + + if ($secureEcom->status == 'AUTHENTICATION_SUCCESSFUL') { + $response = $this->card->charge(10.01) + ->withCurrency('USD') + ->execute(); + + $this->assertNotNull($response); + $this->assertEquals('00', $response->responseCode); + } else { + $this->fail('Signature verification failed.'); + } + } else { + $this->fail('Card not enrolled'); + } + } + public function testFullCycle_Any() { $secureEcom = Secure3dService::checkEnrollment($this->card) ->withAmount(1.00) ->withCurrency('USD') - ->execute(Secure3dVersion::ANY); + ->execute(); $this->assertNotNull($secureEcom); if ($secureEcom->enrolled) { @@ -258,7 +305,7 @@ public function testFullCycle_Any() public function testFullCycle_v2_StoredCard() { $secureEcom = Secure3dService::checkEnrollment($this->stored) - ->execute(Secure3dVersion::TWO); + ->execute('default', Secure3dVersion::TWO); $this->assertNotNull($secureEcom); $this->assertNotNull($secureEcom->serverTransactionId); @@ -301,7 +348,7 @@ public function testFullCycle_v2_StoredCard() public function testFullCycle_v2_OTB() { $secureEcom = Secure3dService::checkEnrollment($this->card) - ->execute(Secure3dVersion::TWO); + ->execute('default', Secure3dVersion::TWO); $this->assertNotNull($secureEcom); $this->assertNotNull($secureEcom->serverTransactionId); @@ -344,7 +391,7 @@ public function testFullCycle_v2_OTB() public function testFullCycle_v2_OTB_StoredCard() { $secureEcom = Secure3dService::checkEnrollment($this->stored) - ->execute(Secure3dVersion::TWO); + ->execute('default', Secure3dVersion::TWO); $this->assertNotNull($secureEcom); $this->assertNotNull($secureEcom->serverTransactionId); @@ -387,7 +434,7 @@ public function testFullCycle_v2_OTB_StoredCard() public function testOptionalRequestLevelFields() { $secureEcom = Secure3dService::checkEnrollment($this->card) - ->execute(Secure3dVersion::TWO); + ->execute('default', Secure3dVersion::TWO); $this->assertNotNull($secureEcom); if ($secureEcom->enrolled) { @@ -433,7 +480,7 @@ public function testOptionalRequestLevelFields() public function testOptionalOrderLevelFields() { $secureEcom = Secure3dService::checkEnrollment($this->card) - ->execute(Secure3dVersion::TWO); + ->execute('default', Secure3dVersion::TWO); $this->assertNotNull($secureEcom); if ($secureEcom->enrolled) { @@ -491,7 +538,7 @@ public function testOptionalOrderLevelFields() public function testOptionalPayerLevelFields() { $secureEcom = Secure3dService::checkEnrollment($this->card) - ->execute(Secure3dVersion::TWO); + ->execute('default', Secure3dVersion::TWO); $this->assertNotNull($secureEcom); if ($secureEcom->enrolled) { @@ -554,7 +601,7 @@ public function testOptionalPayerLevelFields() public function testOptionalPriorAuthenticationData() { $secureEcom = Secure3dService::checkEnrollment($this->card) - ->execute(Secure3dVersion::TWO); + ->execute('default', Secure3dVersion::TWO); $this->assertNotNull($secureEcom); if ($secureEcom->enrolled) { @@ -602,7 +649,7 @@ public function testOptionalPriorAuthenticationData() public function testOptionalRecurringData() { $secureEcom = Secure3dService::checkEnrollment($this->card) - ->execute(Secure3dVersion::TWO); + ->execute('default', Secure3dVersion::TWO); $this->assertNotNull($secureEcom); if ($secureEcom->enrolled) { @@ -650,7 +697,7 @@ public function testOptionalRecurringData() public function testOptionalPayerLoginData() { $secureEcom = Secure3dService::checkEnrollment($this->card) - ->execute(Secure3dVersion::TWO); + ->execute('default', Secure3dVersion::TWO); $this->assertNotNull($secureEcom); if ($secureEcom->enrolled) { @@ -698,7 +745,7 @@ public function testOptionalPayerLoginData() public function testOptionalMobileFields() { $secureEcom = Secure3dService::checkEnrollment($this->card) - ->execute(Secure3dVersion::TWO); + ->execute('default', Secure3dVersion::TWO); $this->assertNotNull($secureEcom); if ($secureEcom->enrolled) { @@ -753,7 +800,7 @@ public function testCheckVersion_Not_Enrolled() $card->expMonth = 12; $card->expYear = TestCards::validCardExpYear(); $secureEcom = Secure3dService::checkEnrollment($card) - ->execute(Secure3dVersion::ANY); + ->execute(); $this->assertNotNull($secureEcom); $this->assertFalse((bool)$secureEcom->enrolled); }