From a37594643af2a59303fc95bdead1abf301087acd Mon Sep 17 00:00:00 2001
From: Pedro Silva
Date: Fri, 22 Dec 2023 16:02:00 +0000
Subject: [PATCH 1/3] Add Basic Checkout Validation and Early Checkout
Validation to Card Fields
---
modules/ppcp-button/resources/js/button.js | 38 ++++++++++++-------
.../ActionHandler/CheckoutActionHandler.js | 12 ++++--
.../js/modules/Renderer/CardFieldsRenderer.js | 13 ++++++-
3 files changed, 46 insertions(+), 17 deletions(-)
diff --git a/modules/ppcp-button/resources/js/button.js b/modules/ppcp-button/resources/js/button.js
index 40997d15a..9bc2e4b49 100644
--- a/modules/ppcp-button/resources/js/button.js
+++ b/modules/ppcp-button/resources/js/button.js
@@ -40,11 +40,6 @@ const bootstrap = () => {
);
const spinner = new Spinner();
- let creditCardRenderer = new HostedFieldsRenderer(PayPalCommerceGateway, errorHandler, spinner);
- if (typeof paypal.CardFields !== 'undefined') {
- creditCardRenderer = new CardFieldsRenderer(PayPalCommerceGateway, errorHandler, spinner);
- }
-
const formSaver = new FormSaver(
PayPalCommerceGateway.ajax.save_checkout_form.endpoint,
PayPalCommerceGateway.ajax.save_checkout_form.nonce,
@@ -73,13 +68,7 @@ const bootstrap = () => {
&& document.querySelector(PayPalCommerceGateway.messages.wrapper);
}
- const onSmartButtonClick = async (data, actions) => {
- window.ppcpFundingSource = data.fundingSource;
- const requiredFields = jQuery('form.woocommerce-checkout .validate-required:visible :input');
- requiredFields.each((i, input) => {
- jQuery(input).trigger('validate');
- });
-
+ const doBasicCheckoutValidation = () => {
if (PayPalCommerceGateway.basic_checkout_validation_enabled) {
// A quick fix to get the errors about empty form fields before attempting PayPal order,
// it should solve #513 for most of the users, but it is not a proper solution.
@@ -117,9 +106,26 @@ const bootstrap = () => {
errorHandler.message(PayPalCommerceGateway.labels.error.required.generic);
}
- return actions.reject();
+ return false;
}
}
+ return true;
+ };
+
+ const onCardFieldsBeforeSubmit = () => {
+ return doBasicCheckoutValidation();
+ };
+
+ const onSmartButtonClick = async (data, actions) => {
+ window.ppcpFundingSource = data.fundingSource;
+ const requiredFields = jQuery('form.woocommerce-checkout .validate-required:visible :input');
+ requiredFields.each((i, input) => {
+ jQuery(input).trigger('validate');
+ });
+
+ if (!doBasicCheckoutValidation()) {
+ return actions.reject();
+ }
const form = document.querySelector(checkoutFormSelector);
if (form) {
@@ -149,6 +155,12 @@ const bootstrap = () => {
jQuery(document).trigger('ppcp-smart-buttons-init', this);
buttonsSpinner.unblock();
};
+
+ let creditCardRenderer = new HostedFieldsRenderer(PayPalCommerceGateway, errorHandler, spinner);
+ if (typeof paypal.CardFields !== 'undefined') {
+ creditCardRenderer = new CardFieldsRenderer(PayPalCommerceGateway, errorHandler, spinner, onCardFieldsBeforeSubmit);
+ }
+
const renderer = new Renderer(creditCardRenderer, PayPalCommerceGateway, onSmartButtonClick, onSmartButtonsInit);
const messageRenderer = new MessageRenderer(PayPalCommerceGateway.messages);
diff --git a/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js b/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js
index 93ecf7c8f..75b5f9848 100644
--- a/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js
+++ b/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js
@@ -18,7 +18,7 @@ class CheckoutActionHandler {
try {
await validateCheckoutForm(this.config);
} catch (error) {
- throw {type: 'form-validation-error'};
+ throw { type: 'form-validation-error' };
}
return actions.subscription.create({
@@ -48,7 +48,13 @@ class CheckoutActionHandler {
configuration() {
const spinner = this.spinner;
- const createOrder = (data, actions) => {
+ const createOrder = async (data, actions) => {
+ try {
+ await validateCheckoutForm(this.config);
+ } catch (error) {
+ throw { type: 'form-validation-error' };
+ }
+
const payer = payerData();
const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ?
this.config.bn_codes[this.config.context] : '';
@@ -136,7 +142,7 @@ class CheckoutActionHandler {
console.error(err);
spinner.unblock();
- if (err && err.type === 'create-order-error') {
+ if (err && (err.type === 'create-order-error' || err.type === 'form-validation-error')) {
return;
}
diff --git a/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsRenderer.js b/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsRenderer.js
index 377568fcb..babb2b4fc 100644
--- a/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsRenderer.js
+++ b/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsRenderer.js
@@ -3,7 +3,7 @@ import {cardFieldStyles} from "../Helper/CardFieldsHelper";
class CardFieldsRenderer {
- constructor(defaultConfig, errorHandler, spinner) {
+ constructor(defaultConfig, errorHandler, spinner, onCardFieldsBeforeSubmit) {
this.defaultConfig = defaultConfig;
this.errorHandler = errorHandler;
this.spinner = spinner;
@@ -11,6 +11,7 @@ class CardFieldsRenderer {
this.formValid = false;
this.emptyFields = new Set(['number', 'cvv', 'expirationDate']);
this.currentHostedFieldsInstance = null;
+ this.onCardFieldsBeforeSubmit = onCardFieldsBeforeSubmit;
}
render(wrapper, contextConfig) {
@@ -110,10 +111,20 @@ class CardFieldsRenderer {
return;
}
+ if (typeof this.onCardFieldsBeforeSubmit === 'function' && !this.onCardFieldsBeforeSubmit()) {
+ this.spinner.unblock();
+ return;
+ }
+
cardField.submit()
.catch((error) => {
this.spinner.unblock();
console.error(error)
+
+ if (error.type === 'form-validation-error') {
+ return;
+ }
+
this.errorHandler.message(this.defaultConfig.hosted_fields.labels.fields_not_valid);
});
});
From 282d1a73e07ed296375b3c2d035189ed0e39f570 Mon Sep 17 00:00:00 2001
From: Pedro Silva
Date: Wed, 3 Jan 2024 11:13:01 +0000
Subject: [PATCH 2/3] Rollback button early validation and add support for
Credit Card Gateway.
---
.../js/modules/ActionHandler/CheckoutActionHandler.js | 10 ++--------
.../js/modules/Renderer/CardFieldsRenderer.js | 5 -----
.../ppcp-button/src/Endpoint/CreateOrderEndpoint.php | 2 +-
3 files changed, 3 insertions(+), 14 deletions(-)
diff --git a/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js b/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js
index 75b5f9848..da0ca7a4f 100644
--- a/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js
+++ b/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js
@@ -18,7 +18,7 @@ class CheckoutActionHandler {
try {
await validateCheckoutForm(this.config);
} catch (error) {
- throw { type: 'form-validation-error' };
+ throw {type: 'form-validation-error'};
}
return actions.subscription.create({
@@ -49,12 +49,6 @@ class CheckoutActionHandler {
configuration() {
const spinner = this.spinner;
const createOrder = async (data, actions) => {
- try {
- await validateCheckoutForm(this.config);
- } catch (error) {
- throw { type: 'form-validation-error' };
- }
-
const payer = payerData();
const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ?
this.config.bn_codes[this.config.context] : '';
@@ -142,7 +136,7 @@ class CheckoutActionHandler {
console.error(err);
spinner.unblock();
- if (err && (err.type === 'create-order-error' || err.type === 'form-validation-error')) {
+ if (err && (err.type === 'create-order-error')) {
return;
}
diff --git a/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsRenderer.js b/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsRenderer.js
index babb2b4fc..13f37cda0 100644
--- a/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsRenderer.js
+++ b/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsRenderer.js
@@ -120,11 +120,6 @@ class CardFieldsRenderer {
.catch((error) => {
this.spinner.unblock();
console.error(error)
-
- if (error.type === 'form-validation-error') {
- return;
- }
-
this.errorHandler.message(this.defaultConfig.hosted_fields.labels.fields_not_valid);
});
});
diff --git a/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php b/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php
index 2150b931f..ca34e59fb 100644
--- a/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php
+++ b/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php
@@ -294,7 +294,7 @@ class CreateOrderEndpoint implements EndpointInterface {
if ( $this->early_validation_enabled
&& $this->form
&& 'checkout' === $data['context']
- && in_array( $payment_method, array( PayPalGateway::ID, CardButtonGateway::ID ), true )
+ && in_array( $payment_method, array( PayPalGateway::ID, CardButtonGateway::ID, CreditCardGateway::ID ), true )
) {
$this->validate_form( $this->form );
}
From c2946b0516aed47f3a5aa8c5f9532860435c094b Mon Sep 17 00:00:00 2001
From: Pedro Silva
Date: Wed, 3 Jan 2024 11:18:30 +0000
Subject: [PATCH 3/3] Revert unneeded changes.
---
.../js/modules/ActionHandler/CheckoutActionHandler.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js b/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js
index da0ca7a4f..93ecf7c8f 100644
--- a/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js
+++ b/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js
@@ -48,7 +48,7 @@ class CheckoutActionHandler {
configuration() {
const spinner = this.spinner;
- const createOrder = async (data, actions) => {
+ const createOrder = (data, actions) => {
const payer = payerData();
const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ?
this.config.bn_codes[this.config.context] : '';
@@ -136,7 +136,7 @@ class CheckoutActionHandler {
console.error(err);
spinner.unblock();
- if (err && (err.type === 'create-order-error')) {
+ if (err && err.type === 'create-order-error') {
return;
}