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 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 ); } } diff --git a/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js b/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js index dc5035383..d506fadce 100644 --- a/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js +++ b/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js @@ -8,6 +8,8 @@ class CreditCardRenderer { this.spinner = spinner; this.cardValid = false; this.formValid = false; + this.currentHostedFieldsInstance = null; + this.formSubmissionSubscribed = false; } render(wrapper, contextConfig) { @@ -31,6 +33,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,36 +100,10 @@ class CreditCardRenderer { } } }).then(hostedFields => { - const submitEvent = (event) => { - this.spinner.block(); - if (event) { - event.preventDefault(); - } - this.errorHandler.clear(); + this.currentHostedFieldsInstance = hostedFields; - 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 ) { @@ -137,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( @@ -151,5 +140,36 @@ 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; + const contingency = this.defaultConfig.hosted_fields.contingency; + const hostedFieldsData = { + vault: vault + }; + if (contingency !== 'NO_3D_SECURE') { + hostedFieldsData.contingencies = [contingency]; + } + this.currentHostedFieldsInstance.submit(hostedFieldsData).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; 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( diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 428caf750..077062d6b 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -1846,6 +1846,62 @@ 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', + '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' => 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' ), + '3D_SECURE' => __( 'Always trigger 3D Secure', '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 a08591379..690c5d91f 100644 --- a/modules/ppcp-wc-gateway/src/Settings/class-settingsrenderer.php +++ b/modules/ppcp-wc-gateway/src/Settings/class-settingsrenderer.php @@ -394,8 +394,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(); } @@ -445,45 +443,6 @@ class SettingsRenderer { - - - -

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

    - - -