From 7f34519e9109d419a82bb8c320fcdb0fbc553b04 Mon Sep 17 00:00:00 2001 From: securesubmit-buildmaster Date: Tue, 7 Jun 2022 08:34:56 -0400 Subject: [PATCH] OctopusDeploy release: 4.0.0 --- CHANGELOG.md | 6 + README.md | 8 +- composer.json | 2 +- examples/gp-api/google-pay/charge.php | 56 + examples/gp-api/google-pay/index.html | 19 + examples/gp-api/google-pay/main.js | 257 +++ examples/gp-api/google-pay/styles.css | 7 + metadata.xml | 2 +- phpunit.xml.dist | 8 +- src/Builders/AuthorizationBuilder.php | 32 - src/Builders/ManagementBuilder.php | 1 + .../GpApiAuthorizationRequestBuilder.php | 5 +- .../GpApi/GpApiManagementRequestBuilder.php | 3 +- .../GpApi/GpApiReportRequestBuilder.php | 3 +- .../GpApi/GpApiSecure3DRequestBuilder.php | 3 +- .../GpEcomAuthorizationRequestBuilder.php | 571 ++++++ .../GpEcom/GpEcomManagementRequestBuilder.php | 156 ++ .../GpEcom/GpEcomRecurringRequestBuilder.php | 369 ++++ .../GpEcom/GpEcomReportRequestBuilder.php | 73 + .../GpEcom/GpEcomRequestBuilder.php | 24 + .../RequestBuilder/RequestBuilderFactory.php | 46 + src/Builders/TransactionBuilder.php | 32 + src/Entities/GpApi/DTO/PaymentMethod.php | 1 + src/Entities/GpApi/GpApiRequest.php | 18 +- .../GpApi/GpApiRequestBuilderFactory.php | 26 - src/Entities/Request.php | 20 + src/Entities/Schedule.php | 52 + src/Gateways/GpApiConnector.php | 6 +- src/Gateways/GpEcomConnector.php | 612 ++++++ src/Gateways/RealexConnector.php | 1765 ----------------- src/Mapping/EnumMapping.php | 22 +- src/Mapping/GpEcomMapping.php | 390 ++++ src/PaymentMethods/RecurringPaymentMethod.php | 7 +- src/ServiceConfigs/Gateways/GeniusConfig.php | 4 - src/ServiceConfigs/Gateways/GpEcomConfig.php | 26 +- src/Utils/GenerationUtils.php | 15 +- .../CreditCardNotPresentTest.php | 13 + .../ApiCaseTest.php | 50 +- .../ApmTest.php} | 4 +- .../Certifications/SdkTest.php | 5 +- .../CreditTest.php | 28 +- .../GpEcom3dSecureTests.php} | 4 +- .../Hpp/GpEcomHppClient.php} | 4 +- .../HppTest.php | 43 +- .../HppTestCase.php | 5 +- .../OpenBankingTest.php | 0 .../GpEcomConnector/RecurringTest.php | 811 ++++++++ .../ReportingTest.php | 2 +- .../Secure3DSExemptionsTest.php | 0 .../Secure3dServiceTest.php | 2 +- .../RealexConnector/RecurringTest.php | 389 ---- .../Gateways/RealexConnector/CreditTest.php | 2 +- 52 files changed, 3654 insertions(+), 2355 deletions(-) create mode 100644 examples/gp-api/google-pay/charge.php create mode 100644 examples/gp-api/google-pay/index.html create mode 100644 examples/gp-api/google-pay/main.js create mode 100644 examples/gp-api/google-pay/styles.css rename src/{Entities => Builders/RequestBuilder}/GpApi/GpApiAuthorizationRequestBuilder.php (99%) rename src/{Entities => Builders/RequestBuilder}/GpApi/GpApiManagementRequestBuilder.php (98%) rename src/{Entities => Builders/RequestBuilder}/GpApi/GpApiReportRequestBuilder.php (99%) rename src/{Entities => Builders/RequestBuilder}/GpApi/GpApiSecure3DRequestBuilder.php (99%) create mode 100644 src/Builders/RequestBuilder/GpEcom/GpEcomAuthorizationRequestBuilder.php create mode 100644 src/Builders/RequestBuilder/GpEcom/GpEcomManagementRequestBuilder.php create mode 100644 src/Builders/RequestBuilder/GpEcom/GpEcomRecurringRequestBuilder.php create mode 100644 src/Builders/RequestBuilder/GpEcom/GpEcomReportRequestBuilder.php create mode 100644 src/Builders/RequestBuilder/GpEcom/GpEcomRequestBuilder.php create mode 100644 src/Builders/RequestBuilder/RequestBuilderFactory.php delete mode 100644 src/Entities/GpApi/GpApiRequestBuilderFactory.php create mode 100644 src/Entities/Request.php create mode 100644 src/Gateways/GpEcomConnector.php delete mode 100644 src/Gateways/RealexConnector.php create mode 100644 src/Mapping/GpEcomMapping.php rename test/Integration/Gateways/{RealexConnector => GpEcomConnector}/ApiCaseTest.php (97%) rename test/Integration/Gateways/{RealexConnector/RealexApmTest.php => GpEcomConnector/ApmTest.php} (99%) rename test/Integration/Gateways/{RealexConnector => GpEcomConnector}/Certifications/SdkTest.php (99%) rename test/Integration/Gateways/{RealexConnector => GpEcomConnector}/CreditTest.php (89%) rename test/Integration/Gateways/{RealexConnector/Realex3dSecureTests.php => GpEcomConnector/GpEcom3dSecureTests.php} (99%) rename test/Integration/Gateways/{RealexConnector/Hpp/RealexHppClient.php => GpEcomConnector/Hpp/GpEcomHppClient.php} (99%) rename test/Integration/Gateways/{RealexConnector => GpEcomConnector}/HppTest.php (97%) rename test/Integration/Gateways/{RealexConnector => GpEcomConnector}/HppTestCase.php (98%) rename test/Integration/Gateways/{RealexConnector => GpEcomConnector}/OpenBankingTest.php (100%) create mode 100644 test/Integration/Gateways/GpEcomConnector/RecurringTest.php rename test/Integration/Gateways/{RealexConnector => GpEcomConnector}/ReportingTest.php (96%) rename test/Integration/Gateways/{RealexConnector => GpEcomConnector}/Secure3DSExemptionsTest.php (100%) rename test/Integration/Gateways/{RealexConnector => GpEcomConnector}/Secure3dServiceTest.php (99%) delete mode 100644 test/Integration/Gateways/RealexConnector/RecurringTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 864e7ce3..d7bb45af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ ## Latest version #### Enhancements: +- GP-ECOM: Add payment scheduler +- GP-ECOM/GP-API: Structure refacto +- Upgrade to min PHP 7.1 + +## v3.1.1 (05/17/2022) +#### Enhancements: - GP-ECOM: Add HPP capture billing/shipping address - Add intl and mbstring extensions on composer - GP-API: Refacto reporting for disputes / search stored payment methods / LodgingData diff --git a/README.md b/README.md index 416a68da..c5a57c0c 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ This SDK makes it easy to integrate your PHP application with our Card Not Prese ## Requirements -- PHP 5.5.9+ +- PHP 7.1.0+ - OpenSSL 1.0.1+ - PHP Curl extension - PHP DOM extension @@ -64,7 +64,7 @@ In addition you can find working examples in the our example code repository. *Quick Tip*: The included [test suite](https://github.com/globalpayments/php-sdk/tree/master/test) can be a great source of code samples for using the SDK! -#### Process a Payment Example +### Process a Payment Example ```csharp $card = new CreditCardData(); @@ -85,7 +85,7 @@ try { } ``` -#### Test Card Data +### Test Card Data Name | Number | Exp Month | Exp Year | CVN ----------- | ---------------- | --------- | -------- | ---- @@ -97,7 +97,7 @@ Amex | 374101000000608 | 12 | 2025 | 1234 JCB | 3566000000000000 | 12 | 2025 | 123 Diners Club | 36256000000725 | 12 | 2025 | 123 -#### Testing Exceptions +### Testing Exceptions During your integration you will want to test for specific issuer responses such as 'Card Declined'. Because our sandbox environments do not actually reach out to issuing banks for authorizations, there are specific transaction amounts and/or card numbers that will trigger gateway and issuing bank responses. Please contact your support representative for a complete listing of values used to simulate transaction AVS/CVV results, declines, errors, and other responses that can be caught in your code. Example error handling code: diff --git a/composer.json b/composer.json index bca0dd9f..9b80b95e 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ } ], "require": { - "php": ">= 5.5.9", + "php": "^7.1", "ext-curl": "*", "ext-dom": "*", "ext-openssl": "*", diff --git a/examples/gp-api/google-pay/charge.php b/examples/gp-api/google-pay/charge.php new file mode 100644 index 00000000..3230b437 --- /dev/null +++ b/examples/gp-api/google-pay/charge.php @@ -0,0 +1,56 @@ +appId = 'i872l4VgZRtSrykvSn8Lkah8RE1jihvT'; +$config->appKey = '9pArW2uWoA8enxKc'; +$config->environment = Environment::TEST; +$config->channel = Channel::CardNotPresent; +$config->requestLogger = new SampleRequestLogger(new Logger("logs")); + +ServicesContainer::configureService($config); + +$card = new CreditCardData(); +$card->token = $googlePayToken; +$card->mobileType = EncyptedMobileType::GOOGLE_PAY; + +try { + $transaction = $card->charge('10') + ->withCurrency('GBP') + ->withModifier(TransactionModifier::ENCRYPTED_MOBILE) + ->execute(); + + echo 'Transaction successful, your transaction id is: ' . $transaction->transactionId; + echo '
'; + echo 'Transaction status: ' . $transaction->responseMessage; +} catch (\Exception $e) { + echo 'Failure: ' . $e->getMessage(); + exit; +} diff --git a/examples/gp-api/google-pay/index.html b/examples/gp-api/google-pay/index.html new file mode 100644 index 00000000..a196dfe5 --- /dev/null +++ b/examples/gp-api/google-pay/index.html @@ -0,0 +1,19 @@ + + + + + Global Payments Google Pay with GP-API example + + + + + +
+

In order to process payments via Google Pay, please switch to HTTPS.

