Commit 925eec72 authored by attilak's avatar attilak

Move all alternative payment methods to generic component (frontend)

Remove unnecessary custom function from the frontend
Remove state data observers
Use the component's paymentMethods object to list all the methods
parent 4c8f2bb9
...@@ -36,9 +36,26 @@ define( ...@@ -36,9 +36,26 @@ define(
'Magento_Checkout/js/action/place-order', 'Magento_Checkout/js/action/place-order',
'uiLayout', 'uiLayout',
'Magento_Ui/js/model/messages', 'Magento_Ui/js/model/messages',
'Adyen_Payment/js/bundle' 'Adyen_Payment/js/bundle',
'Adyen_Payment/js/model/adyen-configuration'
], ],
function (ko, $, Component, selectPaymentMethodAction, quote, checkoutData, additionalValidators, storage, adyenPaymentService, urlBuilder, customer, fullScreenLoader, placeOrderAction, layout, Messages, AdyenComponent) { function (ko,
$,
Component,
selectPaymentMethodAction,
quote,
checkoutData,
additionalValidators,
storage,
adyenPaymentService,
urlBuilder,
customer,
fullScreenLoader,
placeOrderAction,
layout,
Messages,
AdyenComponent,
adyenConfiguration) {
'use strict'; 'use strict';
var brandCode = ko.observable(null); var brandCode = ko.observable(null);
var paymentMethod = ko.observable(null); var paymentMethod = ko.observable(null);
...@@ -55,21 +72,13 @@ define( ...@@ -55,21 +72,13 @@ define(
self: this, self: this,
defaults: { defaults: {
template: 'Adyen_Payment/payment/hpp-form', template: 'Adyen_Payment/payment/hpp-form',
brandCode: '' brandCode: '',
stateData: {}
}, },
initObservable: function () { initObservable: function () {
this._super() this._super()
.observe([ .observe([
'brandCode', 'brandCode'
'issuer',
'gender',
'dob',
'telephone',
'ownerName',
'ibanNumber',
'ssn',
'bankAccountNumber',
'bankLocationId'
]); ]);
return this; return this;
}, initialize: function () { }, initialize: function () {
...@@ -83,9 +92,10 @@ define( ...@@ -83,9 +92,10 @@ define(
* Create sherable checkout component * Create sherable checkout component
* @type {AdyenCheckout} * @type {AdyenCheckout}
*/ */
self.checkoutComponent = new AdyenCheckout({ locale: self.getLocale()}); self.checkoutComponent = adyenPaymentService.getCheckoutComponent();
var paymentMethods = self.checkoutComponent.paymentMethodsResponse.paymentMethods;
var paymentMethods = adyenPaymentService.getAvailablePaymentMethods();
// create component needs to be in initialize method // create component needs to be in initialize method
var messageComponents = {}; var messageComponents = {};
...@@ -123,13 +133,22 @@ define( ...@@ -123,13 +133,22 @@ define(
fullScreenLoader.stopLoader(); fullScreenLoader.stopLoader();
} }
var paymentMethods = adyenPaymentService.getAvailablePaymentMethods(); // filter unnecessary field details from checkout component
console.log(paymentMethods); // TODO refactor
console.log(paymentMethods.paymentMethods); self.checkoutComponent.paymentMethodsResponse.paymentMethods.forEach(function (paymentMethod, index) {
if (!!self.checkoutComponent.paymentMethodsResponse.paymentMethods[index].details) {
if (!!self.checkoutComponent.paymentMethodsResponse.paymentMethods[index].details.personalDetails) {
self.checkoutComponent.paymentMethodsResponse.paymentMethods[index].details =
self.filterOutOpenInvoiceComponentDetails(paymentMethod.details);
}
}
});
// Get paymentMethod list with filtered details
var paymentMethods = self.checkoutComponent.paymentMethodsResponse.paymentMethods;
// Iterate through the payment methods and render them
var paymentList = _.reduce(paymentMethods, function (accumulator, value) { var paymentList = _.reduce(paymentMethods, function (accumulator, value) {
console.log(value);
if (!self.isPaymentMethodSupported(value.type)) { if (!self.isPaymentMethodSupported(value.type)) {
return accumulator; return accumulator;
} }
...@@ -144,8 +163,8 @@ define( ...@@ -144,8 +163,8 @@ define(
return self.getBrandCodeFromPaymentMethod(value); return self.getBrandCodeFromPaymentMethod(value);
}; };
result.value = result.getBrandCode(); result.brandCode = result.getBrandCode();
result.name = value; result.name = value.name;
result.method = self.item.method; result.method = self.item.method;
/** /**
* Observable to enable and disable place order buttons for payment methods * Observable to enable and disable place order buttons for payment methods
...@@ -176,335 +195,42 @@ define( ...@@ -176,335 +195,42 @@ define(
result.afterPlaceOrder = function () { result.afterPlaceOrder = function () {
return self.afterPlaceOrder(); return self.afterPlaceOrder();
}; };
/**
* Checks if payment method is open invoice
* @returns {*|isPaymentMethodOpenInvoiceMethod}
*/
result.isPaymentMethodOpenInvoiceMethod = function () {
return value.isPaymentMethodOpenInvoiceMethod;
};
/**
* Checks if payment method is open invoice but not in the list below
* [klarna, afterpay]
* @returns {boolean}
*/
result.isPaymentMethodOtherOpenInvoiceMethod = function () {
if (
!result.isPaymentMethodAfterPay() &&
!result.isPaymentMethodKlarna() &&
!result.isPaymentMethodAfterPayTouch() &&
value.isPaymentMethodOpenInvoiceMethod
) {
return true;
}
return false;
};
/**
* Checks if payment method is klarna
* @returns {boolean}
*/
result.isPaymentMethodKlarna = function () {
if (result.getBrandCode() === "klarna") {
return true;
}
return false;
};
/**
* Checks if payment method is after pay
* @returns {boolean}
*/
result.isPaymentMethodAfterPay = function () {
if (result.getBrandCode() === "afterpay_default") {
return true;
}
return false;
};
/**
* Checks if payment method is after pay touch
* @returns {boolean}
*/
result.isPaymentMethodAfterPayTouch = function () {
if (result.getBrandCode() === "afterpaytouch") {
return true;
}
return false;
};
/**
* Get personal number (SSN) length based on the buyer's country
* @returns {number}
*/
result.getSsnLength = function () {
if (quote.billingAddress().countryId == "NO") {
//14 digits for Norway ÅÅÅÅMMDD-XXXXX
return 14;
}
else {
//13 digits for other Nordic countries ÅÅÅÅMMDD-XXXX
return 13;
}
};
/**
* Get max length for the Bank account number
*/
result.getBankAccountNumberMaxLength = function () {
return 17;
};
/**
* Finds the issuer property in the payment method's response and if available returns it's index
* @returns
*/
result.findIssuersProperty = function () {
var issuerKey = false;
if (typeof value.details !== 'undefined') {
$.each(value.details, function (key, detail) {
if (typeof detail.items !== 'undefined' && detail.key == 'issuer') {
issuerKey = key;
}
});
}
return issuerKey;
}
/**
* Checks if the payment method has issuers property available
* @returns {boolean}
*/
result.hasIssuersProperty = function () {
if (result.findIssuersProperty() !== false) {
return true;
}
return false;
};
/**
* Checks if the payment method has issuer(s) available
* @returns {boolean}
*/
result.hasIssuersAvailable = function () {
if (result.hasIssuersProperty() && value.details[result.findIssuersProperty()].items.length > 0) {
return true;
}
return false;
};
/**
* Returns the issuers for a payment method
* @returns {*}
*/
result.getIssuers = function () {
if (result.hasIssuersAvailable()) {
return value.details[result.findIssuersProperty()].items;
}
return [];
};
/**
* Checks if payment method is iDeal
* @returns {boolean}
*/
result.isIdeal = function () {
if (result.getBrandCode().indexOf("ideal") >= 0) {
return true;
}
return false;
};
/**
* Checks if payment method is ACH
* @returns {boolean}
*/
result.isAch = function () {
if (result.getBrandCode().indexOf("ach") == 0) {
return true;
}
return false;
};
/**
* Checks if payment method is sepa direct debit
*/
result.isSepaDirectDebit = function () {
if (result.getBrandCode().indexOf("sepadirectdebit") >= 0) {
return true;
}
return false;
};
/** /**
* Renders the secure fields, * Renders the secure fields,
* creates the ideal component, * creates the ideal component,
* sets up the callbacks for ideal components and * sets up the callbacks for ideal components and
*/ */
result.renderIdealComponent = function () { result.renderCheckoutComponent = function () {
result.isPlaceOrderAllowed(false); result.isPlaceOrderAllowed(false);
try {
var idealNode = document.getElementById('iDealContainer'); self.checkoutComponent.create(result.getBrandCode(), {
onChange: function (state) {
var ideal = self.checkoutComponent.create('ideal', { if (!!state.isValid) {
items: result.getIssuers(), result.stateData = state.data;
onChange: function (state) { result.isPlaceOrderAllowed(true);
if (!!state.isValid) { } else {
result.issuer(state.data.paymentMethod.issuer); result.stateData = {};
result.isPlaceOrderAllowed(true); result.isPlaceOrderAllowed(false);
}
} else {
result.isPlaceOrderAllowed(false);
}
}
});
ideal.mount(idealNode);
};
/**
* Creates the sepa direct debit component,
* sets up the callbacks for sepa components
*/
result.renderSepaDirectDebitComponent = function () {
result.isPlaceOrderAllowed(false);
var sepaDirectDebitNode = document.getElementById('sepaDirectDebitContainer');
var sepaDirectDebit = self.checkoutComponent.create('sepadirectdebit', {
countryCode: self.getLocale(),
onChange: function (state) {
if (!!state.isValid) {
result.ownerName(state.data.paymentMethod["sepa.ownerName"]);
result.ibanNumber(state.data.paymentMethod["sepa.ibanNumber"]);
result.isPlaceOrderAllowed(true);
} else {
result.isPlaceOrderAllowed(false);
} }
} }).mount('#adyen-alternative-payment-container-' + result.getBrandCode());
}); } catch (err) {
// The component does not exist yet
sepaDirectDebit.mount(sepaDirectDebitNode);
};
/**
* Creates the klarna component,
* sets up the callbacks for klarna components
*/
result.renderKlarnaComponent = function () {
/* The new Klarna integration doesn't return details and the component does not handle it */
if (!value.details) {
return;
} }
var klarnaNode = document.getElementById('klarnaContainer');
var klarna = self.checkoutComponent.create('klarna', {
countryCode: self.getLocale(),
details: self.filterOutOpenInvoiceComponentDetails(value.details),
visibility: {
personalDetails: "editable"
},
onChange: function (state) {
if (!!state.isValid) {
result.dob(state.data.paymentMethod.personalDetails.dateOfBirth);
result.telephone(state.data.paymentMethod.personalDetails.telephoneNumber);
result.gender(state.data.paymentMethod.personalDetails.gender);
result.isPlaceOrderAllowed(true);
} else {
result.isPlaceOrderAllowed(false);
}
}
}).mount(klarnaNode);
}; };
/** result.getRatePayDeviceIdentToken = function () {
* Creates the afterpay component, return window.checkoutConfig.payment.adyenHpp.deviceIdentToken;
* sets up the callbacks for klarna components
*/
result.renderAfterPayComponent = function () {
var afterPay = self.checkoutComponent.create('afterpay', {
countryCode: self.getLocale(),
details: self.filterOutOpenInvoiceComponentDetails(value.details),
visibility: {
personalDetails: "editable"
},
onChange: function (state) {
if (!!state.isValid) {
result.dob(state.data.paymentMethod.personalDetails.dateOfBirth);
result.telephone(state.data.paymentMethod.personalDetails.telephoneNumber);
result.gender(state.data.paymentMethod.personalDetails.gender);
result.isPlaceOrderAllowed(true);
} else {
result.isPlaceOrderAllowed(false);
}
}
}).mount(document.getElementById('afterPayContainer'));
}; };
if (result.hasIssuersProperty()) {
if (!result.hasIssuersAvailable()) {
return false;
}
result.issuerIds = result.getIssuers();
result.issuer = ko.observable(null);
} else if (value.isPaymentMethodOpenInvoiceMethod) {
result.telephone = ko.observable(quote.shippingAddress().telephone);
result.gender = ko.observable(window.checkoutConfig.payment.adyenHpp.gender);
result.dob = ko.observable(window.checkoutConfig.payment.adyenHpp.dob);
result.datepickerValue = ko.observable(); // needed ??
result.ssn = ko.observable();
result.getRatePayDeviceIdentToken = function () {
return window.checkoutConfig.payment.adyenHpp.deviceIdentToken;
};
result.showSsn = function () {
if (result.getBrandCode().indexOf("klarna") >= 0) {
var ba = quote.billingAddress();
if (ba != null) {
var nordicCountriesList = window.checkoutConfig.payment.adyenHpp.nordicCountries;
if (nordicCountriesList.indexOf(ba.countryId) >= 0) {
return true;
}
}
}
return false;
};
} else if (result.isSepaDirectDebit()) {
result.ownerName = ko.observable(null);
result.ibanNumber = ko.observable(null);
} else if (result.isAch()) {
result.ownerName = ko.observable(null);
result.bankAccountNumber = ko.observable(null);
result.bankLocationId = ko.observable(null);
}
accumulator.push(result); accumulator.push(result);
return accumulator; return accumulator;
}, []); }, []);
return paymentList; return paymentList;
}, },
/**
* Some payment methods we do not want to render as it requires extra implementation // TODO prefill gender in components where it is available
* or is already implemented in a separate payment method.
* Using a match as we want to prevent to render all Boleto and most of the WeChat types
* @param paymentMethod
* @returns {boolean}
*/
isPaymentMethodSupported: function (paymentMethod) {
if (paymentMethod == 'wechatpayWeb') {
return true;
}
for (var i = 0; i < unsupportedPaymentMethods.length; i++) {
var match = paymentMethod.match(unsupportedPaymentMethods[i]);
if (match) {
return false;
}
}
return true;
},
getGenderTypes: function () { getGenderTypes: function () {
return _.map(window.checkoutConfig.payment.adyenHpp.genderTypes, function (value, key) { return _.map(window.checkoutConfig.payment.adyenHpp.genderTypes, function (value, key) {
return { return {
...@@ -520,28 +246,14 @@ define( ...@@ -520,28 +246,14 @@ define(
if (this.validate() && additionalValidators.validate()) { if (this.validate() && additionalValidators.validate()) {
var data = {}; var data = {};
data.stateData = self.stateData;
data.method = self.method; data.method = self.method;
var additionalData = {}; var additionalData = {};
additionalData.brand_code = self.value; additionalData.brand_code = self.brandCode;
if (self.hasIssuersAvailable()) { if (brandCode() == "ratepay") {
additionalData.issuer_id = this.issuer(); additionalData.df_value = this.getRatePayDeviceIdentToken();
} else if (self.isPaymentMethodOpenInvoiceMethod()) {
additionalData.gender = this.gender();
additionalData.dob = this.dob();
additionalData.telephone = this.telephone();
additionalData.ssn = this.ssn();
if (brandCode() == "ratepay") {
additionalData.df_value = this.getRatePayDeviceIdentToken();
}
} else if (self.isSepaDirectDebit()) {
additionalData.ownerName = this.ownerName();
additionalData.ibanNumber = this.ibanNumber();
} else if (self.isAch()) {
additionalData.bankAccountOwnerName = this.ownerName();
additionalData.bankAccountNumber = this.bankAccountNumber();
additionalData.bankLocationId = this.bankLocationId();
} }
data.additional_data = additionalData; data.additional_data = additionalData;
...@@ -550,26 +262,16 @@ define( ...@@ -550,26 +262,16 @@ define(
return false; return false;
}, },
selectPaymentMethodBrandCode: function () {
var self = this;
// set payment method to adyen_hpp
var data = {
"method": self.method,
"po_number": null,
"additional_data": {
brand_code: self.value
}
};
// set the brandCode
brandCode(self.value);
// set payment method // DEFAULT FUNCTIONS
paymentMethod(self.method); validate: function (brandCode) {
var form = '#payment_form_' + this.getCode() + '_' + brandCode;
var validate = $(form).validation() && $(form).validation('isValid');
selectPaymentMethodAction(data); if (!validate) {
checkoutData.setSelectedPaymentMethod(self.method); return false;
}
return true; return true;
}, },
...@@ -612,8 +314,48 @@ define( ...@@ -612,8 +314,48 @@ define(
} }
) )
}, },
isBrandCodeChecked: ko.computed(function () {
/**
*
* @returns {boolean}
*/
selectPaymentMethodBrandCode: function () {
var self = this;
// set payment method to adyen_hpp
var data = {
"method": self.method,
"po_number": null,
"additional_data": {
brand_code: self.brandCode
}
};
// set the brandCode
brandCode(self.brandCode);
// set payment method
paymentMethod(self.method);
selectPaymentMethodAction(data);
checkoutData.setSelectedPaymentMethod(self.method);
return true;
},
// CONFIGURATIONS
isIconEnabled: function () {
return window.checkoutConfig.payment.adyen.showLogo;
},
getRatePayDeviceIdentToken: function () {
return window.checkoutConfig.payment.adyenHpp.deviceIdentToken;
},
/**
*
*/
isBrandCodeChecked: ko.computed(function () {
if (!quote.paymentMethod()) { if (!quote.paymentMethod()) {
return null; return null;
} }
...@@ -621,19 +363,27 @@ define( ...@@ -621,19 +363,27 @@ define(
if (quote.paymentMethod().method == paymentMethod()) { if (quote.paymentMethod().method == paymentMethod()) {
return brandCode(); return brandCode();
} }
return null; return null;
}), }),
isIconEnabled: function () {
return window.checkoutConfig.payment.adyen.showLogo;
},
validate: function (brandCode) {
var form = '#payment_form_' + this.getCode() + '_' + brandCode;
var validate = $(form).validation() && $(form).validation('isValid');
if (!validate) { /**
return false; * Some payment methods we do not want to render as it requires extra implementation
* or is already implemented in a separate payment method.
* Using a match as we want to prevent to render all Boleto and most of the WeChat types
* @param paymentMethod
* @returns {boolean}
*/
isPaymentMethodSupported: function (paymentMethod) {
if (paymentMethod == 'wechatpayWeb') {
return true;
}
for (var i = 0; i < unsupportedPaymentMethods.length; i++) {
var match = paymentMethod.match(unsupportedPaymentMethods[i]);
if (match) {
return false;
}
} }
return true; return true;
}, },
/** /**
...@@ -648,12 +398,6 @@ define( ...@@ -648,12 +398,6 @@ define(
return ''; return '';
}, },
getRatePayDeviceIdentToken: function () {
return window.checkoutConfig.payment.adyenHpp.deviceIdentToken;
},
getLocale: function () {
return window.checkoutConfig.payment.adyenHpp.locale;
},
/** /**
* In the open invoice components we need to validate only the personal details and only the * In the open invoice components we need to validate only the personal details and only the
* dateOfBirth, telephoneNumber and gender if it's set in the admin * dateOfBirth, telephoneNumber and gender if it's set in the admin
......
...@@ -23,14 +23,14 @@ ...@@ -23,14 +23,14 @@
--> -->
<!-- ko foreach: getAdyenHppPaymentMethods() --> <!-- ko foreach: getAdyenHppPaymentMethods() -->
<div class="payment-method" data-bind="css: {'_active': (value == $parent.isBrandCodeChecked())}"> <div class="payment-method" data-bind="css: {'_active': (brandCode == $parent.isBrandCodeChecked())}">
<div class="payment-method-title field choice"> <div class="payment-method-title field choice">
<input type="radio" <input type="radio"
name="payment[method]" name="payment[method]"
class="radio" class="radio"
data-bind="attr: {'id': value}, value: value, checked: $parent.isBrandCodeChecked, click: $parent.selectPaymentMethodBrandCode"/> data-bind="attr: {'id': 'paymentmethod_' + brandCode}, value: 'paymentmethod_' + brandCode, checked: brandCode == $parent.isBrandCodeChecked, click: $parent.selectPaymentMethodBrandCode"/>
<label data-bind="attr: {'for': value}" class="label"> <label data-bind="attr: {'for': 'paymentmethod_' + brandCode}" class="label">
<!-- ko if: name.icon --> <!-- ko if: name.icon -->
<img data-bind="attr: { <img data-bind="attr: {
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
}"> }">
<!--/ko--> <!--/ko-->
<span data-bind="text: name.title"></span> <span data-bind="text: name"></span>
</label> </label>
</div> </div>
<div class="payment-method-content"> <div class="payment-method-content">
...@@ -51,9 +51,10 @@ ...@@ -51,9 +51,10 @@
<!--/ko--> <!--/ko-->
</div> </div>
<form class="form" data-role="adyen-hpp-form" action="#" method="post" data-bind="mageInit: { 'validation':[]}, attr: {id: 'payment_form_' + $parent.getCode() + '_' + value}"> <form class="form" data-role="adyen-hpp-form" action="#" method="post" data-bind="mageInit: { 'validation':[]}, attr: {id: 'payment_form_' + $parent.getCode() + '_' + brandCode}">
<fieldset class="fieldset" data-bind='attr: {id: "payment_fieldset_" + $parent.getCode() + "_" + value}'> <fieldset class="fieldset" data-bind='attr: {id: "payment_fieldset_" + $parent.getCode() + "_" + brandCode}'>
<div class="adyen-alternative-payment-container"></div> <div data-bind='attr: {id: "adyen-alternative-payment-container-" + brandCode}'
afterRender="renderCheckoutComponent()"></div>
</fieldset> </fieldset>
...@@ -64,7 +65,7 @@ ...@@ -64,7 +65,7 @@
</div> </div>
<div> <div>
<span class="message message-error error hpp-message" data-bind="attr: {id: 'messages-' + value}"></span> <span class="message message-error error hpp-message" data-bind="attr: {id: 'messages-' + brandCode}"></span>
</div> </div>
<div class="actions-toolbar"> <div class="actions-toolbar">
...@@ -73,7 +74,7 @@ ...@@ -73,7 +74,7 @@
type="submit" type="submit"
data-bind=" data-bind="
click: $parent.continueToAdyenBrandCode, click: $parent.continueToAdyenBrandCode,
enable: placeOrderAllowed() && (value == $parent.isBrandCodeChecked()), enable: placeOrderAllowed() && (brandCode == $parent.isBrandCodeChecked()),
css: {disabled: !$parent.isPlaceOrderActionAllowed()}" css: {disabled: !$parent.isPlaceOrderActionAllowed()}"
disabled> disabled>
<span data-bind="text: $t('Place Order')"></span> <span data-bind="text: $t('Place Order')"></span>
......
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