Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/release/8.8.1' into trunk
Browse files Browse the repository at this point in the history
  • Loading branch information
diegocurbelo committed Oct 28, 2024
2 parents 5fbe0b8 + eab2f2a commit 6ae72f2
Show file tree
Hide file tree
Showing 29 changed files with 453 additions and 179 deletions.
7 changes: 7 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
*** Changelog ***

= 8.8.1 - 2024-10-28 =
* Tweak - Disables APMs when using the legacy checkout experience due Stripe deprecation by October 29, 2024.
* Fix - Prevent marking orders on-hold with order note "Process order to take payment" when the payment has failed.
* Fix - Prevent subscriptions from being marked as "Pending" when a customer attempts to change their payment method to a declining card.
* Fix - Delay updating the subscription's payment method until after the intent is confirmed when using the new checkout experience.
* Fix - Display a success notice to customers after successfully changing their subscription payment method to a card that required 3DS authentication.

= 8.8.0 - 2024-10-17 =
* Fix - Update URL and path constants to support use of symlinked plugin.
* Tweak - Disable ECE when cart has virtual products and tax is based on customer billing or shipping address.
Expand Down
25 changes: 23 additions & 2 deletions client/classic/upe/payment-processing.js
Original file line number Diff line number Diff line change
Expand Up @@ -405,14 +405,15 @@ export const confirmVoucherPayment = async ( api, jQueryForm ) => {
*/
export const confirmWalletPayment = async ( api, jQueryForm ) => {
const isOrderPay = getStripeServerData()?.isOrderPay;
const isChangingPayment = getStripeServerData()?.isChangingPayment;

// The Order Pay page does a hard refresh when the hash changes, so we need to block the UI again.
if ( isOrderPay ) {
blockUI( jQueryForm );
}

const partials = window.location.href.match(
/#wc-stripe-wallet-(.+):(.+):(.+):(.+):(.+)$/
/#wc-stripe-wallet-(.+):(.+):(.+):(.+):(.+):(.+)$/
);

if ( ! partials ) {
Expand Down Expand Up @@ -495,7 +496,27 @@ export const confirmWalletPayment = async ( api, jQueryForm ) => {
// Do not redirect to the order received page if the modal is closed without payment.
// Otherwise redirect to the order received page.
if ( intentObject.status !== 'requires_action' ) {
window.location.href = returnURL;
if ( ! isChangingPayment ) {
window.location.href = returnURL;
}

// If we're changing a subscription's payment method, there's an extra step needed.
// We need to confirm the change payment intent via the confirm_change_payment AJAX request and then redirect to the return URL.
const response = await api.request(
api.getAjaxUrl( 'confirm_change_payment' ),
{
order_id: orderId,
intent_id: intentObject.id,
payment_method_id: intentObject.payment_method || null,
_ajax_nonce: partials[ 6 ],
}
);

if ( response.success ) {
window.location.href = response.data.return_url;
} else {
throw new Error( response.data.error.message );
}
}
} catch ( error ) {
showErrorCheckout( error.message );
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';
import { screen, render } from '@testing-library/react';
import PaymentMethodDeprecationPill from '..';
import UpeToggleContext from 'wcstripe/settings/upe-toggle/context';

describe( 'PaymentMethodDeprecationPill', () => {
it( 'should render', () => {
render(
<UpeToggleContext.Provider>
<PaymentMethodDeprecationPill />
</UpeToggleContext.Provider>
);

expect( screen.queryByText( 'Deprecated' ) ).toBeInTheDocument();
} );
} );
79 changes: 79 additions & 0 deletions client/components/payment-method-deprecation-pill/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { __ } from '@wordpress/i18n';
import React from 'react';
import styled from '@emotion/styled';
import { Icon, info } from '@wordpress/icons';
import interpolateComponents from 'interpolate-components';
import Pill from 'wcstripe/components/pill';
import Popover from 'wcstripe/components/popover';

const StyledPill = styled( Pill )`
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 } ) => (
<IconWrapper { ...props }>
<AlertIcon icon={ info } size="16" />
{ children }
</IconWrapper>
);

const PaymentMethodDeprecationPill = () => {
return (
<StyledPill>
{ __( 'Deprecated', 'woocommerce-gateway-stripe' ) }
<Popover
BaseComponent={ IconComponent }
content={ interpolateComponents( {
mixedString:
/* translators: $1: a payment method name. %2: Currency(ies). */
__(
'This payment method is deprecated on the {{currencySettingsLink}}legacy checkout as of Oct 29th, 2024{{/currencySettingsLink}}.',
'woocommerce-gateway-stripe'
),
components: {
currencySettingsLink: (
<StyledLink
href="https://support.stripe.com/topics/shutdown-of-the-legacy-sources-api-for-non-card-payment-methods"
target="_blank"
rel="noreferrer"
onClick={ ( ev ) => {
// Stop propagation is necessary so it doesn't trigger the tooltip click event.
ev.stopPropagation();
} }
/>
),
},
} ) }
/>
</StyledPill>
);
};

export default PaymentMethodDeprecationPill;
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ describe( 'GeneralSettingsSection', () => {

beforeEach( () => {
global.wcSettings = { currency: { code: 'EUR' } };
global.wc_stripe_settings_params = { are_apms_deprecated: false };
useGetCapabilities.mockReturnValue( {
card_payments: 'active',
alipay_payments: 'active',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ const IconWrapper = styled.span`
flex-shrink: 0;
`;

const PaymentMethodCheckbox = ( { id, label, isAllowingManualCapture } ) => {
const PaymentMethodCheckbox = ( {
id,
label,
isAllowingManualCapture,
disabled,
} ) => {
const [ isManualCaptureEnabled ] = useManualCapture();
const [ isConfirmationModalOpen, setIsConfirmationModalOpen ] = useState(
false
Expand All @@ -40,6 +45,9 @@ const PaymentMethodCheckbox = ( { id, label, isAllowingManualCapture } ) => {
const { isUpeEnabled } = useContext( UpeToggleContext );

const handleCheckboxChange = ( hasBeenChecked ) => {
if ( disabled ) {
return;
}
if ( ! hasBeenChecked ) {
setIsConfirmationModalOpen( true );
return;
Expand Down Expand Up @@ -98,7 +106,10 @@ const PaymentMethodCheckbox = ( { id, label, isAllowingManualCapture } ) => {
<StyledCheckbox
label={ <VisuallyHidden>{ label }</VisuallyHidden> }
onChange={ handleCheckboxChange }
checked={ enabledPaymentMethods.includes( id ) }
checked={
disabled ? false : enabledPaymentMethods.includes( id )
}
disabled={ disabled }
/>
) }
{ isConfirmationModalOpen && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import styled from '@emotion/styled';
import PaymentMethodMissingCurrencyPill from '../../components/payment-method-missing-currency-pill';
import PaymentMethodCapabilityStatusPill from 'wcstripe/components/payment-method-capability-status-pill';
import PaymentMethodDeprecationPill from 'wcstripe/components/payment-method-deprecation-pill';

const Wrapper = styled.div`
display: flex;
Expand Down Expand Up @@ -43,6 +44,7 @@ const PaymentMethodDescription = ( {
label,
description,
id,
deprecated,
...restProps
} ) => {
return (
Expand All @@ -53,14 +55,19 @@ const PaymentMethodDescription = ( {
<div>
<LabelWrapper>
<Label>{ label }</Label>
<PaymentMethodMissingCurrencyPill
id={ id }
label={ label }
/>
<PaymentMethodCapabilityStatusPill
id={ id }
label={ label }
/>
{ deprecated && <PaymentMethodDeprecationPill /> }
{ ! deprecated && (
<>
<PaymentMethodMissingCurrencyPill
id={ id }
label={ label }
/>
<PaymentMethodCapabilityStatusPill
id={ id }
label={ label }
/>
</>
) }
</LabelWrapper>
<Description>{ description }</Description>
</div>
Expand Down
19 changes: 19 additions & 0 deletions client/settings/general-settings-section/payment-methods-list.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* global wc_stripe_settings_params */
import { __, sprintf } from '@wordpress/i18n';
import React, { useState } from 'react';
import styled from '@emotion/styled';
Expand Down Expand Up @@ -235,6 +236,15 @@ const GeneralSettingsSection = ( {
return null;
}

// Remove APMs (legacy checkout) due deprecation by Stripe on Oct 31st, 2024.
if (
// eslint-disable-next-line camelcase
wc_stripe_settings_params.are_apms_deprecated &&
method !== 'card'
) {
return null;
}

const {
Icon,
label,
Expand Down Expand Up @@ -288,6 +298,12 @@ const GeneralSettingsSection = ( {
allows_manual_capture: isAllowingManualCapture,
} = PaymentMethodsMap[ method ];

// Remove APMs (legacy checkout) due deprecation by Stripe on Oct 31st, 2024.
const deprecated =
// eslint-disable-next-line camelcase
wc_stripe_settings_params.are_apms_deprecated &&
method !== 'card';

return (
<div key={ method }>
<ListElement
Expand All @@ -305,6 +321,7 @@ const GeneralSettingsSection = ( {
isAllowingManualCapture={
isAllowingManualCapture
}
disabled={ deprecated }
/>
<PaymentMethodWrapper>
<PaymentMethodDescription
Expand All @@ -315,6 +332,7 @@ const GeneralSettingsSection = ( {
data.account?.default_currency
) }
label={ label }
deprecated={ deprecated }
/>
<StyledFees id={ method } />
</PaymentMethodWrapper>
Expand All @@ -327,6 +345,7 @@ const GeneralSettingsSection = ( {
[ method ]: true,
} )
}
disabled={ deprecated }
>
{ __(
'Customize',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ useDispatch.mockImplementation( ( storeName ) => {
const setShowPromotionalBanner = jest.fn();

describe( 'PromotionalBanner', () => {
beforeEach( () => {
global.wc_stripe_settings_params = { are_apms_deprecated: false };
} );

it( 'dismiss function should be called', () => {
render(
<PromotionalBannerSection
Expand Down
20 changes: 16 additions & 4 deletions client/settings/payment-settings/promotional-banner-section.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* global wc_stripe_settings_params */
import { __ } from '@wordpress/i18n';
import { useDispatch } from '@wordpress/data';
import { React } from 'react';
Expand Down Expand Up @@ -163,6 +164,20 @@ const PromotionalBannerSection = ( {
</CardBody>
);

let newCheckoutExperienceAPMsBannerDescription = '';
// eslint-disable-next-line camelcase
if ( wc_stripe_settings_params.are_apms_deprecated ) {
newCheckoutExperienceAPMsBannerDescription = __(
'Stripe ended support for non-card payment methods in the {{StripeLegacyLink}}legacy checkout on October 29, 2024{{/StripeLegacyLink}}. To continue accepting non-card payments, you must enable the new checkout experience or remove non-card payment methods from your checkout to avoid payment disruptions.',
'woocommerce-gateway-stripe'
);
} else {
newCheckoutExperienceAPMsBannerDescription = __(
'Stripe will end support for non-card payment methods in the {{StripeLegacyLink}}legacy checkout on October 29, 2024{{/StripeLegacyLink}}. To continue accepting non-card payments, you must enable the new checkout experience or remove non-card payment methods from your checkout to avoid payment disruptions.',
'woocommerce-gateway-stripe'
);
}

const NewCheckoutExperienceAPMsBanner = () => (
<CardBody data-testid="new-checkout-apms-banner">
<CardInner>
Expand All @@ -178,10 +193,7 @@ const PromotionalBannerSection = ( {
</h4>
<p>
{ interpolateComponents( {
mixedString: __(
'Stripe will end support for non-card payment methods in the {{StripeLegacyLink}}legacy checkout on October 29, 2024{{/StripeLegacyLink}}. To continue accepting non-card payments, you must enable the new checkout experience or remove non-card payment methods from your checkout to avoid payment disruptions.',
'woocommerce-gateway-stripe'
),
mixedString: newCheckoutExperienceAPMsBannerDescription,
components: {
StripeLegacyLink: (
<ExternalLink href="https://support.stripe.com/topics/shutdown-of-the-legacy-sources-api-for-non-card-payment-methods" />
Expand Down
2 changes: 1 addition & 1 deletion client/utils/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*global wc_add_to_cart_variation_params */
/* global wc_add_to_cart_variation_params */
export const getAddToCartVariationParams = ( key ) => {
// eslint-disable-next-line camelcase
const wcAddToCartVariationParams = wc_add_to_cart_variation_params;
Expand Down
1 change: 1 addition & 0 deletions includes/admin/class-wc-stripe-settings-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ public function admin_scripts( $hook_suffix ) {
'is_test_mode' => $this->gateway->is_in_test_mode(),
'plugin_version' => WC_STRIPE_VERSION,
'account_country' => $this->account->get_account_country(),
'are_apms_deprecated' => WC_Stripe_Feature_Flags::are_apms_deprecated(),
];
wp_localize_script(
'woocommerce_stripe_admin',
Expand Down
10 changes: 10 additions & 0 deletions includes/class-wc-stripe-feature-flags.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,14 @@ public static function did_merchant_disable_upe() {
$stripe_settings = WC_Stripe_Helper::get_stripe_settings();
return ! empty( $stripe_settings[ self::UPE_CHECKOUT_FEATURE_ATTRIBUTE_NAME ] ) && 'disabled' === $stripe_settings[ self::UPE_CHECKOUT_FEATURE_ATTRIBUTE_NAME ];
}


/**
* Checks if the APMs are deprecated. Stripe deprecated them on October 29, 2024 (for the legacy checkout).
*
* @return bool Whether the APMs are deprecated.
*/
public static function are_apms_deprecated() {
return ( new \DateTime() )->format( 'Y-m-d' ) > '2024-10-28' && ! self::is_upe_checkout_enabled();
}
}
Loading

0 comments on commit 6ae72f2

Please sign in to comment.