Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ECP-9259] - Update payment method validation so updating billing information get's processed correctly. #2677

Merged
merged 10 commits into from
Aug 7, 2024
144 changes: 109 additions & 35 deletions view/frontend/web/js/view/payment/method-renderer/adyen-pm-method.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@
this._super();
let self = this;

this.isPlaceOrderAllowed(true);

let paymentMethodsObserver = adyenPaymentService.getPaymentMethods();
paymentMethodsObserver.subscribe(
Expand All @@ -78,6 +77,8 @@
}
},

paymentMethodStates: {},

createCheckoutComponent: async function(paymentMethodsResponse) {
// Set to null by default and modify depending on the paymentMethods response
this.adyenPaymentMethod(null);
Expand Down Expand Up @@ -178,17 +179,43 @@
self.isPlaceOrderAllowed(true);
});
},

renderCheckoutComponent: function() {
this.isPlaceOrderAllowed(false);
let methodCode = this.getMethodCode();
let state = this.initializeMethod(methodCode);
Fixed Show fixed Hide fixed

let configuration = this.buildComponentConfiguration(this.paymentMethod(), this.paymentMethodsExtraInfo());

this.mountPaymentMethodComponent(this.paymentMethod(), configuration);
this.mountPaymentMethodComponent(this.paymentMethod(), configuration, methodCode);


console.log(configuration)
raoulritter marked this conversation as resolved.
Show resolved Hide resolved
// Use setTimeout to ensure the component has been mounted
setTimeout(() => {
this.updatePlaceOrderButtonState(methodCode);
}, 0);
},
updatePlaceOrderButtonState: function(methodCode) {
let state = this.initializeMethod(methodCode);
let container = $(`#${methodCode}Container`);

// Check if the payment method has any input fields
let hasForm = container.find('input, select, textarea').length > 0;

if (hasForm) {
// If there's a form, start with button disabled and let the onChange handler manage its state
state.isPlaceOrderAllowed(false);
} else {
// If there's no form, it's likely a direct redirect method, so enable the button
state.isPlaceOrderAllowed(true);
}
},

buildComponentConfiguration: function (paymentMethod, paymentMethodsExtraInfo) {
let self = this;
let showPayButton = false;
let methodCode = this.getMethodCode();
Fixed Show fixed Hide fixed
let state = this.initializeMethod(methodCode);
Fixed Show fixed Hide fixed


raoulritter marked this conversation as resolved.
Show resolved Hide resolved
let formattedShippingAddress = {};
let formattedBillingAddress = {};
Expand Down Expand Up @@ -222,49 +249,96 @@
return this.item.method;
},

mountPaymentMethodComponent(paymentMethod, configuration)
{
mountPaymentMethodComponent: function(paymentMethod, configuration, methodCode) {
let self = this;
let state = this.initializeMethod(methodCode);

try {
const containerId = '#' + paymentMethod.type + 'Container';

this.paymentComponent = adyenCheckout.mountPaymentMethodComponent(
state.paymentComponent = adyenCheckout.mountPaymentMethodComponent(
self.checkoutComponent,
self.getTxVariant(),
configuration,
containerId
);
} catch (err) {
// The component does not exist yet
if ('test' === adyenConfiguration.getCheckoutEnvironment()) {
console.log(err);
}
}
},

validate: function() {
let state = this.initializeMethod(this.getMethodCode());

if (!state.paymentComponent) {
return true;
}

state.paymentComponent.showValidation();

if (!this.isComponentValid(state.paymentComponent)) {
return false;
}

const form = '#adyen-' + this.getTxVariant() + '-form';
const validate = $(form).validation() && $(form).validation('isValid');
return validate && additionalValidators.validate();
return $(form).validation() && $(form).validation('isValid') && additionalValidators.validate();
},

isComponentValid: function(component) {
return component.state.isValid !== false &&
!this.isPaymentDataEmpty(component.state) &&
!this.isPaymentDataEmpty(component.data);
},

isPaymentDataEmpty: function(obj) {
if (obj && obj.data && typeof obj.data === 'object' && Object.keys(obj.data).length > 0) {
return Object.values(obj.data).every(value =>
value === '' || (typeof value === 'object' && Object.keys(value).length === 0)
);
}
return false;
},


showErrorMessage: function(message) {
messageList.addErrorMessage({
message: message
});
},


initializeMethod: function(methodCode) {
if (!this.paymentMethodStates[methodCode]) {
this.paymentMethodStates[methodCode] = {
isPlaceOrderAllowed: ko.observable(true),
paymentComponent: null
};
}
return this.paymentMethodStates[methodCode];
},

isPlaceOrderAllowed: function(methodCode) {
let state = this.initializeMethod(methodCode);
return state.isPlaceOrderAllowed;
},

isPlaceOrderAllowed: function(bool) {
this.isPlaceOrderActionAllowed(bool);
return this.isPlaceOrderActionAllowed(bool);
setPlaceOrderAllowed: function(methodCode, allowed) {
let state = this.initializeMethod(methodCode);
state.isPlaceOrderAllowed(allowed);
},

showPlaceOrderButton: function() {
return this.placeOrderButtonVisible;
},

placeOrder: function() {
if (this.paymentComponent) {
let methodCode = this.getMethodCode();
let state = this.initializeMethod(methodCode);

this.paymentComponent.showValidation();
if (this.paymentComponent.state.isValid === false) {
return false;
}
if (state.paymentComponent) {
state.paymentComponent.showValidation();
}

if (this.validate()) {
Expand All @@ -277,8 +351,8 @@
additionalData.frontendType = 'luma';

let stateData;
if (this.paymentComponent) {
stateData = this.paymentComponent.data;
if (state.paymentComponent) {
stateData = state.paymentComponent.data;
} else {
stateData = {
paymentMethod: {
Expand All @@ -290,7 +364,9 @@
additionalData.stateData = JSON.stringify(stateData);
data.additional_data = additionalData;

this.placeRedirectOrder(data, this.paymentComponent);
this.placeRedirectOrder(data, state.paymentComponent);
} else {
this.isPlaceOrderAllowed(true);
}

return false;
Expand All @@ -299,28 +375,25 @@
placeRedirectOrder: async function(data, component) {
const self = this;

// Place Order but use our own redirect url after
fullScreenLoader.startLoader();
$('.hpp-message').slideUp();
self.isPlaceOrderAllowed(false);

await $.when(placeOrderAction(data, self.currentMessageContainer)).fail(
function(response) {
self.handleOnFailure(response, component);
}
).done(
function(orderId) {
self.afterPlaceOrder();
adyenPaymentService.getOrderPaymentStatus(orderId).done(function(responseJSON) {
self.validateActionOrPlaceOrder(responseJSON, orderId, component);
});
}
);
try {
const orderId = await placeOrderAction(data, self.currentMessageContainer);
self.afterPlaceOrder();
const responseJSON = await adyenPaymentService.getOrderPaymentStatus(orderId);
self.validateActionOrPlaceOrder(responseJSON, orderId, component);
} catch (response) {
self.handleOnFailure(response, component);
}
},


handleOnFailure: function(response, component) {
this.isPlaceOrderAllowed(true);
fullScreenLoader.stopLoader();
errorProcessor.process(response, this.currentMessageContainer);
},

/**
Expand Down Expand Up @@ -366,7 +439,8 @@


isButtonActive: function() {
return this.isPlaceOrderActionAllowed();
let methodCode = this.getMethodCode();
return this.isPlaceOrderAllowed(methodCode);
},

/**
Expand Down
Loading