Skip to content

Commit

Permalink
Merge branch 'develop' into fix/3568-duplicate-order-notes-subscripti…
Browse files Browse the repository at this point in the history
…on-renewals
  • Loading branch information
mattallan authored Nov 6, 2024
2 parents 86ab175 + d6c5821 commit 6d86767
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 5 deletions.
2 changes: 2 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
*** Changelog ***

= 8.9.0 - xxxx-xx-xx =
* Fix - Fix issues when detaching payment methods on staging sites (with the new checkout experience enabled).
* Fix - Display a notice if taxes vary by customer's billing address when checking out using the Stripe Express Checkout Element.
* Tweak - Makes the new Stripe Express Checkout Element enabled by default.
* Dev - Add multiple unit tests for the Stripe Express Checkout Element implementation (for both frontend and backend).
Expand All @@ -15,6 +16,7 @@
* Tweak - Add error logging in ECE critical Ajax requests.
* Add - Add support for Stripe Link payments via the new Stripe Checkout Element on the block cart and block checkout pages.
* Add - Add support for Stripe Link payments via the new Stripe Checkout Element on the product, cart, checkout and pay for order pages.
* Add - Show ECE button preview on settings page.
* Tweak - Remove the subscription order notes added each time a source wasn't migrated.
* Fix - Prevent marking renewal orders as processing/completed multiple times due to handling the Stripe webhook in parallel.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ const getMockPaymentRequestLocations = (
];