+
+ +
+ + diff --git a/examples/gp-api/google-pay/main.js b/examples/gp-api/google-pay/main.js new file mode 100644 index 00000000..9ab9f643 --- /dev/null +++ b/examples/gp-api/google-pay/main.js @@ -0,0 +1,257 @@ +/** + * Config for Google Pay + */ +const config = { + googleMerchant: '12345678901234567890', // The Merchant id Provided by Google, it can be empty in Sandbox + globalPaymentsMerchant: 'gpapiqa1', // The Merchant Id provided by Global Payments + environment: 'TEST', + countryCode: 'GB', + currencyCode: 'GBP', + amount: '10.00', + buttonColor: 'black' +} + +/** + * Define the version of the Google Pay API referenced when creating your + * configuration + * + * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#PaymentDataRequest|apiVersion in PaymentDataRequest} + */ +const baseRequest = { + apiVersion: 2, + apiVersionMinor: 0 +}; + +/** + * Card networks supported by your site and your gateway + * + * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#CardParameters|CardParameters} + * @todo confirm card networks supported by your site and gateway + */ +const allowedCardNetworks = ["AMEX", "DISCOVER", "JCB", "MASTERCARD", "VISA"]; + +/** + * Card authentication methods supported by your site and your gateway + * + * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#CardParameters|CardParameters} + * @todo confirm your processor supports Android device tokens for your + * supported card networks + */ +const allowedCardAuthMethods = ["PAN_ONLY", "CRYPTOGRAM_3DS"]; + +/** + * Identify your gateway and your site's gateway merchant identifier + * + * The Google Pay API response will return an encrypted payment method capable + * of being charged by a supported gateway after payer authorization + * + * @todo check with your gateway on the parameters to pass + * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#gateway|PaymentMethodTokenizationSpecification} + */ +const tokenizationSpecification = { + type: 'PAYMENT_GATEWAY', + parameters: { + 'gateway': 'globalpayments', + 'gatewayMerchantId': config.globalPaymentsMerchant + } +}; + +/** + * Describe your site's support for the CARD payment method and its required + * fields + * + * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#CardParameters|CardParameters} + */ +const baseCardPaymentMethod = { + type: 'CARD', + parameters: { + allowedAuthMethods: allowedCardAuthMethods, + allowedCardNetworks: allowedCardNetworks + } +}; + +/** + * Describe your site's support for the CARD payment method including optional + * fields + * + * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#CardParameters|CardParameters} + */ +const cardPaymentMethod = Object.assign( + {}, + baseCardPaymentMethod, + { + tokenizationSpecification: tokenizationSpecification + } +); + +/** + * An initialized google.payments.api.PaymentsClient object or null if not yet set + * + * @see {@link getGooglePaymentsClient} + */ +let paymentsClient = null; + +/** + * Configure your site's support for payment methods supported by the Google Pay + * API. + * + * Each member of allowedPaymentMethods should contain only the required fields, + * allowing reuse of this base request when determining a viewer's ability + * to pay and later requesting a supported payment method + * + * @returns {object} Google Pay API version, payment methods supported by the site + */ +function getGoogleIsReadyToPayRequest() { + return Object.assign( + {}, + baseRequest, + { + allowedPaymentMethods: [baseCardPaymentMethod] + } + ); +} + +/** + * Configure support for the Google Pay API + * + * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#PaymentDataRequest|PaymentDataRequest} + * @returns {object} PaymentDataRequest fields + */ +function getGooglePaymentDataRequest() { + const paymentDataRequest = Object.assign({}, baseRequest); + paymentDataRequest.allowedPaymentMethods = [cardPaymentMethod]; + paymentDataRequest.transactionInfo = getGoogleTransactionInfo(); + paymentDataRequest.merchantInfo = { + // @todo a merchant ID is available for a production environment after approval by Google + // See {@link https://developers.google.com/pay/api/web/guides/test-and-deploy/integration-checklist|Integration checklist} + merchantId: config.googleMerchant + }; + return paymentDataRequest; +} + +/** + * Return an active PaymentsClient or initialize + * + * @see {@link https://developers.google.com/pay/api/web/reference/client#PaymentsClient|PaymentsClient constructor} + * @returns {google.payments.api.PaymentsClient} Google Pay API client + */ +function getGooglePaymentsClient() { + if (paymentsClient === null) { + paymentsClient = new google.payments.api.PaymentsClient({environment: config.environment}); + } + return paymentsClient; +} + +/** + * Initialize Google PaymentsClient after Google-hosted JavaScript has loaded + * + * Display a Google Pay payment button after confirmation of the viewer's + * ability to pay. + */ +function onGooglePayLoaded() { + if (!deviceSupported()) { + showError(); + return false; + } + + const paymentsClient = getGooglePaymentsClient(); + paymentsClient.isReadyToPay(getGoogleIsReadyToPayRequest()) + .then(function(response) { + if (response.result) { + addGooglePayButton(); + } + }) + .catch(function(err) { + // show error in developer console for debugging + console.error(err); + }); +} + + +/** + * Add a Google Pay purchase button alongside an existing checkout button + * + * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#ButtonOptions|Button options} + * @see {@link https://developers.google.com/pay/api/web/guides/brand-guidelines|Google Pay brand guidelines} + */ +function addGooglePayButton() { + const paymentsClient = getGooglePaymentsClient(); + const button = paymentsClient.createButton( + { + buttonColor: config.buttonColor, + onClick: onGooglePaymentButtonClicked + } + ); + document.querySelector('#container').appendChild(button); +} + +/** + * Provide Google Pay API with a payment amount, currency, and amount status + * + * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#TransactionInfo|TransactionInfo} + * @returns {object} transaction info, suitable for use as transactionInfo property of PaymentDataRequest + */ +function getGoogleTransactionInfo() { + return { + countryCode: config.countryCode, + currencyCode: config.currencyCode, + totalPriceStatus: 'FINAL', + // set to cart total + totalPrice: config.amount + }; +} + +/** + * Show Google Pay payment sheet when Google Pay payment button is clicked + */ +function onGooglePaymentButtonClicked() { + const paymentDataRequest = getGooglePaymentDataRequest(); + paymentDataRequest.transactionInfo = getGoogleTransactionInfo(); + + const paymentsClient = getGooglePaymentsClient(); + paymentsClient.loadPaymentData(paymentDataRequest) + .then(function(paymentData) { + // handle the response + processPayment(paymentData); + }) + .catch(function(err) { + // show error in developer console for debugging + console.error(err); + }); +} + +/** + * Process payment data returned by the Google Pay API + * + * @param {object} paymentData response from Google Pay API after user approves payment + * @see {@link https://developers.google.com/pay/api/web/reference/response-objects#PaymentData|PaymentData object reference} + */ +function processPayment(paymentData) { + /** + * Google sends a JSON with some characters encoded (which should not be). + * Parsing the JSON and then stringifying it again fixes the issue. + */ + var paymentToken = JSON.stringify(JSON.parse(paymentData.paymentMethodData.tokenizationData.token)); + setToken(paymentToken); + submitForm(); +} + +/** + * Set the token received from Google to the form + * @param googleToken + */ +function setToken(googleToken) { + document.querySelector('#googlePayToken').value = googleToken; +} + +function submitForm() { + document.querySelector('#form').submit(); +} + +function showError() { + document.querySelector('.error').classList.remove('hide'); +} + +function deviceSupported() { + return location.protocol === 'https:'; +} diff --git a/examples/gp-api/google-pay/styles.css b/examples/gp-api/google-pay/styles.css new file mode 100644 index 00000000..bf7326ce --- /dev/null +++ b/examples/gp-api/google-pay/styles.css @@ -0,0 +1,7 @@ +.error { + color: red; +} + +.hide { + display: none; +} diff --git a/metadata.xml b/metadata.xml index 0f73eb45..1fa918bc 100644 --- a/metadata.xml +++ b/metadata.xml @@ -1,3 +1,3 @@ - 3.1.1 + 4.0.0 \ No newline at end of file diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 5dca361e..3991199f 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -25,14 +25,14 @@ ./test/Integration/Gateways/PorticoConnector/Certifications/ - ./test/Integration/Gateways/RealexConnector/Certifications/ + ./test/Integration/Gateways/GpEcomConnector/Certifications/ ./test/Integration/Gateways/GpApiConnector/Certifications/ - + ./test/Integration/Gateways/PorticoConnector/ - - ./test/Integration/Gateways/RealexConnector/ + + ./test/Integration/Gateways/GpEcomConnector/ ./test/Integration/Gateways/GpApiConnector/ diff --git a/src/Builders/AuthorizationBuilder.php b/src/Builders/AuthorizationBuilder.php index 8743c5f1..bfbaee50 100644 --- a/src/Builders/AuthorizationBuilder.php +++ b/src/Builders/AuthorizationBuilder.php @@ -389,13 +389,6 @@ class AuthorizationBuilder extends TransactionBuilder */ public $timestamp; - /** - * Request supplementary data - * - * @var array - */ - public $supplementaryData; - /** * DCC rate Data * @@ -1322,31 +1315,6 @@ public function withMultiCapture($multiCapture = false) return $this; } - /** - * Depending on the parameters received, - * Add supplementary data or - * Add multiple values to the supplementaryData array - * - * @param string|array $key - * @param string $value - * - * @return AuthorizationBuilder - */ - public function withSupplementaryData($key, $value = null) - { - if ($value === null && is_array($key)) { - foreach ($key as $k => $v) { - $this->withSupplementaryData($k, $v); - } - } - - if ($key && isset($value)) { - $this->supplementaryData[$key] = (string) $value; - } - - return $this; - } - /** * @param $value */ diff --git a/src/Builders/ManagementBuilder.php b/src/Builders/ManagementBuilder.php index ec06f0dc..7e0a50c8 100644 --- a/src/Builders/ManagementBuilder.php +++ b/src/Builders/ManagementBuilder.php @@ -207,6 +207,7 @@ class ManagementBuilder extends TransactionBuilder public function __construct($type, $paymentMethod = null) { parent::__construct($type, $paymentMethod); + $this->supplementaryData = []; } /** diff --git a/src/Entities/GpApi/GpApiAuthorizationRequestBuilder.php b/src/Builders/RequestBuilder/GpApi/GpApiAuthorizationRequestBuilder.php similarity index 99% rename from src/Entities/GpApi/GpApiAuthorizationRequestBuilder.php rename to src/Builders/RequestBuilder/GpApi/GpApiAuthorizationRequestBuilder.php index fae7e351..18a93263 100644 --- a/src/Entities/GpApi/GpApiAuthorizationRequestBuilder.php +++ b/src/Builders/RequestBuilder/GpApi/GpApiAuthorizationRequestBuilder.php @@ -1,6 +1,6 @@ name = $paymentMethodContainer instanceof AlternativePaymentMethod ? $paymentMethodContainer->accountHolderName : (!empty($paymentMethodContainer->cardHolderName) ? $paymentMethodContainer->cardHolderName : null); - + $paymentMethod->narrative = !empty($builder->dynamicDescriptor) ? $builder->dynamicDescriptor : null; switch (get_class($paymentMethodContainer)) { case CreditCardData::class; $paymentMethod->fingerprint_mode = diff --git a/src/Entities/GpApi/GpApiManagementRequestBuilder.php b/src/Builders/RequestBuilder/GpApi/GpApiManagementRequestBuilder.php similarity index 98% rename from src/Entities/GpApi/GpApiManagementRequestBuilder.php rename to src/Builders/RequestBuilder/GpApi/GpApiManagementRequestBuilder.php index bea19622..6ff01eab 100644 --- a/src/Entities/GpApi/GpApiManagementRequestBuilder.php +++ b/src/Builders/RequestBuilder/GpApi/GpApiManagementRequestBuilder.php @@ -1,6 +1,6 @@ transactionModifier) && + $builder->transactionModifier === TransactionModifier::ENCRYPTED_MOBILE && + $builder->paymentMethod->mobileType === EncyptedMobileType::GOOGLE_PAY && + (empty($builder->amount) || empty($builder->currency)) + ) { + throw new BuilderException("Amount and Currency cannot be null for google payment"); + } + + $xml = new DOMDocument(); + $timestamp = isset($builder->timestamp) ? $builder->timestamp : GenerationUtils::generateTimestamp(); + $orderId = isset($builder->orderId) ? $builder->orderId : GenerationUtils::generateOrderId(); + $transactionType = GpEcomMapping::mapAuthRequestType($builder); + + // Build Request + $request = $xml->createElement("request"); + $request->setAttribute("timestamp", $timestamp); + $request->setAttribute("type", $transactionType); + + $request->appendChild($xml->createElement("merchantid", $config->merchantId)); + + if ($config->accountId !== null) { + $request->appendChild($xml->createElement("account", $config->accountId)); + } + if ($config->channel !== null && !($builder->paymentMethod instanceof AlternativePaymentMethod)) { + $request->appendChild($xml->createElement("channel", $config->channel)); + } + + if (isset($builder->amount)) { + $amount = $xml->createElement("amount", preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount))); + $amount->setAttribute("currency", $builder->currency); + $request->appendChild($amount); + } + + // This needs to be figured out based on txn type and set to 0, 1 or MULTI + if ($builder->transactionType === TransactionType::SALE || $builder->transactionType == TransactionType::AUTH) { + $autoSettle = $builder->transactionType === TransactionType::SALE ? "1" : "0"; + $element = $xml->createElement("autosettle"); + $element->setAttribute("flag", $autoSettle); + $request->appendChild($element); + } + + $request->appendChild($xml->createElement("orderid", $orderId)); + + // For Fraud Decision Manager + if (!empty($builder->customerData)) { + $customerValue = $builder->customerData; + $customer = $xml->createElement("customer"); + $customer->appendChild($xml->createElement("customerid", $customerValue->id)); + $customer->appendChild($xml->createElement("firstname", $customerValue->firstName)); + $customer->appendChild($xml->createElement("lastname", $customerValue->lastName)); + $customer->appendChild($xml->createElement("dateofbirth", $customerValue->dateOfBirth)); + $customer->appendChild($xml->createElement("customerpassword", $customerValue->customerPassword)); + $customer->appendChild($xml->createElement("email", $customerValue->email)); + $customer->appendChild($xml->createElement("domainname", $customerValue->domainName)); + $customer->appendChild($xml->createElement("devicefingerprint", $customerValue->deviceFingerPrint)); + $customer->appendChild($xml->createElement("phonenumber", $customerValue->homePhone)); + $request->appendChild($customer); + } + + if (!empty($builder->productData)) { + $prod = []; + $productValues = $builder->productData; + $products = $xml->createElement("products"); + + foreach ($productValues as $prod) { + $product = $xml->createElement("product"); + $product->appendChild($xml->createElement('product_id', $prod['product_id'])); + $product->appendChild($xml->createElement('productname', $prod['productname'])); + $product->appendChild($xml->createElement('quantity', $prod['quantity'])); + $product->appendChild($xml->createElement('unitprice', $prod['unitprice'])); + $product->appendChild($xml->createElement('gift', $prod['gift'])); + $product->appendChild($xml->createElement('type', $prod['type'])); + $product->appendChild($xml->createElement('risk', $prod['risk'])); + $product->appendChild($products); + $request->appendChild($product); + } + } + + if ($builder->decisionManager !== null) { + $dmValues = $builder->decisionManager; + $fraud = $xml->createElement("fraud"); + $dm = $fraud->appendChild($xml->createElement('dm')); + $dm->appendChild($xml->createElement('billtohostname', $dmValues->billToHostName)); + $dm->appendChild($xml->createElement( + 'billtohttpbrowsercookiesaccepted', + ($dmValues->billToHttpBrowserCookiesAccepted) != true ? 'false' : 'true' + )); + $dm->appendChild($xml->createElement('billtohttpbrowseremail', $dmValues->billToHttpBrowserEmail)); + $dm->appendChild($xml->createElement('billtohttpbrowsertype', $dmValues->billToHttpBrowserType)); + $dm->appendChild($xml->createElement('billtoipnetworkaddress', $dmValues->billToIpNetworkAddress)); + $dm->appendChild($xml->createElement( + 'businessrulesscorethreshold', + $dmValues->businessRulessCoreThresHold + )); + $dm->appendChild($xml->createElement('billtopersonalid', $dmValues->billToPersonalId)); + $dm->appendChild($xml->createElement('invoiceheadertendertype', $dmValues->invoiceHeaderTenderType)); + $dm->appendChild($xml->createElement( + 'invoiceheaderisgift', + ($dmValues->invoiceHeaderIsGift) != true ? 'false' : 'true' + )); + $dm->appendChild($xml->createElement('decisionmanagerprofile', $dmValues->decisionManagerProfile)); + $dm->appendChild($xml->createElement( + 'invoiceheaderreturnsaccepted', + ($dmValues->invoiceHeaderReturnsAccepted) != true ? 'false' : 'true' + )); + $dm->appendChild($xml->createElement('itemhosthedge', $dmValues->itemHostHedge)); + $dm->appendChild($xml->createElement('itemnonsensicalhedge', $dmValues->itemNonsensicalHedge)); + $dm->appendChild($xml->createElement('itemobscenitieshedge', $dmValues->itemObscenitiesHedge)); + $dm->appendChild($xml->createElement('itemphonehedge', $dmValues->itemPhoneHedge)); + $dm->appendChild($xml->createElement('itemtimehedge', $dmValues->itemTimeHedge)); + $dm->appendChild($xml->createElement('itemvelocityhedge', $dmValues->itemVelocityHedge)); + $request->appendChild($dm); + } + + if (!empty($builder->customData)) { + $customValues = $builder->customData; + $custom = $xml->createElement("custom"); + + foreach ($customValues as $cust) { + $custom->appendChild($xml->createElement('field01', $cust['field01'])); + $custom->appendChild($xml->createElement('field02', $cust['field02'])); + $custom->appendChild($xml->createElement('field03', $cust['field03'])); + $custom->appendChild($xml->createElement('field04', $cust['field04'])); + $request->appendChild($custom); + } + } + + // For DCC charge/auth + if (!empty($builder->dccRateData)) { + $dccinfo = $xml->createElement("dccinfo"); + $dccinfo->appendChild($xml->createElement( + "ccp", + !empty($builder->dccRateData->dccProcessor) ? $builder->dccRateData->dccProcessor : DccProcessor::FEXCO) + ); + $dccinfo->appendChild($xml->createElement( + "type", + !empty($builder->dccRateData->dccType) ? $builder->dccRateData->dccType : "1") + ); + $dccinfo->appendChild($xml->createElement("ratetype", $builder->dccRateData->dccRateType)); + if ($builder->transactionType !== TransactionType::DCC_RATE_LOOKUP) { + $amount = $xml->createElement("amount", preg_replace('/[^0-9]/', '', $builder->dccRateData->cardHolderAmount)); + $amount->setAttribute("currency", $builder->dccRateData->cardHolderCurrency); + $dccinfo->appendChild($amount); + $dccinfo->appendChild($xml->createElement("rate", $builder->dccRateData->cardHolderRate)); + } + $request->appendChild($dccinfo); + } + + if ( + ( + $builder->transactionType === TransactionType::AUTH || + $builder->transactionType === TransactionType::CAPTURE || + $builder->transactionType === TransactionType::REFUND + ) && + !empty($builder->dynamicDescriptor) + ) { + $narrative = $xml->createElement("narrative"); + $narrative->appendChild($xml->createElement("chargedescription", strtoupper($builder->dynamicDescriptor))); + $request->appendChild($narrative); + } + + // Hydrate the payment data fields + if ($builder->paymentMethod instanceof CreditCardData) { + $card = $builder->paymentMethod; + + if ($builder->transactionModifier === TransactionModifier::ENCRYPTED_MOBILE) { + $request->appendChild($xml->createElement("token", $card->token)); + $request->appendChild($xml->createElement("mobile", $card->mobileType)); + } else { + $cardElement = $xml->createElement("card"); + $cardElement->appendChild($xml->createElement("number", $card->number)); + $cardElement->appendChild($xml->createElement("expdate", $card->getShortExpiry())); + $cardElement->appendChild($xml->createElement("chname", $card->cardHolderName)); + + $cardElement->appendChild($xml->createElement( + "type", + strtoupper(EnumMapping::mapCardType(GatewayProvider::GP_ECOM, CardUtils::getBaseCardType($card->getCardType()))) + )); + + if ($card->cvn !== null) { + //if cvn number is not empty indicator should be PRESENT + $cvnPresenceIndicator = (!empty($card->cvn)) ? + CvnPresenceIndicator::PRESENT: + $card->cvnPresenceIndicator; + + $cvnElement = $xml->createElement("cvn"); + $cvnElement->appendChild($xml->createElement("number", $card->cvn)); + $cvnElement->appendChild($xml->createElement("presind", $cvnPresenceIndicator)); + $cardElement->appendChild($cvnElement); + } + $request->appendChild($cardElement); + } + // issueno + $hash = ''; + if ($builder->transactionType === TransactionType::VERIFY) { + $hash = GenerationUtils::generateHash( + $config->sharedSecret, + implode('.', [ + $timestamp, + $config->merchantId, + $orderId, + $card->number + ]) + ); + } else { + $requestValues = $this->getShal1RequestValues($timestamp, $orderId, $builder, $card, $config); + + $hash = GenerationUtils::generateHash( + $config->sharedSecret, + implode('.', $requestValues) + ); + } + + $request->appendChild($xml->createElement("sha1hash", $hash)); + } + + if ($builder->paymentMethod instanceof RecurringPaymentMethod) { + $recurring = $builder->paymentMethod; + $request->appendChild($xml->createElement("payerref", $recurring->customerKey)); + $request->appendChild($xml->createElement( + "paymentmethod", + isset($recurring->key) ? $recurring->key : $recurring->id + )); + + if ($builder->cvn !== null && $builder->cvn !== '') { + $paymentData = $xml->createElement("paymentdata"); + $cvn = $xml->createElement("cvn"); + $cvn->appendChild($xml->createElement("number", $builder->cvn)); + $paymentData->appendChild($cvn); + $request->appendChild($paymentData); + } + + $hash = ''; + if ($builder->transactionType === TransactionType::VERIFY) { + if (!empty($builder->transactionModifier) && + $builder->transactionModifier === TransactionModifier::SECURE3D) { + $hash = GenerationUtils::generateHash( + $config->sharedSecret, + implode('.', [ + $timestamp, + $config->merchantId, + $orderId, + preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount)), + $builder->currency, + $recurring->customerKey, + ]) + ); + } else { + $hash = GenerationUtils::generateHash( + $config->sharedSecret, + implode('.', [ + $timestamp, + $config->merchantId, + $orderId, + $recurring->customerKey, + ]) + ); + } + } else { + $hash = GenerationUtils::generateHash( + $config->sharedSecret, + implode('.', [ + $timestamp, + $config->merchantId, + $orderId, + preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount)), + $builder->currency, + $recurring->customerKey, + ]) + ); + } + $request->appendChild($xml->createElement("sha1hash", $hash)); + } else { + // TODO: Token Processing + //$request->appendChild($xml->createElement("sha1hash", GenerateHash(order, token)); + } + + // refund hash + if ($builder->transactionType === TransactionType::REFUND) { + $request->appendChild($xml->createElement( + "refundhash", + GenerationUtils::generateHash($config->refundPassword) ?: '' + )); + } + + + + if ($builder->paymentMethod instanceof AlternativePaymentMethod) { + $this->buildAlternativePaymentMethod($builder, $request, $xml); + } + + // comment ...TODO: needs to be multiple + if ($builder->description != null) { + $comments = $xml->createElement("comments"); + $comment = $xml->createElement("comment", $builder->description); + $comment->setAttribute("id", "1"); + $comments->appendChild($comment); + + $request->appendChild($comments); + } + + if ($builder->paymentMethod instanceof AlternativePaymentMethod) { + $hash = GenerationUtils::generateHash( + $config->sharedSecret, + implode('.', [ + $timestamp, + $config->merchantId, + $orderId, + preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount)), + $builder->currency, + $builder->paymentMethod->alternativePaymentMethodType, + ]) + ); + $request->appendChild($xml->createElement("sha1hash", $hash)); + } + + if ($builder->recurringType !== null || $builder->recurringSequence !== null) { + $recurring = $xml->createElement("recurring"); + $recurring->setAttribute("type", strtolower($builder->recurringType)); + $recurring->setAttribute("sequence", strtolower($builder->recurringSequence)); + $request->appendChild($recurring); + } + + // fraud filter + $this->buildFraudFilter($builder, $xml, $request); + + // tssinfo + + // stored credential + if ($builder->storedCredential != null) { + $storedCredential = $xml->createElement("storedcredential"); + $storedCredential->appendChild($xml->createElement("type", $builder->storedCredential->type)); + $storedCredential->appendChild($xml->createElement("initiator", $builder->storedCredential->initiator)); + $storedCredential->appendChild($xml->createElement("sequence", $builder->storedCredential->sequence)); + $storedCredential->appendChild($xml->createElement("srd", $builder->storedCredential->schemeId)); + $request->appendChild($storedCredential); + } + + //Supplementary Data + if (!empty($builder->supplementaryData)) { + $this->buildSupplementaryData($builder, $xml,$request); + } + + // mpi + if (!empty($builder->paymentMethod->threeDSecure)) { + $secureEcom = $builder->paymentMethod->threeDSecure; + $mpi = $xml->createElement("mpi"); + $mpi->appendChild($xml->createElement("eci", $secureEcom->eci)); + $mpi->appendChild($xml->createElement("cavv", $secureEcom->cavv)); + $mpi->appendChild($xml->createElement("xid", $secureEcom->xid)); + + 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); + } + + return new Request('', 'POST', $xml->saveXML($request)); + } + + public function buildAlternativePaymentMethod($builder, $request, $xml) + { + $request->appendChild($xml->createElement( + "paymentmethod", + $builder->paymentMethod->alternativePaymentMethodType + )); + + $paymentMethodDetails = $xml->createElement("paymentmethoddetails"); + list($returnUrl, $statusUpdateUrl, $cancelUrl) = + $this->mapAPMUrls($builder->paymentMethod->alternativePaymentMethodType); + $paymentMethodDetails->appendChild( + $xml->createElement($returnUrl, $builder->paymentMethod->returnUrl) + ); + $paymentMethodDetails->appendChild( + $xml->createElement($statusUpdateUrl, $builder->paymentMethod->statusUpdateUrl) + ); + if (!empty($builder->paymentMethod->cancelUrl)) { + $paymentMethodDetails->appendChild( + $xml->createElement($cancelUrl, $builder->paymentMethod->cancelUrl) + ); + } + + if (!empty($builder->paymentMethod->descriptor)) { + $paymentMethodDetails->appendChild( + $xml->createElement("descriptor", $builder->paymentMethod->descriptor) + ); + } + + $paymentMethodDetails->appendChild($xml->createElement("country", $builder->paymentMethod->country)); + $paymentMethodDetails->appendChild($xml->createElement( + "accountholdername", + $builder->paymentMethod->accountHolderName + )); + + $request->appendChild($paymentMethodDetails); + } + + public function buildFraudFilter($builder, $xml, $request) + { + // tssinfo fraudfilter + // fraudfilter + if (!empty($builder->fraudFilter)) { + $fraudFilter = $xml->createElement("fraudfilter"); + $fraudFilter->setAttribute("mode", $builder->fraudFilter); + if (!empty($builder->fraudRules)) { + $rules = $xml->createElement("rules"); + foreach ($builder->fraudRules as $fraudRule) { + $rule = $xml->createElement("rule"); + $rule->setAttribute("id", $fraudRule->key); + $rule->setAttribute("mode", $fraudRule->mode); + $rules->appendChild($rule); + } + $fraudFilter->appendChild($rules); + } + $request->appendChild($fraudFilter); + } + if ($builder->customerId !== null || $builder->productId !== null || + $builder->clientTransactionId !== null || $builder->verifyAddress !== false + ) { + $tssInfo = $xml->createElement("tssinfo"); + + if (!empty($builder->customerId)) { + $tssInfo->appendChild($xml->createElement("custnum", $builder->customerId)); + } + + if (!empty($builder->productId)) { + $tssInfo->appendChild($xml->createElement("prodid", $builder->productId)); + } + + if (!empty($builder->clientTransactionId)) { + $tssInfo->appendChild($xml->createElement("varref", $builder->clientTransactionId)); + } + + if (!empty($builder->customerIpAddress)) { + $tssInfo->appendChild($xml->createElement("custipaddress", $builder->customerIpAddress)); + } + + if (!empty($builder->billingAddress)) { + $billingAddress = $xml->createElement("address"); + $billingAddress->setAttribute("type", 'billing'); + $billingAddress->appendChild($xml->createElement("code", $builder->billingAddress->postalCode)); + $billingAddress->appendChild($xml->createElement("country", $builder->billingAddress->country)); + $tssInfo->appendChild($billingAddress); + } + + if (!empty($builder->shippingAddress)) { + $shippingAddress = $xml->createElement("address"); + $shippingAddress->setAttribute("type", 'shipping'); + $shippingAddress->appendChild($xml->createElement("code", $builder->shippingAddress->postalCode)); + $shippingAddress->appendChild($xml->createElement("country", $builder->shippingAddress->country)); + $tssInfo->appendChild($shippingAddress); + } + if (!empty($tssInfo->childNodes->length)) { + $request->appendChild($tssInfo); + } + } + } + + private function mapAPMUrls($paymentMethodType) + { + switch ($paymentMethodType) { + case AlternativePaymentType::PAYPAL: + return ['ReturnURL', 'StatusUpdateURL', 'CancelURL']; + default: + return ['returnurl', 'statusupdateurl', 'cancelurl']; + } + } + + /** + * Return the request values for Shal hash generation based on transaction type + * EncyptedMobileType::GOOGLE_PAY requires amount and currency with token + * EncyptedMobileType::APPLE_PAY doesn't requires amount and currency. token contains those values + * + * @param string $timestamp current timestamp + * @param int $orderId current order id + * @param object $builder auth builder object + * @param object $card + * @param GpEcomConfig $config + * + * @return array + */ + private function getShal1RequestValues($timestamp, $orderId, $builder, $card, $config) + { + $requestValues = [ + $timestamp, + $config->merchantId, + $orderId, + preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount)), + $builder->currency, + $card->number + ]; + + if (($builder->transactionModifier === TransactionModifier::ENCRYPTED_MOBILE)) { + switch ($card->mobileType) { + case EncyptedMobileType::GOOGLE_PAY: + case EncyptedMobileType::APPLE_PAY: + $requestValues = [ + $timestamp, + $config->merchantId, + $orderId, + preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount)), + $builder->currency, + $card->token + ]; + break; + default: + break; + } + } + return $requestValues; + } +} \ No newline at end of file diff --git a/src/Builders/RequestBuilder/GpEcom/GpEcomManagementRequestBuilder.php b/src/Builders/RequestBuilder/GpEcom/GpEcomManagementRequestBuilder.php new file mode 100644 index 00000000..4c2e37c4 --- /dev/null +++ b/src/Builders/RequestBuilder/GpEcom/GpEcomManagementRequestBuilder.php @@ -0,0 +1,156 @@ +orderId ?: GenerationUtils::generateOrderId(); + $transactionType = GpEcomMapping::mapManageRequestType($builder); + // Build Request + $request = $xml->createElement("request"); + $request->setAttribute("timestamp", $timestamp); + $request->setAttribute("type", $transactionType); + + $request->appendChild($xml->createElement("merchantid", $config->merchantId)); + + if ($config->accountId !== null) { + $request->appendChild($xml->createElement("account", $config->accountId)); + } + if (is_null($builder->alternativePaymentType)) { + $request->appendChild($xml->createElement("channel", $config->channel)); + } + + if ($builder->amount !== null) { + $amount = $xml->createElement("amount", preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount))); + $amount->setAttribute("currency", $builder->currency); + $request->appendChild($amount); + } elseif ($builder->transactionType === TransactionType::CAPTURE) { + throw new BuilderException("Amount cannot be null for capture."); + } + + $request->appendChild($xml->createElement("orderid", $orderId)); + $request->appendChild($xml->createElement("pasref", $builder->transactionId)); + + // rebate hash + if ($builder->transactionType === TransactionType::REFUND && + is_null($builder->alternativePaymentType)) { + $request->appendChild($xml->createElement("authcode", $builder->paymentMethod->authCode)); + } + + // reason code + if ($builder->reasonCode !== null) { + $request->appendChild($xml->createElement("reasoncode", $builder->reasonCode)); + } + + if ($builder->alternativePaymentType !== null) { + $request->appendChild($xml->createElement("paymentmethod", $builder->alternativePaymentType)); + if ($builder->transactionType == TransactionType::CONFIRM) { + $paymentMethodDetails = $xml->createElement("paymentmethoddetails"); + $apmResponse = $builder->paymentMethod->alternativePaymentResponse; + if ($builder->alternativePaymentType == AlternativePaymentType::PAYPAL) { + $paymentMethodDetails->appendChild($xml->createElement('Token', $apmResponse->sessionToken)); + $paymentMethodDetails->appendChild( + $xml->createElement('PayerID', $apmResponse->providerReference) + ); + } + $request->appendChild($paymentMethodDetails); + } + } + + if ($builder->transactionType === TransactionType::VERIFY_SIGNATURE) { + $request->appendChild($xml->createElement("pares", $builder->payerAuthenticationResponse)); + } + + //supplementarydata + if ( + in_array($builder->transactionType,[TransactionType::REFUND, TransactionType::CAPTURE]) && + !empty($builder->supplementaryData) + ) { + $this->buildSupplementaryData($builder, $xml,$request); + } + + // comments needs to be multiple + if ($builder->description !== null) { + $comments = $xml->createElement("comments"); + $comment = $xml->createElement("comment", $builder->description); + $comment->setAttribute("id", "1"); + $comments->appendChild($comment); + $request->appendChild($comments); + } + + $toHash = [ + $timestamp, + $config->merchantId, + $orderId, + ($builder->amount !== null ? preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount)) : ''), + ($builder->currency !== null ? $builder->currency : ''), + ($builder->alternativePaymentType !== null ? $builder->alternativePaymentType : '') + ]; + + if ( + ( + $builder->transactionType === TransactionType::CAPTURE || + $builder->transactionType === TransactionType::REFUND + ) && + !empty($builder->dynamicDescriptor) + ) { + $narrative = $xml->createElement("narrative"); + $narrative->appendChild($xml->createElement("chargedescription", strtoupper($builder->dynamicDescriptor))); + $request->appendChild($narrative); + } + + $request->appendChild( + $xml->createElement( + "sha1hash", + GenerationUtils::generateHash($config->sharedSecret, implode('.', $toHash)) + ) + ); + + // rebate hash + if ($builder->transactionType === TransactionType::REFUND) { + $request->appendChild( + $xml->createElement( + "refundhash", + GenerationUtils::generateHash(isset($config->rebatePassword) ? $config->rebatePassword : '') + ) + ); + } + + return new Request('', 'POST', $xml->saveXML($request)); + } +} \ No newline at end of file diff --git a/src/Builders/RequestBuilder/GpEcom/GpEcomRecurringRequestBuilder.php b/src/Builders/RequestBuilder/GpEcom/GpEcomRecurringRequestBuilder.php new file mode 100644 index 00000000..9459cc7f --- /dev/null +++ b/src/Builders/RequestBuilder/GpEcom/GpEcomRecurringRequestBuilder.php @@ -0,0 +1,369 @@ +orderId ? $builder->orderId : GenerationUtils::generateOrderId(); + $shaHashTagName = "sha1hash"; + + // Build Request + $request = $xml->createElement("request"); + $request->setAttribute("timestamp", $timestamp); + $request->setAttribute("type", $this->mapRecurringRequestType($builder)); + + $request->appendChild($xml->createElement("merchantid", $config->merchantId)); + + + /** + * @var RecurringBuilder $builder + */ + switch ($builder->transactionType) { + case TransactionType::CREATE: + case TransactionType::EDIT: + $request->appendChild($xml->createElement("channel", $config->channel)); + if ($config->accountId !== null) { + $request->appendChild($xml->createElement("account", $config->accountId)); + } + if ($builder->entity instanceof Customer) { + $request->appendChild($xml->createElement("orderid", $orderId)); + $hash = GenerationUtils::generateHash( + $config->sharedSecret, + implode('.', [ + $timestamp, + $config->merchantId, + $orderId, + '', + '', + $builder->entity->key + ]) + ); + + $request->appendChild($this->buildCustomer($xml, $builder)); + } elseif ($builder->entity instanceof RecurringPaymentMethod) { + $payment = $builder->entity; + $paymentKey = (!empty($payment->key)) ? $payment->key : $payment->id; + + if ($builder->transactionType == TransactionType::CREATE) { + $hash = GenerationUtils::generateHash( + $config->sharedSecret, + implode('.', [ + $timestamp, + $config->merchantId, + $orderId, + '', + '', + $payment->customerKey, + $payment->paymentMethod->cardHolderName, + $payment->paymentMethod->number + ]) + ); + } else { + $hash = GenerationUtils::generateHash( + $config->sharedSecret, + implode('.', [ + $timestamp, + $config->merchantId, + $payment->customerKey, + $paymentKey, + $payment->paymentMethod->getShortExpiry(), + $payment->paymentMethod->number + ]) + ); + } + $request->appendChild($xml->createElement("orderid", $orderId)); + $request->appendChild($this->buildCardElement($xml, $payment, $paymentKey)); + $request->appendChild($xml->createElement("defaultcard", 1)); + } elseif ($builder->entity instanceof Schedule) { + $schedule = $builder->entity; + $amount = preg_replace('/[^0-9]/', '', sprintf('%01.2f', $schedule->amount)); + $frequency = EnumMapping::mapScheduleFrequency( + GatewayProvider::GP_ECOM, + $schedule->frequency + ); + $hash = GenerationUtils::generateHash( + $config->sharedSecret, + implode('.', [ + $timestamp, + $config->merchantId, + $schedule->id, + $amount, + $schedule->currency, + $schedule->customerKey, + $frequency + ]) + ); + + $request->appendChild($xml->createElement("scheduleref", $schedule->id)); + $request->appendChild($xml->createElement("alias",$schedule->name)); + $request->appendChild($xml->createElement("orderidstub",$schedule->orderPrefix)); + $request->appendChild($xml->createElement("transtype","auth")); + $request->appendChild($xml->createElement("schedule", $frequency)); + if (!empty($schedule->startDate)) { + $request->appendChild($xml->createElement("startdate",$schedule->startDate->format('Ymd'))); + } + $request->appendChild($xml->createElement("numtimes",$schedule->numberOfPaymentsRemaining)); + if (!empty($schedule->endDate)) { + $request->appendChild($xml->createElement("enddate",$schedule->endDate->format('Ymd'))); + } + $request->appendChild($xml->createElement("payerref",$schedule->customerKey)); + $request->appendChild($xml->createElement("paymentmethod",$schedule->paymentKey)); + $amount = $xml->createElement("amount", $amount); + $amount->setAttribute("currency", $schedule->currency); + $request->appendChild($amount); + $request->appendChild($xml->createElement("prodid",$schedule->productId)); + $request->appendChild($xml->createElement("varref",$schedule->poNumber)); + $request->appendChild($xml->createElement("custno",$schedule->customerNumber)); + $request->appendChild($xml->createElement("comment",$schedule->description )); + } + + //set hash value + $request->appendChild($xml->createElement($shaHashTagName, $hash)); + break; + case TransactionType::DELETE: + if ($builder->entity instanceof RecurringPaymentMethod) { + $request->appendChild($xml->createElement("channel", $config->channel)); + if ($config->accountId !== null) { + $request->appendChild($xml->createElement("account", $config->accountId)); + } + $payment = $builder->entity; + $paymentKey = (!empty($payment->key)) ? $payment->key : $payment->id; + $cardElement = $xml->createElement("card"); + $cardElement->appendChild($xml->createElement("ref", $paymentKey)); + $cardElement->appendChild($xml->createElement("payerref", $payment->customerKey)); + $request->appendChild($cardElement); + + $hash = GenerationUtils::generateHash( + $config->sharedSecret, + implode('.', [ + $timestamp, + $config->merchantId, + $payment->customerKey, + $paymentKey + ]) + ); + } elseif ($builder->entity instanceof Schedule) { + $schedule = $builder->entity; + $request->appendChild($xml->createElement("scheduleref", $schedule->key)); + $hash = GenerationUtils::generateHash( + $config->sharedSecret, + implode('.', [ + $timestamp, + $config->merchantId, + $schedule->key, + ]) + ); + } + $request->appendChild($xml->createElement($shaHashTagName, $hash)); + break; + case TransactionType::FETCH: + if ($builder->entity instanceof Schedule) { + $scheduleRef = $builder->entity->key; + $request->appendChild($xml->createElement( + 'scheduleref', + $scheduleRef) + ); + $hash = GenerationUtils::generateHash( + $config->sharedSecret, + implode('.', [ + $timestamp, + $config->merchantId, + $scheduleRef, + ]) + ); + + $request->appendChild($xml->createElement($shaHashTagName, $hash)); + } + break; + case TransactionType::SEARCH: + if ($builder->entity instanceof Schedule) { + $customerKey = $paymentKey = ''; + if (isset($builder->searchCriteria[SearchCriteria::CUSTOMER_ID])) { + $customerKey = $builder->searchCriteria[SearchCriteria::CUSTOMER_ID]; + $request->appendChild($xml->createElement( + 'payerref', + $customerKey) + ); + } + if (isset($builder->searchCriteria[SearchCriteria::PAYMENT_METHOD_KEY])) { + $paymentKey = $builder->searchCriteria[SearchCriteria::PAYMENT_METHOD_KEY]; + $request->appendChild($xml->createElement( + 'paymentmethod', + $paymentKey) + ); + } + $hash = GenerationUtils::generateHash( + $config->sharedSecret, + implode('.', [ + $timestamp, + $config->merchantId, + $customerKey, + $paymentKey + ]) + ); + + $request->appendChild($xml->createElement($shaHashTagName, $hash)); + } + break; + default: + break; + } + + return new Request('', 'POST', $xml->saveXML($request)); + } + + private function buildCustomer($xml, $builder) + { + $customer = $builder->entity; + $type = 'Retail'; + if ($builder->transactionType === TransactionType::EDIT) { + $type = 'Subscriber'; + } + $payer = $xml->createElement("payer"); + $payer->setAttribute("ref", (!empty($customer->key)) ? $customer->key : + GenerationUtils::generateRecurringKey()); + $payer->setAttribute("type", $type); + + $payer->appendChild($xml->createElement("title", $customer->title)); + $payer->appendChild($xml->createElement("firstname", $customer->firstName)); + $payer->appendChild($xml->createElement("surname", $customer->lastName)); + $payer->appendChild($xml->createElement("company", $customer->company)); + + + if ($customer->address != null) { + $address = $xml->createElement("address"); + $address->appendChild($xml->createElement("line1", $customer->address->streetAddress1)); + $address->appendChild($xml->createElement("line2", $customer->address->streetAddress2)); + $address->appendChild($xml->createElement("line3", $customer->address->streetAddress3)); + $address->appendChild($xml->createElement("city", $customer->address->city)); + $address->appendChild($xml->createElement("county", $customer->address->getProvince())); + $address->appendChild($xml->createElement("postcode", $customer->address->postalCode)); + + $country = $xml->createElement("country", $customer->address->country); + if (!empty($customer->address->countryCode)) { + $country->setAttribute("code", $customer->address->countryCode); + } + $address->appendChild($country); + + $payer->appendChild($address); + } + + $phonenumbers = $xml->createElement("phonenumbers"); + $phonenumbers->appendChild($xml->createElement("home", $customer->homePhone)); + $phonenumbers->appendChild($xml->createElement("work", $customer->workPhone)); + $phonenumbers->appendChild($xml->createElement("fax", $customer->fax)); + $phonenumbers->appendChild($xml->createElement("mobile", $customer->mobilePhone)); + + $payer->appendChild($phonenumbers); + $payer->appendChild($xml->createElement("email", $customer->email)); + + return $payer; + } + + private function buildCardElement($xml, $payment, $paymentKey = '') + { + $card = $payment->paymentMethod; + $cardElement = $xml->createElement("card"); + $cardElement->appendChild($xml->createElement("ref", $paymentKey)); + $cardElement->appendChild($xml->createElement("payerref", $payment->customerKey)); + $cardElement->appendChild($xml->createElement("number", $card->number)); + $cardElement->appendChild($xml->createElement("expdate", $card->getShortExpiry())); + $cardElement->appendChild($xml->createElement("chname", $card->cardHolderName)); + $cardElement->appendChild($xml->createElement("type", strtoupper($card->getCardType()))); + + return $cardElement; + } + + /** + * Maps a transaction builder to a GP-ECOM request type + * + * @param RecurringBuilder $builder Transaction builder + * + * @return string + */ + private function mapRecurringRequestType(RecurringBuilder $builder) + { + $entity = $builder->entity; + + switch ($builder->transactionType) { + case TransactionType::CREATE: + if ($entity instanceof Customer) { + return "payer-new"; + } elseif ($entity instanceof RecurringPaymentMethod) { + return "card-new"; + } elseif ($entity instanceof Schedule) { + return "schedule-new"; + } + break; + case TransactionType::EDIT: + if ($entity instanceof Customer) { + return "payer-edit"; + } elseif ($entity instanceof RecurringPaymentMethod) { + return "card-update-card"; + } + break; + case TransactionType::DELETE: + if ($entity instanceof RecurringPaymentMethod) { + return "card-cancel-card"; + } elseif ($entity instanceof Schedule) { + return "schedule-delete"; + } + break; + case TransactionType::FETCH: + if ($entity instanceof Schedule) { + return "schedule-get"; + } + break; + case TransactionType::SEARCH: + if ($entity instanceof Schedule) { + return "schedule-search"; + } + break; + default: + break; + } + throw new UnsupportedTransactionException( + 'The selected gateway does not support this transaction type.' + ); + } +} \ No newline at end of file diff --git a/src/Builders/RequestBuilder/GpEcom/GpEcomReportRequestBuilder.php b/src/Builders/RequestBuilder/GpEcom/GpEcomReportRequestBuilder.php new file mode 100644 index 00000000..617dd58c --- /dev/null +++ b/src/Builders/RequestBuilder/GpEcom/GpEcomReportRequestBuilder.php @@ -0,0 +1,73 @@ +createElement("request"); + $request->setAttribute("timestamp", $timestamp); + $request->setAttribute("type", $this->mapReportRequestType($builder->reportType)); + $request->appendChild($xml->createElement("merchantid", $config->merchantId)); + + if ($config->accountId !== null) { + $request->appendChild($xml->createElement("account", $config->accountId)); + } + $request->appendChild($xml->createElement("orderid", $builder->transactionId)); + $hash = GenerationUtils::generateHash( + $config->sharedSecret, + implode('.', [ + $timestamp, + $config->merchantId, + $builder->transactionId, + '', + '', + '' + ]) + ); + $request->appendChild($xml->createElement("sha1hash", $hash)); + + return new Request('', 'POST', $xml->saveXML($request)); + } + + /** + * @param ReportType $reportType + */ + private function mapReportRequestType($reportType) + { + switch ($reportType) { + case ReportType::TRANSACTION_DETAIL: + return 'query'; + default: + throw new UnsupportedTransactionException("This reporting call is not supported by your currently configured gateway."); + } + } +} \ No newline at end of file diff --git a/src/Builders/RequestBuilder/GpEcom/GpEcomRequestBuilder.php b/src/Builders/RequestBuilder/GpEcom/GpEcomRequestBuilder.php new file mode 100644 index 00000000..5a372806 --- /dev/null +++ b/src/Builders/RequestBuilder/GpEcom/GpEcomRequestBuilder.php @@ -0,0 +1,24 @@ +createElement("supplementarydata"); + foreach ($builder->supplementaryData as $key => $items) { + $item = $xml->createElement("item"); + $item->setAttribute('type', $key); + if (!is_array($items)) { + $items = explode(' ', $items); + } + for ($i = 1; $i <= count($items); $i++) { + $item->appendChild($xml->createElement('field' . sprintf("%02d", $i), $items[$i - 1])); + } + $supplementaryData->appendChild($item); + } + $request->appendChild($supplementaryData); + + } +} \ No newline at end of file diff --git a/src/Builders/RequestBuilder/RequestBuilderFactory.php b/src/Builders/RequestBuilder/RequestBuilderFactory.php new file mode 100644 index 00000000..59f2973a --- /dev/null +++ b/src/Builders/RequestBuilder/RequestBuilderFactory.php @@ -0,0 +1,46 @@ + [ + GpEcomRecurringRequestBuilder::class, + GpEcomAuthorizationRequestBuilder::class, + GpEcomReportRequestBuilder::class, + GpEcomManagementRequestBuilder::class, + ], + GatewayProvider::GP_API => [ + GpApiAuthorizationRequestBuilder::class, + GpApiManagementRequestBuilder::class, + GpApiReportRequestBuilder::class, + GpApiSecure3DRequestBuilder::class + ] + ]; + + public function getRequestBuilder(BaseBuilder $builder, $gatewayProvider) + { + if (!isset(self::$processes[$gatewayProvider])) { + return null; + } + foreach (self::$processes[$gatewayProvider] as $gateway => $processName) { + if (call_user_func(array($processName, 'canProcess'), $builder)) { + return new $processName; + } + } + + return null; + } +} \ No newline at end of file diff --git a/src/Builders/TransactionBuilder.php b/src/Builders/TransactionBuilder.php index efa409aa..fc1df71b 100644 --- a/src/Builders/TransactionBuilder.php +++ b/src/Builders/TransactionBuilder.php @@ -62,6 +62,13 @@ abstract class TransactionBuilder extends BaseBuilder */ public $allowDuplicates; + /** + * Request supplementary data + * + * @var array + */ + public $supplementaryData; + /** * Instantiates a new builder * @@ -117,4 +124,29 @@ public function withAllowDuplicates($allowDuplicates) $this->allowDuplicates = $allowDuplicates; return $this; } + + /** + * Depending on the parameters received, + * Add supplementary data or + * Add multiple values to the supplementaryData array + * + * @param string|array $key + * @param string $value + * + * @return $this + */ + public function withSupplementaryData($key, $value = null) + { + if ($value === null && is_array($key)) { + foreach ($key as $k => $v) { + $this->withSupplementaryData($k, $v); + } + } + + if ($key && isset($value)) { + $this->supplementaryData[$key] = $value; + } + + return $this; + } } diff --git a/src/Entities/GpApi/DTO/PaymentMethod.php b/src/Entities/GpApi/DTO/PaymentMethod.php index 88fa7df7..756610a9 100644 --- a/src/Entities/GpApi/DTO/PaymentMethod.php +++ b/src/Entities/GpApi/DTO/PaymentMethod.php @@ -20,6 +20,7 @@ class PaymentMethod /** @var array */ public $apm; public $fingerprint_mode; + public $narrative; const PAYMENT_METHOD_TOKEN_PREFIX = 'PMT_'; } \ No newline at end of file diff --git a/src/Entities/GpApi/GpApiRequest.php b/src/Entities/GpApi/GpApiRequest.php index 1f325ab1..1900a497 100644 --- a/src/Entities/GpApi/GpApiRequest.php +++ b/src/Entities/GpApi/GpApiRequest.php @@ -2,7 +2,9 @@ namespace GlobalPayments\Api\Entities\GpApi; -class GpApiRequest +use GlobalPayments\Api\Entities\Request; + +class GpApiRequest extends Request { const ACCESS_TOKEN_ENDPOINT = '/accesstoken'; const TRANSACTION_ENDPOINT = '/transactions'; @@ -17,18 +19,4 @@ class GpApiRequest const ACTIONS_ENDPOINT = '/actions'; const MERCHANT_MANAGEMENT_ENDPOINT = '/merchants'; const DCC_ENDPOINT= '/currency-conversions'; - - public $endpoint; - public $requestBody; - public $queryParams; - public $httpVerb; - public $resultsField; - - public function __construct($endpoint, $httpVerb, $requestBody = '', $queryParams = null) - { - $this->endpoint = $endpoint; - $this->httpVerb = $httpVerb; - $this->requestBody = $requestBody; - $this->queryParams = $queryParams; - } } \ No newline at end of file diff --git a/src/Entities/GpApi/GpApiRequestBuilderFactory.php b/src/Entities/GpApi/GpApiRequestBuilderFactory.php deleted file mode 100644 index fd8c43d4..00000000 --- a/src/Entities/GpApi/GpApiRequestBuilderFactory.php +++ /dev/null @@ -1,26 +0,0 @@ -endpoint = $endpoint; + $this->httpVerb = $httpVerb; + $this->requestBody = $requestBody; + $this->queryParams = $queryParams; + } +} \ No newline at end of file diff --git a/src/Entities/Schedule.php b/src/Entities/Schedule.php index 65979f27..9ec37744 100644 --- a/src/Entities/Schedule.php +++ b/src/Entities/Schedule.php @@ -122,6 +122,8 @@ class Schedule extends RecurringEntity */ public $poNumber; + public $orderPrefix; + /** * The identifier of the payment method associated with * the schedule. @@ -166,6 +168,17 @@ class Schedule extends RecurringEntity */ public $taxAmount; + public $productId; + + /** + * A unique reference for this customer for example from your CRM system. + * @var string + */ + public $customerNumber; + + /** @var string */ + public $scheduletext; + /** * Instantiates a new `Schedule` object. * @@ -433,4 +446,43 @@ public function withTaxAmount($value) $this->taxAmount = $value; return $this; } + + /** + * Set the request product ID + * + * @param string|float $productId Request product ID + * + * @return Schedule + */ + public function withProductId($productId) + { + $this->productId = $productId; + return $this; + } + + /** + * Set a string to be used as the prefix of the Order ID for each scheduled payment. + * + * @param string $orderPrefix + * + * @return $this + */ + public function withOrderPrefix($orderPrefix) + { + $this->orderPrefix = $orderPrefix; + + return $this; + } + + /** + * @param string $customerNumber + * + * @return $this + */ + public function withCustomerNumber($customerNumber) + { + $this->customerNumber = $customerNumber; + + return $this; + } } diff --git a/src/Gateways/GpApiConnector.php b/src/Gateways/GpApiConnector.php index 18a9e4b0..1f6223c3 100644 --- a/src/Gateways/GpApiConnector.php +++ b/src/Gateways/GpApiConnector.php @@ -5,6 +5,7 @@ use GlobalPayments\Api\Builders\AuthorizationBuilder; use GlobalPayments\Api\Builders\ManagementBuilder; use GlobalPayments\Api\Builders\ReportBuilder; +use GlobalPayments\Api\Builders\RequestBuilder\RequestBuilderFactory; use GlobalPayments\Api\Builders\Secure3dBuilder; use GlobalPayments\Api\Entities\Enums\PaymentMethodType; use GlobalPayments\Api\Entities\Enums\Secure3dVersion; @@ -13,7 +14,6 @@ use GlobalPayments\Api\Entities\GpApi\AccessTokenInfo; use GlobalPayments\Api\Entities\GpApi\GpApiRequest; use GlobalPayments\Api\Entities\GpApi\GpApiTokenResponse; -use GlobalPayments\Api\Entities\GpApi\GpApiRequestBuilderFactory; use GlobalPayments\Api\Entities\GpApi\GpApiSessionInfo; use GlobalPayments\Api\Entities\GpApi\PagedResult; use GlobalPayments\Api\Entities\IRequestBuilder; @@ -139,11 +139,11 @@ public function processReport(ReportBuilder $builder) private function executeProcess($builder) { - $processFactory = new GpApiRequestBuilderFactory(); + $processFactory = new RequestBuilderFactory(); /** * @var IRequestBuilder $requestBuilder */ - $requestBuilder = $processFactory->getRequestBuilder($builder); + $requestBuilder = $processFactory->getRequestBuilder($builder, $this->gpApiConfig->gatewayProvider); if (empty($requestBuilder)) { throw new ApiException("Request builder not found!"); } diff --git a/src/Gateways/GpEcomConnector.php b/src/Gateways/GpEcomConnector.php new file mode 100644 index 00000000..896eb943 --- /dev/null +++ b/src/Gateways/GpEcomConnector.php @@ -0,0 +1,612 @@ +config = $config; + } + + /** @return Secure3dVersion */ + public function getVersion() + { + return Secure3dVersion::ONE; + } + + /** + * {@inheritdoc} + * + * @param AuthorizationBuilder $builder The transaction's builder + * + * @return Transaction + */ + public function processAuthorization(AuthorizationBuilder $builder) + { + $response = $this->executeProcess($builder); + $transactionType = GpEcomMapping::mapAuthRequestType($builder); + $acceptedResponseCodes = $this->mapAcceptedCodes($transactionType); + + return GpEcomMapping::mapResponse($response, $acceptedResponseCodes); + } + + public function processReport(ReportBuilder $builder) + { + $response = $this->executeProcess($builder); + + return GpEcomMapping::mapReportResponse($response, $builder->reportType); + } + + public function processRecurring(RecurringBuilder $builder) + { + $response = $this->executeProcess($builder); + + if ( + !empty($response->sha1hash) && + (string)$response->sha1hash !== $this->checkHashResponse($response, $builder->entity) + ) { + throw new ApiException(sprintf('Unexpected shahash response: %s', (string)$response->sha1hash)); + } + + if ( + $builder->entity instanceof Schedule && + ( + $builder->transactionType === TransactionType::FETCH || + $builder->transactionType === TransactionType::SEARCH + ) + ) { + return GpEcomMapping::mapScheduleReport($response, $builder->transactionType); + } + + return GpEcomMapping::mapResponse($response); + } + + /** + * {@inheritdoc} + * + * @param ManagementBuilder $builder The transaction's builder + * + * @return Transaction + * + * + */ + public function manageTransaction(ManagementBuilder $builder) + { + $response = $this->executeProcess($builder); + $transactionType = GpEcomMapping::mapManageRequestType($builder); + + return GpEcomMapping::mapResponse($response, $this->mapAcceptedCodes($transactionType)); + } + + /** + * @param $builder + * @return string + * + * @throws ApiException + * @throws GatewayException + */ + private function executeProcess($builder) + { + $processFactory = new RequestBuilderFactory(); + + /** + * @var IRequestBuilder $requestBuilder + */ + $requestBuilder = $processFactory->getRequestBuilder($builder, $this->config->gatewayProvider); + if (empty($requestBuilder)) { + throw new ApiException("Request builder not found!"); + } + + /** + * @var Request $request + */ + $request = $requestBuilder->buildRequest($builder, $this->config); + + if (empty($request)) { + throw new ApiException("Request was not generated!"); + } + + $response = $this->doTransaction($request->requestBody); + + return $this->xml2object($response); + } + + /** + * Converts a XML string to a simple object for use, + * removing extra nodes that are not necessary for + * handling the response + * + * @param string $xml Response XML from the gateway + * + * @return SimpleXMLElement + */ + protected function xml2object($xml) + { + if (is_object($xml) && $xml instanceof \SimpleXMLElement) { + return $xml; + } + + $envelope = simplexml_load_string( + $xml, + 'SimpleXMLElement' + ); + + return $envelope; + } + + /** + * @return Transaction + */ + public function processSecure3d(Secure3dBuilder $builder) + { + $transType = $builder->getTransactionType(); + + if ($transType === TransactionType::VERIFY_ENROLLED) { + $authBuilder = (new AuthorizationBuilder($transType, $builder->getPaymentMethod())) + ->withAmount($builder->getAmount()) + ->withCurrency($builder->getCurrency()) + ->withOrderId($builder->getOrderId()); + + return $this->processAuthorization($authBuilder); + } elseif ($transType === TransactionType::VERIFY_SIGNATURE) { + // Get our three d secure object + $secureEcom = $builder->getThreeDSecure(); + + // Create our transaction reference + $reference = new TransactionReference(); + $reference->orderId = $secureEcom->getOrderId(); + + $managementBuilder = (new ManagementBuilder($transType)) + ->withAmount($secureEcom->getAmount()) + ->withCurrency($secureEcom->getCurrency()) + ->withPayerAuthenticationResponse($builder->getPayerAuthenticationResponse()) + ->withPaymentMethod($reference); + return $this->manageTransaction($managementBuilder); + } + throw new UnsupportedTransactionException(sprintf("Unknown transaction type %s", $transType)); + } + + public function serializeRequest(AuthorizationBuilder $builder) + { + // check for hpp config + if ($this->hostedPaymentConfig === null) { + throw new ApiException("Hosted configuration missing, Please check you configuration."); + } + + // check for right transaction types + if ($builder->transactionType !== TransactionType::SALE + && $builder->transactionType !== TransactionType::AUTH + && $builder->transactionType !== TransactionType::VERIFY + ) { + throw new UnsupportedTransactionException("Only Charge and Authorize are supported through HPP."); + } + + if ($builder->paymentMethod instanceof BankPayment && + $builder->transactionType !== TransactionType::SALE) { + throw new UnsupportedTransactionException("Only Charge is supported for Bank Payment through HPP."); + } + + $orderId = isset($builder->orderId) ? $builder->orderId : GenerationUtils::generateOrderId(); + $timestamp = isset($builder->timestamp) ? $builder->timestamp : GenerationUtils::generateTimestamp(); + $amount = preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount)); + + $this->setSerializeData('MERCHANT_ID', $this->config->merchantId); + $this->setSerializeData('ACCOUNT', $this->config->accountId); + $this->setSerializeData('HPP_CHANNEL', $this->config->channel); + $this->setSerializeData('ORDER_ID', $orderId); + if ($builder->amount !== null) { + $this->setSerializeData('AMOUNT', $amount); + } + $this->setSerializeData('CURRENCY', $builder->currency); + $this->setSerializeData('TIMESTAMP', $timestamp); + + $this->setSerializeData( + 'AUTO_SETTLE_FLAG', + ($builder->transactionType == TransactionType::SALE) ? "1" : "0" + ); + + if ( + !empty($builder->hostedPaymentData->bankPayment) && + $builder->hostedPaymentData->bankPayment instanceof BankPayment + ) { + $this->buildOpenBankingHppRequest($builder); + } + + $this->setSerializeData('COMMENT1', $builder->description); + + if (isset($this->hostedPaymentConfig->requestTransactionStabilityScore)) { + $this->serializeData["RETURN_TSS"] = + $this->hostedPaymentConfig->requestTransactionStabilityScore ? "1" : "0"; + } + if (isset($this->hostedPaymentConfig->directCurrencyConversionEnabled)) { + $this->serializeData["DCC_ENABLE"] = + $this->hostedPaymentConfig->directCurrencyConversionEnabled ? "1" : "0"; + } + + if (!empty($builder->hostedPaymentData)) { + $hostedPaymentData = $builder->hostedPaymentData; + $this->setSerializeData('CUST_NUM', $builder->hostedPaymentData->customerNumber); + + if (!empty($this->hostedPaymentConfig->displaySavedCards) && + !empty($builder->hostedPaymentData->customerKey)) { + $this->setSerializeData('HPP_SELECT_STORED_CARD', $builder->hostedPaymentData->customerKey); + } + + if (isset($builder->hostedPaymentData->offerToSaveCard)) { + $this->setSerializeData( + 'OFFER_SAVE_CARD', + $builder->hostedPaymentData->offerToSaveCard ? "1" : "0" + ); + } + if (isset($builder->hostedPaymentData->customerExists)) { + $this->setSerializeData( + 'PAYER_EXIST', + $builder->hostedPaymentData->customerExists ? "1" : "0" + ); + } + if (isset($builder->hostedPaymentData->customerKey)) { + $this->setSerializeData('PAYER_REF', $builder->hostedPaymentData->customerKey); + } + if (isset($builder->hostedPaymentData->paymentKey)) { + $this->setSerializeData('PMT_REF', $builder->hostedPaymentData->paymentKey); + } + if (isset($builder->hostedPaymentData->productId)) { + $this->setSerializeData('PROD_ID', $builder->hostedPaymentData->productId); + } + // APMs Fields + if (!empty($hostedPaymentData->customerCountry)) { + $this->setSerializeData('HPP_CUSTOMER_COUNTRY', $hostedPaymentData->customerCountry); + } + if (!empty($hostedPaymentData->customerFirstName)) { + $this->setSerializeData('HPP_CUSTOMER_FIRSTNAME', $hostedPaymentData->customerFirstName); + } + if (!empty($hostedPaymentData->customerLastName)) { + $this->setSerializeData('HPP_CUSTOMER_LASTNAME', $hostedPaymentData->customerLastName); + } + if (!empty($hostedPaymentData->customerFirstName) && !empty($hostedPaymentData->customerLastName)) { + $this->setSerializeData( + 'HPP_NAME', + $hostedPaymentData->customerFirstName . ' ' . $hostedPaymentData->customerLastName + ); + } + if (!empty($hostedPaymentData->merchantResponseUrl)) { + $this->setSerializeData('MERCHANT_RESPONSE_URL', $hostedPaymentData->merchantResponseUrl); + } + if (!empty($hostedPaymentData->transactionStatusUrl)) { + $this->setSerializeData('HPP_TX_STATUS_URL', $hostedPaymentData->transactionStatusUrl); + } + if (!empty($hostedPaymentData->presetPaymentMethods)) { + $this->setSerializeData('PM_METHODS', implode( '|', $hostedPaymentData->presetPaymentMethods)); + } + // end APMs Fields + } elseif (isset($builder->customerId)) { + $this->setSerializeData('CUST_NUM', $builder->customerId); + } + if (!empty($builder->shippingAddress)) { + + $countryCode = CountryUtils::getCountryCodeByCountry($builder->shippingAddress->country); + $shippingCode = $this->generateCode($builder->shippingAddress); + + // Fraud values + $this->setSerializeData('SHIPPING_CODE', $shippingCode); + $this->setSerializeData('SHIPPING_CO', $countryCode); + + // 3DS 2.0 values + $this->setSerializeData('HPP_SHIPPING_STREET1', $builder->shippingAddress->streetAddress1); + $this->setSerializeData('HPP_SHIPPING_STREET2', $builder->shippingAddress->streetAddress2); + $this->setSerializeData('HPP_SHIPPING_STREET3', $builder->shippingAddress->streetAddress3); + $this->setSerializeData('HPP_SHIPPING_CITY', $builder->shippingAddress->city); + $this->setSerializeData('HPP_SHIPPING_STATE', $builder->shippingAddress->state); + $this->setSerializeData('HPP_SHIPPING_POSTALCODE', $builder->shippingAddress->postalCode); + $this->setSerializeData('HPP_SHIPPING_COUNTRY', CountryUtils::getNumericCodeByCountry($builder->shippingAddress->country)); + } + if (!empty($builder->billingAddress)) { + $countryCode = CountryUtils::getCountryCodeByCountry($builder->billingAddress->country); + $billingCode = $this->generateCode($builder->billingAddress); + // Fraud values + $this->setSerializeData('BILLING_CODE', $billingCode); + $this->setSerializeData('BILLING_CO', $countryCode); + + // 3DS 2.0 values + $this->setSerializeData('HPP_BILLING_STREET1', $builder->billingAddress->streetAddress1); + $this->setSerializeData('HPP_BILLING_STREET2', $builder->billingAddress->streetAddress2); + $this->setSerializeData('HPP_BILLING_STREET3', $builder->billingAddress->streetAddress3); + $this->setSerializeData('HPP_BILLING_CITY', $builder->billingAddress->city); + $this->setSerializeData('HPP_BILLING_STATE', $builder->billingAddress->state); + $this->setSerializeData('HPP_BILLING_POSTALCODE', $builder->billingAddress->postalCode); + $this->setSerializeData( + 'HPP_BILLING_COUNTRY', + CountryUtils::getNumericCodeByCountry($builder->billingAddress->country) + ); + } + + $this->setSerializeData('VAR_REF', $builder->clientTransactionId); + $this->setSerializeData('HPP_LANG', $this->hostedPaymentConfig->language); + $this->setSerializeData('MERCHANT_RESPONSE_URL', $this->hostedPaymentConfig->responseUrl); + $this->setSerializeData('CARD_PAYMENT_BUTTON', $this->hostedPaymentConfig->paymentButtonText); + if (!empty($builder->hostedPaymentData)) { + $hostedPaymentData = $builder->hostedPaymentData; + $this->setSerializeData('HPP_CUSTOMER_EMAIL', $hostedPaymentData->customerEmail); + $this->setSerializeData('HPP_CUSTOMER_PHONENUMBER_MOBILE', $hostedPaymentData->customerPhoneMobile); + $this->setSerializeData('HPP_PHONE', $hostedPaymentData->customerPhoneMobile); + $this->setSerializeData('HPP_CHALLENGE_REQUEST_INDICATOR', $hostedPaymentData->challengeRequest); + if (isset($hostedPaymentData->addressesMatch)) { + $this->setSerializeData('HPP_ADDRESS_MATCH_INDICATOR', $hostedPaymentData->addressesMatch ? 'TRUE' : 'FALSE'); + } + if (!empty($hostedPaymentData->supplementaryData)) { + $this->serializeSupplementaryData($hostedPaymentData->supplementaryData); + } + + if (isset($hostedPaymentData->addressCapture)) { + $this->setSerializeData('HPP_CAPTURE_ADDRESS', $hostedPaymentData->addressCapture == true); + } + if (isset($hostedPaymentData->notReturnAddress)) { + $this->setSerializeData('HPP_DO_NOT_RETURN_ADDRESS', $hostedPaymentData->notReturnAddress == true); + } + } + if (isset($this->hostedPaymentConfig->cardStorageEnabled)) { + $this->setSerializeData('CARD_STORAGE_ENABLE', $this->hostedPaymentConfig->cardStorageEnabled ? '1' : '0'); + } + if ($builder->transactionType === TransactionType::VERIFY) { + $this->setSerializeData( + 'VALIDATE_CARD_ONLY', + $builder->transactionType === TransactionType::VERIFY ? '1' : '0' + ); + } + if ($this->hostedPaymentConfig->fraudFilterMode != FraudFilterMode::NONE) { + $this->setSerializeData('HPP_FRAUDFILTER_MODE', $this->hostedPaymentConfig->fraudFilterMode); + if ($this->hostedPaymentConfig->fraudFilterMode !== FraudFilterMode::NONE && !empty($this->hostedPaymentConfig->fraudFilterRules)) { + foreach ($this->hostedPaymentConfig->fraudFilterRules->rules as $fraudRule) { + $this->setSerializeData( + 'HPP_FRAUDFILTER_RULE_' . $fraudRule->key, + $fraudRule->mode + ); + } + } + } + + if ($builder->recurringType !== null || $builder->recurringSequence !== null) { + $this->setSerializeData('RECURRING_TYPE', strtolower($builder->recurringType)); + $this->setSerializeData('RECURRING_SEQUENCE', strtolower($builder->recurringSequence)); + } + if (isset($this->hostedPaymentConfig->version)) { + $this->setSerializeData('HPP_VERSION', $this->hostedPaymentConfig->version); + } + if (isset($this->hostedPaymentConfig->postDimensions)) { + $this->setSerializeData('HPP_POST_DIMENSIONS', $this->hostedPaymentConfig->postDimensions); + } + if (isset($this->hostedPaymentConfig->postResponse)) { + $this->setSerializeData('HPP_POST_RESPONSE', $this->hostedPaymentConfig->postResponse); + } + if (!empty($builder->supplementaryData)) { + $this->serializeSupplementaryData($builder->supplementaryData); + } + + $toHash = [ + $timestamp, + $this->config->merchantId, + $orderId, + ($builder->amount !== null) ? preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount)) : null, + $builder->currency, + ]; + + if ($this->hostedPaymentConfig->cardStorageEnabled + || ($builder->hostedPaymentData != null + && $builder->hostedPaymentData->offerToSaveCard) + || $this->hostedPaymentConfig->displaySavedCards + ) { + $toHash[] = ($builder->hostedPaymentData->customerKey !== null) ? + $builder->hostedPaymentData->customerKey : + null; + $toHash[] = ($builder->hostedPaymentData->paymentKey !== null) ? + $builder->hostedPaymentData->paymentKey : + null; + } + + if ( + !empty($this->hostedPaymentConfig->fraudFilterMode) && + $this->hostedPaymentConfig->fraudFilterMode !== FraudFilterMode::NONE + ) { + $toHash[] = $this->hostedPaymentConfig->fraudFilterMode; + } + + if ( + !empty($builder->hostedPaymentData->bankPayment) && + $builder->hostedPaymentData->bankPayment instanceof BankPayment + ) { + $bankPayment = $builder->hostedPaymentData->bankPayment; + $toHash = array_merge($toHash, [ + !empty($bankPayment->sortCode) ? $bankPayment->sortCode : '', + !empty($bankPayment->accountNumber) ? $bankPayment->accountNumber : '', + !empty($bankPayment->iban) ? $bankPayment->iban : '' + ]); + } + + if (!empty($builder->dynamicDescriptor)) { + $this->serializeData["CHARGE_DESCRIPTION"] = $builder->dynamicDescriptor; + } + + list($tagHashName, $tagHashValue) = $this->mapShaHash(implode('.', $toHash)); + $this->setSerializeData($tagHashName, $tagHashValue); + + return GenerationUtils::convertArrayToJson($this->serializeData, $this->hostedPaymentConfig->version); + } + + private function checkHashResponse($response, $entity) + { + switch (get_class($entity)) { + case Schedule::class: + $hash = GenerationUtils::generateHash( + $this->config->sharedSecret, + implode('.', [ + $response['timestamp'], + $response->merchantid, + $response->result, + ]) + ); + break; + case Customer::class: + case RecurringPaymentMethod::class: + $hash = GenerationUtils::generateHash( + $this->config->sharedSecret, + implode('.', [ + $response['timestamp'], + $response->merchantid, + $response->orderid, + $response->result, + $response->message, + $response->pasref, + $response->authcode, + ]) + ); + break; + default: + $hash = ''; + break; + } + + return $hash; + } + + public function supportsHostedPayments() + { + return $this->supportsHostedPayments; + } + + private function mapAcceptedCodes($paymentMethodType) + { + switch ($paymentMethodType) { + case "3ds-verifysig": + case "3ds-verifyenrolled": + return ["00", "110"]; + case "payment-set": + return ["01", "00"]; + default: + return ["00"]; + } + } + + private function setSerializeData($key, $value = null) + { + if ($value !== null) { + $this->serializeData[$key] = $value; + } + } + + /** + * @param array> $supplementaryData + */ + private function serializeSupplementaryData($supplementaryData) + { + foreach ($supplementaryData as $key => $value) { + $this->setSerializeData(strtoupper($key), $value); + } + } + + private function generateCode(Address $address) + { + $countryCode = CountryUtils::getCountryCodeByCountry($address->country); + switch ($countryCode) + { + case 'GB': + return filter_var($address->postalCode, FILTER_SANITIZE_NUMBER_INT) . '|' . filter_var($address->streetAddress1, FILTER_SANITIZE_NUMBER_INT); + case 'US': + case 'CA': + return $address->postalCode . '|' . $address->streetAddress1; + default: + return null; + } + } + + /** + * @param AuthorizationBuilder $builder + */ + private function buildOpenBankingHppRequest($builder) + { + $paymentMethod = $builder->hostedPaymentData->bankPayment; + $this->setSerializeData( + 'HPP_OB_PAYMENT_SCHEME', + !empty($paymentMethod->bankPaymentType) ? + $paymentMethod->bankPaymentType : OpenBankingProvider::getBankPaymentType($builder->currency) + ); + $this->setSerializeData('HPP_OB_REMITTANCE_REF_TYPE', $builder->remittanceReferenceType); + $this->setSerializeData('HPP_OB_REMITTANCE_REF_VALUE', $builder->remittanceReferenceValue); + $this->setSerializeData('HPP_OB_DST_ACCOUNT_IBAN', $paymentMethod->iban); + $this->setSerializeData('HPP_OB_DST_ACCOUNT_NAME', $paymentMethod->accountName); + $this->setSerializeData('HPP_OB_DST_ACCOUNT_NUMBER', $paymentMethod->accountNumber); + $this->setSerializeData('HPP_OB_DST_ACCOUNT_SORT_CODE', $paymentMethod->sortCode); + if (!empty($builder->hostedPaymentData)) { + $hostedPaymentData = $builder->hostedPaymentData; + $this->setSerializeData('HPP_OB_CUSTOMER_COUNTRIES', $hostedPaymentData->customerCountry); + } + } + + private function mapShaHash($toHash) + { + if (empty($this->config->shaHashType)) { + throw new ApiException(sprintf("%s not supported. Please check your code and the Developers Documentation.", $this->config->shaHashType)); + } + + return [ + $this->config->shaHashType . 'HASH', + GenerationUtils::generateNewHash($this->config->sharedSecret, $toHash, $this->config->shaHashType) + ]; + } +} diff --git a/src/Gateways/RealexConnector.php b/src/Gateways/RealexConnector.php deleted file mode 100644 index a5dd97a0..00000000 --- a/src/Gateways/RealexConnector.php +++ /dev/null @@ -1,1765 +0,0 @@ -transactionModifier) && - $builder->transactionModifier === TransactionModifier::ENCRYPTED_MOBILE && - $builder->paymentMethod->mobileType === EncyptedMobileType::GOOGLE_PAY && - (empty($builder->amount) || empty($builder->currency)) - ) { - throw new BuilderException("Amount and Currency cannot be null for google payment"); - } - - $xml = new DOMDocument(); - $timestamp = isset($builder->timestamp) ? $builder->timestamp : GenerationUtils::generateTimestamp(); - $orderId = isset($builder->orderId) ? $builder->orderId : GenerationUtils::generateOrderId(); - $transactionType = $this->mapAuthRequestType($builder); - - // Build Request - $request = $xml->createElement("request"); - $request->setAttribute("timestamp", $timestamp); - $request->setAttribute("type", $transactionType); - - $request->appendChild($xml->createElement("merchantid", $this->merchantId)); - - if ($this->accountId !== null) { - $request->appendChild($xml->createElement("account", $this->accountId)); - } - if ($this->channel !== null) { - $request->appendChild($xml->createElement("channel", $this->channel)); - } - - if (isset($builder->amount)) { - $amount = $xml->createElement("amount", preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount))); - $amount->setAttribute("currency", $builder->currency); - $request->appendChild($amount); - } - - // This needs to be figured out based on txn type and set to 0, 1 or MULTI - if ($builder->transactionType === TransactionType::SALE || $builder->transactionType == TransactionType::AUTH) { - $autoSettle = $builder->transactionType === TransactionType::SALE ? "1" : "0"; - $element = $xml->createElement("autosettle"); - $element->setAttribute("flag", $autoSettle); - $request->appendChild($element); - } - - $request->appendChild($xml->createElement("orderid", $orderId)); - - // For Fraud Decision Manager - if (!empty($builder->customerData)) { - $customerValue = $builder->customerData; - $customer = $xml->createElement("customer"); - $customer->appendChild($xml->createElement("customerid", $customerValue->id)); - $customer->appendChild($xml->createElement("firstname", $customerValue->firstName)); - $customer->appendChild($xml->createElement("lastname", $customerValue->lastName)); - $customer->appendChild($xml->createElement("dateofbirth", $customerValue->dateOfBirth)); - $customer->appendChild($xml->createElement("customerpassword", $customerValue->customerPassword)); - $customer->appendChild($xml->createElement("email", $customerValue->email)); - $customer->appendChild($xml->createElement("domainname", $customerValue->domainName)); - $customer->appendChild($xml->createElement("devicefingerprint", $customerValue->deviceFingerPrint)); - $customer->appendChild($xml->createElement("phonenumber", $customerValue->homePhone)); - $request->appendChild($customer); - } - - if (!empty($builder->productData)) { - $prod = []; - $productValues = $builder->productData; - $products = $xml->createElement("products"); - - foreach ($productValues as $prod) { - $product = $xml->createElement("product"); - $product->appendChild($xml->createElement('product_id', $prod['product_id'])); - $product->appendChild($xml->createElement('productname', $prod['productname'])); - $product->appendChild($xml->createElement('quantity', $prod['quantity'])); - $product->appendChild($xml->createElement('unitprice', $prod['unitprice'])); - $product->appendChild($xml->createElement('gift', $prod['gift'])); - $product->appendChild($xml->createElement('type', $prod['type'])); - $product->appendChild($xml->createElement('risk', $prod['risk'])); - $product->appendChild($products); - $request->appendChild($product); - } - } - - if ($builder->decisionManager !== null) { - $dmValues = $builder->decisionManager; - $fraud = $xml->createElement("fraud"); - $dm = $fraud->appendChild($xml->createElement('dm')); - $dm->appendChild($xml->createElement('billtohostname', $dmValues->billToHostName)); - $dm->appendChild($xml->createElement( - 'billtohttpbrowsercookiesaccepted', - ($dmValues->billToHttpBrowserCookiesAccepted) != true ? 'false' : 'true' - )); - $dm->appendChild($xml->createElement('billtohttpbrowseremail', $dmValues->billToHttpBrowserEmail)); - $dm->appendChild($xml->createElement('billtohttpbrowsertype', $dmValues->billToHttpBrowserType)); - $dm->appendChild($xml->createElement('billtoipnetworkaddress', $dmValues->billToIpNetworkAddress)); - $dm->appendChild($xml->createElement( - 'businessrulesscorethreshold', - $dmValues->businessRulessCoreThresHold - )); - $dm->appendChild($xml->createElement('billtopersonalid', $dmValues->billToPersonalId)); - $dm->appendChild($xml->createElement('invoiceheadertendertype', $dmValues->invoiceHeaderTenderType)); - $dm->appendChild($xml->createElement( - 'invoiceheaderisgift', - ($dmValues->invoiceHeaderIsGift) != true ? 'false' : 'true' - )); - $dm->appendChild($xml->createElement('decisionmanagerprofile', $dmValues->decisionManagerProfile)); - $dm->appendChild($xml->createElement( - 'invoiceheaderreturnsaccepted', - ($dmValues->invoiceHeaderReturnsAccepted) != true ? 'false' : 'true' - )); - $dm->appendChild($xml->createElement('itemhosthedge', $dmValues->itemHostHedge)); - $dm->appendChild($xml->createElement('itemnonsensicalhedge', $dmValues->itemNonsensicalHedge)); - $dm->appendChild($xml->createElement('itemobscenitieshedge', $dmValues->itemObscenitiesHedge)); - $dm->appendChild($xml->createElement('itemphonehedge', $dmValues->itemPhoneHedge)); - $dm->appendChild($xml->createElement('itemtimehedge', $dmValues->itemTimeHedge)); - $dm->appendChild($xml->createElement('itemvelocityhedge', $dmValues->itemVelocityHedge)); - $request->appendChild($dm); - } - - if (!empty($builder->customData)) { - $cust = []; - $customValues = $builder->customData; - $custom = $xml->createElement("custom"); - - foreach ($customValues as $cust) { - $custom->appendChild($xml->createElement('field01', $cust['field01'])); - $custom->appendChild($xml->createElement('field02', $cust['field02'])); - $custom->appendChild($xml->createElement('field03', $cust['field03'])); - $custom->appendChild($xml->createElement('field04', $cust['field04'])); - $request->appendChild($custom); - } - } - - - // For DCC charge/auth - if (!empty($builder->dccRateData)) { - $dccinfo = $xml->createElement("dccinfo"); - $dccinfo->appendChild($xml->createElement( - "ccp", - !empty($builder->dccRateData->dccProcessor) ? $builder->dccRateData->dccProcessor : DccProcessor::FEXCO) - ); - $dccinfo->appendChild($xml->createElement( - "type", - !empty($builder->dccRateData->dccType) ? $builder->dccRateData->dccType : "1") - ); - $dccinfo->appendChild($xml->createElement("ratetype", $builder->dccRateData->dccRateType)); - if ($builder->transactionType !== TransactionType::DCC_RATE_LOOKUP) { - $amount = $xml->createElement("amount", preg_replace('/[^0-9]/', '', $builder->dccRateData->cardHolderAmount)); - $amount->setAttribute("currency", $builder->dccRateData->cardHolderCurrency); - $dccinfo->appendChild($amount); - $dccinfo->appendChild($xml->createElement("rate", $builder->dccRateData->cardHolderRate)); - } - $request->appendChild($dccinfo); - } - - if ( - ( - $builder->transactionType === TransactionType::AUTH || - $builder->transactionType === TransactionType::CAPTURE || - $builder->transactionType === TransactionType::REFUND - ) && - !empty($builder->dynamicDescriptor) - ) { - $narrative = $xml->createElement("narrative"); - $narrative->appendChild($xml->createElement("chargedescription", strtoupper($builder->dynamicDescriptor))); - $request->appendChild($narrative); - } - - // Hydrate the payment data fields - if ($builder->paymentMethod instanceof CreditCardData) { - $card = $builder->paymentMethod; - - if ($builder->transactionModifier === TransactionModifier::ENCRYPTED_MOBILE) { - $request->appendChild($xml->createElement("token", $card->token)); - $request->appendChild($xml->createElement("mobile", $card->mobileType)); - } else { - $cardElement = $xml->createElement("card"); - $cardElement->appendChild($xml->createElement("number", $card->number)); - $cardElement->appendChild($xml->createElement("expdate", $card->getShortExpiry())); - $cardElement->appendChild($xml->createElement("chname", $card->cardHolderName)); - - $cardElement->appendChild($xml->createElement( - "type", - strtoupper(EnumMapping::mapCardType(GatewayProvider::GP_ECOM, CardUtils::getBaseCardType($card->getCardType()))) - )); - - if ($card->cvn !== null) { - //if cvn number is not empty indicator should be PRESENT - $cvnPresenceIndicator = (!empty($card->cvn)) ? - CvnPresenceIndicator::PRESENT: - $card->cvnPresenceIndicator; - - $cvnElement = $xml->createElement("cvn"); - $cvnElement->appendChild($xml->createElement("number", $card->cvn)); - $cvnElement->appendChild($xml->createElement("presind", $cvnPresenceIndicator)); - $cardElement->appendChild($cvnElement); - } - $request->appendChild($cardElement); - } - // issueno - $hash = ''; - if ($builder->transactionType === TransactionType::VERIFY) { - $hash = GenerationUtils::generateHash( - $this->sharedSecret, - implode('.', [ - $timestamp, - $this->merchantId, - $orderId, - $card->number - ]) - ); - } else { - $requestValues = $this->getShal1RequestValues($timestamp, $orderId, $builder, $card); - $hash = GenerationUtils::generateHash( - $this->sharedSecret, - implode('.', $requestValues) - ); - } - $request->appendChild($xml->createElement("sha1hash", $hash)); - } - if ($builder->paymentMethod instanceof RecurringPaymentMethod) { - $recurring = $builder->paymentMethod; - $request->appendChild($xml->createElement("payerref", $recurring->customerKey)); - $request->appendChild($xml->createElement( - "paymentmethod", - isset($recurring->key) ? $recurring->key : $recurring->id - )); - - if ($builder->cvn !== null && $builder->cvn !== '') { - $paymentData = $xml->createElement("paymentdata"); - $cvn = $xml->createElement("cvn"); - $cvn->appendChild($xml->createElement("number", $builder->cvn)); - $paymentData->appendChild($cvn); - $request->appendChild($paymentData); - } - - $hash = ''; - if ($builder->transactionType === TransactionType::VERIFY) { - if (!empty($builder->transactionModifier) && - $builder->transactionModifier === TransactionModifier::SECURE3D) { - $hash = GenerationUtils::generateHash( - $this->sharedSecret, - implode('.', [ - $timestamp, - $this->merchantId, - $orderId, - preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount)), - $builder->currency, - $recurring->customerKey, - ]) - ); - } else { - $hash = GenerationUtils::generateHash( - $this->sharedSecret, - implode('.', [ - $timestamp, - $this->merchantId, - $orderId, - $recurring->customerKey, - ]) - ); - } - } else { - $hash = GenerationUtils::generateHash( - $this->sharedSecret, - implode('.', [ - $timestamp, - $this->merchantId, - $orderId, - preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount)), - $builder->currency, - $recurring->customerKey, - ]) - ); - } - $request->appendChild($xml->createElement("sha1hash", $hash)); - } else { - // TODO: Token Processing - //$request->appendChild($xml->createElement("sha1hash", GenerateHash(order, token)); - } - - // refund hash - if ($builder->transactionType === TransactionType::REFUND) { - $request->appendChild($xml->createElement( - "refundhash", - GenerationUtils::generateHash($this->refundPassword) ?: '' - )); - } - - - - if ($builder->paymentMethod instanceof AlternativePaymentMethod) { - $this->buildAlternativePaymentMethod($builder, $request, $xml); - } - - // comment ...TODO: needs to be multiple - if ($builder->description != null) { - $comments = $xml->createElement("comments"); - $comment = $xml->createElement("comment", $builder->description); - $comment->setAttribute("id", "1"); - $comments->appendChild($comment); - $request->appendChild($comments); - } - - if ($builder->paymentMethod instanceof AlternativePaymentMethod) { - $hash = GenerationUtils::generateHash( - $this->sharedSecret, - implode('.', [ - $timestamp, - $this->merchantId, - $orderId, - preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount)), - $builder->currency, - $builder->paymentMethod->alternativePaymentMethodType, - ]) - ); - $request->appendChild($xml->createElement("sha1hash", $hash)); - } - - if ($builder->recurringType !== null || $builder->recurringSequence !== null) { - $recurring = $xml->createElement("recurring"); - $recurring->setAttribute("type", strtolower($builder->recurringType)); - $recurring->setAttribute("sequence", strtolower($builder->recurringSequence)); - $request->appendChild($recurring); - } - - // fraud filter - $this->buildFraudFilter($builder, $xml, $request); - - // tssinfo - - // stored credential - if ($builder->storedCredential != null) { - $storedCredential = $xml->createElement("storedcredential"); - $storedCredential->appendChild($xml->createElement("type", $builder->storedCredential->type)); - $storedCredential->appendChild($xml->createElement("initiator", $builder->storedCredential->initiator)); - $storedCredential->appendChild($xml->createElement("sequence", $builder->storedCredential->sequence)); - $storedCredential->appendChild($xml->createElement("srd", $builder->storedCredential->schemeId)); - $request->appendChild($storedCredential); - } - - // mpi - if (!empty($builder->paymentMethod->threeDSecure)) { - $secureEcom = $builder->paymentMethod->threeDSecure; - $mpi = $xml->createElement("mpi"); - $mpi->appendChild($xml->createElement("eci", $secureEcom->eci)); - $mpi->appendChild($xml->createElement("cavv", $secureEcom->cavv)); - $mpi->appendChild($xml->createElement("xid", $secureEcom->xid)); - - 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); - } - - $acceptedResponseCodes = $this->mapAcceptedCodes($transactionType); - $response = $this->doTransaction($xml->saveXML($request)); - return $this->mapResponse($response, $acceptedResponseCodes); - } - - /** - * @return Transaction - */ - public function processSecure3d(Secure3dBuilder $builder) - { - $transType = $builder->getTransactionType(); - - if ($transType === TransactionType::VERIFY_ENROLLED) { - $authBuilder = (new AuthorizationBuilder($transType, $builder->getPaymentMethod())) - ->withAmount($builder->getAmount()) - ->withCurrency($builder->getCurrency()) - ->withOrderId($builder->getOrderId()); - - return $this->processAuthorization($authBuilder); - } elseif ($transType === TransactionType::VERIFY_SIGNATURE) { - // Get our three d secure object - $secureEcom = $builder->getThreeDSecure(); - - // Create our transaction reference - $reference = new TransactionReference(); - $reference->orderId = $secureEcom->getOrderId(); - - $managementBuilder = (new ManagementBuilder($transType)) - ->withAmount($secureEcom->getAmount()) - ->withCurrency($secureEcom->getCurrency()) - ->withPayerAuthenticationResponse($builder->getPayerAuthenticationResponse()) - ->withPaymentMethod($reference); - return $this->manageTransaction($managementBuilder); - } - throw new UnsupportedTransactionException(sprintf("Unknown transaction type %s", $transType)); - } - - public function serializeRequest(AuthorizationBuilder $builder) - { - // check for hpp config - if ($this->hostedPaymentConfig === null) { - throw new ApiException("Hosted configuration missing, Please check you configuration."); - } - - // check for right transaction types - if ($builder->transactionType !== TransactionType::SALE - && $builder->transactionType !== TransactionType::AUTH - && $builder->transactionType !== TransactionType::VERIFY - ) { - throw new UnsupportedTransactionException("Only Charge and Authorize are supported through HPP."); - } - - if ($builder->paymentMethod instanceof BankPayment && - $builder->transactionType !== TransactionType::SALE) { - throw new UnsupportedTransactionException("Only Charge is supported for Bank Payment through HPP."); - } - - $orderId = isset($builder->orderId) ? $builder->orderId : GenerationUtils::generateOrderId(); - $timestamp = isset($builder->timestamp) ? $builder->timestamp : GenerationUtils::generateTimestamp(); - $amount = preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount)); - - $this->setSerializeData('MERCHANT_ID', $this->merchantId); - $this->setSerializeData('ACCOUNT', $this->accountId); - $this->setSerializeData('HPP_CHANNEL', $this->channel); - $this->setSerializeData('ORDER_ID', $orderId); - if ($builder->amount !== null) { - $this->setSerializeData('AMOUNT', $amount); - } - $this->setSerializeData('CURRENCY', $builder->currency); - $this->setSerializeData('TIMESTAMP', $timestamp); - - $this->setSerializeData( - 'AUTO_SETTLE_FLAG', - ($builder->transactionType == TransactionType::SALE) ? "1" : "0" - ); - - if ( - !empty($builder->hostedPaymentData->bankPayment) && - $builder->hostedPaymentData->bankPayment instanceof BankPayment - ) { - $this->buildOpenBankingHppRequest($builder); - } - - $this->setSerializeData('COMMENT1', $builder->description); - - if (isset($this->hostedPaymentConfig->requestTransactionStabilityScore)) { - $this->serializeData["RETURN_TSS"] = - $this->hostedPaymentConfig->requestTransactionStabilityScore ? "1" : "0"; - } - if (isset($this->hostedPaymentConfig->directCurrencyConversionEnabled)) { - $this->serializeData["DCC_ENABLE"] = - $this->hostedPaymentConfig->directCurrencyConversionEnabled ? "1" : "0"; - } - - if (!empty($builder->hostedPaymentData)) { - $hostedPaymentData = $builder->hostedPaymentData; - $this->setSerializeData('CUST_NUM', $builder->hostedPaymentData->customerNumber); - - if (!empty($this->hostedPaymentConfig->displaySavedCards) && - !empty($builder->hostedPaymentData->customerKey)) { - $this->setSerializeData('HPP_SELECT_STORED_CARD', $builder->hostedPaymentData->customerKey); - } - - if (isset($builder->hostedPaymentData->offerToSaveCard)) { - $this->setSerializeData( - 'OFFER_SAVE_CARD', - $builder->hostedPaymentData->offerToSaveCard ? "1" : "0" - ); - } - if (isset($builder->hostedPaymentData->customerExists)) { - $this->setSerializeData( - 'PAYER_EXIST', - $builder->hostedPaymentData->customerExists ? "1" : "0" - ); - } - if (isset($builder->hostedPaymentData->customerKey)) { - $this->setSerializeData('PAYER_REF', $builder->hostedPaymentData->customerKey); - } - if (isset($builder->hostedPaymentData->paymentKey)) { - $this->setSerializeData('PMT_REF', $builder->hostedPaymentData->paymentKey); - } - if (isset($builder->hostedPaymentData->productId)) { - $this->setSerializeData('PROD_ID', $builder->hostedPaymentData->productId); - } - // APMs Fields - if (!empty($hostedPaymentData->customerCountry)) { - $this->setSerializeData('HPP_CUSTOMER_COUNTRY', $hostedPaymentData->customerCountry); - } - if (!empty($hostedPaymentData->customerFirstName)) { - $this->setSerializeData('HPP_CUSTOMER_FIRSTNAME', $hostedPaymentData->customerFirstName); - } - if (!empty($hostedPaymentData->customerLastName)) { - $this->setSerializeData('HPP_CUSTOMER_LASTNAME', $hostedPaymentData->customerLastName); - } - if (!empty($hostedPaymentData->customerFirstName) && !empty($hostedPaymentData->customerLastName)) { - $this->setSerializeData( - 'HPP_NAME', - $hostedPaymentData->customerFirstName . ' ' . $hostedPaymentData->customerLastName - ); - } - if (!empty($hostedPaymentData->merchantResponseUrl)) { - $this->setSerializeData('MERCHANT_RESPONSE_URL', $hostedPaymentData->merchantResponseUrl); - } - if (!empty($hostedPaymentData->transactionStatusUrl)) { - $this->setSerializeData('HPP_TX_STATUS_URL', $hostedPaymentData->transactionStatusUrl); - } - if (!empty($hostedPaymentData->presetPaymentMethods)) { - $this->setSerializeData('PM_METHODS', implode( '|', $hostedPaymentData->presetPaymentMethods)); - } - // end APMs Fields - } elseif (isset($builder->customerId)) { - $this->setSerializeData('CUST_NUM', $builder->customerId); - } - if (!empty($builder->shippingAddress)) { - - $countryCode = CountryUtils::getCountryCodeByCountry($builder->shippingAddress->country); - $shippingCode = $this->generateCode($builder->shippingAddress); - - // Fraud values - $this->setSerializeData('SHIPPING_CODE', $shippingCode); - $this->setSerializeData('SHIPPING_CO', $countryCode); - - // 3DS 2.0 values - $this->setSerializeData('HPP_SHIPPING_STREET1', $builder->shippingAddress->streetAddress1); - $this->setSerializeData('HPP_SHIPPING_STREET2', $builder->shippingAddress->streetAddress2); - $this->setSerializeData('HPP_SHIPPING_STREET3', $builder->shippingAddress->streetAddress3); - $this->setSerializeData('HPP_SHIPPING_CITY', $builder->shippingAddress->city); - $this->setSerializeData('HPP_SHIPPING_STATE', $builder->shippingAddress->state); - $this->setSerializeData('HPP_SHIPPING_POSTALCODE', $builder->shippingAddress->postalCode); - $this->setSerializeData('HPP_SHIPPING_COUNTRY', CountryUtils::getNumericCodeByCountry($builder->shippingAddress->country)); - } - if (!empty($builder->billingAddress)) { - $countryCode = CountryUtils::getCountryCodeByCountry($builder->billingAddress->country); - $billingCode = $this->generateCode($builder->billingAddress); - // Fraud values - $this->setSerializeData('BILLING_CODE', $billingCode); - $this->setSerializeData('BILLING_CO', $countryCode); - - // 3DS 2.0 values - $this->setSerializeData('HPP_BILLING_STREET1', $builder->billingAddress->streetAddress1); - $this->setSerializeData('HPP_BILLING_STREET2', $builder->billingAddress->streetAddress2); - $this->setSerializeData('HPP_BILLING_STREET3', $builder->billingAddress->streetAddress3); - $this->setSerializeData('HPP_BILLING_CITY', $builder->billingAddress->city); - $this->setSerializeData('HPP_BILLING_STATE', $builder->billingAddress->state); - $this->setSerializeData('HPP_BILLING_POSTALCODE', $builder->billingAddress->postalCode); - $this->setSerializeData( - 'HPP_BILLING_COUNTRY', - CountryUtils::getNumericCodeByCountry($builder->billingAddress->country) - ); - } - - $this->setSerializeData('VAR_REF', $builder->clientTransactionId); - $this->setSerializeData('HPP_LANG', $this->hostedPaymentConfig->language); - $this->setSerializeData('MERCHANT_RESPONSE_URL', $this->hostedPaymentConfig->responseUrl); - $this->setSerializeData('CARD_PAYMENT_BUTTON', $this->hostedPaymentConfig->paymentButtonText); - if (!empty($builder->hostedPaymentData)) { - $hostedPaymentData = $builder->hostedPaymentData; - $this->setSerializeData('HPP_CUSTOMER_EMAIL', $hostedPaymentData->customerEmail); - $this->setSerializeData('HPP_CUSTOMER_PHONENUMBER_MOBILE', $hostedPaymentData->customerPhoneMobile); - $this->setSerializeData('HPP_PHONE', $hostedPaymentData->customerPhoneMobile); - $this->setSerializeData('HPP_CHALLENGE_REQUEST_INDICATOR', $hostedPaymentData->challengeRequest); - if (isset($hostedPaymentData->addressesMatch)) { - $this->setSerializeData('HPP_ADDRESS_MATCH_INDICATOR', $hostedPaymentData->addressesMatch ? 'TRUE' : 'FALSE'); - } - if (!empty($hostedPaymentData->supplementaryData)) { - $this->serializeSupplementaryData($hostedPaymentData->supplementaryData); - } - - if (isset($hostedPaymentData->addressCapture)) { - $this->setSerializeData('HPP_CAPTURE_ADDRESS', $hostedPaymentData->addressCapture == true); - } - if (isset($hostedPaymentData->notReturnAddress)) { - $this->setSerializeData('HPP_DO_NOT_RETURN_ADDRESS', $hostedPaymentData->notReturnAddress == true); - } - } - if (isset($this->hostedPaymentConfig->cardStorageEnabled)) { - $this->setSerializeData('CARD_STORAGE_ENABLE', $this->hostedPaymentConfig->cardStorageEnabled ? '1' : '0'); - } - if ($builder->transactionType === TransactionType::VERIFY) { - $this->setSerializeData( - 'VALIDATE_CARD_ONLY', - $builder->transactionType === TransactionType::VERIFY ? '1' : '0' - ); - } - if ($this->hostedPaymentConfig->fraudFilterMode != FraudFilterMode::NONE) { - $this->setSerializeData('HPP_FRAUDFILTER_MODE', $this->hostedPaymentConfig->fraudFilterMode); - if ($this->hostedPaymentConfig->fraudFilterMode !== FraudFilterMode::NONE && !empty($this->hostedPaymentConfig->fraudFilterRules)) { - foreach ($this->hostedPaymentConfig->fraudFilterRules->rules as $fraudRule) { - $this->setSerializeData( - 'HPP_FRAUDFILTER_RULE_' . $fraudRule->key, - $fraudRule->mode - ); - } - } - } - - if ($builder->recurringType !== null || $builder->recurringSequence !== null) { - $this->setSerializeData('RECURRING_TYPE', strtolower($builder->recurringType)); - $this->setSerializeData('RECURRING_SEQUENCE', strtolower($builder->recurringSequence)); - } - if (isset($this->hostedPaymentConfig->version)) { - $this->setSerializeData('HPP_VERSION', $this->hostedPaymentConfig->version); - } - if (isset($this->hostedPaymentConfig->postDimensions)) { - $this->setSerializeData('HPP_POST_DIMENSIONS', $this->hostedPaymentConfig->postDimensions); - } - if (isset($this->hostedPaymentConfig->postResponse)) { - $this->setSerializeData('HPP_POST_RESPONSE', $this->hostedPaymentConfig->postResponse); - } - if (!empty($builder->supplementaryData)) { - $this->serializeSupplementaryData($builder->supplementaryData); - } - - $toHash = [ - $timestamp, - $this->merchantId, - $orderId, - ($builder->amount !== null) ? preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount)) : null, - $builder->currency, - ]; - - if ($this->hostedPaymentConfig->cardStorageEnabled - || ($builder->hostedPaymentData != null - && $builder->hostedPaymentData->offerToSaveCard) - || $this->hostedPaymentConfig->displaySavedCards - ) { - $toHash[] = ($builder->hostedPaymentData->customerKey !== null) ? - $builder->hostedPaymentData->customerKey : - null; - $toHash[] = ($builder->hostedPaymentData->paymentKey !== null) ? - $builder->hostedPaymentData->paymentKey : - null; - } - - if ( - !empty($this->hostedPaymentConfig->fraudFilterMode) && - $this->hostedPaymentConfig->fraudFilterMode !== FraudFilterMode::NONE - ) { - $toHash[] = $this->hostedPaymentConfig->fraudFilterMode; - } - - if ( - !empty($builder->hostedPaymentData->bankPayment) && - $builder->hostedPaymentData->bankPayment instanceof BankPayment - ) { - $bankPayment = $builder->hostedPaymentData->bankPayment; - $toHash = array_merge($toHash, [ - !empty($bankPayment->sortCode) ? $bankPayment->sortCode : '', - !empty($bankPayment->accountNumber) ? $bankPayment->accountNumber : '', - !empty($bankPayment->iban) ? $bankPayment->iban : '' - ]); - } - - if (!empty($builder->dynamicDescriptor)) { - $this->serializeData["CHARGE_DESCRIPTION"] = $builder->dynamicDescriptor; - } - - list($tagHashName, $tagHashValue) = $this->mapShaHash(implode('.', $toHash)); - $this->setSerializeData($tagHashName, $tagHashValue); - - return GenerationUtils::convertArrayToJson($this->serializeData, $this->hostedPaymentConfig->version); - } - - private function mapShaHash($toHash) - { - if (empty($this->shaHashType)) { - throw new ApiException(sprintf("%s not supported. Please check your code and the Developers Documentation.", $this->shaHashType)); - } - - return [ - $this->shaHashType . 'HASH', - GenerationUtils::generateNewHash($this->sharedSecret, $toHash, $this->shaHashType) - ]; - } - - /** - * @param AuthorizationBuilder $builder - */ - private function buildOpenBankingHppRequest($builder) - { - $paymentMethod = $builder->hostedPaymentData->bankPayment; - $this->setSerializeData( - 'HPP_OB_PAYMENT_SCHEME', - !empty($paymentMethod->bankPaymentType) ? - $paymentMethod->bankPaymentType : OpenBankingProvider::getBankPaymentType($builder->currency) - ); - $this->setSerializeData('HPP_OB_REMITTANCE_REF_TYPE', $builder->remittanceReferenceType); - $this->setSerializeData('HPP_OB_REMITTANCE_REF_VALUE', $builder->remittanceReferenceValue); - $this->setSerializeData('HPP_OB_DST_ACCOUNT_IBAN', $paymentMethod->iban); - $this->setSerializeData('HPP_OB_DST_ACCOUNT_NAME', $paymentMethod->accountName); - $this->setSerializeData('HPP_OB_DST_ACCOUNT_NUMBER', $paymentMethod->accountNumber); - $this->setSerializeData('HPP_OB_DST_ACCOUNT_SORT_CODE', $paymentMethod->sortCode); - if (!empty($builder->hostedPaymentData)) { - $hostedPaymentData = $builder->hostedPaymentData; - $this->setSerializeData('HPP_OB_CUSTOMER_COUNTRIES', $hostedPaymentData->customerCountry); - } - } - - /** - * {@inheritdoc} - * - * @param ManagementBuilder $builder The transaction's builder - * - * @return Transaction - */ - public function manageTransaction(ManagementBuilder $builder) - { - $xml = new DOMDocument(); - $timestamp = GenerationUtils::generateTimestamp(); - $orderId = $builder->orderId ?: GenerationUtils::generateOrderId(); - $transactionType = $this->mapManageRequestType($builder); - // Build Request - $request = $xml->createElement("request"); - $request->setAttribute("timestamp", $timestamp); - $request->setAttribute("type", $transactionType); - - $request->appendChild($xml->createElement("merchantid", $this->merchantId)); - - if ($this->accountId !== null) { - $request->appendChild($xml->createElement("account", $this->accountId)); - } - if (is_null($builder->alternativePaymentType)) { - $request->appendChild($xml->createElement("channel", $this->channel)); - } - - if ($builder->amount !== null) { - $amount = $xml->createElement("amount", preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount))); - $amount->setAttribute("currency", $builder->currency); - $request->appendChild($amount); - } elseif ($builder->transactionType === TransactionType::CAPTURE) { - throw new BuilderException("Amount cannot be null for capture."); - } - - $request->appendChild($xml->createElement("orderid", $orderId)); - $request->appendChild($xml->createElement("pasref", $builder->transactionId)); - - // rebate hash - if ($builder->transactionType === TransactionType::REFUND && - is_null($builder->alternativePaymentType)) { - $request->appendChild($xml->createElement("authcode", $builder->paymentMethod->authCode)); - } - - // reason code - if ($builder->reasonCode !== null) { - $request->appendChild($xml->createElement("reasoncode", $builder->reasonCode)); - } - - if ($builder->alternativePaymentType !== null) { - $request->appendChild($xml->createElement("paymentmethod", $builder->alternativePaymentType)); - if ($builder->transactionType == TransactionType::CONFIRM) { - $paymentMethodDetails = $xml->createElement("paymentmethoddetails"); - $apmResponse = $builder->paymentMethod->alternativePaymentResponse; - if ($builder->alternativePaymentType == AlternativePaymentType::PAYPAL) { - $paymentMethodDetails->appendChild($xml->createElement('Token', $apmResponse->sessionToken)); - $paymentMethodDetails->appendChild( - $xml->createElement('PayerID', $apmResponse->providerReference) - ); - } - $request->appendChild($paymentMethodDetails); - } - } - - if ($builder->transactionType === TransactionType::VERIFY_SIGNATURE) { - $request->appendChild($xml->createElement("pares", $builder->payerAuthenticationResponse)); - } - - // comments needs to be multiple - if ($builder->description !== null) { - $comments = $xml->createElement("comments"); - $comment = $xml->createElement("comment", $builder->description); - $comment->setAttribute("id", "1"); - $comments->appendChild($comment); - $request->appendChild($comments); - } - - $toHash = [ - $timestamp, - $this->merchantId, - $orderId, - ($builder->amount !== null ? preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount)) : ''), - ($builder->currency !== null ? $builder->currency : ''), - ($builder->alternativePaymentType !== null ? $builder->alternativePaymentType : '') - ]; - - if ( - ( - $builder->transactionType === TransactionType::CAPTURE || - $builder->transactionType === TransactionType::REFUND - ) && - !empty($builder->dynamicDescriptor) - ) { - $narrative = $xml->createElement("narrative"); - $narrative->appendChild($xml->createElement("chargedescription", strtoupper($builder->dynamicDescriptor))); - $request->appendChild($narrative); - } - - $request->appendChild( - $xml->createElement( - "sha1hash", - GenerationUtils::generateHash($this->sharedSecret, implode('.', $toHash)) - ) - ); - - // rebate hash - if ($builder->transactionType === TransactionType::REFUND) { - $request->appendChild( - $xml->createElement( - "refundhash", - GenerationUtils::generateHash(isset($this->rebatePassword) ? $this->rebatePassword : '') - ) - ); - } - - $response = $this->doTransaction($xml->saveXML($request)); - return $this->mapResponse($response, $this->mapAcceptedCodes($transactionType)); - } - - public function processReport(ReportBuilder $builder) - { - $xml = new DOMDocument(); - $timestamp = GenerationUtils::generateTimestamp(); - - $request = $xml->createElement("request"); - $request->setAttribute("timestamp", $timestamp); - $request->setAttribute("type", $this->mapReportRequestType($builder->reportType)); - $request->appendChild($xml->createElement("merchantid", $this->merchantId)); - - if ($this->accountId !== null) { - $request->appendChild($xml->createElement("account", $this->accountId)); - } - $request->appendChild($xml->createElement("orderid", $builder->transactionId)); - $hash = GenerationUtils::generateHash( - $this->sharedSecret, - implode('.', [ - $timestamp, - $this->merchantId, - $builder->transactionId, - '', - '', - '' - ]) - ); - $request->appendChild($xml->createElement("sha1hash", $hash)); - $response = $this->doTransaction($xml->saveXML($request)); - return $this->MapReportResponse($response, $builder->reportType); - } - - public function processRecurring(RecurringBuilder $builder) - { - $xml = new DOMDocument(); - $timestamp = GenerationUtils::generateTimestamp(); - $orderId = $builder->orderId ? $builder->orderId : GenerationUtils::generateOrderId(); - - // Build Request - $request = $xml->createElement("request"); - $request->setAttribute("timestamp", $timestamp); - $request->setAttribute("type", $this->mapRecurringRequestType($builder)); - - $request->appendChild($xml->createElement("merchantid", $this->merchantId)); - - if ($this->accountId !== null) { - $request->appendChild($xml->createElement("account", $this->accountId)); - } - $request->appendChild($xml->createElement("channel", $this->channel)); - $request->appendChild($xml->createElement("orderid", $orderId)); - - if ($builder->transactionType == TransactionType::CREATE || - $builder->transactionType == TransactionType::EDIT) { - if ($builder->entity instanceof Customer) { - $hash = GenerationUtils::generateHash( - $this->sharedSecret, - implode('.', [ - $timestamp, - $this->merchantId, - $orderId, - '', - '', - $builder->entity->key - ]) - ); - - $request->appendChild($this->buildCustomer($xml, $builder)); - } elseif ($builder->entity instanceof RecurringPaymentMethod) { - $payment = $builder->entity; - $paymentKey = (!empty($payment->key)) ? $payment->key : $payment->id; - - if ($builder->transactionType == TransactionType::CREATE) { - $hash = GenerationUtils::generateHash( - $this->sharedSecret, - implode('.', [ - $timestamp, - $this->merchantId, - $orderId, - '', - '', - $payment->customerKey, - $payment->paymentMethod->cardHolderName, - $payment->paymentMethod->number - ]) - ); - } else { - $hash = GenerationUtils::generateHash( - $this->sharedSecret, - implode('.', [ - $timestamp, - $this->merchantId, - $payment->customerKey, - $paymentKey, - $payment->paymentMethod->getShortExpiry(), - $payment->paymentMethod->number - ]) - ); - } - $request->appendChild($this->buildCardElement($xml, $payment, $paymentKey)); - $request->appendChild($xml->createElement("defaultcard", 1)); - } - - //set hash value - $request->appendChild($xml->createElement("sha1hash", $hash)); - } elseif ($builder->transactionType == TransactionType::DELETE) { - if ($builder->entity instanceof RecurringPaymentMethod) { - $payment = $builder->entity; - $paymentKey = (!empty($payment->key)) ? $payment->key : $payment->id; - $cardElement = $xml->createElement("card"); - $cardElement->appendChild($xml->createElement("ref", $paymentKey)); - $cardElement->appendChild($xml->createElement("payerref", $payment->customerKey)); - $request->appendChild($cardElement); - - $hash = GenerationUtils::generateHash( - $this->sharedSecret, - implode('.', [ - $timestamp, - $this->merchantId, - $payment->customerKey, - $paymentKey - ]) - ); - $request->appendChild($xml->createElement("sha1hash", $hash)); - } - } - - $response = $this->doTransaction($xml->saveXML($request)); - return $this->mapResponse($response); - } - - private function buildCustomer($xml, $builder) - { - $customer = $builder->entity; - $type = 'Retail'; - if ($builder->transactionType === TransactionType::EDIT) { - $type = 'Subscriber'; - } - $payer = $xml->createElement("payer"); - $payer->setAttribute("ref", (!empty($customer->key)) ? $customer->key : - GenerationUtils::generateRecurringKey()); - $payer->setAttribute("type", $type); - - $payer->appendChild($xml->createElement("title", $customer->title)); - $payer->appendChild($xml->createElement("firstname", $customer->firstName)); - $payer->appendChild($xml->createElement("surname", $customer->lastName)); - $payer->appendChild($xml->createElement("company", $customer->company)); - - - if ($customer->address != null) { - $address = $xml->createElement("address"); - $address->appendChild($xml->createElement("line1", $customer->address->streetAddress1)); - $address->appendChild($xml->createElement("line2", $customer->address->streetAddress2)); - $address->appendChild($xml->createElement("line3", $customer->address->streetAddress3)); - $address->appendChild($xml->createElement("city", $customer->address->city)); - $address->appendChild($xml->createElement("county", $customer->address->getProvince())); - $address->appendChild($xml->createElement("postcode", $customer->address->postalCode)); - - $country = $xml->createElement("country", $customer->address->country); - if (!empty($customer->address->countryCode)) { - $country->setAttribute("code", $customer->address->countryCode); - } - $address->appendChild($country); - - $payer->appendChild($address); - } - - $phonenumbers = $xml->createElement("phonenumbers"); - $phonenumbers->appendChild($xml->createElement("home", $customer->homePhone)); - $phonenumbers->appendChild($xml->createElement("work", $customer->workPhone)); - $phonenumbers->appendChild($xml->createElement("fax", $customer->fax)); - $phonenumbers->appendChild($xml->createElement("mobile", $customer->mobilePhone)); - - $payer->appendChild($phonenumbers); - $payer->appendChild($xml->createElement("email", $customer->email)); - - return $payer; - } - - private function buildCardElement($xml, $payment, $paymentKey = '') - { - $card = $payment->paymentMethod; - $cardElement = $xml->createElement("card"); - $cardElement->appendChild($xml->createElement("ref", $paymentKey)); - $cardElement->appendChild($xml->createElement("payerref", $payment->customerKey)); - $cardElement->appendChild($xml->createElement("number", $card->number)); - $cardElement->appendChild($xml->createElement("expdate", $card->getShortExpiry())); - $cardElement->appendChild($xml->createElement("chname", $card->cardHolderName)); - $cardElement->appendChild($xml->createElement( - "type", - strtoupper(EnumMapping::mapCardType( - GatewayProvider::GP_ECOM, - CardUtils::getBaseCardType($card->getCardType()))) - )); - - return $cardElement; - } - - /** - * Deserializes the gateway's XML response - * - * @param string $rawResponse The XML response - * - * @return Transaction - */ - protected function mapResponse($rawResponse, array $acceptedCodes = null) - { - $result = new Transaction(); - - $root = $this->xml2object($rawResponse); - - $this->checkResponse($root, $acceptedCodes); - - $result->responseCode = (string)$root->result; - $result->responseMessage = (string)$root->message; - $result->cvnResponseCode = (string)$root->cvnresult; - $result->avsResponseCode = (string)$root->avspostcoderesponse; - $result->avsAddressResponse = (string)$root->avsaddressresponse; - $result->transactionReference = new TransactionReference(); - $result->transactionReference->paymentMethodType = PaymentMethodType::CREDIT; - $result->transactionReference->transactionId = (string)$root->pasref; - $result->transactionReference->authCode = (string)$root->authcode; - $result->transactionReference->orderId = (string)$root->orderid; - $result->timestamp = (!empty($root->attributes()->timestamp)) ? - (string) $root->attributes()->timestamp : - ''; - - // 3d secure enrolled - if (!empty($root->enrolled)) { - $result->threeDSecure = new ThreeDSecure(); - $result->threeDSecure->enrolled = (string)$root->enrolled; - $result->threeDSecure->xid = (string)$root->xid; - $result->threeDSecure->issuerAcsUrl = (string)$root->url; - $result->threeDSecure->payerAuthenticationRequest = (string)$root->pareq; - } - - // 3d secure signature - if (!empty($root->threedsecure)) { - $secureEcom = new ThreeDSecure(); - $secureEcom->status = (string)$root->threedsecure->status; - $secureEcom->eci = (string)$root->threedsecure->eci; - $secureEcom->cavv = (string)$root->threedsecure->cavv; - $secureEcom->xid = (string)$root->threedsecure->xid; - $secureEcom->algorithm = (int)$root->threedsecure->algorithm; - $result->threeDSecure = $secureEcom; - } - - // stored credential - $result->schemeId = (string)$root->srd; - - // dccinfo - if (!empty($root->dccinfo)) { - $result->dccRateData = new DccRateData(); - - $result->dccRateData->cardHolderCurrency = (string)$root->dccinfo->cardholdercurrency; - $result->dccRateData->cardHolderAmount = (string)$root->dccinfo->cardholderamount; - $result->dccRateData->cardHolderRate = (string)$root->dccinfo->cardholderrate; - $result->dccRateData->merchantCurrency = (string)$root->dccinfo->merchantcurrency; - $result->dccRateData->merchantAmount = (string)$root->dccinfo->merchantamount; - $result->dccRateData->marginRatePercentage = (string)$root->dccinfo->marginratepercentage; - $result->dccRateData->exchangeRateSourceName = (string)$root->dccinfo->exchangeratesourcename; - $result->dccRateData->commissionPercentage = (string)$root->dccinfo->commissionpercentage; - $result->dccRateData->exchangeRateSourceTimestamp = (string) - $root->dccinfo->exchangeratesourcetimestamp; - } - - // fraud filter - if (!empty($root->fraudresponse)) { - $fraudResponse = $root->fraudresponse; - $result->fraudFilterResponse = new FraudManagementResponse(); - - foreach ($fraudResponse->attributes() as $attrName => $attrValue) { - $result->fraudFilterResponse->fraudResponseMode = (!empty($attrValue)) ? (string) $attrValue : ''; - } - - $result->fraudFilterResponse->fraudResponseResult = (!empty($fraudResponse->result)) ? - (string) $fraudResponse->result : ''; - - if (!empty($fraudResponse->rules)) { - foreach ($fraudResponse->rules->rule as $rule) { - $ruleDetails = [ - 'id' => (string) $rule->attributes()->id, - 'name' => (string) $rule->attributes()->name, - 'action' => (string) $rule->action - ]; - $result->fraudFilterResponse->fraudResponseRules[] = $ruleDetails; - } - } - } - - // alternativePaymentResponse - if (!empty($root->paymentmethoddetails)) { - $result->alternativePaymentResponse = new AlternativePaymentResponse(); - - $result->alternativePaymentResponse->paymentMethod = (string) - $root->paymentmethoddetails->paymentmethod; - $result->alternativePaymentResponse->bankAccount = (string) - $root->paymentmethoddetails->bankaccount; - $result->alternativePaymentResponse->accountHolderName = (string) - $root->paymentmethoddetails->accountholdername; - $result->alternativePaymentResponse->country = (string) - $root->paymentmethoddetails->country; - $result->alternativePaymentResponse->redirectUrl = (string) - $root->paymentmethoddetails->redirecturl; - $result->alternativePaymentResponse->paymentPurpose = (string) - $root->paymentmethoddetails->paymentpurpose; - $result->alternativePaymentResponse->providerName = (string) $root->paymentmethod; - if (!empty($root->paymentmethoddetails->SetExpressCheckoutResponse)) { - $apmResponseDetails = $root->paymentmethoddetails->SetExpressCheckoutResponse; - } elseif (!empty($root->paymentmethoddetails->DoExpressCheckoutPaymentResponse)) { - $apmResponseDetails = $root->paymentmethoddetails->DoExpressCheckoutPaymentResponse; - } - if (!empty($apmResponseDetails)) { - $result->alternativePaymentResponse->sessionToken = !empty($apmResponseDetails->Token) ? - (string) $apmResponseDetails->Token : null; - $result->alternativePaymentResponse->ack = !empty($apmResponseDetails->Ack) ? - (string) $apmResponseDetails->Ack : null; - $result->alternativePaymentResponse->timeCreatedReference = !empty($apmResponseDetails->Timestamp) ? - (string) $apmResponseDetails->Timestamp : null; - $result->alternativePaymentResponse->correlationReference = !empty($apmResponseDetails->CorrelationID) ? - (string) $apmResponseDetails->CorrelationID : null; - $result->alternativePaymentResponse->versionReference = !empty($apmResponseDetails->Version) ? - (string) $apmResponseDetails->Version : null; - $result->alternativePaymentResponse->buildReference = !empty($apmResponseDetails->Build) ? - (string) $apmResponseDetails->Build : null; - if (!empty($apmResponseDetails->PaymentInfo)) { - $paymentInfo = $apmResponseDetails->PaymentInfo; - $result->alternativePaymentResponse->transactionReference = (string) $paymentInfo->TransactionID; - $result->alternativePaymentResponse->paymentType = (string) $paymentInfo->PaymentType; - $result->alternativePaymentResponse->paymentTimeReference = (string) $paymentInfo->PaymentDate; - $result->alternativePaymentResponse->grossAmount = (string) $paymentInfo->GrossAmount; - $result->alternativePaymentResponse->feeAmount = (string) $paymentInfo->TaxAmount; - $result->alternativePaymentResponse->paymentStatus = (string) $paymentInfo->PaymentStatus; - $result->alternativePaymentResponse->pendingReason = (string) $paymentInfo->PendingReason; - $result->alternativePaymentResponse->reasonCode = (string) $paymentInfo->ReasonCode; - $result->alternativePaymentResponse->authProtectionEligibilty = (string) $paymentInfo->ProtectionEligibility; - $result->alternativePaymentResponse->authProtectionEligibiltyType = (string) $paymentInfo->ProtectionEligibilityType; - } - } - } - - return $result; - } - - protected function checkResponse($root, array $acceptedCodes = null) - { - if ($acceptedCodes === null) { - $acceptedCodes = [ "00" ]; - } - - $responseCode = (string)$root->result; - $responseMessage = (string)$root->message; - - if (!in_array($responseCode, $acceptedCodes)) { - throw new GatewayException( - sprintf('Unexpected Gateway Response: %s - %s', $responseCode, $responseMessage), - $responseCode, - $responseMessage - ); - } - } - - /** - * Generates a request hash from the request data - * - * @param string $timestamp Request timestamp - * @param string $orderId Request order ID - * @param string $amount Request amount - * @param string $currency Request currency - * @param string $paymentData Request payment data - * @param bool $verify Is request a verify transaction - * - * @return string - */ - protected function generateHash( - $timestamp, - $orderId, - $amount, - $currency, - $paymentData = null, - $verify = false - ) { - $data = [ - $timestamp, - $this->merchantId, - $orderId, - ]; - - if (false === $verify) { - $data[] = $amount; - $data[] = $currency; - } - - $data[] = $paymentData; - - return GenerationUtils::generateHash( - $this->sharedSecret, - implode('.', $data) - ); - } - - /** - * Maps a transaction builder to a Realex request type - * - * @param AuthorizationBuilder $builder Transaction builder - * - * @return string - */ - protected function mapAuthRequestType(AuthorizationBuilder $builder) - { - switch ($builder->transactionType) { - case TransactionType::SALE: - case TransactionType::AUTH: - if ($builder->paymentMethod->paymentMethodType == PaymentMethodType::CREDIT) { - if ($builder->transactionModifier === TransactionModifier::OFFLINE) { - return 'offline'; - } elseif ($builder->transactionModifier === TransactionModifier::ENCRYPTED_MOBILE) { - return 'auth-mobile'; - } - } elseif ($builder->paymentMethod->paymentMethodType == PaymentMethodType::RECURRING) { - return (!empty($builder->recurringSequence) && - $builder->recurringSequence == RecurringSequence::FIRST) ? - 'auth' : - 'receipt-in'; - } elseif ($builder->paymentMethod->paymentMethodType == PaymentMethodType::APM) { - return "payment-set"; - } - return 'auth'; - case TransactionType::CAPTURE: - return 'settle'; - case TransactionType::VERIFY: - if ($builder->paymentMethod->paymentMethodType == PaymentMethodType::RECURRING) { - if (!empty($builder->transactionModifier) && - $builder->transactionModifier === TransactionModifier::SECURE3D) { - return 'realvault-3ds-verifyenrolled'; - } - return 'receipt-in-otb'; - } - return 'otb'; - case TransactionType::REFUND: - if ($builder->paymentMethod->paymentMethodType == PaymentMethodType::CREDIT) { - return 'credit'; - } - return 'payment-out'; - case TransactionType::DCC_RATE_LOOKUP: - if ($builder->paymentMethod->paymentMethodType == PaymentMethodType::CREDIT) { - return "dccrate"; - } - return "realvault-dccrate"; - - case TransactionType::REVERSAL: - // TODO: should be customer type - throw new UnsupportedTransactionException( - 'The selected gateway does not support this transaction type.' - ); - case TransactionType::VERIFY_ENROLLED: - if ($builder->paymentMethod instanceof RecurringPaymentMethod) { - return 'realvault-3ds-verifyenrolled'; - } - return '3ds-verifyenrolled'; - default: - return 'unknown'; - } - } - - /** - * Maps a transaction builder to a Realex request type - * - * @param ManagementBuilder $builder Transaction builder - * - * @return string - */ - protected function mapManageRequestType(ManagementBuilder $builder) - { - switch ($builder->transactionType) { - case TransactionType::CAPTURE: - return 'settle'; - case TransactionType::HOLD: - return 'hold'; - case TransactionType::REFUND: - if ($builder->alternativePaymentType !== null) { - return 'payment-credit'; - } - return 'rebate'; - case TransactionType::RELEASE: - return 'release'; - case TransactionType::VOID: - case TransactionType::REVERSAL: - return 'void'; - case TransactionType::VERIFY_SIGNATURE: - return '3ds-verifysig'; - case TransactionType::CONFIRM: - return 'payment-do'; - default: - return 'unknown'; - } - } - - /** - * Maps a transaction builder to a Realex request type - * - * @param RecurringBuilder $builder Transaction builder - * - * @return string - */ - private function mapRecurringRequestType(RecurringBuilder $builder) - { - $entity = $builder->entity; - - switch ($builder->transactionType) { - case TransactionType::CREATE: - if ($entity instanceof Customer) { - return "payer-new"; - } elseif ($entity instanceof RecurringPaymentMethod) { - return "card-new"; - } - throw new UnsupportedTransactionException( - 'The selected gateway does not support this transaction type.' - ); - case TransactionType::EDIT: - if ($entity instanceof Customer) { - return "payer-edit"; - } elseif ($entity instanceof RecurringPaymentMethod) { - return "card-update-card"; - } - throw new UnsupportedTransactionException(); - case TransactionType::DELETE: - if ($entity instanceof RecurringPaymentMethod) { - return "card-cancel-card"; - } - throw new UnsupportedTransactionException( - 'The selected gateway does not support this transaction type.' - ); - default: - throw new UnsupportedTransactionException( - 'The selected gateway does not support this transaction type.' - ); - } - } - - /** - * Converts a XML string to a simple object for use, - * removing extra nodes that are not necessary for - * handling the response - * - * @param string $xml Response XML from the gateway - * - * @return SimpleXMLElement - */ - protected function xml2object($xml) - { - $envelope = simplexml_load_string( - $xml, - 'SimpleXMLElement' - ); - - return $envelope; - } - - /** - * Return the request values for Shal hash generation based on transaction type - * EncyptedMobileType::GOOGLE_PAY requires amount and currency with token - * EncyptedMobileType::APPLE_PAY doesn't requires amount and currency. token contains those values - * - * @param string $timestamp current timestamp - * @param int $orderId current order id - * @param object $builder auth builder object - * @param object $card - * - * @return array - */ - private function getShal1RequestValues($timestamp, $orderId, $builder, $card) - { - $requestValues = [ - $timestamp, - $this->merchantId, - $orderId, - preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount)), - $builder->currency, - $card->number - ]; - - if (($builder->transactionModifier === TransactionModifier::ENCRYPTED_MOBILE)) { - switch ($card->mobileType) { - case EncyptedMobileType::GOOGLE_PAY: - case EncyptedMobileType::APPLE_PAY: - $requestValues = [ - $timestamp, - $this->merchantId, - $orderId, - preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount)), - $builder->currency, - $card->token - ]; - break; - default: - break; - } - } - - return $requestValues; - } - - public function buildFraudFilter($builder, $xml, $request) - { - // tssinfo fraudfilter - // fraudfilter - if (!empty($builder->fraudFilter)) { - $fraudFilter = $xml->createElement("fraudfilter"); - $fraudFilter->setAttribute("mode", $builder->fraudFilter); - if (!empty($builder->fraudRules)) { - $rules = $xml->createElement("rules"); - foreach ($builder->fraudRules as $fraudRule) { - $rule = $xml->createElement("rule"); - $rule->setAttribute("id", $fraudRule->key); - $rule->setAttribute("mode", $fraudRule->mode); - $rules->appendChild($rule); - } - $fraudFilter->appendChild($rules); - } - $request->appendChild($fraudFilter); - } - if ($builder->customerId !== null || $builder->productId !== null || - $builder->clientTransactionId !== null || $builder->verifyAddress !== false - ) { - $tssInfo = $xml->createElement("tssinfo"); - - if (!empty($builder->customerId)) { - $tssInfo->appendChild($xml->createElement("custnum", $builder->customerId)); - } - - if (!empty($builder->productId)) { - $tssInfo->appendChild($xml->createElement("prodid", $builder->productId)); - } - - if (!empty($builder->clientTransactionId)) { - $tssInfo->appendChild($xml->createElement("varref", $builder->clientTransactionId)); - } - - if (!empty($builder->customerIpAddress)) { - $tssInfo->appendChild($xml->createElement("custipaddress", $builder->customerIpAddress)); - } - - if (!empty($builder->billingAddress)) { - $billingAddress = $xml->createElement("address"); - $billingAddress->setAttribute("type", 'billing'); - $billingAddress->appendChild($xml->createElement("code", $builder->billingAddress->postalCode)); - $billingAddress->appendChild($xml->createElement("country", $builder->billingAddress->country)); - $tssInfo->appendChild($billingAddress); - } - - if (!empty($builder->shippingAddress)) { - $shippingAddress = $xml->createElement("address"); - $shippingAddress->setAttribute("type", 'shipping'); - $shippingAddress->appendChild($xml->createElement("code", $builder->shippingAddress->postalCode)); - $shippingAddress->appendChild($xml->createElement("country", $builder->shippingAddress->country)); - $tssInfo->appendChild($shippingAddress); - } - if (!empty($tssInfo->childNodes->length)) { - $request->appendChild($tssInfo); - } - } - return; - } - - public function supportsHostedPayments() - { - return $this->supportsHostedPayments; - } - - - public function buildAlternativePaymentMethod($builder, $request, $xml) - { - $request->appendChild($xml->createElement( - "paymentmethod", - $builder->paymentMethod->alternativePaymentMethodType - )); - - $paymentMethodDetails = $xml->createElement("paymentmethoddetails"); - list($returnUrl, $statusUpdateUrl, $cancelUrl) = - $this->mapAPMUrls($builder->paymentMethod->alternativePaymentMethodType); - $paymentMethodDetails->appendChild( - $xml->createElement($returnUrl, $builder->paymentMethod->returnUrl) - ); - $paymentMethodDetails->appendChild( - $xml->createElement($statusUpdateUrl, $builder->paymentMethod->statusUpdateUrl) - ); - if (!empty($builder->paymentMethod->cancelUrl)) { - $paymentMethodDetails->appendChild( - $xml->createElement($cancelUrl, $builder->paymentMethod->cancelUrl) - ); - } - - if (!empty($builder->paymentMethod->descriptor)) { - $paymentMethodDetails->appendChild( - $xml->createElement("descriptor", $builder->paymentMethod->descriptor) - ); - } - - $paymentMethodDetails->appendChild($xml->createElement("country", $builder->paymentMethod->country)); - $paymentMethodDetails->appendChild($xml->createElement( - "accountholdername", - $builder->paymentMethod->accountHolderName - )); - - $request->appendChild($paymentMethodDetails); - - return; - } - - private function mapAcceptedCodes($paymentMethodType) - { - switch ($paymentMethodType) { - case "3ds-verifysig": - case "3ds-verifyenrolled": - return ["00", "110"]; - case "payment-set": - return ["01", "00"]; - default: - return ["00"]; - } - } - - private function mapAPMUrls($paymentMethodType) - { - switch ($paymentMethodType) { - case AlternativePaymentType::PAYPAL: - return ['ReturnURL', 'StatusUpdateURL', 'CancelURL']; - default: - return ['returnurl', 'statusupdateurl', 'cancelurl']; - } - } - - private function setSerializeData($key, $value = null) - { - if ($value !== null) { - $this->serializeData[$key] = $value; - } - } - - /** - * @param array> $supplementaryData - */ - private function serializeSupplementaryData($supplementaryData) - { - foreach ($supplementaryData as $key => $value) { - $this->setSerializeData(strtoupper($key), $value); - } - } - - private function generateCode(Address $address) - { - $countryCode = CountryUtils::getCountryCodeByCountry($address->country); - switch ($countryCode) - { - case 'GB': - return filter_var($address->postalCode, FILTER_SANITIZE_NUMBER_INT) . '|' . filter_var($address->streetAddress1, FILTER_SANITIZE_NUMBER_INT); - case 'US': - case 'CA': - return $address->postalCode . '|' . $address->streetAddress1; - default: - return null; - } - } - - /** - * @param string $reportType - */ - private function mapReportRequestType($reportType) - { - switch ($reportType) { - case ReportType::TRANSACTION_DETAIL: - return 'query'; - default: - throw new UnsupportedTransactionException("This reporting call is not supported by your currently configured gateway."); - } - } - - private function mapReportResponse($rawResponse, $reportType) - { - $summary = new TransactionSummary(); - $root = $this->xml2object($rawResponse); - - $this->checkResponse($root); - try { - switch ($reportType) { - case ReportType::TRANSACTION_DETAIL: - $summary->transactionId = (string)$root->pasref; - $summary->orderId = (string)$root->orderid; - $summary->authCode = (string)$root->authcode; - $summary->maskedCardNumber = (string)$root->cardnumber; - $summary->avsResponseCode = (string)$root->avspostcoderesponse; - $summary->cvnResponseCode = (string)$root->cvnresult; - $summary->gatewayResponseCode = (string)$root->result; - $summary->gatewayResponseMessage = (string)$root->message; - $summary->batchSequenceNumber = (string)$root->batchid; - $summary->gatewayResponseCode = (string)$root->result; - if (!empty($root->fraudresponse)) { - $summary->fraudRuleInfo = (string)$root->fraudresponse->result; - } - if (!empty($root->threedsecure)) { - $summary->cavvResponseCode = (string)$root->threedsecure->cavv; - $summary->eciIndicator = (string)$root->threedsecure->eci; - $summary->xid = (string)$root->threedsecure->xid; - } - if (!empty($root->srd)) { - $summary->schemeReferenceData = (string)$root->srd; - } - break; - default: - break; - } - } catch (Exception $e) { - throw new ApiException($e->getMessage(), $e); - } - return $summary; - } -} diff --git a/src/Mapping/EnumMapping.php b/src/Mapping/EnumMapping.php index a24bc8db..b4a91700 100644 --- a/src/Mapping/EnumMapping.php +++ b/src/Mapping/EnumMapping.php @@ -7,6 +7,7 @@ use GlobalPayments\Api\Entities\Enums\EmvLastChipRead; use GlobalPayments\Api\Entities\Enums\EncyptedMobileType; use GlobalPayments\Api\Entities\Enums\GatewayProvider; +use GlobalPayments\Api\Entities\Enums\ScheduleFrequency; use GlobalPayments\Api\Entities\Enums\MessageCategory; use GlobalPayments\Api\Entities\Enums\SdkUiType; use GlobalPayments\Api\Entities\Enums\StoredCredentialInitiator; @@ -115,6 +116,25 @@ public static function mapCardType($gateway, $value) } } + public static function mapScheduleFrequency($gateway, $value) + { + switch ($gateway) { + case GatewayProvider::GP_ECOM: + switch ($value) { + case ScheduleFrequency::BI_MONTHLY: + return 'bimonthly'; + case ScheduleFrequency::SEMI_ANNUALLY: + return 'halfyearly'; + case ScheduleFrequency::ANNUALLY: + return 'yearly'; + default: + return $value; + } + default: + return $value; + } + } + public static function mapSdkUiType($gateway, $value) { switch ($gateway) { @@ -126,7 +146,7 @@ public static function mapSdkUiType($gateway, $value) return $value; } default: - return null; + return $value; } } diff --git a/src/Mapping/GpEcomMapping.php b/src/Mapping/GpEcomMapping.php new file mode 100644 index 00000000..2fdf2a94 --- /dev/null +++ b/src/Mapping/GpEcomMapping.php @@ -0,0 +1,390 @@ +responseCode = (string)$root->result; + $result->responseMessage = (string)$root->message; + $result->cvnResponseCode = (string)$root->cvnresult; + $result->avsResponseCode = (string)$root->avspostcoderesponse; + $result->avsAddressResponse = (string)$root->avsaddressresponse; + $result->transactionReference = new TransactionReference(); + $result->transactionReference->paymentMethodType = PaymentMethodType::CREDIT; + $result->transactionReference->transactionId = (string)$root->pasref; + $result->transactionReference->authCode = (string)$root->authcode; + $result->transactionReference->orderId = (string)$root->orderid; + $result->timestamp = (!empty($root->attributes()->timestamp)) ? + (string) $root->attributes()->timestamp : + ''; + + // 3d secure enrolled + if (!empty($root->enrolled)) { + $result->threeDSecure = new ThreeDSecure(); + $result->threeDSecure->enrolled = (string)$root->enrolled; + $result->threeDSecure->xid = (string)$root->xid; + $result->threeDSecure->issuerAcsUrl = (string)$root->url; + $result->threeDSecure->payerAuthenticationRequest = (string)$root->pareq; + } + + // 3d secure signature + if (!empty($root->threedsecure)) { + $secureEcom = new ThreeDSecure(); + $secureEcom->status = (string)$root->threedsecure->status; + $secureEcom->eci = (string)$root->threedsecure->eci; + $secureEcom->cavv = (string)$root->threedsecure->cavv; + $secureEcom->xid = (string)$root->threedsecure->xid; + $secureEcom->algorithm = (int)$root->threedsecure->algorithm; + $result->threeDSecure = $secureEcom; + } + + // stored credential + $result->schemeId = (string)$root->srd; + + // dccinfo + if (!empty($root->dccinfo)) { + $result->dccRateData = new DccRateData(); + + $result->dccRateData->cardHolderCurrency = (string)$root->dccinfo->cardholdercurrency; + $result->dccRateData->cardHolderAmount = (string)$root->dccinfo->cardholderamount; + $result->dccRateData->cardHolderRate = (string)$root->dccinfo->cardholderrate; + $result->dccRateData->merchantCurrency = (string)$root->dccinfo->merchantcurrency; + $result->dccRateData->merchantAmount = (string)$root->dccinfo->merchantamount; + $result->dccRateData->marginRatePercentage = (string)$root->dccinfo->marginratepercentage; + $result->dccRateData->exchangeRateSourceName = (string)$root->dccinfo->exchangeratesourcename; + $result->dccRateData->commissionPercentage = (string)$root->dccinfo->commissionpercentage; + $result->dccRateData->exchangeRateSourceTimestamp = (string) + $root->dccinfo->exchangeratesourcetimestamp; + } + + // fraud filter + if (!empty($root->fraudresponse)) { + $fraudResponse = $root->fraudresponse; + $result->fraudFilterResponse = new FraudManagementResponse(); + + foreach ($fraudResponse->attributes() as $attrName => $attrValue) { + $result->fraudFilterResponse->fraudResponseMode = (!empty($attrValue)) ? (string) $attrValue : ''; + } + + $result->fraudFilterResponse->fraudResponseResult = (!empty($fraudResponse->result)) ? + (string) $fraudResponse->result : ''; + + if (!empty($fraudResponse->rules)) { + foreach ($fraudResponse->rules->rule as $rule) { + $ruleDetails = [ + 'id' => (string) $rule->attributes()->id, + 'name' => (string) $rule->attributes()->name, + 'action' => (string) $rule->action + ]; + $result->fraudFilterResponse->fraudResponseRules[] = $ruleDetails; + } + } + } + + // alternativePaymentResponse + if (!empty($root->paymentmethoddetails)) { + $result->alternativePaymentResponse = new AlternativePaymentResponse(); + + $result->alternativePaymentResponse->paymentMethod = (string) + $root->paymentmethoddetails->paymentmethod; + $result->alternativePaymentResponse->bankAccount = (string) + $root->paymentmethoddetails->bankaccount; + $result->alternativePaymentResponse->accountHolderName = (string) + $root->paymentmethoddetails->accountholdername; + $result->alternativePaymentResponse->country = (string) + $root->paymentmethoddetails->country; + $result->alternativePaymentResponse->redirectUrl = (string) + $root->paymentmethoddetails->redirecturl; + $result->alternativePaymentResponse->paymentPurpose = (string) + $root->paymentmethoddetails->paymentpurpose; + $result->alternativePaymentResponse->providerName = (string) $root->paymentmethod; + if (!empty($root->paymentmethoddetails->SetExpressCheckoutResponse)) { + $apmResponseDetails = $root->paymentmethoddetails->SetExpressCheckoutResponse; + } elseif (!empty($root->paymentmethoddetails->DoExpressCheckoutPaymentResponse)) { + $apmResponseDetails = $root->paymentmethoddetails->DoExpressCheckoutPaymentResponse; + } + if (!empty($apmResponseDetails)) { + $result->alternativePaymentResponse->sessionToken = !empty($apmResponseDetails->Token) ? + (string) $apmResponseDetails->Token : null; + $result->alternativePaymentResponse->ack = !empty($apmResponseDetails->Ack) ? + (string) $apmResponseDetails->Ack : null; + $result->alternativePaymentResponse->timeCreatedReference = !empty($apmResponseDetails->Timestamp) ? + (string) $apmResponseDetails->Timestamp : null; + $result->alternativePaymentResponse->correlationReference = !empty($apmResponseDetails->CorrelationID) ? + (string) $apmResponseDetails->CorrelationID : null; + $result->alternativePaymentResponse->versionReference = !empty($apmResponseDetails->Version) ? + (string) $apmResponseDetails->Version : null; + $result->alternativePaymentResponse->buildReference = !empty($apmResponseDetails->Build) ? + (string) $apmResponseDetails->Build : null; + if (!empty($apmResponseDetails->PaymentInfo)) { + $paymentInfo = $apmResponseDetails->PaymentInfo; + $result->alternativePaymentResponse->transactionReference = (string) $paymentInfo->TransactionID; + $result->alternativePaymentResponse->paymentType = (string) $paymentInfo->PaymentType; + $result->alternativePaymentResponse->paymentTimeReference = (string) $paymentInfo->PaymentDate; + $result->alternativePaymentResponse->grossAmount = (string) $paymentInfo->GrossAmount; + $result->alternativePaymentResponse->feeAmount = (string) $paymentInfo->TaxAmount; + $result->alternativePaymentResponse->paymentStatus = (string) $paymentInfo->PaymentStatus; + $result->alternativePaymentResponse->pendingReason = (string) $paymentInfo->PendingReason; + $result->alternativePaymentResponse->reasonCode = (string) $paymentInfo->ReasonCode; + $result->alternativePaymentResponse->authProtectionEligibilty = (string) $paymentInfo->ProtectionEligibility; + $result->alternativePaymentResponse->authProtectionEligibiltyType = (string) $paymentInfo->ProtectionEligibilityType; + } + } + } + + return $result; + } + + public static function mapScheduleReport($response, $reportType) + { + switch ($reportType) + { + case TransactionType::FETCH: + return self::hydrateSchedule($response); + case TransactionType::SEARCH: + $scheduleList = []; + if (!empty($response->schedules)) { + foreach ($response->schedules->schedule as $scheduleItem) { + $scheduleList[] = self::hydrateSchedule($scheduleItem); + } + } + return $scheduleList; + } + + return []; + } + + private static function hydrateSchedule($response) + { + $schedule = new Schedule(); + $schedule->id = !empty($response->scheduleref) ? (string)$response->scheduleref : null; + $schedule->key = !empty($response->scheduleref) ? (string)$response->scheduleref : null; + $schedule->customerKey = !empty($response->payerref) ? (string)$response->payerref : null; + $schedule->paymentKey = !empty($response->paymentmethod) ? (string)$response->paymentmethod : null; + $schedule->orderPrefix = !empty($response->orderidstub) ? (string)$response->orderidstub : null; + $schedule->amount = !empty($response->amount) ? (string)$response->amount : null; + $schedule->currency = !empty($response->amount) ? (string)$response->amount['currency'] : null; + $schedule->frequency = !empty($response->schedule) ? self::mapFrequency($response->schedule) : null ; + $schedule->productId = !empty($response->prodid) ? (string)$response->prodid : null; + $schedule->description = !empty($response->comment) ? (string)$response->comment : null; + $schedule->poNumber = !empty($response->varref) ? (string)$response->varref : null; + $schedule->startDate = !empty($response->startdate) ? new \DateTime((string)$response->startdate) : ''; + $schedule->endDate = !empty($response->enddate) ? new \DateTime((string)$response->enddate) : ''; + $schedule->numberOfPaymentsRemaining = !empty($response->numtimes) && isset($response->timesrun) ? + ((int)$response->numtimes - (int)$response->timesrun) : null; + $schedule->scheduletext = !empty($response->scheduletext) ? (string)$response->scheduletext : null; + + return $schedule; + } + + private static function mapFrequency($value) + { + list($day, $month, $year) = explode(" ", $value); + if ($day === '?' && $month === '*') { + return ScheduleFrequency::WEEKLY; + } + if ($year === '?') { + switch ($month) { + case '*': + return ScheduleFrequency::MONTHLY; + case '*/2': + return ScheduleFrequency::BI_MONTHLY; + case '*/3': + return ScheduleFrequency::QUARTERLY; + case '*/6': + return ScheduleFrequency::SEMI_ANNUALLY; + } + } + + if (is_numeric($day) && is_numeric($month) && $year === '?') { + return ScheduleFrequency::ANNUALLY; + } + } + + /** + * Maps a transaction builder to a GP-ECOM request type + * + * @param AuthorizationBuilder $builder Transaction builder + * + * @return string + */ + public static function mapAuthRequestType(AuthorizationBuilder $builder) + { + switch ($builder->transactionType) { + case TransactionType::SALE: + case TransactionType::AUTH: + if ($builder->paymentMethod->paymentMethodType == PaymentMethodType::CREDIT) { + if ($builder->transactionModifier === TransactionModifier::OFFLINE) { + return 'offline'; + } elseif ($builder->transactionModifier === TransactionModifier::ENCRYPTED_MOBILE) { + return 'auth-mobile'; + } + } elseif ($builder->paymentMethod->paymentMethodType == PaymentMethodType::RECURRING) { + return (!empty($builder->recurringSequence) && + $builder->recurringSequence == RecurringSequence::FIRST) ? + 'auth' : + 'receipt-in'; + } elseif ($builder->paymentMethod->paymentMethodType == PaymentMethodType::APM) { + return "payment-set"; + } + return 'auth'; + case TransactionType::CAPTURE: + return 'settle'; + case TransactionType::VERIFY: + if ($builder->paymentMethod->paymentMethodType == PaymentMethodType::RECURRING) { + if (!empty($builder->transactionModifier) && + $builder->transactionModifier === TransactionModifier::SECURE3D) { + return 'realvault-3ds-verifyenrolled'; + } + return 'receipt-in-otb'; + } + return 'otb'; + case TransactionType::REFUND: + if ($builder->paymentMethod->paymentMethodType == PaymentMethodType::CREDIT) { + return 'credit'; + } + return 'payment-out'; + case TransactionType::DCC_RATE_LOOKUP: + if ($builder->paymentMethod->paymentMethodType == PaymentMethodType::CREDIT) { + return "dccrate"; + } + return "realvault-dccrate"; + + case TransactionType::REVERSAL: + // TODO: should be customer type + throw new UnsupportedTransactionException( + 'The selected gateway does not support this transaction type.' + ); + case TransactionType::VERIFY_ENROLLED: + if ($builder->paymentMethod instanceof RecurringPaymentMethod) { + return 'realvault-3ds-verifyenrolled'; + } + return '3ds-verifyenrolled'; + default: + return 'unknown'; + } + } + + /** + * Maps a transaction builder to a GP-ECOM request type + * + * @param ManagementBuilder $builder Transaction builder + * + * @return string + */ + public static function mapManageRequestType(ManagementBuilder $builder) + { + switch ($builder->transactionType) { + case TransactionType::CAPTURE: + return 'settle'; + case TransactionType::HOLD: + return 'hold'; + case TransactionType::REFUND: + if ($builder->alternativePaymentType !== null) { + return 'payment-credit'; + } + return 'rebate'; + case TransactionType::RELEASE: + return 'release'; + case TransactionType::VOID: + case TransactionType::REVERSAL: + return 'void'; + case TransactionType::VERIFY_SIGNATURE: + return '3ds-verifysig'; + case TransactionType::CONFIRM: + return 'payment-do'; + default: + return 'unknown'; + } + } + + public static function mapReportResponse($root, $reportType) + { + $summary = new TransactionSummary(); + + try { + self::checkResponse($root); + switch ($reportType) { + case ReportType::TRANSACTION_DETAIL: + $summary->transactionId = (string)$root->pasref; + $summary->orderId = (string)$root->orderid; + $summary->authCode = (string)$root->authcode; + $summary->maskedCardNumber = (string)$root->cardnumber; + $summary->avsResponseCode = (string)$root->avspostcoderesponse; + $summary->cvnResponseCode = (string)$root->cvnresult; + $summary->gatewayResponseCode = (string)$root->result; + $summary->gatewayResponseMessage = (string)$root->message; + $summary->batchSequenceNumber = (string)$root->batchid; + $summary->gatewayResponseCode = (string)$root->result; + if (!empty($root->fraudresponse)) { + $summary->fraudRuleInfo = (string)$root->fraudresponse->result; + } + if (!empty($root->threedsecure)) { + $summary->cavvResponseCode = (string)$root->threedsecure->cavv; + $summary->eciIndicator = (string)$root->threedsecure->eci; + $summary->xid = (string)$root->threedsecure->xid; + } + if (!empty($root->srd)) { + $summary->schemeReferenceData = (string)$root->srd; + } + break; + default: + break; + } + } catch (Exception $e) { + throw new ApiException($e->getMessage(), $e); + } + return $summary; + } + + protected static function checkResponse($root, array $acceptedCodes = null) + { + if ($acceptedCodes === null) { + $acceptedCodes = [ "00" ]; + } + + $responseCode = (string)$root->result; + $responseMessage = (string)$root->message; + + if (!in_array($responseCode, $acceptedCodes)) { + throw new GatewayException( + sprintf('Unexpected Gateway Response: %s - %s', $responseCode, $responseMessage), + $responseCode, + $responseMessage + ); + } + } +} \ No newline at end of file diff --git a/src/PaymentMethods/RecurringPaymentMethod.php b/src/PaymentMethods/RecurringPaymentMethod.php index 0376d22b..161b1d13 100644 --- a/src/PaymentMethods/RecurringPaymentMethod.php +++ b/src/PaymentMethods/RecurringPaymentMethod.php @@ -3,12 +3,10 @@ namespace GlobalPayments\Api\PaymentMethods; use GlobalPayments\Api\Entities\DccRateData; -use GlobalPayments\Api\ServicesContainer; use GlobalPayments\Api\Builders\AuthorizationBuilder; use GlobalPayments\Api\Entities\RecurringEntity; use GlobalPayments\Api\Entities\Enums\PaymentMethodType; use GlobalPayments\Api\Entities\Exceptions\ArgumentException; -use GlobalPayments\Api\Entities\Exceptions\UnsupportedTransactionException; use GlobalPayments\Api\Entities\Schedule; use GlobalPayments\Api\PaymentMethods\Interfaces\IAuthable; use GlobalPayments\Api\PaymentMethods\Interfaces\IChargable; @@ -16,8 +14,6 @@ use GlobalPayments\Api\PaymentMethods\Interfaces\IRefundable; use GlobalPayments\Api\PaymentMethods\Interfaces\IVerifyable; use GlobalPayments\Api\Entities\Enums\TransactionType; -use GlobalPayments\Api\Entities\Enums\DccProcessor; -use GlobalPayments\Api\Entities\Enums\DccRateType; use GlobalPayments\Api\PaymentMethods\Interfaces\ISecure3d; /** @@ -207,7 +203,8 @@ public function verify() */ public function addSchedule($scheduleId) { - $schedule = new Schedule($this->customerKey, $this->key); + $key = !empty($this->key) ? $this->key : $this->id; + $schedule = new Schedule($this->customerKey, $key); $schedule->id = $scheduleId; return $schedule; } diff --git a/src/ServiceConfigs/Gateways/GeniusConfig.php b/src/ServiceConfigs/Gateways/GeniusConfig.php index fb2ac2d3..54ae19e3 100644 --- a/src/ServiceConfigs/Gateways/GeniusConfig.php +++ b/src/ServiceConfigs/Gateways/GeniusConfig.php @@ -5,13 +5,9 @@ use GlobalPayments\Api\Entities\Enums\Environment; use GlobalPayments\Api\Entities\Enums\GatewayProvider; use GlobalPayments\Api\ConfiguredServices; -use GlobalPayments\Api\Entities\Enums\Secure3dVersion; use GlobalPayments\Api\Entities\Enums\ServiceEndpoints; use GlobalPayments\Api\Entities\Exceptions\ConfigurationException; use GlobalPayments\Api\Gateways\GeniusConnector; -use GlobalPayments\Api\Gateways\Gp3DSProvider; -use GlobalPayments\Api\Gateways\MerchantwareConnector; -use GlobalPayments\Api\Gateways\RealexConnector; class GeniusConfig extends GatewayConfig { diff --git a/src/ServiceConfigs/Gateways/GpEcomConfig.php b/src/ServiceConfigs/Gateways/GpEcomConfig.php index e00dd816..e97ba6c0 100644 --- a/src/ServiceConfigs/Gateways/GpEcomConfig.php +++ b/src/ServiceConfigs/Gateways/GpEcomConfig.php @@ -9,8 +9,8 @@ use GlobalPayments\Api\Entities\Enums\ShaHashType; use GlobalPayments\Api\Entities\Exceptions\ConfigurationException; use GlobalPayments\Api\Gateways\Gp3DSProvider; +use GlobalPayments\Api\Gateways\GpEcomConnector; use GlobalPayments\Api\Gateways\OpenBankingProvider; -use GlobalPayments\Api\Gateways\RealexConnector; use GlobalPayments\Api\ConfiguredServices; class GpEcomConfig extends GatewayConfig @@ -51,17 +51,11 @@ public function configureContainer(ConfiguredServices $services) $this->serviceUrl = $this->environment == Environment::TEST ? ServiceEndpoints::GLOBAL_ECOM_TEST : ServiceEndpoints::GLOBAL_ECOM_PRODUCTION; } - $gateway = new RealexConnector(); - $gateway->accountId = $this->accountId; - $gateway->channel = $this->channel; - $gateway->merchantId = $this->merchantId; - $gateway->rebatePassword = $this->rebatePassword; - $gateway->sharedSecret = $this->sharedSecret; - $gateway->shaHashType = $this->shaHashType; + $gateway = new GpEcomConnector($this); $gateway->timeout = $this->timeout; - $gateway->serviceUrl = $this->serviceUrl; - $gateway->refundPassword = $this->refundPassword; $gateway->hostedPaymentConfig = $this->hostedPaymentConfig; + + $gateway->serviceUrl = $this->serviceUrl; $gateway->requestLogger = $this->requestLogger; $gateway->webProxy = $this->webProxy; @@ -78,9 +72,9 @@ public function configureContainer(ConfiguredServices $services) if ($this->secure3dVersion == Secure3dVersion::TWO || $this->secure3dVersion == Secure3dVersion::ANY) { $secure3d2 = new Gp3DSProvider(); - $secure3d2->setMerchantId($gateway->merchantId); - $secure3d2->setAccountId($gateway->accountId); - $secure3d2->setSharedSecret($gateway->sharedSecret); + $secure3d2->setMerchantId($this->merchantId); + $secure3d2->setAccountId($this->accountId); + $secure3d2->setSharedSecret($this->sharedSecret); $secure3d2->serviceUrl = $this->environment == Environment::TEST ? ServiceEndpoints::THREE_DS_AUTH_TEST : ServiceEndpoints::THREE_DS_AUTH_PRODUCTION; $secure3d2->setMerchantContactUrl($this->merchantContactUrl); $secure3d2->setMethodNotificationUrl($this->methodNotificationUrl); @@ -93,9 +87,9 @@ public function configureContainer(ConfiguredServices $services) } if ($this->enableBankPayment === true) { $openBanking = new OpenBankingProvider(); - $openBanking->merchantId = $gateway->merchantId; - $openBanking->accountId = $gateway->accountId; - $openBanking->sharedSecret = $gateway->sharedSecret; + $openBanking->merchantId = $this->merchantId; + $openBanking->accountId = $this->accountId; + $openBanking->sharedSecret = $this->sharedSecret; $openBanking->shaHashType = $this->shaHashType; $openBanking->serviceUrl = $this->environment === Environment::PRODUCTION ? ServiceEndpoints::OPEN_BANKING_PRODUCTION : ServiceEndpoints::OPEN_BANKING_TEST; diff --git a/src/Utils/GenerationUtils.php b/src/Utils/GenerationUtils.php index f24636f5..f47a21cd 100644 --- a/src/Utils/GenerationUtils.php +++ b/src/Utils/GenerationUtils.php @@ -14,7 +14,7 @@ class GenerationUtils { /** - * Generate a hash, required for all messages sent to Realex to prove it + * Generate a hash, required for all messages sent to GP-ECOM to prove it * was not tampered with. * * Each message sent to Realex should have a hash attached. For a message @@ -183,4 +183,17 @@ public static function convertObjectToArray($object) return $array; } + + public static function generateScheduleId() + { + $uuid = self::getGuid(); + $mostSignificantBits = substr($uuid, 0, 8); + $leastSignificantBits = substr($uuid, 23, 8); + + return strtolower(substr( + base64_encode($mostSignificantBits . $leastSignificantBits), + 0, + 20 + )); + } } diff --git a/test/Integration/Gateways/GpApiConnector/CreditCardNotPresentTest.php b/test/Integration/Gateways/GpApiConnector/CreditCardNotPresentTest.php index 3cc2d667..2411e4a3 100644 --- a/test/Integration/Gateways/GpApiConnector/CreditCardNotPresentTest.php +++ b/test/Integration/Gateways/GpApiConnector/CreditCardNotPresentTest.php @@ -950,6 +950,19 @@ public function testCreditSale_WithStoredCredentials() $this->assertEquals(TransactionStatus::CAPTURED, $response->responseMessage); } + public function testCreditSale_WithDynamicDescriptor() + { + $dynamicDescriptor = 'My company'; + $response = $this->card->charge(50) + ->withCurrency("EUR") + ->withDynamicDescriptor($dynamicDescriptor) + ->execute(); + + $this->assertNotNull($response); + $this->assertEquals('SUCCESS', $response->responseCode); + $this->assertEquals(TransactionStatus::CAPTURED, $response->responseMessage); + } + public function testCreditReverseTransactionWrongId() { $transaction = new Transaction(); diff --git a/test/Integration/Gateways/RealexConnector/ApiCaseTest.php b/test/Integration/Gateways/GpEcomConnector/ApiCaseTest.php similarity index 97% rename from test/Integration/Gateways/RealexConnector/ApiCaseTest.php rename to test/Integration/Gateways/GpEcomConnector/ApiCaseTest.php index 46d8c87a..c732b1d0 100644 --- a/test/Integration/Gateways/RealexConnector/ApiCaseTest.php +++ b/test/Integration/Gateways/GpEcomConnector/ApiCaseTest.php @@ -1,6 +1,6 @@ assertNotEquals(null, $response); $this->assertEquals("00", $responseCode); } catch (ApiException $e) { - // TODO: Add your error handling here + $this->assertEquals('508', $e->responseCode); + $this->assertEquals('Original transaction not found.', $e->responseMessage); } } @@ -299,7 +279,8 @@ public function testtransactionManagementVoid() $this->assertNotEquals(null, $response); $this->assertEquals("00", $responseCode); } catch (ApiException $e) { - // TODO: Add your error handling here + $this->assertEquals('508', $e->responseCode); + $this->assertEquals('Original transaction not found.', $e->responseMessage); } } @@ -500,27 +481,6 @@ public function testfraudManagementRelease() $this->assertEquals("00", $responseCode); } - /* 26. Dcc Rate Lookup */ - - public function testdccRateLookup() - { - // will update later - } - - /* 27. Dcc Present Choice */ - - public function testdccPresentChoice() - { - // will update later - } - - /* 28. Dcc Auth Data Submission */ - - public function testdccAuthDataSubmission() - { - // will update later - } - /* 29. Google pay */ public function testauthMobileGooglePay() diff --git a/test/Integration/Gateways/RealexConnector/RealexApmTest.php b/test/Integration/Gateways/GpEcomConnector/ApmTest.php similarity index 99% rename from test/Integration/Gateways/RealexConnector/RealexApmTest.php rename to test/Integration/Gateways/GpEcomConnector/ApmTest.php index d8bb941e..16a3b3b8 100644 --- a/test/Integration/Gateways/RealexConnector/RealexApmTest.php +++ b/test/Integration/Gateways/GpEcomConnector/ApmTest.php @@ -1,6 +1,6 @@ rebatePassword = 'rebate'; $config->refundPassword = 'refund'; $config->serviceUrl = 'https://api.sandbox.realexpayments.com/epage-remote.cgi'; + $config->requestLogger = new SampleRequestLogger(new Logger("logs")); return $config; } @@ -294,4 +295,25 @@ public function testCreditAuthorizationWithDynamicDescriptor() $this->assertNotNull($capture); $this->assertEquals('00', $capture->responseCode, $capture->responseMessage); } + + public function testCreditAuthorizationSupplementaryData() + { + $authorize = $this->card->authorize(10) + ->withCurrency('EUR') + ->withSupplementaryData(["taxInfo" => ["VATREF", "763637283332"]]) + ->withSupplementaryData(["indentityInfo"=> ["Passport", "PPS736353"]]) + ->withSupplementaryData(["RANDOM_KEY1" => "VALUE_1", "RANDOM_KEY2" => "VALUE_2"]) + ->withSupplementaryData('RANDOM_KEY3', 'ACTIVE') + ->execute(); + + $this->assertNotNull($authorize); + $this->assertEquals('00', $authorize->responseCode, $authorize->responseMessage); + + $capture = $authorize->capture(5) + ->withSupplementaryData(["taxInfo" => ["VATREF1", "7636372833321"]]) + ->execute(); + + $this->assertNotNull($capture); + $this->assertEquals('00', $capture->responseCode, $capture->responseMessage); + } } diff --git a/test/Integration/Gateways/RealexConnector/Realex3dSecureTests.php b/test/Integration/Gateways/GpEcomConnector/GpEcom3dSecureTests.php similarity index 99% rename from test/Integration/Gateways/RealexConnector/Realex3dSecureTests.php rename to test/Integration/Gateways/GpEcomConnector/GpEcom3dSecureTests.php index d725785a..5470ec6b 100644 --- a/test/Integration/Gateways/RealexConnector/Realex3dSecureTests.php +++ b/test/Integration/Gateways/GpEcomConnector/GpEcom3dSecureTests.php @@ -1,6 +1,6 @@ hostedPaymentConfig->language = "GB"; $config->hostedPaymentConfig->responseUrl = "http://requestb.in/10q2bjb1"; - $client = new RealexHppClient("secret"); + $client = new GpEcomHppClient("secret"); $address = new Address(); $address->postalCode = "123|56"; @@ -115,7 +116,7 @@ public function testCreditSale() $config->hostedPaymentConfig->language = "GB"; $config->hostedPaymentConfig->responseUrl = "http://requestb.in/10q2bjb1"; - $client = new RealexHppClient("secret"); + $client = new GpEcomHppClient("secret"); $address = new Address(); $address->postalCode = "123|56"; @@ -156,7 +157,7 @@ public function testCreditVerify() $config->hostedPaymentConfig->language = "GB"; $config->hostedPaymentConfig->responseUrl = "http://requestb.in/10q2bjb1"; - $client = new RealexHppClient("secret"); + $client = new GpEcomHppClient("secret"); $address = new Address(); $address->postalCode = "123|56"; @@ -251,7 +252,7 @@ public function testCardStorageCreatePayer() $config->hostedPaymentConfig->language = "GB"; $config->hostedPaymentConfig->responseUrl = "http://requestb.in/10q2bjb1"; - $client = new RealexHppClient("secret"); + $client = new GpEcomHppClient("secret"); // data to be passed to the HPP along with transaction level settings $hostedPaymentData = new HostedPaymentData(); @@ -292,7 +293,7 @@ public function testCardStorageDisplayStoredCard() $config->hostedPaymentConfig->language = "GB"; $config->hostedPaymentConfig->responseUrl = "http://requestb.in/10q2bjb1"; - $client = new RealexHppClient("secret"); + $client = new GpEcomHppClient("secret"); // data to be passed to the HPP along with transaction level settings $hostedPaymentData = new HostedPaymentData(); @@ -335,7 +336,7 @@ public function testContinuousAuthorityRequest() $config->hostedPaymentConfig->language = "GB"; $config->hostedPaymentConfig->responseUrl = "http://requestb.in/10q2bjb1"; - $client = new RealexHppClient("secret"); + $client = new GpEcomHppClient("secret"); //run test cases for different version foreach ($this->hppVersionList as $hppVersion) { @@ -377,7 +378,7 @@ public function testEnableDynamicCurrencyConversionRequest() $config->hostedPaymentConfig->directCurrencyConversionEnabled = "1"; $service = new HostedService($config); - $client = new RealexHppClient("secret"); + $client = new GpEcomHppClient("secret"); //serialize the request $json = $service->Charge(19) @@ -407,7 +408,7 @@ public function testDisableDynamicCurrencyConversionRequest() $config->hostedPaymentConfig->directCurrencyConversionEnabled = "0"; $service = new HostedService($config); - $client = new RealexHppClient("secret"); + $client = new GpEcomHppClient("secret"); //serialize the request $json = $service->Charge(19) @@ -437,7 +438,7 @@ public function testFraudManagementRequest() $config->hostedPaymentConfig->fraudFilterMode = FraudFilterMode::PASSIVE; $service = new HostedService($config); - $client = new RealexHppClient("secret"); + $client = new GpEcomHppClient("secret"); // data to be passed to the HPP along with transaction level settings $hostedPaymentData = new HostedPaymentData(); @@ -489,7 +490,7 @@ public function testFraudManagementRequestWithRules() $config->hostedPaymentConfig->fraudFilterRules = $rules; $service = new HostedService($config); - $client = new RealexHppClient("secret"); + $client = new GpEcomHppClient("secret"); // data to be passed to the HPP along with transaction level settings $hostedPaymentData = new HostedPaymentData(); @@ -539,7 +540,7 @@ public function testBasicAuthHppVersion1() $config->hostedPaymentConfig->version = HppVersion::VERSION_1; $service = new HostedService($config); - $client = new RealexHppClient("secret"); + $client = new GpEcomHppClient("secret"); $json = $service->authorize(19.99) ->withCurrency("EUR") @@ -565,7 +566,7 @@ public function testBasicAuthHppVersion2() $config->hostedPaymentConfig->version = HppVersion::VERSION_2; $service = new HostedService($config); - $client = new RealexHppClient("secret"); + $client = new GpEcomHppClient("secret"); $json = $service->authorize(19.99) ->withCurrency("EUR") @@ -591,7 +592,7 @@ public function testBasicSale() $config->hostedPaymentConfig->version = HppVersion::VERSION_2; $service = new HostedService($config); - $client = new RealexHppClient("secret"); + $client = new GpEcomHppClient("secret"); $json = $service->charge(19.99) ->withCurrency("EUR") @@ -617,7 +618,7 @@ public function testBasicHostedPaymentDataHppVersion1() $config->hostedPaymentConfig->version = HppVersion::VERSION_1; $service = new HostedService($config); - $client = new RealexHppClient("secret"); + $client = new GpEcomHppClient("secret"); $hostedPaymentData = new HostedPaymentData(); $hostedPaymentData->offerToSaveCard = "1"; // display the save card tick box @@ -652,7 +653,7 @@ public function testBasicHostedPaymentDataHppVersion2() $config->hostedPaymentConfig->version = HppVersion::VERSION_2; $service = new HostedService($config); - $client = new RealexHppClient("secret"); + $client = new GpEcomHppClient("secret"); $hostedPaymentData = new HostedPaymentData(); $hostedPaymentData->offerToSaveCard = "1"; // display the save card tick box @@ -684,7 +685,7 @@ public function testParseResponse() $config->hostedPaymentConfig->language = "GB"; $config->hostedPaymentConfig->responseUrl = "http://requestb.in/10q2bjb1"; - $client = new RealexHppClient("secret"); + $client = new GpEcomHppClient("secret"); $address = new Address(); $address->postalCode = "123|56"; @@ -902,7 +903,7 @@ public function testBasicChargeAlternativePayment() $this->assertEquals($hostedPaymentData->transactionStatusUrl, $response['HPP_TX_STATUS_URL']); $this->assertEquals($hostedPaymentData->customerCountry, $response['HPP_CUSTOMER_COUNTRY']); - $client = new RealexHppClient("secret"); + $client = new GpEcomHppClient("secret"); $response = $client->sendRequest($json, $config->hostedPaymentConfig->version); $parsedResponse = $service->parseResponse($response); @@ -927,7 +928,7 @@ public function testCaptureBillingShippingInfo() $config->hostedPaymentConfig->version = HppVersion::VERSION_2; $service = new HostedService($config); - $client = new RealexHppClient("secret"); + $client = new GpEcomHppClient("secret"); $hostedPaymentData = new HostedPaymentData(); $hostedPaymentData->addressCapture = true; @@ -971,7 +972,7 @@ public function testOpenBankingInitiate() $hostedPaymentData->bankPayment = $bankPayment; - $client = new RealexHppClient($config->sharedSecret, ShaHashType::SHA256); + $client = new GpEcomHppClient($config->sharedSecret, ShaHashType::SHA256); $service = new HostedService($config); $json = $service->charge(10.99) diff --git a/test/Integration/Gateways/RealexConnector/HppTestCase.php b/test/Integration/Gateways/GpEcomConnector/HppTestCase.php similarity index 98% rename from test/Integration/Gateways/RealexConnector/HppTestCase.php rename to test/Integration/Gateways/GpEcomConnector/HppTestCase.php index 568ec1d0..4d7e92ff 100644 --- a/test/Integration/Gateways/RealexConnector/HppTestCase.php +++ b/test/Integration/Gateways/GpEcomConnector/HppTestCase.php @@ -1,10 +1,11 @@ format("Ymd")); + } + + public function getPaymentId($type) + { + return sprintf("%s-Realex-%s", (new \DateTime())->format("Ymd"), $type); + } + + public function getScheduleId($type) + { + return sprintf("%s-Realex-%s", (new \DateTime())->format("Ymd"), $type); + } + + protected function config() + { + $config = new GpEcomConfig(); + $config->merchantId = "heartlandgpsandbox"; + $config->accountId = "3dsecure"; + $config->refundPassword = "refund"; + $config->sharedSecret = "secret"; + $config->serviceUrl = "https://api.sandbox.realexpayments.com/epage-remote.cgi"; + $config->requestLogger = new SampleRequestLogger(new Logger("logs")); + $config->channel = 'ECOM'; + return $config; + } + + protected function dccSetup() + { + $config = new GpEcomConfig(); + $config->merchantId = "heartlandgpsandbox"; + $config->accountId = "apidcc"; + $config->refundPassword = "refund"; + $config->sharedSecret = "secret"; + $config->serviceUrl = "https://api.sandbox.realexpayments.com/epage-remote.cgi"; + + ServicesContainer::configureService($config); + } + + public function setup() + { + ServicesContainer::configureService($this->config()); + + $this->newCustomer = new Customer(); + $this->newCustomer->key = $this->getCustomerId(); + $this->newCustomer->title = "Mr."; + $this->newCustomer->firstName = "James"; + $this->newCustomer->lastName = "Mason"; + $this->newCustomer->company = "Realex Payments"; + $this->newCustomer->address = new Address(); + $this->newCustomer->address->streetAddress1 = "Flat 123"; + $this->newCustomer->address->streetAddress2 = "House 456"; + $this->newCustomer->address->streetAddress3 = "The Cul-De-Sac"; + $this->newCustomer->address->city = "Halifax"; + $this->newCustomer->address->province = "West Yorkshire"; + $this->newCustomer->address->postalCode = "W6 9HR"; + $this->newCustomer->address->country = "United Kingdom"; + $this->newCustomer->homePhone = "+35312345678"; + $this->newCustomer->workPhone = "+3531987654321"; + $this->newCustomer->fax = "+124546871258"; + $this->newCustomer->mobilePhone = "+25544778544"; + $this->newCustomer->email = "text@example.com"; + $this->newCustomer->comments = "Campaign Ref E7373G"; + + $this->card = new CreditCardData(); + $this->card->number = "4012001037141112"; + $this->card->expMonth = 10; + $this->card->expYear = TestCards::validCardExpYear(); + $this->card->cvn = '123'; + $this->card->cardHolderName = 'James Mason'; + } + + /* 08. Card Storage Create Payer */ + /* Request Type: payer-new */ + + public function testcardStorageCreatePayer() + { + try { + $response = $this->newCustomer->Create(); + $this->assertNotNull($response); + $this->assertNotNull($response->transactionReference->transactionId); + $this->assertEquals("00", $response->responseCode); + $this->assertEquals("Successful", $response->responseMessage); + } catch (GatewayException $exc) { + if ($exc->responseCode != '501' && $exc->responseCode != '520') { + throw $exc; + } + } + } + + /* 09. Card Storage Store Card */ + /* Request Type: card-new */ + + public function testcardStorageStoreCard() + { + $card = new CreditCardData(); + $card->number = "4012001037141112"; + $card->expMonth = 10; + $card->expYear = TestCards::validCardExpYear(); + $card->cvn = '123'; + $card->cardHolderName = 'James Mason'; + + try { + $paymentMethod = $this->newCustomer + ->addPaymentMethod($this->getPaymentId("Credit"), $card) + ->create(); + + $this->assertNotNull($paymentMethod); + $this->assertEquals("Successful", $paymentMethod->responseMessage); + } catch (GatewayException $exc) { + if ($exc->responseCode != '501' && $exc->responseCode != '520') { + throw $exc; + } + } + } + + /* 10. Card Storage Charge Card */ + /* Request Type: receipt-in */ + + public function testcardStorageChargeCard() + { + $paymentMethod = new RecurringPaymentMethod($this->getCustomerId(), $this->getPaymentId("Credit")); + $response = $paymentMethod->charge(10) + ->withCurrency("EUR") + ->withCvn("123") + ->execute(); + + $responseCode = $response->responseCode; // 00 == Success + $message = $response->responseMessage; // [ test system ] AUTHORISED + // get the reponse details to save to the DB for future transaction management requests + $orderId = $response->orderId; + $authCode = $response->authorizationCode; + $paymentsReference = $response->transactionId; // pasref + + $this->assertNotNull($response); + $this->assertEquals("00", $response->responseCode); + } + + /* 11. CardStorage ThreeDSecure Verify Enrolled */ + /* Request Type: realvault-3ds-verifyenrolled */ + + public function testcardStorageThreeDSecureVerifyEnrolled() + { + $paymentMethod = new RecurringPaymentMethod($this->getCustomerId(), $this->getPaymentId("Credit")); + + $response = $paymentMethod->verify() + ->withAmount(10) + ->withCurrency('USD') + ->withModifier(TransactionModifier::SECURE3D) + ->execute(); + + // get the response details to update the DB + $responseCode = $response->responseCode; // 00 == Success + $message = $response->responseMessage; // [ test system ] AUTHORISED + + $this->assertNotNull($response); + $this->assertEquals("00", $response->responseCode); + } + + /* 12. CardStorage Dcc Rate Lookup */ + /* Request Type: realvault-dccrate */ + + public function testcardStorageDccRateLookup() + { + $this->dccSetup(); + + $orderId = GenerationUtils::generateOrderId(); + $paymentMethod = new RecurringPaymentMethod($this->getCustomerId(), $this->getPaymentId("Credit")); + $dccDetails = $paymentMethod->getDccRate(DccRateType::SALE, DccProcessor::FEXCO) + ->withAmount(1001) + ->withCurrency('EUR') + ->withOrderId($orderId) + ->execute(); + + $this->assertNotNull($dccDetails); + $this->assertEquals('00', $dccDetails->responseCode, $dccDetails->responseMessage); + $this->assertNotNull($dccDetails->dccRateData); + } + + /* 14. CardStorage UpdatePayer */ + /* Request Type: payer-edit */ + + public function testcardStorageUpdatePayer() + { + $customer = new Customer(); + $customer->key = $this->getCustomerId(); + $customer->firstName = "Perry"; + + $response = $customer->saveChanges(); + + $this->assertNotNull($response); + $this->assertEquals("00", $response->responseCode); + } + + /* 15. CardStorage Continuous Authority First */ + /* Request Type: auth */ + + public function testContinuousAuthorityFirst() + { + // create the card object + $card = new CreditCardData(); + $card->number = '5425230000004415'; + $card->expMonth = 12; + $card->expYear = TestCards::validCardExpYear(); + $card->cvn = '131'; + $card->cardHolderName = 'James Mason'; + + + // process an auto-settle authorization + $response = $card->charge(15) + ->withCurrency("EUR") + ->withRecurringInfo(RecurringType::VARIABLE, RecurringSequence::FIRST) + ->execute(); + + $responseCode = $response->responseCode; // 00 == Success + $message = $response->responseMessage; // [ test system ] AUTHORISED + // get the details to save to the DB for future Transaction Management requests + $orderId = $response->orderId; + $authCode = $response->authorizationCode; + $paymentsReference = $response->transactionId; + + $this->assertNotEquals(null, $response); + $this->assertEquals("00", $responseCode); + } + + /* 15. CardStorage Continuous Authority Subsequent */ + /* Request Type: receipt-in */ + + public function testContinuousAuthoritySubsequent() + { + // create the payment method object + $paymentMethod = new RecurringPaymentMethod($this->getCustomerId(), $this->getPaymentId("Credit")); + + // charge the stored card/payment method + $response = $paymentMethod->charge(15) + ->withCurrency("EUR") + ->withCvn("123") + ->withRecurringInfo(RecurringType::VARIABLE, RecurringSequence::SUBSEQUENT) + ->execute(); + + $responseCode = $response->responseCode; // 00 == Success + + $this->assertNotEquals(null, $response); + $this->assertEquals("00", $responseCode); + } + + /* 15. CardStorage Continuous Authority Last */ + /* Request Type: receipt-in */ + + public function testContinuousAuthorityLast() + { + // create the payment method object + $paymentMethod = new RecurringPaymentMethod($this->getCustomerId(), $this->getPaymentId("Credit")); + + // charge the stored card/payment method + $response = $paymentMethod->charge(15) + ->withCurrency("EUR") + ->withCvn("123") + ->withRecurringInfo(RecurringType::VARIABLE, RecurringSequence::LAST) + ->execute(); + + $responseCode = $response->responseCode; // 00 == Success + + $this->assertNotEquals(null, $response); + $this->assertEquals("00", $responseCode); + } + + /* 16. Card Storage Refund */ + /* Request Type: payment-out */ + + public function testcardStorageRefund() + { + // create the payment method object + $paymentMethod = new RecurringPaymentMethod($this->getCustomerId(), $this->getPaymentId("Credit")); + + // charge the stored card/payment method + $response = $paymentMethod->refund(10) + ->withCurrency("EUR") + ->execute(); + + $responseCode = $response->responseCode; // 00 == Success + $message = $response->responseMessage; // [ test system ] AUTHORISED + + $this->assertNotEquals(null, $response); + $this->assertEquals("00", $responseCode); + } + + /* 17. Card Storage UpdateCard */ + /* Request Type: card-update-card */ + + public function testcardStorageUpdateCard() + { + $paymentMethod = new RecurringPaymentMethod($this->getCustomerId(), $this->getPaymentId("Credit")); + + $paymentMethod->paymentMethod = new CreditCardData(); + $paymentMethod->paymentMethod->number = "5425230000004415"; + $paymentMethod->paymentMethod->expMonth = 10; + $paymentMethod->paymentMethod->expYear = TestCards::validCardExpYear(); + $paymentMethod->paymentMethod->cardHolderName = "Philip Marlowe"; + + $response = $paymentMethod->SaveChanges(); + + $this->assertNotNull($response); + $this->assertEquals("00", $response->responseCode); + } + + /* 18. Card Storage Verify Card */ + /* Request Type: receipt-in-otb */ + + public function testcardStorageVerifyCard() + { + $paymentMethod = new RecurringPaymentMethod($this->getCustomerId(), $this->getPaymentId("Credit")); + + // verify the stored card/payment method is valid and active + $response = $paymentMethod->verify() + ->withCvn("123") + ->execute(); + + // get the response details to update the DB + $responseCode = $response->responseCode; // 00 == Success + $message = $response->responseMessage; // [ test system ] AUTHORISED + + $this->assertNotEquals(null, $response); + $this->assertEquals("00", $responseCode); + } + + /* 13. CardStorage DeleteCard */ + /* Request Type: card-cancel-card */ + + public function testcardStorageDeleteCard() + { + $paymentMethod = new RecurringPaymentMethod($this->getCustomerId(), $this->getPaymentId("Credit")); + + // delete the stored card/payment method + // WARNING! This can't be undone + $response = $paymentMethod->Delete(); + + $this->assertNotNull($response); + $this->assertEquals("00", $response->responseCode); + } + + /* Request Type: receipt-in */ + + public function testcardStorageChargeCardDCC() + { + $this->dccSetup(); + $this->testcardStorageCreatePayer(); + $this->testcardStorageStoreCard(); + + $paymentMethod = new RecurringPaymentMethod($this->getCustomerId(), $this->getPaymentId("Credit")); + + $orderId = GenerationUtils::generateOrderId(); + $dccDetails = $paymentMethod->getDccRate(DccRateType::SALE, DccProcessor::FEXCO) + ->withAmount(1001) + ->withCurrency('EUR') + ->withOrderId($orderId) + ->execute(); + + $this->assertNotNull($dccDetails); + $this->assertEquals('00', $dccDetails->responseCode, $dccDetails->responseMessage); + $this->assertNotNull($dccDetails->dccRateData); + + $response = $paymentMethod->charge(1001) + ->withCurrency("EUR") + ->withCvn("123") + ->withDccRateData($dccDetails->dccRateData) + ->withOrderId($orderId) + ->execute(); + + $responseCode = $response->responseCode; // 00 == Success + $message = $response->responseMessage; // [ test system ] AUTHORISED + // get the reponse details to save to the DB for future transaction management requests + $orderId = $response->orderId; + $authCode = $response->authorizationCode; + $paymentsReference = $response->transactionId; // pasref + + $this->assertNotNull($response); + $this->assertEquals("00", $response->responseCode); + } + + /*************************************************** + * Payment Scheduler tests * + ***************************************************/ + + public function testCardStorageAddSchedule() + { + try { + $response = $this->newCustomer->create(); + $this->assertNotNull($response); + $this->assertEquals("00", $response->responseCode); + } catch (GatewayException $exc) { + if ($exc->responseCode != '501' && $exc->responseCode != '520') { + throw $exc; + } + } + + $paymentMethod = $this->newCustomer->addPaymentMethod($this->getPaymentId('Credit'), $this->card); + try { + $response = $paymentMethod->create(); + $this->assertNotNull($response); + $this->assertEquals("00", $response->responseCode); + } catch (GatewayException $exc) { + if ($exc->responseCode != '501' && $exc->responseCode != '520') { + throw $exc; + } + } + + $scheduleId = GenerationUtils::generateScheduleId(); + $response = $paymentMethod->addSchedule($scheduleId) + ->withStartDate(new \DateTime()) + ->withAmount(30.01) + ->withCurrency('USD') + ->withFrequency(ScheduleFrequency::SEMI_ANNUALLY) + ->withReprocessingCount(1) + ->withnumberOfPaymentsRemaining(12) + ->withCustomerNumber('E8953893489') + ->withOrderPrefix('gym') + ->withName('Gym Membership') + ->withDescription('Social Sign-Up') + ->create(); + + $this->assertEquals('00', $response->responseCode); + $this->assertEquals('Schedule created successfully', $response->responseMessage); + + // the schedule id/key is not received in the response from the create request + $schedule = new Schedule(); + $schedule->key = $scheduleId; + /** @var Schedule $schedule */ + $schedule = RecurringService::get($schedule); + + $this->assertEquals($scheduleId, $schedule->id); + $this->assertEquals(12, $schedule->numberOfPaymentsRemaining); + $this->assertEquals(ScheduleFrequency::SEMI_ANNUALLY, $schedule->frequency); + } + + public function testCardStorageAddSchedule_WithIndefinitelyRun() + { + try { + $response = $this->newCustomer->create(); + $this->assertNotNull($response); + $this->assertEquals("00", $response->responseCode); + } catch (GatewayException $exc) { + if ($exc->responseCode != '501' && $exc->responseCode != '520') { + throw $exc; + } + } + + $paymentMethod = $this->newCustomer->addPaymentMethod($this->getPaymentId('Credit'), $this->card); + try { + $response = $paymentMethod->create(); + $this->assertNotNull($response); + $this->assertEquals("00", $response->responseCode); + } catch (GatewayException $exc) { + if ($exc->responseCode != '501' && $exc->responseCode != '520') { + throw $exc; + } + } + + $scheduleId = GenerationUtils::generateScheduleId(); + $response = $paymentMethod->addSchedule($scheduleId) + ->withStartDate(new \DateTime()) + ->withAmount(30.01) + ->withCurrency('USD') + ->withFrequency(ScheduleFrequency::QUARTERLY) + ->withReprocessingCount(1) + ->withnumberOfPaymentsRemaining(-1) + ->withCustomerNumber('E8953893489') + ->withOrderPrefix('gym') + ->withName('Gym Membership') + ->withDescription('Social Sign-Up') + ->create(); + + $this->assertEquals('00', $response->responseCode); + $this->assertEquals('Schedule created successfully', $response->responseMessage); + + // the schedule id/key is not received in the response from the create request + $schedule = new Schedule(); + $schedule->key = $scheduleId; + /** @var Schedule $schedule */ + $schedule = RecurringService::get($schedule); + + $this->assertEquals($scheduleId, $schedule->id); + $this->assertEquals(-1, $schedule->numberOfPaymentsRemaining); + $this->assertEquals(ScheduleFrequency::QUARTERLY, $schedule->frequency); + } + + public function testCardStorageAddSchedule_With999Runs() + { + try { + $response = $this->newCustomer->create(); + $this->assertNotNull($response); + $this->assertEquals("00", $response->responseCode); + } catch (GatewayException $exc) { + if ($exc->responseCode != '501' && $exc->responseCode != '520') { + throw $exc; + } + } + + $paymentMethod = $this->newCustomer->addPaymentMethod($this->getPaymentId('Credit'), $this->card); + try { + $response = $paymentMethod->create(); + $this->assertNotNull($response); + $this->assertEquals("00", $response->responseCode); + } catch (GatewayException $exc) { + if ($exc->responseCode != '501' && $exc->responseCode != '520') { + throw $exc; + } + } + + $scheduleId = GenerationUtils::generateScheduleId(); + $response = $paymentMethod->addSchedule($scheduleId) + ->withStartDate(new \DateTime()) + ->withAmount(30.01) + ->withCurrency('USD') + ->withFrequency(ScheduleFrequency::QUARTERLY) + ->withReprocessingCount(1) + ->withnumberOfPaymentsRemaining(999) + ->withCustomerNumber('E8953893489') + ->withOrderPrefix('gym') + ->withName('Gym Membership') + ->withDescription('Social Sign-Up') + ->create(); + + $this->assertEquals('00', $response->responseCode); + $this->assertEquals('Schedule created successfully', $response->responseMessage); + + // the schedule id/key is not received in the response from the create request + $schedule = new Schedule(); + $schedule->key = $scheduleId; + /** @var Schedule $schedule */ + $schedule = RecurringService::get($schedule); + + $this->assertEquals($scheduleId, $schedule->id); + $this->assertEquals(999, $schedule->numberOfPaymentsRemaining); + $this->assertEquals(ScheduleFrequency::QUARTERLY, $schedule->frequency); + } + + public function testCardStorageAddSchedule_WithoutFrequency() + { + $paymentMethod = $this->newCustomer->addPaymentMethod($this->getPaymentId('Credit'), $this->card); + $scheduleId = GenerationUtils::generateScheduleId(); + $exceptionCaught = false; + + try { + $paymentMethod->addSchedule($scheduleId) + ->withAmount(30.01) + ->withCurrency('USD') + ->withReprocessingCount(1) + ->withnumberOfPaymentsRemaining(12) + ->withCustomerNumber('E8953893489') + ->withOrderPrefix('gym') + ->withName('Gym Membership') + ->withDescription('Social Sign-Up') + ->create(); + } catch (GatewayException $e) { + $exceptionCaught = true; + $this->assertEquals('502', $e->responseCode); + $this->assertEquals('Unexpected Gateway Response: 502 - Mandatory Fields missing: [/request/schedule]. See Developers Guide', $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } + + public function testCardStorageAddSchedule_WithoutAmount() + { + $paymentMethod = $this->newCustomer->addPaymentMethod($this->getPaymentId('Credit'), $this->card); + $scheduleId = GenerationUtils::generateScheduleId(); + $exceptionCaught = false; + + try { + $paymentMethod->addSchedule($scheduleId) + ->withCurrency('USD') + ->withFrequency(ScheduleFrequency::QUARTERLY) + ->withReprocessingCount(1) + ->withnumberOfPaymentsRemaining(12) + ->withCustomerNumber('E8953893489') + ->withOrderPrefix('gym') + ->withName('Gym Membership') + ->withDescription('Social Sign-Up') + ->create(); + } catch (GatewayException $e) { + $exceptionCaught = true; + $this->assertEquals('508', $e->responseCode); + $this->assertEquals('Unexpected Gateway Response: 508 - Zero, negative or insufficient amount specified.', $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } + + public function testCardStorageAddSchedule_WithoutCurrency() + { + $paymentMethod = $this->newCustomer->addPaymentMethod($this->getPaymentId('Credit'), $this->card); + $scheduleId = GenerationUtils::generateScheduleId(); + $exceptionCaught = false; + + try { + $paymentMethod->addSchedule($scheduleId) + ->withAmount(30.01) + ->withFrequency(ScheduleFrequency::QUARTERLY) + ->withReprocessingCount(1) + ->withnumberOfPaymentsRemaining(12) + ->withCustomerNumber('E8953893489') + ->withOrderPrefix('gym') + ->withName('Gym Membership') + ->withDescription('Social Sign-Up') + ->create(); + } catch (GatewayException $e) { + $exceptionCaught = true; + $this->assertEquals('506', $e->responseCode); + $this->assertStringStartsWith('Unexpected Gateway Response: 506 - The line number 2', $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } + + public function testCardStorageAddSchedule_WithoutNumberOfPayments() + { + $paymentMethod = $this->newCustomer->addPaymentMethod($this->getPaymentId('Credit'), $this->card); + $scheduleId = GenerationUtils::generateScheduleId(); + $exceptionCaught = false; + + try { + $paymentMethod->addSchedule($scheduleId) + ->withAmount(30.01) + ->withCurrency('USD') + ->withFrequency(ScheduleFrequency::QUARTERLY) + ->create(); + } catch (GatewayException $e) { + $exceptionCaught = true; + $this->assertEquals('502', $e->responseCode); + $this->assertEquals('Unexpected Gateway Response: 502 - Mandatory Fields missing: [/request/numtimes]. See Developers Guide', $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } + + public function testCardStorageAddSchedule_WithNumberOfPaymentsInvalid() + { + $paymentMethod = $this->newCustomer->addPaymentMethod($this->getPaymentId('Credit'), $this->card); + $scheduleId = GenerationUtils::generateScheduleId(); + $exceptionCaught = false; + + try { + $paymentMethod->addSchedule($scheduleId) + ->withAmount(30.01) + ->withCurrency('USD') + ->withFrequency(ScheduleFrequency::QUARTERLY) + ->withnumberOfPaymentsRemaining(1000) + ->create(); + } catch (GatewayException $e) { + $exceptionCaught = true; + $this->assertEquals('535', $e->responseCode); + $this->assertEquals('Unexpected Gateway Response: 535 - Invalid value, numtimes cannot be greater than 999.', $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } + + public function testCardStorageAddSchedule_WithNumberOfPaymentsZero() + { + $paymentMethod = $this->newCustomer->addPaymentMethod($this->getPaymentId('Credit'), $this->card); + $scheduleId = GenerationUtils::generateScheduleId(); + $exceptionCaught = false; + + try { + $paymentMethod->addSchedule($scheduleId) + ->withAmount(30.01) + ->withCurrency('USD') + ->withFrequency(ScheduleFrequency::QUARTERLY) + ->withnumberOfPaymentsRemaining(0) + ->create(); + } catch (GatewayException $e) { + $exceptionCaught = true; + $this->assertEquals('535', $e->responseCode); + $this->assertEquals('Unexpected Gateway Response: 535 - Invalid value, numtimes cannot be greater than 999.', $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } + + public function testGetListOfPaymentSchedules() + { + $schedules = RecurringService::search(Schedule::class) + ->addSearchCriteria(SearchCriteria::PAYMENT_METHOD_KEY, $this->getPaymentId('Credit')) + ->addSearchCriteria(SearchCriteria::CUSTOMER_ID, $this->getCustomerId()) + ->execute(); + + $this->assertNotEmpty($schedules); + /** @var Schedule $schedule */ + foreach ($schedules as $schedule) { + $this->assertNotEmpty($schedule->key); + } + } + + public function testGetListOfPaymentSchedules_RandomDetails() + { + $schedules = RecurringService::search(Schedule::class) + ->addSearchCriteria(SearchCriteria::PAYMENT_METHOD_KEY, substr(GenerationUtils::getGuid(), 20)) + ->addSearchCriteria(SearchCriteria::CUSTOMER_ID, substr(GenerationUtils::getGuid(), 20)) + ->execute(); + + $this->assertEmpty($schedules); + } + + public function testGetListOfPaymentSchedules_WithoutPayer() + { + $response = RecurringService::search(Schedule::class) + ->addSearchCriteria(SearchCriteria::PAYMENT_METHOD_KEY, substr(GenerationUtils::getGuid(), 20)) + ->execute(); + + $this->assertEmpty($response); + } + + public function testGetListOfPaymentSchedules_WithoutPaymentMethod() + { + $response = RecurringService::search(Schedule::class) + ->addSearchCriteria(SearchCriteria::CUSTOMER_ID, substr(GenerationUtils::getGuid(), 20)) + ->execute(); + + $this->assertEmpty($response); + } + + public function testDeleteSchedule() + { + $schedules = RecurringService::search(Schedule::class) + ->addSearchCriteria(SearchCriteria::PAYMENT_METHOD_KEY, $this->getPaymentId('Credit')) + ->addSearchCriteria(SearchCriteria::CUSTOMER_ID, $this->getCustomerId()) + ->execute(); + + $this->assertNotEmpty($schedules); + $schedule = $schedules[0]; + + $response = $schedule->delete(); + $this->assertEquals('00', $response->responseCode); + $this->assertEquals('OK', $response->responseMessage); + } + + public function testDelete_RandomSchedule() + { + $schedule = new Schedule(); + $schedule->key = substr(GenerationUtils::getGuid(), 20); + $exceptionCaught = false; + try { + $schedule->delete(); + } catch (ApiException $e) { + $exceptionCaught = true; + $this->assertEquals('Failed to delete record, see inner exception for more details', $e->getMessage()); + } finally { + $this->assertTrue($exceptionCaught); + } + } + + public function testGetPaymentScheduleById() + { + $schedule = new Schedule(); + $schedule->key = 'mdq5mgyzzgetmzdlymi4'; + $schedule = RecurringService::get($schedule); + + $this->assertNotNull($schedule); + $this->assertEquals($schedule->id, $schedule->key); + $this->assertNotEmpty($schedule->startDate); + } + + public function testGetPaymentScheduleById_RandomId() + { + $schedule = new Schedule(); + $schedule->key = substr(GenerationUtils::getGuid(), 20); + + $response = RecurringService::get($schedule); + + $this->assertNotNull($response); + $this->assertNull($response->key); + } +} diff --git a/test/Integration/Gateways/RealexConnector/ReportingTest.php b/test/Integration/Gateways/GpEcomConnector/ReportingTest.php similarity index 96% rename from test/Integration/Gateways/RealexConnector/ReportingTest.php rename to test/Integration/Gateways/GpEcomConnector/ReportingTest.php index 82c57629..4b7a6f7e 100644 --- a/test/Integration/Gateways/RealexConnector/ReportingTest.php +++ b/test/Integration/Gateways/GpEcomConnector/ReportingTest.php @@ -1,6 +1,6 @@ format("Ymd")); - } - - public function getPaymentId($type) - { - return sprintf("%s-Realex-%s", (new \DateTime())->format("Ymd"), $type); - } - - protected function config() - { - $config = new GpEcomConfig(); - $config->merchantId = "heartlandgpsandbox"; - $config->accountId = "3dsecure"; - $config->refundPassword = "refund"; - $config->sharedSecret = "secret"; - $config->serviceUrl = "https://api.sandbox.realexpayments.com/epage-remote.cgi"; - return $config; - } - - protected function dccSetup() - { - $config = new GpEcomConfig(); - $config->merchantId = "heartlandgpsandbox"; - $config->accountId = "apidcc"; - $config->refundPassword = "refund"; - $config->sharedSecret = "secret"; - $config->serviceUrl = "https://api.sandbox.realexpayments.com/epage-remote.cgi"; - - ServicesContainer::configureService($config); - } - - public function setup() - { - ServicesContainer::configureService($this->config()); - - $this->newCustomer = new Customer(); - $this->newCustomer->key = $this->getCustomerId(); - $this->newCustomer->title = "Mr."; - $this->newCustomer->firstName = "James"; - $this->newCustomer->lastName = "Mason"; - $this->newCustomer->company = "Realex Payments"; - $this->newCustomer->address = new Address(); - $this->newCustomer->address->streetAddress1 = "Flat 123"; - $this->newCustomer->address->streetAddress2 = "House 456"; - $this->newCustomer->address->streetAddress3 = "The Cul-De-Sac"; - $this->newCustomer->address->city = "Halifax"; - $this->newCustomer->address->province = "West Yorkshire"; - $this->newCustomer->address->postalCode = "W6 9HR"; - $this->newCustomer->address->country = "United Kingdom"; - $this->newCustomer->homePhone = "+35312345678"; - $this->newCustomer->workPhone = "+3531987654321"; - $this->newCustomer->fax = "+124546871258"; - $this->newCustomer->mobilePhone = "+25544778544"; - $this->newCustomer->email = "text@example.com"; - $this->newCustomer->comments = "Campaign Ref E7373G"; - } - - /* 08. Card Storage Create Payer */ - /* Request Type: payer-new */ - - public function testcardStorageCreatePayer() - { - try { - $response = $this->newCustomer->Create(); - $this->assertNotNull($response); - $this->assertEquals("00", $response->responseCode); - } catch (GatewayException $exc) { - if ($exc->responseCode != '501' && $exc->responseCode != '520') { - throw $exc; - } - } - } - - /* 09. Card Storage Store Card */ - /* Request Type: card-new */ - - public function testcardStorageStoreCard() - { - $card = new CreditCardData(); - $card->number = "4012001037141112"; - $card->expMonth = 10; - $card->expYear = TestCards::validCardExpYear(); - $card->cvn = '123'; - $card->cardHolderName = 'James Mason'; - - try { - $paymentMethod = $this->newCustomer - ->addPaymentMethod($this->getPaymentId("Credit"), $card) - ->create(); - $this->assertNotNull($paymentMethod); - } catch (GatewayException $exc) { - if ($exc->responseCode != '501' && $exc->responseCode != '520') { - throw $exc; - } - } - } - - /* 10. Card Storage Charge Card */ - /* Request Type: receipt-in */ - - public function testcardStorageChargeCard() - { - $paymentMethod = new RecurringPaymentMethod($this->getCustomerId(), $this->getPaymentId("Credit")); - $response = $paymentMethod->charge(10) - ->withCurrency("EUR") - ->withCvn("123") - ->execute(); - - $responseCode = $response->responseCode; // 00 == Success - $message = $response->responseMessage; // [ test system ] AUTHORISED - // get the reponse details to save to the DB for future transaction management requests - $orderId = $response->orderId; - $authCode = $response->authorizationCode; - $paymentsReference = $response->transactionId; // pasref - - $this->assertNotNull($response); - $this->assertEquals("00", $response->responseCode); - } - - /* 11. CardStorage ThreeDSecure Verify Enrolled */ - /* Request Type: realvault-3ds-verifyenrolled */ - - public function testcardStorageThreeDSecureVerifyEnrolled() - { - $paymentMethod = new RecurringPaymentMethod($this->getCustomerId(), $this->getPaymentId("Credit")); - - $response = $paymentMethod->verify() - ->withAmount(10) - ->withCurrency('USD') - ->withModifier(TransactionModifier::SECURE3D) - ->execute(); - - // get the response details to update the DB - $responseCode = $response->responseCode; // 00 == Success - $message = $response->responseMessage; // [ test system ] AUTHORISED - - $this->assertNotNull($response); - $this->assertEquals("00", $response->responseCode); - } - - /* 12. CardStorage Dcc Rate Lookup */ - /* Request Type: realvault-dccrate */ - - public function testcardStorageDccRateLookup() - { - $this->dccSetup(); - - $orderId = GenerationUtils::generateOrderId(); - $paymentMethod = new RecurringPaymentMethod($this->getCustomerId(), $this->getPaymentId("Credit")); - $dccDetails = $paymentMethod->getDccRate(DccRateType::SALE,DccProcessor::FEXCO) - ->withAmount(1001) - ->withCurrency('EUR') - ->withOrderId($orderId) - ->execute(); - - $this->assertNotNull($dccDetails); - $this->assertEquals('00', $dccDetails->responseCode, $dccDetails->responseMessage); - $this->assertNotNull($dccDetails->dccRateData); - } - - /* 14. CardStorage UpdatePayer */ - /* Request Type: payer-edit */ - - public function testcardStorageUpdatePayer() - { - $customer = new Customer(); - $customer->key = $this->getCustomerId(); - $customer->firstName = "Perry"; - - $response = $customer->saveChanges(); - - $this->assertNotNull($response); - $this->assertEquals("00", $response->responseCode); - } - - /* 15. CardStorage Continuous Authority First */ - /* Request Type: auth */ - - public function testContinuousAuthorityFirst() - { - // create the card object - $card = new CreditCardData(); - $card->number = '5425230000004415'; - $card->expMonth = 12; - $card->expYear = TestCards::validCardExpYear(); - $card->cvn = '131'; - $card->cardHolderName = 'James Mason'; - - - // process an auto-settle authorization - $response = $card->charge(15) - ->withCurrency("EUR") - ->withRecurringInfo(RecurringType::VARIABLE, RecurringSequence::FIRST) - ->execute(); - - $responseCode = $response->responseCode; // 00 == Success - $message = $response->responseMessage; // [ test system ] AUTHORISED - // get the details to save to the DB for future Transaction Management requests - $orderId = $response->orderId; - $authCode = $response->authorizationCode; - $paymentsReference = $response->transactionId; - - $this->assertNotEquals(null, $response); - $this->assertEquals("00", $responseCode); - } - - /* 15. CardStorage Continuous Authority Subsequent */ - /* Request Type: receipt-in */ - - public function testContinuousAuthoritySubsequent() - { - // create the payment method object - $paymentMethod = new RecurringPaymentMethod($this->getCustomerId(), $this->getPaymentId("Credit")); - - // charge the stored card/payment method - $response = $paymentMethod->charge(15) - ->withCurrency("EUR") - ->withCvn("123") - ->withRecurringInfo(RecurringType::VARIABLE, RecurringSequence::SUBSEQUENT) - ->execute(); - - $responseCode = $response->responseCode; // 00 == Success - - $this->assertNotEquals(null, $response); - $this->assertEquals("00", $responseCode); - } - - /* 15. CardStorage Continuous Authority Last */ - /* Request Type: receipt-in */ - - public function testContinuousAuthorityLast() - { - // create the payment method object - $paymentMethod = new RecurringPaymentMethod($this->getCustomerId(), $this->getPaymentId("Credit")); - - // charge the stored card/payment method - $response = $paymentMethod->charge(15) - ->withCurrency("EUR") - ->withCvn("123") - ->withRecurringInfo(RecurringType::VARIABLE, RecurringSequence::LAST) - ->execute(); - - $responseCode = $response->responseCode; // 00 == Success - - $this->assertNotEquals(null, $response); - $this->assertEquals("00", $responseCode); - } - - /* 16. Card Storage Refund */ - /* Request Type: payment-out */ - - public function testcardStorageRefund() - { - // create the payment method object - $paymentMethod = new RecurringPaymentMethod($this->getCustomerId(), $this->getPaymentId("Credit")); - - // charge the stored card/payment method - $response = $paymentMethod->refund(10) - ->withCurrency("EUR") - ->execute(); - - $responseCode = $response->responseCode; // 00 == Success - $message = $response->responseMessage; // [ test system ] AUTHORISED - - $this->assertNotEquals(null, $response); - $this->assertEquals("00", $responseCode); - } - - /* 17. Card Storage UpdateCard */ - /* Request Type: card-update-card */ - - public function testcardStorageUpdateCard() - { - $paymentMethod = new RecurringPaymentMethod($this->getCustomerId(), $this->getPaymentId("Credit")); - - $paymentMethod->paymentMethod = new CreditCardData(); - $paymentMethod->paymentMethod->number = "5425230000004415"; - $paymentMethod->paymentMethod->expMonth = 10; - $paymentMethod->paymentMethod->expYear = TestCards::validCardExpYear(); - $paymentMethod->paymentMethod->cardHolderName = "Philip Marlowe"; - - $response = $paymentMethod->SaveChanges(); - - $this->assertNotNull($response); - $this->assertEquals("00", $response->responseCode); - } - - /* 18. Card Storage Verify Card */ - /* Request Type: receipt-in-otb */ - - public function testcardStorageVerifyCard() - { - $paymentMethod = new RecurringPaymentMethod($this->getCustomerId(), $this->getPaymentId("Credit")); - - // verify the stored card/payment method is valid and active - $response = $paymentMethod->verify() - ->withCvn("123") - ->execute(); - - // get the response details to update the DB - $responseCode = $response->responseCode; // 00 == Success - $message = $response->responseMessage; // [ test system ] AUTHORISED - - $this->assertNotEquals(null, $response); - $this->assertEquals("00", $responseCode); - } - - /* 13. CardStorage DeleteCard */ - /* Request Type: card-cancel-card */ - - public function testcardStorageDeleteCard() - { - $paymentMethod = new RecurringPaymentMethod($this->getCustomerId(), $this->getPaymentId("Credit")); - - // delete the stored card/payment method - // WARNING! This can't be undone - $response = $paymentMethod->Delete(); - - $this->assertNotNull($response); - $this->assertEquals("00", $response->responseCode); - } - - /* Request Type: receipt-in */ - - public function testcardStorageChargeCardDCC() - { - $this->dccSetup(); - $this->testcardStorageCreatePayer(); - $this->testcardStorageStoreCard(); - - $paymentMethod = new RecurringPaymentMethod($this->getCustomerId(), $this->getPaymentId("Credit")); - - $orderId = GenerationUtils::generateOrderId(); - $dccDetails = $paymentMethod->getDccRate(DccRateType::SALE, DccProcessor::FEXCO) - ->withAmount(1001) - ->withCurrency('EUR') - ->withOrderId($orderId) - ->execute(); - - $this->assertNotNull($dccDetails); - $this->assertEquals('00', $dccDetails->responseCode, $dccDetails->responseMessage); - $this->assertNotNull($dccDetails->dccRateData); - - $response = $paymentMethod->charge(1001) - ->withCurrency("EUR") - ->withCvn("123") - ->withDccRateData($dccDetails->dccRateData) - ->withOrderId($orderId) - ->execute(); - - $responseCode = $response->responseCode; // 00 == Success - $message = $response->responseMessage; // [ test system ] AUTHORISED - // get the reponse details to save to the DB for future transaction management requests - $orderId = $response->orderId; - $authCode = $response->authorizationCode; - $paymentsReference = $response->transactionId; // pasref - - $this->assertNotNull($response); - $this->assertEquals("00", $response->responseCode); - } -} diff --git a/test/Unit/Gateways/RealexConnector/CreditTest.php b/test/Unit/Gateways/RealexConnector/CreditTest.php index 99242b1c..57395dff 100644 --- a/test/Unit/Gateways/RealexConnector/CreditTest.php +++ b/test/Unit/Gateways/RealexConnector/CreditTest.php @@ -1,6 +1,6 @@