diff --git a/changelog.txt b/changelog.txt index 364a4cc015..1941e1ab3e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,6 +1,7 @@ *** Changelog *** = 9.9.0 - xxxx-xx-xx = +* Fix - Removes the credit card payment method requirement for the Optimized Checkout feature * Fix - Payment method test instructions not showing up for the Optimized Checkout payment element * Add - Includes a new notice to highlight the Optimized Checkout feature above the payment methods list in the Stripe settings page * Update - Increases the default font size for the Optimized Checkout payment element to match the rest of the checkout form diff --git a/client/blocks/upe/index.js b/client/blocks/upe/index.js index 12f8a438f6..96936280d7 100644 --- a/client/blocks/upe/index.js +++ b/client/blocks/upe/index.js @@ -5,7 +5,6 @@ import { import { PAYMENT_METHOD_AFFIRM, PAYMENT_METHOD_AMAZON_PAY, - PAYMENT_METHOD_CARD, PAYMENT_METHOD_GIROPAY, PAYMENT_METHOD_KLARNA, PAYMENT_METHOD_LINK, @@ -40,32 +39,25 @@ const api = new WCStripeAPI( const paymentMethodsConfig = getBlocksConfiguration()?.paymentMethodsConfig ?? {}; -// Register UPE Elements. -if ( getBlocksConfiguration()?.isOCEnabled ) { - registerPaymentMethod( - upeElement( PAYMENT_METHOD_CARD, api, paymentMethodsConfig.card ) - ); -} else { - const methodsToFilter = [ - PAYMENT_METHOD_AMAZON_PAY, - PAYMENT_METHOD_LINK, - PAYMENT_METHOD_GIROPAY, // Skip giropay as it was deprecated by Jun, 30th 2024. - ]; - - // Filter out some BNPLs when other official extensions are present. - if ( getBlocksConfiguration()?.hasAffirmGatewayPlugin ) { - methodsToFilter.push( PAYMENT_METHOD_AFFIRM ); - } - if ( getBlocksConfiguration()?.hasKlarnaGatewayPlugin ) { - methodsToFilter.push( PAYMENT_METHOD_KLARNA ); - } +const methodsToFilter = [ + PAYMENT_METHOD_AMAZON_PAY, + PAYMENT_METHOD_LINK, + PAYMENT_METHOD_GIROPAY, // Skip giropay as it was deprecated by Jun, 30th 2024. +]; - Object.entries( paymentMethodsConfig ) - .filter( ( [ method ] ) => ! methodsToFilter.includes( method ) ) - .forEach( ( [ method, config ] ) => { - registerPaymentMethod( upeElement( method, api, config ) ); - } ); +// Filter out some BNPLs when other official extensions are present. +if ( getBlocksConfiguration()?.hasAffirmGatewayPlugin ) { + methodsToFilter.push( PAYMENT_METHOD_AFFIRM ); } +if ( getBlocksConfiguration()?.hasKlarnaGatewayPlugin ) { + methodsToFilter.push( PAYMENT_METHOD_KLARNA ); +} + +Object.entries( paymentMethodsConfig ) + .filter( ( [ method ] ) => ! methodsToFilter.includes( method ) ) + .forEach( ( [ method, config ] ) => { + registerPaymentMethod( upeElement( method, api, config ) ); + } ); if ( getBlocksConfiguration()?.isECEEnabled ) { // Register Express Checkout Elements. diff --git a/client/blocks/upe/upe-element.js b/client/blocks/upe/upe-element.js index a75ebb79ce..bb9c841807 100644 --- a/client/blocks/upe/upe-element.js +++ b/client/blocks/upe/upe-element.js @@ -6,6 +6,8 @@ import { PAYMENT_METHOD_AFTERPAY_CLEARPAY, PAYMENT_METHOD_CLEARPAY, PAYMENT_METHOD_BACS, + PAYMENT_METHOD_CARD, + EXPRESS_PAYMENT_METHODS, } from 'wcstripe/stripe-utils/constants'; import { getBlocksConfiguration } from 'wcstripe/blocks/utils'; import Icons from 'wcstripe/payment-method-icons'; @@ -78,6 +80,18 @@ export const upeElement = ( paymentMethod, api, upeConfig ) => { return false; } + const nonExpressPaymentMethods = upeConfig?.enabledPaymentMethods.filter( + ( method ) => ! EXPRESS_PAYMENT_METHODS.includes( method ) + ); + + if ( + paymentMethod === PAYMENT_METHOD_CARD && + getBlocksConfiguration()?.isOCEnabled && + nonExpressPaymentMethods.length === 0 + ) { + return false; + } + return isAvailableInTheCountry && !! api.getStripe(); }, // see .wc-block-checkout__payment-method styles in blocks/style.scss diff --git a/client/components/payment-method-required-for-oc-pill/__tests__/index.test.js b/client/components/payment-method-required-for-oc-pill/__tests__/index.test.js deleted file mode 100644 index 7e0ce41e9a..0000000000 --- a/client/components/payment-method-required-for-oc-pill/__tests__/index.test.js +++ /dev/null @@ -1,40 +0,0 @@ -import React from 'react'; -import { screen, render } from '@testing-library/react'; -import PaymentMethodRequiredForOCPill from '..'; -import { PAYMENT_METHOD_CARD } from 'wcstripe/stripe-utils/constants'; -import { useIsOCEnabled } from 'wcstripe/data'; - -jest.mock( 'wcstripe/data', () => ( { - useIsOCEnabled: jest.fn(), -} ) ); - -describe( 'PaymentMethodRequiredForOCPill', () => { - beforeEach( () => { - useIsOCEnabled.mockReturnValue( [ false, jest.fn() ] ); - } ); - - it( 'should render the "Required for the Optimized Checkout Suite" text', () => { - useIsOCEnabled.mockReturnValue( [ true, jest.fn() ] ); - global.wc_stripe_settings_params = { is_oc_enabled: true }; - - render( - - ); - - expect( screen.queryByText( 'Required' ) ).toBeInTheDocument(); - } ); - - it( 'should not render when OC is not active', () => { - const { container } = render( - - ); - - expect( container.firstChild ).toBeNull(); - } ); -} ); diff --git a/client/components/payment-method-required-for-oc-pill/index.js b/client/components/payment-method-required-for-oc-pill/index.js deleted file mode 100644 index 1ba3c6fe66..0000000000 --- a/client/components/payment-method-required-for-oc-pill/index.js +++ /dev/null @@ -1,87 +0,0 @@ -import { __, sprintf } from '@wordpress/i18n'; -import React from 'react'; -import styled from '@emotion/styled'; -import interpolateComponents from 'interpolate-components'; -import { Icon, info } from '@wordpress/icons'; -import Popover from 'wcstripe/components/popover'; -import { PAYMENT_METHOD_CARD } from 'wcstripe/stripe-utils/constants'; -import { useIsOCEnabled } from 'wcstripe/data'; - -const StyledPill = styled.span` - display: inline-flex; - align-items: center; - gap: 4px; - padding: 4px 8px; - border: 1px solid #fcf9e8; - border-radius: 2px; - background-color: #fcf9e8; - color: #674600; - font-size: 12px; - font-weight: 400; - line-height: 16px; - width: fit-content; -`; - -const StyledLink = styled.a` - &:focus, - &:visited { - box-shadow: none; - } -`; - -const IconWrapper = styled.span` - height: 16px; - cursor: pointer; -`; - -const AlertIcon = styled( Icon )` - fill: #674600; -`; - -const IconComponent = ( { children, ...props } ) => ( - - - { children } - -); - -const PaymentMethodRequiredForOCPill = ( { id, label } ) => { - const [ isOCEnabled ] = useIsOCEnabled(); - if ( id === PAYMENT_METHOD_CARD && isOCEnabled ) { - return ( - - { __( 'Required', 'woocommerce-gateway-stripe' ) } - { - // Stop propagation is necessary so it doesn't trigger the tooltip click event. - ev.stopPropagation(); - } } - /> - ), - }, - } ) } - /> - - ); - } - - return null; -}; - -export default PaymentMethodRequiredForOCPill; diff --git a/client/settings/general-settings-section/payment-method-checkbox.js b/client/settings/general-settings-section/payment-method-checkbox.js index 5c48ff712a..7d9e4404b1 100644 --- a/client/settings/general-settings-section/payment-method-checkbox.js +++ b/client/settings/general-settings-section/payment-method-checkbox.js @@ -33,7 +33,6 @@ const PaymentMethodCheckbox = ( { label, isAllowingManualCapture, disabled, - disabledButChecked, } ) => { const [ isManualCaptureEnabled ] = useManualCapture(); const [ isConfirmationModalOpen, setIsConfirmationModalOpen ] = useState( @@ -45,12 +44,10 @@ const PaymentMethodCheckbox = ( { ] = useEnabledPaymentMethodIds(); const [ , setIsStripeEnabled ] = useIsStripeEnabled(); const { isUpeEnabled } = useContext( UpeToggleContext ); - const checked = - ! disabled && - ( disabledButChecked || enabledPaymentMethods.includes( id ) ); + const checked = ! disabled && enabledPaymentMethods.includes( id ); const handleCheckboxChange = ( hasBeenChecked ) => { - if ( disabled || disabledButChecked ) { + if ( disabled ) { return; } if ( ! hasBeenChecked ) { @@ -113,7 +110,7 @@ const PaymentMethodCheckbox = ( { label={ { label } } onChange={ handleCheckboxChange } checked={ checked } - disabled={ disabled || disabledButChecked } + disabled={ disabled } /> ) } { isConfirmationModalOpen && ( diff --git a/client/settings/general-settings-section/payment-method-description.js b/client/settings/general-settings-section/payment-method-description.js index 026b603a87..42582b0132 100644 --- a/client/settings/general-settings-section/payment-method-description.js +++ b/client/settings/general-settings-section/payment-method-description.js @@ -5,7 +5,6 @@ import RecurringPaymentIcon from '../../components/recurring-payment-icon'; import PaymentMethodCapabilityStatusPill from 'wcstripe/components/payment-method-capability-status-pill'; import PaymentMethodDeprecationPill from 'wcstripe/components/payment-method-deprecation-pill'; import PaymentMethodUnavailableDueConflictPill from 'wcstripe/components/payment-method-unavailable-due-conflict-pill'; -import PaymentMethodRequiredForOCPill from 'wcstripe/components/payment-method-required-for-oc-pill'; const Wrapper = styled.div` display: flex; @@ -75,10 +74,6 @@ const PaymentMethodDescription = ( { id={ id } label={ label } /> - ) } diff --git a/client/settings/general-settings-section/payment-method.js b/client/settings/general-settings-section/payment-method.js index e511c9ffde..eccb367ac2 100644 --- a/client/settings/general-settings-section/payment-method.js +++ b/client/settings/general-settings-section/payment-method.js @@ -7,7 +7,7 @@ import interpolateComponents from 'interpolate-components'; import PaymentMethodsMap from '../../payment-methods-map'; import PaymentMethodDescription from './payment-method-description'; import PaymentMethodCheckbox from './payment-method-checkbox'; -import { useIsOCEnabled, useManualCapture } from 'wcstripe/data'; +import { useManualCapture } from 'wcstripe/data'; import { PAYMENT_METHOD_AFFIRM, PAYMENT_METHOD_AFTERPAY_CLEARPAY, @@ -105,7 +105,6 @@ const StyledFees = styled( PaymentMethodFeesPill )` `; const PaymentMethod = ( { method, data } ) => { - const [ isOCEnabled ] = useIsOCEnabled(); const [ isManualCaptureEnabled ] = useManualCapture(); const paymentMethodCurrencies = usePaymentMethodCurrencies( method ); @@ -138,8 +137,6 @@ const PaymentMethod = ( { method, data } ) => { // eslint-disable-next-line camelcase wc_stripe_settings_params.has_klarna_gateway_plugin ); - const isDisabledButChecked = PAYMENT_METHOD_CARD === method && isOCEnabled; - return (
{ label={ label } isAllowingManualCapture={ isAllowingManualCapture } disabled={ deprecated || isDisabled } - disabledButChecked={ isDisabledButChecked } /> get_upe_enabled_payment_method_ids(); // Check for BNPLs that should be deactivated. @@ -892,22 +890,10 @@ public function maybe_toggle_payment_methods() { $this->maybe_deactivate_amazon_pay( $enabled_payment_methods ) ); - // Check if cards should be activated. - // TODO: Remove this once card is not a requirement for the Optimized Checkout. - if ( $gateway->is_oc_enabled() - && ! in_array( WC_Stripe_Payment_Methods::CARD, $enabled_payment_methods, true ) ) { - $payment_method_ids_to_enable[] = WC_Stripe_Payment_Methods::CARD; - } - - if ( [] === $payment_method_ids_to_disable && [] === $payment_method_ids_to_enable ) { + if ( [] === $payment_method_ids_to_disable ) { return; } - $enabled_payment_methods = array_merge( - $enabled_payment_methods, - $payment_method_ids_to_enable - ); - $gateway->update_enabled_payment_methods( array_diff( $enabled_payment_methods, $payment_method_ids_to_disable ) ); diff --git a/includes/constants/class-wc-stripe-payment-methods.php b/includes/constants/class-wc-stripe-payment-methods.php index e6cdf63d7e..f2b38e83ad 100644 --- a/includes/constants/class-wc-stripe-payment-methods.php +++ b/includes/constants/class-wc-stripe-payment-methods.php @@ -47,6 +47,18 @@ class WC_Stripe_Payment_Methods { const LINK_LABEL = 'Link'; const PAYMENT_REQUEST_LABEL = 'Payment Request'; + /** + * Payment methods that are considered as express payment methods. + * + * @var array + */ + const EXPRESS_PAYMENT_METHODS = [ + self::AMAZON_PAY, + self::GOOGLE_PAY, + self::APPLE_PAY, + self::LINK, + ]; + /** * Payment methods that are considered as voucher payment methods. * @@ -79,13 +91,6 @@ class WC_Stripe_Payment_Methods { self::WECHAT_PAY, ]; - const EXPRESS_PAYMENT_METHODS = [ - self::AMAZON_PAY, - self::APPLE_PAY, - self::GOOGLE_PAY, - self::LINK, - ]; - /** * List of express payment methods labels. Amazon Pay and Link are not included, * as they have their own payment method classes. diff --git a/includes/payment-methods/class-wc-stripe-upe-payment-gateway.php b/includes/payment-methods/class-wc-stripe-upe-payment-gateway.php index d8a56e3c41..672e7f933c 100644 --- a/includes/payment-methods/class-wc-stripe-upe-payment-gateway.php +++ b/includes/payment-methods/class-wc-stripe-upe-payment-gateway.php @@ -603,9 +603,20 @@ public function javascript_params() { * @return array */ private function get_enabled_payment_method_config() { - $settings = []; + $settings = []; + $enabled_payment_methods = $this->get_upe_enabled_at_checkout_payment_method_ids(); + // If the Optimized Checkout is enabled, we need to return just the card payment method + express methods. + // All payment methods are rendered inside the card container. + if ( $this->oc_enabled ) { + $enabled_express_methods = array_intersect( + $enabled_payment_methods, + WC_Stripe_Payment_Methods::EXPRESS_PAYMENT_METHODS + ); + $enabled_payment_methods = array_merge( [ WC_Stripe_UPE_Payment_Method_CC::STRIPE_ID ], $enabled_express_methods ); + } + foreach ( $enabled_payment_methods as $payment_method_id ) { $payment_method = $this->payment_methods[ $payment_method_id ]; @@ -617,6 +628,7 @@ private function get_enabled_payment_method_config() { 'showSaveOption' => $this->should_upe_payment_method_show_save_option( $payment_method ), 'supportsDeferredIntent' => $payment_method->supports_deferred_intent(), 'countries' => $payment_method->get_available_billing_countries(), + 'enabledPaymentMethods' => $this->get_upe_enabled_payment_method_ids(), // For the Optimized Checkout. ]; } diff --git a/includes/payment-methods/class-wc-stripe-upe-payment-method.php b/includes/payment-methods/class-wc-stripe-upe-payment-method.php index d74a1f4510..fa650dfd09 100644 --- a/includes/payment-methods/class-wc-stripe-upe-payment-method.php +++ b/includes/payment-methods/class-wc-stripe-upe-payment-method.php @@ -175,7 +175,9 @@ public function get_id() { * @return bool */ public function is_enabled() { - return 'yes' === $this->enabled; + return 'yes' === $this->enabled + // When OC is enabled, we use the card payment container to render all the methods. + || ( $this->oc_enabled && WC_Stripe_Payment_Methods::CARD === $this->stripe_id ); } /** @@ -185,8 +187,8 @@ public function is_enabled() { */ public function is_available() { // When OC is enabled, we use the card payment container to render all the methods. - if ( $this->oc_enabled && WC_Stripe_Payment_Methods::CARD !== $this->stripe_id ) { - return false; + if ( $this->oc_enabled ) { + return WC_Stripe_Payment_Methods::CARD === $this->stripe_id; } if ( is_add_payment_method_page() && ! $this->is_reusable() ) { diff --git a/readme.txt b/readme.txt index 1aaca7d45d..4ec547d252 100644 --- a/readme.txt +++ b/readme.txt @@ -111,6 +111,7 @@ If you get stuck, you can ask for help in the [Plugin Forum](https://wordpress.o == Changelog == = 9.9.0 - xxxx-xx-xx = +* Fix - Removes the credit card payment method requirement for the Optimized Checkout feature * Fix - Payment method test instructions not showing up for the Optimized Checkout payment element * Add - Includes a new notice to highlight the Optimized Checkout feature above the payment methods list in the Stripe settings page * Update - Increases the default font size for the Optimized Checkout payment element to match the rest of the checkout form diff --git a/tests/phpunit/PaymentMethods/WC_Stripe_UPE_Payment_Gateway_Test.php b/tests/phpunit/PaymentMethods/WC_Stripe_UPE_Payment_Gateway_Test.php index bdab855db0..7501b9a9de 100644 --- a/tests/phpunit/PaymentMethods/WC_Stripe_UPE_Payment_Gateway_Test.php +++ b/tests/phpunit/PaymentMethods/WC_Stripe_UPE_Payment_Gateway_Test.php @@ -315,15 +315,6 @@ public function test_get_upe_available_payment_methods( $country, $available_pay $this->assertSame( $available_payment_methods, $this->mock_gateway->get_upe_available_payment_methods(), "Available payment methods are not the same for $country" ); } - public function test_get_upe_enabled_at_checkout_payment_method_ids() { - $available_payment_methods = [ - WC_Stripe_UPE_Payment_Method_CC::STRIPE_ID, - WC_Stripe_UPE_Payment_Method_Link::STRIPE_ID, - ]; - $this->mock_payment_method_configurations( $available_payment_methods ); - $this->assertSame( $available_payment_methods, $this->mock_gateway->get_upe_enabled_at_checkout_payment_method_ids() ); - } - public function get_upe_available_payment_methods_provider() { return [ [ @@ -389,6 +380,61 @@ public function get_upe_available_payment_methods_provider() { ]; } + /** + * Tests for `get_upe_enabled_at_checkout_payment_method_ids`. + * + * @param array $available_methods The available payment methods. + * @param bool $oc_enabled Whether the OC feature is enabled. + * @param array $expected The expected payment method IDs. + * @return void + * + * @dataProvider provide_test_get_upe_enabled_at_checkout_payment_method_ids + */ + public function test_get_upe_enabled_at_checkout_payment_method_ids( $available_methods, $oc_enabled, $expected ) { + $this->mock_gateway->oc_enabled = $oc_enabled; + + $this->mock_payment_method_configurations( $available_methods ); + + $actual = $this->mock_gateway->get_upe_enabled_at_checkout_payment_method_ids(); + + // Clean up. + $this->mock_gateway->oc_enabled = false; + + $this->assertSame( $expected, $actual ); + } + + /** + * Data provider for `test_get_upe_enabled_at_checkout_payment_method_ids`. + * + * @return array[] + */ + public function provide_test_get_upe_enabled_at_checkout_payment_method_ids() { + return [ + 'Default' => [ + 'available methods' => [ + WC_Stripe_UPE_Payment_Method_CC::STRIPE_ID, + WC_Stripe_UPE_Payment_Method_Link::STRIPE_ID, + ], + 'OC enabled' => false, + 'expected' => [ + WC_Stripe_UPE_Payment_Method_CC::STRIPE_ID, + WC_Stripe_UPE_Payment_Method_Link::STRIPE_ID, + ], + ], + 'OC enabled' => [ + 'available methods (ignored)' => [ + WC_Stripe_UPE_Payment_Method_CC::STRIPE_ID, + WC_Stripe_UPE_Payment_Method_Link::STRIPE_ID, + ], + 'OC enabled' => true, + 'expected' => [ + WC_Stripe_UPE_Payment_Method_CC::STRIPE_ID, + WC_Stripe_UPE_Payment_Method_Link::STRIPE_ID, + ], + ], + ]; + } + /** * CLASSIC CHECKOUT TESTS. */ diff --git a/tests/phpunit/WC_Stripe_Test.php b/tests/phpunit/WC_Stripe_Test.php index ae2e45c6c7..e4d072c8d3 100644 --- a/tests/phpunit/WC_Stripe_Test.php +++ b/tests/phpunit/WC_Stripe_Test.php @@ -29,7 +29,6 @@ public function test_constants_defined() { * * @param array $active_gateways The active payment gateways. * @param array $enabled_payment_method_ids The enabled payment method IDs. - * @param bool $oc_enabled Whether the one-click payment methods are enabled. * @param int $update_enable_payment_methods_calls The number of times `update_enabled_payment_methods` should be called. * @return void * @@ -38,7 +37,6 @@ public function test_constants_defined() { public function test_maybe_toggle_payment_methods( $active_gateways, $enabled_payment_method_ids, - $oc_enabled, $update_enable_payment_methods_calls ) { $original_payment_gateways = WC()->payment_gateways->payment_gateways; @@ -50,10 +48,6 @@ public function test_maybe_toggle_payment_methods( ->disableOriginalConstructor() ->getMock(); - $upe_payment_gateway->expects( $this->once() ) - ->method( 'is_oc_enabled' ) - ->willReturn( $oc_enabled ); - $upe_payment_gateway->expects( $this->once() ) ->method( 'get_upe_enabled_payment_method_ids' ) ->willReturn( $enabled_payment_method_ids ); @@ -88,7 +82,6 @@ public function provide_test_maybe_toggle_payment_methods() { 'enabled payment method IDs' => [ WC_Stripe_Payment_Methods::CARD, ], - 'OC enabled' => false, 'update enable payment methods calls' => 0, ], 'affirm' => [ @@ -102,7 +95,6 @@ public function provide_test_maybe_toggle_payment_methods() { WC_Stripe_Payment_Methods::CARD, WC_Stripe_Payment_Methods::AFFIRM, ], - 'OC enabled' => false, 'update enable payment methods calls' => 1, ], 'klarna' => [ @@ -116,7 +108,6 @@ public function provide_test_maybe_toggle_payment_methods() { WC_Stripe_Payment_Methods::CARD, WC_Stripe_Payment_Methods::KLARNA, ], - 'OC enabled' => false, 'update enable payment methods calls' => 1, ], 'klarna and affirm active, but not on Stripe' => [ @@ -133,7 +124,6 @@ public function provide_test_maybe_toggle_payment_methods() { 'enabled payment method IDs' => [ WC_Stripe_Payment_Methods::CARD, ], - 'OC enabled' => false, 'update enable payment methods calls' => 0, ], 'klarna and affirm active in both' => [ @@ -152,7 +142,6 @@ public function provide_test_maybe_toggle_payment_methods() { WC_Stripe_Payment_Methods::AFFIRM, WC_Stripe_Payment_Methods::KLARNA, ], - 'OC enabled' => false, 'update enable payment methods calls' => 1, ], 'amazon pay' => [ @@ -161,13 +150,6 @@ public function provide_test_maybe_toggle_payment_methods() { WC_Stripe_Payment_Methods::CARD, WC_Stripe_Payment_Methods::AMAZON_PAY, ], - 'OC enabled' => false, - 'update enable payment methods calls' => 1, - ], - 'card, OC enabled' => [ - 'active gateways' => [], - 'enabled payment method IDs' => [], - 'OC enabled' => true, 'update enable payment methods calls' => 1, ], ];