From 31bd95487095f73ba5a8a0478f2a1abd3a808443 Mon Sep 17 00:00:00 2001 From: Alex P Date: Fri, 20 Aug 2021 17:13:37 +0300 Subject: [PATCH 1/8] Add 3d secure contingency settings --- modules/ppcp-wc-gateway/services.php | 47 +++++++++++++++++++ .../src/Settings/class-settingsrenderer.php | 41 ---------------- 2 files changed, 47 insertions(+), 41 deletions(-) diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index f072e347c..c05de6dcb 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -1804,6 +1804,53 @@ return array( ), 'gateway' => 'dcc', ), + '3d_secure_heading' => array( + 'heading' => __( '3D Secure', 'woocommerce-paypal-payments' ), + 'type' => 'ppcp-heading', + 'description' => wp_kses_post( + sprintf( + // translators: %1$s and %2$s is a link tag. + __( + '3D Secure benefits cardholders and merchants by providing + an additional layer of verification using Verified by Visa, + MasterCard SecureCode and American Express SafeKey. + %1$sLearn more about 3D Secure.%2$s', + 'woocommerce-paypal-payments' + ), + '', + '' + ) + ), + 'screens' => array( + State::STATE_ONBOARDED, + ), + 'requirements' => array( + 'dcc', + ), + 'gateway' => 'dcc', + ), + '3d_secure_contingency' => array( + 'title' => __( 'Contingency for 3D Secure', 'woocommerce-paypal-payments' ), + 'type' => 'select', + 'class' => array(), + 'input_class' => array( 'wc-enhanced-select' ), + 'default' => 'SCA_WHEN_REQUIRED', + 'desc_tip' => false, + 'options' => array( + 'SCA_WHEN_REQUIRED' => __( 'When required', 'woocommerce-paypal-payments' ), + '3D_SECURE' => __( 'Always', 'woocommerce-paypal-payments' ), + ), + 'screens' => array( + State::STATE_ONBOARDED, + ), + 'requirements' => array( + 'dcc', + ), + 'gateway' => 'dcc', + ), ); if ( ! defined( 'PPCP_FLAG_SUBSCRIPTION' ) || ! PPCP_FLAG_SUBSCRIPTION ) { unset( $fields['vault_enabled'] ); diff --git a/modules/ppcp-wc-gateway/src/Settings/class-settingsrenderer.php b/modules/ppcp-wc-gateway/src/Settings/class-settingsrenderer.php index b08533e05..f4e35499a 100644 --- a/modules/ppcp-wc-gateway/src/Settings/class-settingsrenderer.php +++ b/modules/ppcp-wc-gateway/src/Settings/class-settingsrenderer.php @@ -399,8 +399,6 @@ class SettingsRenderer { if ( $this->dcc_applies->for_country_currency() ) { if ( State::STATE_ONBOARDED > $this->state->current_state() ) { $this->render_dcc_onboarding_info(); - } elseif ( State::STATE_ONBOARDED === $this->state->current_state() && $this->dcc_product_status->dcc_is_active() ) { - $this->render_3d_secure_info(); } elseif ( ! $this->dcc_product_status->dcc_is_active() ) { $this->render_dcc_not_active_yet(); } @@ -450,45 +448,6 @@ class SettingsRenderer { - - - -

- ', - '' - ) - ); - ?> -

- - - Date: Fri, 20 Aug 2021 17:47:32 +0300 Subject: [PATCH 2/8] Send 3ds contingency in js --- .../js/modules/Renderer/CreditCardRenderer.js | 2 +- .../ppcp-button/src/Assets/class-smartbutton.php | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js b/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js index dc5035383..a4663ac29 100644 --- a/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js +++ b/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js @@ -104,7 +104,7 @@ class CreditCardRenderer { const vault = document.getElementById('ppcp-credit-card-vault') ? document.getElementById('ppcp-credit-card-vault').checked : save_card; hostedFields.submit({ - contingencies: ['SCA_WHEN_REQUIRED'], + contingencies: [this.defaultConfig.hosted_fields.contingency], vault: vault }).then((payload) => { payload.orderID = payload.orderId; diff --git a/modules/ppcp-button/src/Assets/class-smartbutton.php b/modules/ppcp-button/src/Assets/class-smartbutton.php index 5f3fc0244..a3585567d 100644 --- a/modules/ppcp-button/src/Assets/class-smartbutton.php +++ b/modules/ppcp-button/src/Assets/class-smartbutton.php @@ -601,6 +601,19 @@ class SmartButton implements SmartButtonInterface { return $this->subscription_helper->cart_contains_subscription(); } + /** + * Retrieves the 3D Secure contingency settings. + * + * @return string + */ + private function get_3ds_contingency(): string { + if ( $this->settings->has( '3d_secure_contingency' ) ) { + return $this->settings->get( '3d_secure_contingency' ); + } + + return 'SCA_WHEN_REQUIRED'; + } + /** * The localized data for the smart button. * @@ -677,6 +690,7 @@ class SmartButton implements SmartButtonInterface { ), ), 'valid_cards' => $this->dcc_applies->valid_cards(), + 'contingency' => $this->get_3ds_contingency(), ), 'messages' => $this->message_values(), 'labels' => array( From b988e08c660684bb5e43f2a6b8fbb7ecbe08d053 Mon Sep 17 00:00:00 2001 From: Alex P Date: Mon, 23 Aug 2021 12:27:12 +0300 Subject: [PATCH 3/8] Add "No 3DS" option --- .../js/modules/Renderer/CreditCardRenderer.js | 10 +++++++--- modules/ppcp-wc-gateway/services.php | 5 +++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js b/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js index a4663ac29..b65e033aa 100644 --- a/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js +++ b/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js @@ -103,10 +103,14 @@ class CreditCardRenderer { const save_card = this.defaultConfig.save_card ? true : false; const vault = document.getElementById('ppcp-credit-card-vault') ? document.getElementById('ppcp-credit-card-vault').checked : save_card; - hostedFields.submit({ - contingencies: [this.defaultConfig.hosted_fields.contingency], + const contingency = this.defaultConfig.hosted_fields.contingency; + const hostedFieldsData = { vault: vault - }).then((payload) => { + }; + if (contingency !== 'NO_3D_SECURE') { + hostedFieldsData.contingencies = [contingency]; + } + hostedFields.submit(hostedFieldsData).then((payload) => { payload.orderID = payload.orderId; this.spinner.unblock(); return contextConfig.onApprove(payload); diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index c05de6dcb..538363d32 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -1840,8 +1840,9 @@ return array( 'default' => 'SCA_WHEN_REQUIRED', 'desc_tip' => false, 'options' => array( - 'SCA_WHEN_REQUIRED' => __( 'When required', 'woocommerce-paypal-payments' ), - '3D_SECURE' => __( 'Always', 'woocommerce-paypal-payments' ), + 'NO_3D_SECURE' => __( 'No 3D Secure (transaction will be denied if 3D Secure is required)', 'woocommerce-paypal-payments' ), + 'SCA_WHEN_REQUIRED' => __( '3D Secure when required', 'woocommerce-paypal-payments' ), + '3D_SECURE' => __( 'Always trigger 3D Secure', 'woocommerce-paypal-payments' ), ), 'screens' => array( State::STATE_ONBOARDED, From ac482cc44d3382eb041d4123d9520598d4133a52 Mon Sep 17 00:00:00 2001 From: Alex P Date: Mon, 23 Aug 2021 18:39:07 +0300 Subject: [PATCH 4/8] Do not send payee email if have id --- modules/ppcp-api-client/src/Entity/class-payee.php | 6 +++--- .../ppcp-api-client/src/Factory/class-payeefactory.php | 9 ++------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/modules/ppcp-api-client/src/Entity/class-payee.php b/modules/ppcp-api-client/src/Entity/class-payee.php index a719b10be..c49f13dfb 100644 --- a/modules/ppcp-api-client/src/Entity/class-payee.php +++ b/modules/ppcp-api-client/src/Entity/class-payee.php @@ -68,11 +68,11 @@ class Payee { * @return array */ public function to_array(): array { - $data = array( - 'email_address' => $this->email(), - ); + $data = array(); if ( $this->merchant_id ) { $data['merchant_id'] = $this->merchant_id(); + } else { + $data['email_address'] = $this->email(); } return $data; } diff --git a/modules/ppcp-api-client/src/Factory/class-payeefactory.php b/modules/ppcp-api-client/src/Factory/class-payeefactory.php index ddd489e1d..bb89d07b0 100644 --- a/modules/ppcp-api-client/src/Factory/class-payeefactory.php +++ b/modules/ppcp-api-client/src/Factory/class-payeefactory.php @@ -26,13 +26,8 @@ class PayeeFactory { * @throws RuntimeException When JSON object is malformed. */ public function from_paypal_response( \stdClass $data ) { - if ( ! isset( $data->email_address ) ) { - throw new RuntimeException( - __( 'No email for payee given.', 'woocommerce-paypal-payments' ) - ); - } - + $email = ( isset( $data->email_address ) ) ? $data->email_address : ''; $merchant_id = ( isset( $data->merchant_id ) ) ? $data->merchant_id : ''; - return new Payee( $data->email_address, $merchant_id ); + return new Payee( $email, $merchant_id ); } } From 93cb005b4d805d825d73fc56d9a3e2b0ee00a371 Mon Sep 17 00:00:00 2001 From: Alex Pantechovskis Date: Tue, 31 Aug 2021 10:29:53 +0300 Subject: [PATCH 5/8] Remove travis We don't need it, GitHub Actions do the same and more. And it used PHP 7.0. --- .travis.yml | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 794e0b310..000000000 --- a/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -language: php -os: linux -dist: xenial - -notifications: - email: false - -php: - - 7.0 - -branches: - only: - - master - - trunk - - compat/ppxo - -script: | - CHANGED_FILES=`git diff --name-only --diff-filter=ACMR $TRAVIS_COMMIT_RANGE | grep \\\\.php | awk '{print}' ORS=' '` - - if [ "$CHANGED_FILES" != "" ]; then - composer global require woocommerce/woocommerce-sniffs --update-with-all-dependencies - $HOME/.config/composer/vendor/bin/phpcs -p $CHANGED_FILES - fi From 10d7574e22dd728fd5f01f0fa7946f3a9eb0ab42 Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 7 Sep 2021 17:55:39 +0300 Subject: [PATCH 6/8] Teardown hosted fields on re-render --- .../resources/js/modules/Renderer/CreditCardRenderer.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js b/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js index dc5035383..4fec241f1 100644 --- a/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js +++ b/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js @@ -8,6 +8,7 @@ class CreditCardRenderer { this.spinner = spinner; this.cardValid = false; this.formValid = false; + this.currentHostedFieldsInstance = null; } render(wrapper, contextConfig) { @@ -31,6 +32,12 @@ class CreditCardRenderer { return; } + if (this.currentHostedFieldsInstance) { + this.currentHostedFieldsInstance.teardown() + .catch(err => console.error(`Hosted fields teardown error: ${err}`)); + this.currentHostedFieldsInstance = null; + } + const gateWayBox = document.querySelector('.payment_box.payment_method_ppcp-credit-card-gateway'); const oldDisplayStyle = gateWayBox.style.display; gateWayBox.style.display = 'block'; @@ -92,6 +99,7 @@ class CreditCardRenderer { } } }).then(hostedFields => { + this.currentHostedFieldsInstance = hostedFields; const submitEvent = (event) => { this.spinner.block(); if (event) { From a41f678ac6c54a4272f6c6f50b43477c4fcafc65 Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 7 Sep 2021 17:58:17 +0300 Subject: [PATCH 7/8] Subscribe to form button click only once --- .../js/modules/Renderer/CreditCardRenderer.js | 76 ++++++++++--------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js b/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js index 4fec241f1..72b9756d3 100644 --- a/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js +++ b/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js @@ -9,6 +9,7 @@ class CreditCardRenderer { this.cardValid = false; this.formValid = false; this.currentHostedFieldsInstance = null; + this.formSubmissionSubscribed = false; } render(wrapper, contextConfig) { @@ -100,36 +101,9 @@ class CreditCardRenderer { } }).then(hostedFields => { this.currentHostedFieldsInstance = hostedFields; - const submitEvent = (event) => { - this.spinner.block(); - if (event) { - event.preventDefault(); - } - this.errorHandler.clear(); - if (this.formValid && this.cardValid) { - const save_card = this.defaultConfig.save_card ? true : false; - const vault = document.getElementById('ppcp-credit-card-vault') ? - document.getElementById('ppcp-credit-card-vault').checked : save_card; - hostedFields.submit({ - contingencies: ['SCA_WHEN_REQUIRED'], - vault: vault - }).then((payload) => { - payload.orderID = payload.orderId; - this.spinner.unblock(); - return contextConfig.onApprove(payload); - }).catch(() => { - this.errorHandler.genericError(); - this.spinner.unblock(); - }); - } else { - this.spinner.unblock(); - const message = ! this.cardValid ? this.defaultConfig.hosted_fields.labels.card_not_supported : this.defaultConfig.hosted_fields.labels.fields_not_valid; - this.errorHandler.message(message); - } - } - hostedFields.on('inputSubmitRequest', function () { - submitEvent(null); + hostedFields.on('inputSubmitRequest', () => { + this._submit(contextConfig); }); hostedFields.on('cardTypeChange', (event) => { if ( ! event.cards.length ) { @@ -145,11 +119,18 @@ class CreditCardRenderer { }); this.formValid = formValid; - }) - document.querySelector(wrapper + ' button').addEventListener( - 'click', - submitEvent - ); + }); + + if (!this.formSubmissionSubscribed) { + document.querySelector(wrapper + ' button').addEventListener( + 'click', + event => { + event.preventDefault(); + this._submit(contextConfig); + } + ); + this.formSubmissionSubscribed = true; + } }); document.querySelector('#payment_method_ppcp-credit-card-gateway').addEventListener( @@ -159,5 +140,32 @@ class CreditCardRenderer { } ) } + + _submit(contextConfig) { + this.spinner.block(); + this.errorHandler.clear(); + + if (this.formValid && this.cardValid) { + const save_card = this.defaultConfig.save_card ? true : false; + const vault = document.getElementById('ppcp-credit-card-vault') ? + document.getElementById('ppcp-credit-card-vault').checked : save_card; + this.currentHostedFieldsInstance.submit({ + contingencies: ['SCA_WHEN_REQUIRED'], + vault: vault + }).then((payload) => { + payload.orderID = payload.orderId; + this.spinner.unblock(); + return contextConfig.onApprove(payload); + }).catch(err => { + console.error(err); + this.errorHandler.genericError(); + this.spinner.unblock(); + }); + } else { + this.spinner.unblock(); + const message = ! this.cardValid ? this.defaultConfig.hosted_fields.labels.card_not_supported : this.defaultConfig.hosted_fields.labels.fields_not_valid; + this.errorHandler.message(message); + } + } } export default CreditCardRenderer; From 3580462efc101ba7ecd35469b6a2faa23f360f8a Mon Sep 17 00:00:00 2001 From: dinamiko Date: Wed, 8 Sep 2021 14:39:56 +0200 Subject: [PATCH 8/8] Add tooltip description --- modules/ppcp-wc-gateway/services.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 538363d32..2e8eee082 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -1835,10 +1835,18 @@ return array( '3d_secure_contingency' => array( 'title' => __( 'Contingency for 3D Secure', 'woocommerce-paypal-payments' ), 'type' => 'select', + 'description' => sprintf( + // translators: %1$s and %2$s opening and closing ul tag, %3$s and %4$s opening and closing li tag. + __( '%1$s%3$sNo 3D Secure will cause transactions to be denied if 3D Secure is required by the bank of the cardholder.%4$s%3$sSCA_WHEN_REQUIRED returns a 3D Secure contingency when it is a mandate in the region where you operate.%4$s%3$sSCA_ALWAYS triggers 3D Secure for every transaction, regardless of SCA requirements.%4$s%2$s', 'woocommerce-paypal-payments' ), + '
    ', + '
', + '
  • ', + '
  • ' + ), 'class' => array(), 'input_class' => array( 'wc-enhanced-select' ), 'default' => 'SCA_WHEN_REQUIRED', - 'desc_tip' => false, + 'desc_tip' => true, 'options' => array( 'NO_3D_SECURE' => __( 'No 3D Secure (transaction will be denied if 3D Secure is required)', 'woocommerce-paypal-payments' ), 'SCA_WHEN_REQUIRED' => __( '3D Secure when required', 'woocommerce-paypal-payments' ),