describe( 'PaymentRequestsSettingsSection', () => {
const globalValues = global.wc_stripe_payment_request_settings_params;

beforeEach( () => {
usePaymentRequestEnabledSettings.mockReturnValue(
getMockPaymentRequestEnabledSettings( true, jest.fn() )
Expand All @@ -63,6 +65,18 @@ describe( 'PaymentRequestsSettingsSection', () => {
usePaymentRequestLocations.mockReturnValue(
getMockPaymentRequestLocations( true, true, true, jest.fn() )
);

global.wc_stripe_payment_request_settings_params = {
...globalValues,
key: 'pk_test_123',
locale: 'en',
is_ece_enabled: true,
};
} );

afterEach( () => {
jest.clearAllMocks();
global.wc_stripe_payment_request_settings_params = globalValues;
} );

it( 'should enable express checkout locations when express checkout is enabled', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const getMockPaymentRequestLocations = (
];

describe( 'PaymentRequestsSettingsSection', () => {
const globalValues = global.wc_stripe_payment_request_settings_params;
beforeEach( () => {
usePaymentRequestEnabledSettings.mockReturnValue(
getMockPaymentRequestEnabledSettings( true, jest.fn() )
Expand All @@ -65,6 +66,18 @@ describe( 'PaymentRequestsSettingsSection', () => {
usePaymentRequestLocations.mockReturnValue(
getMockPaymentRequestLocations( true, true, true, jest.fn() )
);

global.wc_stripe_payment_request_settings_params = {
...globalValues,
key: 'pk_test_123',
locale: 'en',
is_ece_enabled: true,
};
} );

afterEach( () => {
jest.clearAllMocks();
global.wc_stripe_payment_request_settings_params = globalValues;
} );

it( 'renders settings with defaults', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/* global wc_stripe_payment_request_settings_params */

import { __ } from '@wordpress/i18n';
import { useState, useMemo } from 'react';
import { Elements, ExpressCheckoutElement } from '@stripe/react-stripe-js';
import { loadStripe } from '@stripe/stripe-js';
import { getDefaultBorderRadius } from 'wcstripe/express-checkout/utils';
import InlineNotice from 'components/inline-notice';

const buttonSizeToPxMap = {
small: 40,
default: 48,
large: 56,
};

const ExpressCheckoutPreviewComponent = ( { buttonType, theme, size } ) => {
const [ canRenderButtons, setCanRenderButtons ] = useState( true );

/* eslint-disable camelcase */
const stripePromise = useMemo( () => {
return loadStripe( wc_stripe_payment_request_settings_params.key, {
locale: wc_stripe_payment_request_settings_params.locale,
} );
}, [] );
/* eslint-enable camelcase */

const options = {
mode: 'payment',
amount: 1000,
currency: 'usd',
appearance: {
variables: {
borderRadius: `${ getDefaultBorderRadius() }px`,
spacingUnit: '6px',
},
},
};

const height = buttonSizeToPxMap[ size ] || buttonSizeToPxMap.medium;

const mapThemeConfigToButtonTheme = ( paymentMethod, buttonTheme ) => {
switch ( buttonTheme ) {
case 'dark':
return 'black';
case 'light':
return 'white';
case 'light-outline':
if ( paymentMethod === 'googlePay' ) {
return 'white';
}

return 'white-outline';
default:
return 'black';
}
};

const type = buttonType === 'default' ? 'plain' : buttonType;

const buttonOptions = {
buttonHeight: Math.min( Math.max( height, 40 ), 55 ),
buttonTheme: {
googlePay: mapThemeConfigToButtonTheme( 'googlePay', theme ),
applePay: mapThemeConfigToButtonTheme( 'applePay', theme ),
},
buttonType: {
googlePay: type,
applePay: type,
},
paymentMethods: {
link: 'never',
googlePay: 'always',
applePay: 'always',
},
layout: { overflow: 'never' },
};

const onReady = ( { availablePaymentMethods } ) => {
if ( availablePaymentMethods ) {
setCanRenderButtons( true );
} else {
setCanRenderButtons( false );
}
};

if ( canRenderButtons ) {
return (
<div
key={ `${ buttonType }-${ theme }` }
style={ { minHeight: `${ height }px`, width: '100%' } }
>
<Elements stripe={ stripePromise } options={ options }>
<ExpressCheckoutElement
options={ buttonOptions }
onClick={ () => {} }
onReady={ onReady }
/>
</Elements>
</div>
);
}

return (
<InlineNotice icon status="error" isDismissible={ false }>
{ __(
'Failed to preview the Apple Pay or Google Pay button. ' +
'Ensure your store uses HTTPS on a publicly available domain ' +
"and you're viewing this page in a Safari or Chrome browser. " +
'Your device must be configured to use Apple Pay or Google Pay.',
'woocommerce-gateway-stripe'
) }
</InlineNotice>
);
};

export default ExpressCheckoutPreviewComponent;
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* global wc_stripe_payment_request_settings_params */

import { ADMIN_URL, getSetting } from '@woocommerce/settings';
import { __ } from '@wordpress/i18n';
import React, { useMemo } from 'react';
Expand All @@ -11,6 +13,7 @@ import interpolateComponents from 'interpolate-components';
import { Elements } from '@stripe/react-stripe-js';
import { loadStripe } from '@stripe/stripe-js';
import PaymentRequestButtonPreview from './payment-request-button-preview';
import ExpressCheckoutPreviewComponent from './express-checkout-button-preview';
import {
usePaymentRequestEnabledSettings,
usePaymentRequestLocations,
Expand Down Expand Up @@ -130,6 +133,8 @@ const PaymentRequestsSettingsSection = () => {
const accountId = useAccount().data?.account?.id;
const [ publishableKey ] = useAccountKeysPublishableKey();
const [ testPublishableKey ] = useAccountKeysTestPublishableKey();
const isECEEnabled =
wc_stripe_payment_request_settings_params.is_ece_enabled; // eslint-disable-line camelcase

const stripePromise = useMemo( () => {
return loadStripe(
Expand Down Expand Up @@ -260,9 +265,18 @@ const PaymentRequestsSettingsSection = () => {
/>
<p>{ __( 'Preview', 'woocommerce-gateway-stripe' ) }</p>
<LoadableAccountSection numLines={ 7 }>
<Elements stripe={ stripePromise }>
<PaymentRequestButtonPreview />
</Elements>
{ isECEEnabled ? (
<ExpressCheckoutPreviewComponent
stripe={ stripePromise }
buttonType={ buttonType }
theme={ theme }
size={ size }
/>
) : (
<Elements stripe={ stripePromise }>
<PaymentRequestButtonPreview />
</Elements>
) }
</LoadableAccountSection>
</CardBody>
</Card>
Expand Down
12 changes: 12 additions & 0 deletions includes/admin/class-wc-stripe-payment-requests-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ public function admin_scripts() {
);
wp_enqueue_script( 'wc-stripe-payment-request-settings' );

$stripe_settings = WC_Stripe_Helper::get_stripe_settings();
$params = [
'key' => 'yes' === $stripe_settings['testmode'] ? $stripe_settings['test_publishable_key'] : $stripe_settings['publishable_key'],
'locale' => WC_Stripe_Helper::convert_wc_locale_to_stripe_locale( get_locale() ),
'is_ece_enabled' => WC_Stripe_Feature_Flags::is_stripe_ece_enabled(),
];
wp_localize_script(
'wc-stripe-payment-request-settings',
'wc_stripe_payment_request_settings_params',
$params
);

wp_register_style(
'wc-stripe-payment-request-settings',
plugins_url( 'build/payment_requests_settings.css', WC_STRIPE_MAIN_FILE ),
Expand Down
23 changes: 21 additions & 2 deletions includes/class-wc-stripe-payment-tokens.php
Original file line number Diff line number Diff line change
Expand Up @@ -412,9 +412,28 @@ public function woocommerce_payment_token_deleted( $token_id, $token ) {
$stripe_customer = new WC_Stripe_Customer( $token->get_user_id() );
try {
if ( WC_Stripe_Feature_Flags::is_upe_checkout_enabled() ) {
if ( in_array( $token->get_gateway_id(), self::UPE_REUSABLE_GATEWAYS_BY_PAYMENT_METHOD, true ) ) {
$stripe_customer->detach_payment_method( $token->get_token() );
// If it's not reusable payment method, we don't need to perform any additional checks.
if ( ! in_array( $token->get_gateway_id(), self::UPE_REUSABLE_GATEWAYS_BY_PAYMENT_METHOD, true ) ) {
return;
}

/**
* 1. Check if it's live mode.
* 2. Check if it's admin.
* 3. Check if it's not production environment.
* When all conditions are met, we don't want to delete the payment method from Stripe.
* This is to avoid detaching the payment method from the live stripe account on non production environments.
*/
$settings = WC_Stripe_Helper::get_stripe_settings();
if (
'no' === $settings['testmode'] &&
is_admin() &&
'production' !== wp_get_environment_type()
) {
return;
}

$stripe_customer->detach_payment_method( $token->get_token() );
} else {
if ( 'stripe' === $token->get_gateway_id() || 'stripe_sepa' === $token->get_gateway_id() ) {
$stripe_customer->delete_source( $token->get_token() );
Expand Down
2 changes: 2 additions & 0 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ If you get stuck, you can ask for help in the [Plugin Forum](https://wordpress.o
== Changelog ==

= 8.9.0 - xxxx-xx-xx =
* Fix - Fix issues when detaching payment methods on staging sites (with the new checkout experience enabled).
* Fix - Display a notice if taxes vary by customer's billing address when checking out using the Stripe Express Checkout Element.
* Tweak - Makes the new Stripe Express Checkout Element enabled by default.
* Dev - Add multiple unit tests for the Stripe Express Checkout Element implementation (for both frontend and backend).
Expand All @@ -125,6 +126,7 @@ If you get stuck, you can ask for help in the [Plugin Forum](https://wordpress.o
* Tweak - Add error logging in ECE critical Ajax requests.
* Add - Add support for Stripe Link payments via the new Stripe Checkout Element on the block cart and block checkout pages.
* Add - Add support for Stripe Link payments via the new Stripe Checkout Element on the product, cart, checkout and pay for order pages.
* Add - Show ECE button preview on settings page.
* Tweak - Remove the subscription order notes added each time a source wasn't migrated.
* Fix - Prevent marking renewal orders as processing/completed multiple times due to handling the Stripe webhook in parallel.

Expand Down

0 comments on commit 6d86767

Please sign in to comment.