♻️ Move 3D Secure settings from Payment Methods to Settings tab

This commit is contained in:
Daniel Dudzic 2025-04-23 14:09:50 +02:00
parent a362780c8e
commit 6a904e1b1d
No known key found for this signature in database
GPG key ID: 31B40D33E3465483
11 changed files with 125 additions and 80 deletions

View file

@ -11,7 +11,6 @@ namespace WooCommerce\PayPalCommerce\Compat\Settings;
use WooCommerce\PayPalCommerce\Axo\Gateway\AxoGateway;
use WooCommerce\PayPalCommerce\Settings\Data\AbstractDataModel;
use WooCommerce\PayPalCommerce\Settings\Data\PaymentSettings;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
/**
@ -22,15 +21,6 @@ use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
*/
class PaymentMethodSettingsMapHelper {
/**
* A map of new to old 3d secure values.
*/
protected const THREE_D_SECURE_VALUES_MAP = array(
'no-3d-secure' => 'NO_3D_SECURE',
'only-required-3d-secure' => 'SCA_WHEN_REQUIRED',
'always-3d-secure' => 'SCA_ALWAYS',
);
/**
* Maps old setting keys to new payment method settings names.
*
@ -40,7 +30,6 @@ class PaymentMethodSettingsMapHelper {
return array(
'dcc_enabled' => CreditCardGateway::ID,
'axo_enabled' => AxoGateway::ID,
'3d_secure_contingency' => 'three_d_secure',
);
}
@ -52,17 +41,6 @@ class PaymentMethodSettingsMapHelper {
* @return mixed The value of the mapped setting, (null if not found).
*/
public function mapped_value( string $old_key, ?AbstractDataModel $payment_settings ) {
switch ( $old_key ) {
case '3d_secure_contingency':
if ( is_null( $payment_settings ) ) {
return null;
}
assert( $payment_settings instanceof PaymentSettings );
$selected_three_d_secure = $payment_settings->get_three_d_secure();
return self::THREE_D_SECURE_VALUES_MAP[ $selected_three_d_secure ] ?? null;
default:
$payment_method = $this->map()[ $old_key ] ?? false;
if ( ! $payment_method ) {
@ -71,7 +49,6 @@ class PaymentMethodSettingsMapHelper {
return $this->is_gateway_enabled( $payment_method );
}
}
/**
* Checks if the payment gateway with the given name is enabled.

View file

@ -23,6 +23,15 @@ class SettingsTabMapHelper {
use ContextTrait;
/**
* A map of new to old 3d secure values.
*/
protected const THREE_D_SECURE_VALUES_MAP = array(
'no-3d-secure' => 'NO_3D_SECURE',
'only-required-3d-secure' => 'SCA_WHEN_REQUIRED',
'always-3d-secure' => 'SCA_ALWAYS',
);
/**
* Maps old setting keys to new setting keys.
*
@ -43,6 +52,7 @@ class SettingsTabMapHelper {
'blocks_final_review_enabled' => 'enable_pay_now',
'logging_enabled' => 'enable_logging',
'vault_enabled' => 'save_paypal_and_venmo',
'3d_secure_contingency' => 'threeDSecure',
);
}
@ -69,11 +79,30 @@ class SettingsTabMapHelper {
case 'blocks_final_review_enabled':
return $this->mapped_pay_now_value( $settings_model );
case '3d_secure_contingency':
return $this->mapped_3d_secure_value( $settings_model );
default:
return $settings_model[ $new_key ] ?? null;
}
}
/**
* Retrieves the mapped value for the '3d_secure_contingency' from the new settings.
*
* @param array<string, scalar|array> $settings_model The new settings model data as an array.
* @return string|null The mapped '3d_secure_contingency' setting value.
*/
protected function mapped_3d_secure_value( array $settings_model ): ?string {
$three_d_secure = $settings_model['threeDSecure'] ?? null;
if ( is_null( $three_d_secure ) ) {
return null;
}
return self::THREE_D_SECURE_VALUES_MAP[ $three_d_secure ] ?? null;
}
/**
* Retrieves the mapped value for the 'mismatch_behavior' from the new settings.
*

View file

@ -12,12 +12,8 @@ import { PaymentHooks } from '../../../../../data';
const Modal = ( { method, setModalIsVisible, onSave } ) => {
const { all: paymentMethods } = PaymentHooks.usePaymentMethods();
const {
paypalShowLogo,
threeDSecure,
fastlaneCardholderName,
fastlaneDisplayWatermark,
} = PaymentHooks.usePaymentMethodsModal();
const { paypalShowLogo, fastlaneCardholderName, fastlaneDisplayWatermark } =
PaymentHooks.usePaymentMethodsModal();
const [ settings, setSettings ] = useState( () => {
if ( ! method?.id ) {
@ -44,7 +40,6 @@ const Modal = ( { method, setModalIsVisible, onSave } ) => {
} );
initialSettings.paypalShowLogo = paypalShowLogo;
initialSettings.threeDSecure = threeDSecure;
initialSettings.fastlaneCardholderName = fastlaneCardholderName;
initialSettings.fastlaneDisplayWatermark = fastlaneDisplayWatermark;

View file

@ -2,11 +2,15 @@ import { __ } from '@wordpress/i18n';
import Accordion from '../../../../../ReusableComponents/AccordionSection';
import SettingsBlock from '../../../../../ReusableComponents/SettingsBlock';
import { ControlSelect } from '../../../../../ReusableComponents/Controls';
import {
ControlSelect,
ControlRadioGroup,
} from '../../../../../ReusableComponents/Controls';
import { SettingsHooks } from '../../../../../../data';
const OtherSettings = () => {
const { disabledCards, setDisabledCards } = SettingsHooks.useSettings();
const { disabledCards, setDisabledCards, threeDSecure, setThreeDSecure } =
SettingsHooks.useSettings();
return (
<Accordion
@ -40,12 +44,24 @@ const OtherSettings = () => {
) }
/>
</SettingsBlock>
<SettingsBlock
title={ __( '3D Secure', 'woocommerce-paypal-payments' ) }
description={ __(
'Authenticate cardholders through their card issuers to reduce fraud and improve transaction security. Successful 3D Secure authentication can shift liability for fraudulent chargebacks to the card issuer.',
'woocommerce-paypal-payments'
) }
>
<ControlRadioGroup
options={ threeDSecureOptions }
value={ threeDSecure }
onChange={ setThreeDSecure }
/>
</SettingsBlock>
</Accordion>
);
};
export default OtherSettings;
const disabledCardChoices = [
{ value: '', label: __( 'Select', 'woocommerce-paypal-payments' ) },
{
@ -63,3 +79,32 @@ const disabledCardChoices = [
label: __( 'Diners Club', 'woocommerce-paypal-payments' ),
},
];
const threeDSecureOptions = [
{
value: 'no-3d-secure',
label: __( 'No 3D Secure', 'woocommerce-paypal-payments' ),
description: __(
'Do not use 3D Secure authentication for any transactions.',
'woocommerce-paypal-payments'
),
},
{
value: 'only-required-3d-secure',
label: __( 'Only when required', 'woocommerce-paypal-payments' ),
description: __(
'Use 3D Secure when required by the card issuer or payment processor.',
'woocommerce-paypal-payments'
),
},
{
value: 'always-3d-secure',
label: __( 'Always require 3D Secure', 'woocommerce-paypal-payments' ),
description: __(
'Always authenticate transactions with 3D Secure when available.',
'woocommerce-paypal-payments'
),
},
];
export default OtherSettings;

View file

@ -129,7 +129,6 @@ export const usePaymentMethodsModal = () => {
const { usePersistent } = useStoreData();
const [ paypalShowLogo ] = usePersistent( 'paypalShowLogo' );
const [ threeDSecure ] = usePersistent( 'threeDSecure' );
const [ fastlaneCardholderName ] = usePersistent(
'fastlaneCardholderName'
);
@ -139,7 +138,6 @@ export const usePaymentMethodsModal = () => {
return {
paypalShowLogo,
threeDSecure,
fastlaneCardholderName,
fastlaneDisplayWatermark,
};

View file

@ -67,6 +67,8 @@ const useHooks = () => {
const [ disabledCards, setDisabledCards ] =
usePersistent( 'disabledCards' );
const [ threeDSecure, setThreeDSecure ] = usePersistent( 'threeDSecure' );
return {
invoicePrefix,
setInvoicePrefix,
@ -94,6 +96,8 @@ const useHooks = () => {
setButtonLanguage,
disabledCards,
setDisabledCards,
threeDSecure,
setThreeDSecure,
};
};
@ -138,6 +142,8 @@ export const useSettings = () => {
setButtonLanguage,
disabledCards,
setDisabledCards,
threeDSecure,
setThreeDSecure,
} = useHooks();
return {
@ -167,5 +173,7 @@ export const useSettings = () => {
setButtonLanguage,
disabledCards,
setDisabledCards,
threeDSecure,
setThreeDSecure,
};
};

View file

@ -34,6 +34,7 @@ const defaultPersistent = Object.freeze( {
subtotalAdjustment: 'no_details', // [correction|no_details] Handling for subtotal mismatches
landingPage: 'any', // [any|login|guest_checkout] PayPal checkout landing page
buttonLanguage: '', // Language for PayPal buttons
threeDSecure: 'only-required-3d-secure', // [no-3d-secure|only-required-3d-secure|always-3d-secure] 3D Secure settings
// Boolean flags.
authorizeOnly: false, // Whether to only authorize payments initially

View file

@ -240,40 +240,7 @@ class PaymentMethodsDefinition {
'title' => __( 'Advanced Credit and Debit Card Payments', 'woocommerce-paypal-payments' ),
'description' => __( "Present custom credit and debit card fields to your payers so they can pay with credit and debit cards using your site's branding.", 'woocommerce-paypal-payments' ),
'icon' => 'payment-method-advanced-cards',
'fields' => array(
'threeDSecure' => array(
'type' => 'radio',
'default' => $this->settings->get_three_d_secure(),
'label' => __( '3D Secure', 'woocommerce-paypal-payments' ),
'description' => __(
'Authenticate cardholders through their card issuers to reduce fraud and improve transaction security. Successful 3D Secure authentication can shift liability for fraudulent chargebacks to the card issuer.',
'woocommerce-paypal-payments'
),
'options' => array(
array(
'label' => __(
'No 3D Secure',
'woocommerce-paypal-payments'
),
'value' => 'no-3d-secure',
),
array(
'label' => __(
'Only when required',
'woocommerce-paypal-payments'
),
'value' => 'only-required-3d-secure',
),
array(
'label' => __(
'Always require 3D Secure',
'woocommerce-paypal-payments'
),
'value' => 'always-3d-secure',
),
),
),
),
'fields' => array(),
);
$group[] = array(
'id' => AxoGateway::ID,

View file

@ -40,6 +40,13 @@ class SettingsModel extends AbstractDataModel {
*/
public const LANDING_PAGE_OPTIONS = array( 'any', 'login', 'guest_checkout' );
/**
* Valid options for 3D Secure.
*
* @var array
*/
public const THREE_D_SECURE_OPTIONS = array( 'no-3d-secure', 'only-required-3d-secure', 'always-3d-secure' );
/**
* Data sanitizer service.
*
@ -74,6 +81,7 @@ class SettingsModel extends AbstractDataModel {
'subtotal_adjustment' => 'correction', // Options: [correction|no_details].
'landing_page' => 'any', // Options: [any|login|guest_checkout].
'button_language' => '', // empty or a language locale code.
'three_d_secure' => 'only-required-3d-secure', // Options: [no-3d-secure|only-required-3d-secure|always-3d-secure].
// Boolean flags.
'authorize_only' => false,
@ -199,6 +207,24 @@ class SettingsModel extends AbstractDataModel {
$this->data['button_language'] = $this->sanitizer->sanitize_text( $language );
}
/**
* Gets the 3D Secure setting.
*
* @return string The 3D Secure setting.
*/
public function get_three_d_secure() : string {
return $this->data['three_d_secure'];
}
/**
* Sets the 3D Secure setting.
*
* @param string $setting The 3D Secure setting to set.
*/
public function set_three_d_secure( string $setting ) : void {
$this->data['three_d_secure'] = $this->sanitizer->sanitize_enum( $setting, self::THREE_D_SECURE_OPTIONS );
}
/**
* Gets the authorize only setting.
*

View file

@ -77,10 +77,6 @@ class PaymentRestEndpoint extends RestEndpoint {
'js_name' => 'paypalShowLogo',
'sanitize' => 'to_boolean',
),
'three_d_secure' => array(
'js_name' => 'threeDSecure',
'sanitize' => 'sanitize_text_field',
),
'fastlane_cardholder_name' => array(
'js_name' => 'fastlaneCardholderName',
'sanitize' => 'to_boolean',
@ -203,7 +199,6 @@ class PaymentRestEndpoint extends RestEndpoint {
}
$gateway_settings['paypalShowLogo'] = $this->payment_settings->get_paypal_show_logo();
$gateway_settings['threeDSecure'] = $this->payment_settings->get_three_d_secure();
$gateway_settings['fastlaneCardholderName'] = $this->payment_settings->get_fastlane_cardholder_name();
$gateway_settings['fastlaneDisplayWatermark'] = $this->payment_settings->get_fastlane_display_watermark();

View file

@ -89,6 +89,10 @@ class SettingsRestEndpoint extends RestEndpoint {
'disabled_cards' => array(
'js_name' => 'disabledCards',
),
'three_d_secure' => array(
'js_name' => 'threeDSecure',
'sanitize' => 'sanitize_text_field',
),
);
/**