We will work on Apr 26th (Saturday) and will be off from Apr 30th (Wednesday) until May 2nd (Friday) for public holiday in our country

Commit 6eeed37f authored by alessio's avatar alessio Committed by attilak

PW-1103: Added Oneclick support for 3ds2, added temporary TODOs for challengeshopper

parent 44574199
...@@ -23,12 +23,13 @@ ...@@ -23,12 +23,13 @@
namespace Adyen\Payment\Helper; namespace Adyen\Payment\Helper;
use Adyen\Payment\Observer\AdyenOneclickDataAssignObserver;
use Magento\Framework\App\Helper\AbstractHelper; use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Vault\Model\Ui\VaultConfigProvider; use Magento\Vault\Model\Ui\VaultConfigProvider;
use Adyen\Payment\Observer\AdyenHppDataAssignObserver; use Adyen\Payment\Observer\AdyenHppDataAssignObserver;
use Adyen\Payment\Observer\AdyenCcDataAssignObserver; use Adyen\Payment\Observer\AdyenCcDataAssignObserver;
//TODO: enable stateOrProvince field if no issues with empty values
class Requests extends AbstractHelper class Requests extends AbstractHelper
{ {
/** /**
...@@ -148,14 +149,14 @@ class Requests extends AbstractHelper ...@@ -148,14 +149,14 @@ class Requests extends AbstractHelper
"postalCode" => '', "postalCode" => '',
"city" => "N/A", "city" => "N/A",
"houseNumberOrName" => '', "houseNumberOrName" => '',
"stateOrProvince" => '', // "stateOrProvince" => '',
"country" => "ZZ" "country" => "ZZ"
]; ];
// Save the defaults for later to compare if anything has changed // Save the defaults for later to compare if anything has changed
$requestBilling = $requestBillingDefaults; $requestBilling = $requestBillingDefaults;
$address = $this->getStreetStringFromBillingAddress($billingAddress); $address = $this->getStreetStringFromAddress($billingAddress);
if (!empty($address["name"])) { if (!empty($address["name"])) {
$requestBilling["street"] = $address["name"]; $requestBilling["street"] = $address["name"];
...@@ -173,9 +174,9 @@ class Requests extends AbstractHelper ...@@ -173,9 +174,9 @@ class Requests extends AbstractHelper
$requestBilling["city"] = $billingAddress->getCity(); $requestBilling["city"] = $billingAddress->getCity();
} }
if (!empty($billingAddress->getRegionCode())) { // if (!empty($billingAddress->getRegionCode())) {
$requestBilling["stateOrProvince"] = $billingAddress->getRegionCode(); // $requestBilling["stateOrProvince"] = $billingAddress->getRegionCode();
} // }
if (!empty($billingAddress->getCountryId())) { if (!empty($billingAddress->getCountryId())) {
$requestBilling["country"] = $billingAddress->getCountryId(); $requestBilling["country"] = $billingAddress->getCountryId();
...@@ -195,7 +196,7 @@ class Requests extends AbstractHelper ...@@ -195,7 +196,7 @@ class Requests extends AbstractHelper
"postalCode" => '', "postalCode" => '',
"city" => "N/A", "city" => "N/A",
"houseNumberOrName" => '', "houseNumberOrName" => '',
"stateOrProvince" => '', // "stateOrProvince" => '',
"country" => "ZZ" "country" => "ZZ"
]; ];
...@@ -203,7 +204,7 @@ class Requests extends AbstractHelper ...@@ -203,7 +204,7 @@ class Requests extends AbstractHelper
$requestDelivery = $requestDeliveryDefaults; $requestDelivery = $requestDeliveryDefaults;
// Parse address into street and house number where possible // Parse address into street and house number where possible
$address = $this->adyenHelper->getStreetFromString($shippingAddress->getStreetFull()); $address = $this->getStreetStringFromAddress($shippingAddress);
if (!empty($address['name'])) { if (!empty($address['name'])) {
$requestDelivery["street"] = $address["name"]; $requestDelivery["street"] = $address["name"];
...@@ -221,9 +222,9 @@ class Requests extends AbstractHelper ...@@ -221,9 +222,9 @@ class Requests extends AbstractHelper
$requestDelivery["city"] = $shippingAddress->getCity(); $requestDelivery["city"] = $shippingAddress->getCity();
} }
if (!empty($shippingAddress->getRegionCode())) { // if (!empty($shippingAddress->getRegionCode())) {
$requestDelivery["stateOrProvince"] = $shippingAddress->getRegionCode(); // $requestDelivery["stateOrProvince"] = $shippingAddress->getRegionCode();
} // }
if (!empty($shippingAddress->getCountryId())) { if (!empty($shippingAddress->getCountryId())) {
$requestDelivery["country"] = $shippingAddress->getCountryId(); $requestDelivery["country"] = $shippingAddress->getCountryId();
...@@ -288,8 +289,8 @@ class Requests extends AbstractHelper ...@@ -288,8 +289,8 @@ class Requests extends AbstractHelper
$request['browserInfo']['screenHeight'] = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::SCREEN_HEIGHT); $request['browserInfo']['screenHeight'] = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::SCREEN_HEIGHT);
$request['browserInfo']['colorDepth'] = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::SCREEN_COLOR_DEPTH); $request['browserInfo']['colorDepth'] = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::SCREEN_COLOR_DEPTH);
$request['browserInfo']['timeZoneOffset'] = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::TIMEZONE_OFFSET); $request['browserInfo']['timeZoneOffset'] = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::TIMEZONE_OFFSET);
$request['browserInfo']['language'] = $this->adyenHelper->getCurrentLocaleCode($store); $request['browserInfo']['language'] = "nl-NL";//$this->adyenHelper->getCurrentLocaleCode($store); TODO change format to nl-NL instead of nl_NL
$request['browserInfo']['javaEnabled'] = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::JAVA_ENABLED); $request['browserInfo']['javaEnabled'] = false; //$payment->getAdditionalInformation(AdyenCcDataAssignObserver::JAVA_ENABLED);TODO make sure it is not passed as null
// uset browser related data from additional information // uset browser related data from additional information
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::SCREEN_WIDTH); $payment->unsAdditionalInformation(AdyenCcDataAssignObserver::SCREEN_WIDTH);
...@@ -370,6 +371,10 @@ class Requests extends AbstractHelper ...@@ -370,6 +371,10 @@ class Requests extends AbstractHelper
$request['paymentMethod']['encryptedSecurityCode'] = $securityCode; $request['paymentMethod']['encryptedSecurityCode'] = $securityCode;
} }
if ($recurringDetailReference = $payment->getAdditionalInformation(AdyenOneclickDataAssignObserver::RECURRING_DETAIL_REFERENCE)) {
$request['paymentMethod']['recurringDetailReference'] = $recurringDetailReference;
}
// Remove from additional information // Remove from additional information
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_CREDIT_CARD_NUMBER); $payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_CREDIT_CARD_NUMBER);
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_MONTH); $payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_MONTH);
...@@ -424,13 +429,13 @@ class Requests extends AbstractHelper ...@@ -424,13 +429,13 @@ class Requests extends AbstractHelper
* @param $billingAddress * @param $billingAddress
* @return array * @return array
*/ */
private function getStreetStringFromBillingAddress($billingAddress) private function getStreetStringFromAddress($address)
{ {
if (method_exists($billingAddress, 'getStreetFull')) { if (method_exists($address, 'getStreetFull')) {
// Parse address into street and house number where possible // Parse address into street and house number where possible
$address = $this->adyenHelper->getStreetFromString($billingAddress->getStreetFull()); $address = $this->adyenHelper->getStreetFromString($address->getStreetFull());
} else { } else {
$address = $this->adyenHelper->getStreetFromString($billingAddress->getStreetLine1()); $address = $this->adyenHelper->getStreetFromString($address->getStreetLine1());
} }
return $address; return $address;
......
...@@ -35,6 +35,11 @@ class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver ...@@ -35,6 +35,11 @@ class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver
const ENCRYPTED_SECURITY_CODE = 'cvc'; const ENCRYPTED_SECURITY_CODE = 'cvc';
const NUMBER_OF_INSTALLMENTS = 'number_of_installments'; const NUMBER_OF_INSTALLMENTS = 'number_of_installments';
const VARIANT = 'variant'; const VARIANT = 'variant';
const JAVA_ENABLED = 'java_enabled';
const SCREEN_COLOR_DEPTH = 'screen_color_depth';
const SCREEN_WIDTH = 'screen_width';
const SCREEN_HEIGHT = 'screen_height';
const TIMEZONE_OFFSET = 'timezone_offset';
/** /**
* @var array * @var array
...@@ -43,7 +48,12 @@ class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver ...@@ -43,7 +48,12 @@ class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver
self::RECURRING_DETAIL_REFERENCE, self::RECURRING_DETAIL_REFERENCE,
self::ENCRYPTED_SECURITY_CODE, self::ENCRYPTED_SECURITY_CODE,
self::NUMBER_OF_INSTALLMENTS, self::NUMBER_OF_INSTALLMENTS,
self::VARIANT self::VARIANT,
self::JAVA_ENABLED,
self::SCREEN_COLOR_DEPTH,
self::SCREEN_WIDTH,
self::SCREEN_HEIGHT,
self::TIMEZONE_OFFSET
]; ];
/** /**
......
...@@ -528,15 +528,7 @@ ...@@ -528,15 +528,7 @@
<virtualType name="AdyenPaymentOneclickAuthorizeRequest" type="Magento\Payment\Gateway\Request\BuilderComposite"> <virtualType name="AdyenPaymentOneclickAuthorizeRequest" type="Magento\Payment\Gateway\Request\BuilderComposite">
<arguments> <arguments>
<argument name="builders" xsi:type="array"> <argument name="builders" xsi:type="array">
<item name="merchantaccount" xsi:type="string">Adyen\Payment\Gateway\Request\MerchantAccountDataBuilder</item>
<item name="customer" xsi:type="string">Adyen\Payment\Gateway\Request\CustomerDataBuilder</item>
<item name="customerip" xsi:type="string">Adyen\Payment\Gateway\Request\CustomerIpDataBuilder</item>
<item name="address" xsi:type="string">Adyen\Payment\Gateway\Request\AddressDataBuilder</item>
<item name="payment" xsi:type="string">Adyen\Payment\Gateway\Request\PaymentDataBuilder</item>
<item name="browserinfo" xsi:type="string">Adyen\Payment\Gateway\Request\BrowserInfoDataBuilder</item>
<item name="recurring" xsi:type="string">Adyen\Payment\Gateway\Request\RecurringDataBuilder</item>
<item name="transaction" xsi:type="string">Adyen\Payment\Gateway\Request\CcAuthorizationDataBuilder</item> <item name="transaction" xsi:type="string">Adyen\Payment\Gateway\Request\CcAuthorizationDataBuilder</item>
<item name="oneclick" xsi:type="string">Adyen\Payment\Gateway\Request\OneclickAuthorizationDataBuilder</item>
</argument> </argument>
</arguments> </arguments>
</virtualType> </virtualType>
......
...@@ -32,10 +32,15 @@ define( ...@@ -32,10 +32,15 @@ define(
'Magento_Checkout/js/action/redirect-on-success', 'Magento_Checkout/js/action/redirect-on-success',
'uiLayout', 'uiLayout',
'Magento_Ui/js/model/messages', 'Magento_Ui/js/model/messages',
'Magento_Checkout/js/action/place-order', 'mage/url',
'mage/url' 'Adyen_Payment/js/threeds2-js-utils',
'Magento_Checkout/js/model/full-screen-loader',
'Magento_Paypal/js/action/set-payment-method',
'Magento_Checkout/js/model/url-builder',
'mage/storage',
'Magento_Checkout/js/action/place-order'
], ],
function (ko, _, $, Component, selectPaymentMethodAction, additionalValidators, quote, checkoutData, redirectOnSuccessAction, layout, Messages, placeOrderAction, url) { function (ko, _, $, Component, selectPaymentMethodAction, additionalValidators, quote, checkoutData, redirectOnSuccessAction, layout, Messages, url, threeDS2Utils, fullScreenLoader, setPaymentMethodAction, urlBuilder, storage, placeOrderAction) {
'use strict'; 'use strict';
...@@ -59,7 +64,7 @@ define( ...@@ -59,7 +64,7 @@ define(
.observe([ .observe([
'recurringDetailReference', 'recurringDetailReference',
'creditCardType', 'creditCardType',
'creditCardVerificationNumber', 'encryptedCreditCardVerificationNumber',
'variant', 'variant',
'numberOfInstallments' 'numberOfInstallments'
]); ]);
...@@ -165,46 +170,50 @@ define( ...@@ -165,46 +170,50 @@ define(
return self.isActive() && this.getCode() == self.isChecked() && self.isBillingAgreementChecked() && this.placeOrderAllowed(); return self.isActive() && this.getCode() == self.isChecked() && self.isBillingAgreementChecked() && this.placeOrderAllowed();
}, },
/** /**
* Custom place order function
*
* @override * @override
*
* @param data
* @param event
* @returns {boolean}
*/ */
placeOrder: function (data, event) { placeOrder: function (data, event) {
var self = this; var self = this;
console.log("placeorder");
if (event) { if (event) {
event.preventDefault(); event.preventDefault();
} }
// only use installments for cards // only use installments for cards
if (self.agreement_data.card) { if (self.agreement_data.card) {
if (self.hasVerification()) { if (self.hasVerification()) {
var options = {enableValidations: false}; var options = {enableValidations: false};
} }
// set payment method to adyen_hpp // set payment method to adyen_hpp
// TODO can observer in front-end this not needed // TODO can observer in front-end this not needed
numberOfInstallments(self.installment); numberOfInstallments(self.installment);
} }
// in different context so need custom place order logic
if (this.validate() && additionalValidators.validate()) { if (this.validate() && additionalValidators.validate()) {
fullScreenLoader.startLoader();
self.isPlaceOrderActionAllowed(false); self.isPlaceOrderActionAllowed(false);
this.getPlaceOrderDeferredObject() //update payment method information if additional data was changed
.fail( selectPaymentMethodAction(this.getCcData());
function () { setPaymentMethodAction(this.messageContainer).done(
self.isPlaceOrderActionAllowed(true); function (responseJSON) {
} fullScreenLoader.stopLoader();
).done( self.isPlaceOrderActionAllowed(true);
function () { self.validateThreeDS2OrPlaceOrder(responseJSON);
self.afterPlaceOrder(); });
// use custom redirect Link for supporting 3D secure return false;
window.location.replace(url.build(window.checkoutConfig.payment[quote.paymentMethod().method].redirectUrl));
}
);
return true;
} }
return false; return false;
}, },
/** /**
* Renders the secure CVC field, * Renders the secure CVC field,
* creates the card component, * creates the card component,
...@@ -275,6 +284,131 @@ define( ...@@ -275,6 +284,131 @@ define(
window.adyencheckout = oneClickCard; window.adyencheckout = oneClickCard;
}, },
/**
* Builds the payment details part of the payment information reqeust
*
* @returns {{method: *, additional_data: {card_brand: *, cc_type: *, number: *, cvc: *, expiryMonth: *, expiryYear: *, holderName: *, store_cc: (boolean|*), number_of_installments: *, java_enabled: boolean, screen_color_depth: number, screen_width, screen_height, timezone_offset: *}}}
*/
getCcData: function () {
var self = this;
var browserInfo = threeDS2Utils.getBrowserInfo();
var data = {
'method': self.method,
additional_data: {
'variant': variant(),
'recurring_detail_reference': recurringDetailReference(),
'number_of_installments': numberOfInstallments(),
'cvc': self.encryptedCreditCardVerificationNumber,
'expiryMonth': self.creditCardExpMonth(),
'expiryYear': self.creditCardExpYear(),
'java_enabled': browserInfo.javaEnabled,
'screen_color_depth': browserInfo.colorDepth,
'screen_width': browserInfo.screenWidth,
'screen_height': browserInfo.screenHeight,
'timezone_offset': browserInfo.timeZoneOffset
}
};
return data;
},
/**
* Based on the response we can start a 3DS2 validation or place the order
* @param responseJSON
*/
validateThreeDS2OrPlaceOrder: function(responseJSON) {
var self = this;
var response = JSON.parse(responseJSON);
if (!!response.threeDS2) {
// render component
self.renderThreeDS2Component(response.type, response.token);
} else {
this.getPlaceOrderDeferredObject()
.fail(
function () {
self.isPlaceOrderActionAllowed(true);
}
).done(
function () {
self.afterPlaceOrder();
window.location.replace(url.build(window.checkoutConfig.payment[quote.paymentMethod().method].redirectUrl));
}
);
}
},
/**
* The results that the 3DS2 components returns in the onComplete callback needs to be sent to the
* backend to the /adyen/threeDS2Process endpoint and based on the response render a new threeDS2
* component or place the order (validateThreeDS2OrPlaceOrder)
* @param response
*/
processThreeDS2: function(data) {
var self = this;
fullScreenLoader.startLoader();
var payload = {
"payload": JSON.stringify(data)
};
var serviceUrl = urlBuilder.createUrl('/adyen/threeDS2Process', {});
storage.post(
serviceUrl,
JSON.stringify(payload),
true
).done(function(responseJSON) {
fullScreenLoader.stopLoader();
self.validateThreeDS2OrPlaceOrder(responseJSON)
});
},
/**
* Rendering the 3DS2.0 components
* To do the device fingerprint at the response of IdentifyShopper render the threeDS2DeviceFingerprint
* component
* To render the challenge for the customer at the response of ChallengeShopper render the
* threeDS2Challenge component
* Both of them is going to be rendered in a Magento dialog popup
*
* @param type
* @param token
*/
renderThreeDS2Component: function(type, token) {
var self = this;
var threeDS2Node = document.getElementById('threeDS2ContainerOneClick');
if (type == "IdentifyShopper") {
fullScreenLoader.startLoader();
self.threeDS2Component = checkout.create('threeDS2DeviceFingerprint', {
fingerprintToken: token,
onComplete: function(result) {
fullScreenLoader.stopLoader();
self.processThreeDS2(result.data);
}
});
} else if (type == "ChallengeShopper") {
$('#threeDS2ModalOneClick').modal({
// disable user to hide popup
clickableOverlay: false,
// empty buttons, we don't need that
buttons: []
});
$('#threeDS2ModalOneClick').modal("openModal");
self.threeDS2Component = checkout
.create('threeDS2Challenge', {
challengeToken: token,
onComplete: function(result) {
self.processThreeDS2(result.data);
$('#threeDS2ModalOneClick').modal("closeModal");
}
});
}
self.threeDS2Component.mount(threeDS2Node);
},
/** /**
* We use the billingAgreements to save the oneClick stored payments but we don't store the * We use the billingAgreements to save the oneClick stored payments but we don't store the
* details object that we get from the paymentMethods call. This function is a fix for BCMC. * details object that we get from the paymentMethods call. This function is a fix for BCMC.
......
...@@ -134,6 +134,11 @@ ...@@ -134,6 +134,11 @@
</div> </div>
</div> </div>
<!-- /ko --> <!-- /ko -->
<div id="threeDS2ModalOneClick">
<div id="threeDS2ContainerOneClick"></div>
</div>
</fieldset> </fieldset>
</form> </form>
<div class="checkout-agreements-block"> <div class="checkout-agreements-block">
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment