Skip to content

Commit 8f01d94

Browse files
authored
Disabling BNPLs when other official plugins are active (#4492)
* Disabling BNPLs when other official plugins are active * Simplifying logic * Changelog and readme entries * Unit tests * Checking for specific official plugins instead of any * Adding constants * Unit test * Fix methods availability in the block checkout * Fix methods availability in the block checkout * Keeping methods visible in the settings page * Fix methods availability in the shortcode checkout * New pill to inform about the conflict * Unit test * Disable checkbox when unavailable * Reverting unit tests removal * Update index.js * Update index.test.js * Update index.js
1 parent 81f5fe8 commit 8f01d94

File tree

14 files changed

+348
-28
lines changed

14 files changed

+348
-28
lines changed

changelog.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
*** Changelog ***
22

33
= 9.7.0 - xxxx-xx-xx =
4+
* Update - Removes BNPL payment methods (Klarna and Affirm) when other official plugins are active
45
* Fix - Moves the existing order lock functionality earlier in the order processing flow to prevent duplicate processing requests
56
* Add - Adds two new safety filters to the subscriptions detached debug tool: `wc_stripe_detached_subscriptions_maximum_time` and `wc_stripe_detached_subscriptions_maximum_count`
67
* Add - Show a notice when editing an active subscription that has no payment method attached

client/blocks/upe/index.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import {
33
registerExpressPaymentMethod,
44
} from '@woocommerce/blocks-registry';
55
import {
6+
PAYMENT_METHOD_AFFIRM,
67
PAYMENT_METHOD_AMAZON_PAY,
78
PAYMENT_METHOD_CARD,
89
PAYMENT_METHOD_GIROPAY,
10+
PAYMENT_METHOD_KLARNA,
911
PAYMENT_METHOD_LINK,
1012
} from '../../stripe-utils/constants';
1113
import { updateTokenLabelsWhenLoaded } from './token-label-updater.js';
@@ -38,18 +40,26 @@ const api = new WCStripeAPI(
3840
const paymentMethodsConfig =
3941
getBlocksConfiguration()?.paymentMethodsConfig ?? {};
4042

41-
const methodsToFilter = [
42-
PAYMENT_METHOD_AMAZON_PAY,
43-
PAYMENT_METHOD_LINK,
44-
PAYMENT_METHOD_GIROPAY, // Skip giropay as it was deprecated by Jun, 30th 2024.
45-
];
46-
4743
// Register UPE Elements.
4844
if ( getBlocksConfiguration()?.isOCEnabled ) {
4945
registerPaymentMethod(
5046
upeElement( PAYMENT_METHOD_CARD, api, paymentMethodsConfig.card )
5147
);
5248
} else {
49+
const methodsToFilter = [
50+
PAYMENT_METHOD_AMAZON_PAY,
51+
PAYMENT_METHOD_LINK,
52+
PAYMENT_METHOD_GIROPAY, // Skip giropay as it was deprecated by Jun, 30th 2024.
53+
];
54+
55+
// Filter out some BNPLs when other official extensions are present.
56+
if ( getBlocksConfiguration()?.hasAffirmGatewayPlugin ) {
57+
methodsToFilter.push( PAYMENT_METHOD_AFFIRM );
58+
}
59+
if ( getBlocksConfiguration()?.hasKlarnaGatewayPlugin ) {
60+
methodsToFilter.push( PAYMENT_METHOD_KLARNA );
61+
}
62+
5363
Object.entries( paymentMethodsConfig )
5464
.filter( ( [ method ] ) => ! methodsToFilter.includes( method ) )
5565
.forEach( ( [ method, config ] ) => {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import React from 'react';
2+
import { screen, render } from '@testing-library/react';
3+
import PaymentMethodUnavailableDueConflictPill from '..';
4+
import { PAYMENT_METHOD_AFFIRM } from 'wcstripe/stripe-utils/constants';
5+
6+
describe( 'PaymentMethodUnavailableDueConflictPill', () => {
7+
beforeEach( () => {
8+
global.wc_stripe_settings_params = { has_affirm_gateway_plugin: false };
9+
} );
10+
11+
it( 'should render the "Has plugin conflict" text', () => {
12+
global.wc_stripe_settings_params = { has_affirm_gateway_plugin: true };
13+
14+
render(
15+
<PaymentMethodUnavailableDueConflictPill
16+
id={ PAYMENT_METHOD_AFFIRM }
17+
label="Affirm"
18+
/>
19+
);
20+
21+
expect(
22+
screen.queryByText( 'Has plugin conflict' )
23+
).toBeInTheDocument();
24+
} );
25+
26+
it( 'should not render when other extensions are not active', () => {
27+
const { container } = render(
28+
<PaymentMethodUnavailableDueConflictPill
29+
id={ PAYMENT_METHOD_AFFIRM }
30+
label="Affirm"
31+
/>
32+
);
33+
34+
expect( container.firstChild ).toBeNull();
35+
} );
36+
} );
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/* global wc_stripe_settings_params */
2+
import { __, sprintf } from '@wordpress/i18n';
3+
import React from 'react';
4+
import styled from '@emotion/styled';
5+
import interpolateComponents from 'interpolate-components';
6+
import { Icon, info } from '@wordpress/icons';
7+
import Popover from 'wcstripe/components/popover';
8+
import {
9+
PAYMENT_METHOD_AFFIRM,
10+
PAYMENT_METHOD_KLARNA,
11+
} from 'wcstripe/stripe-utils/constants';
12+
13+
const StyledPill = styled.span`
14+
display: inline-flex;
15+
align-items: center;
16+
gap: 4px;
17+
padding: 4px 8px;
18+
border: 1px solid #fcf9e8;
19+
border-radius: 2px;
20+
background-color: #fcf9e8;
21+
color: #674600;
22+
font-size: 12px;
23+
font-weight: 400;
24+
line-height: 16px;
25+
width: fit-content;
26+
`;
27+
28+
const StyledLink = styled.a`
29+
&:focus,
30+
&:visited {
31+
box-shadow: none;
32+
}
33+
`;
34+
35+
const IconWrapper = styled.span`
36+
height: 16px;
37+
cursor: pointer;
38+
`;
39+
40+
const AlertIcon = styled( Icon )`
41+
fill: #674600;
42+
`;
43+
44+
const IconComponent = ( { children, ...props } ) => (
45+
<IconWrapper { ...props }>
46+
<AlertIcon icon={ info } size="16" />
47+
{ children }
48+
</IconWrapper>
49+
);
50+
51+
const PaymentMethodUnavailableDueConflictPill = ( { id, label } ) => {
52+
if (
53+
( id === PAYMENT_METHOD_AFFIRM &&
54+
// eslint-disable-next-line camelcase
55+
wc_stripe_settings_params.has_affirm_gateway_plugin ) ||
56+
( id === PAYMENT_METHOD_KLARNA &&
57+
// eslint-disable-next-line camelcase
58+
wc_stripe_settings_params.has_klarna_gateway_plugin )
59+
) {
60+
return (
61+
<StyledPill>
62+
{ __( 'Has plugin conflict', 'woocommerce-gateway-stripe' ) }
63+
<Popover
64+
BaseComponent={ IconComponent }
65+
content={ interpolateComponents( {
66+
mixedString: sprintf(
67+
/* translators: $1: a payment method name */
68+
__(
69+
'%1$s is unavailable due to another official plugin being active.',
70+
'woocommerce-gateway-stripe'
71+
),
72+
label
73+
),
74+
components: {
75+
currencySettingsLink: (
76+
<StyledLink
77+
href="/wp-admin/admin.php?page=wc-settings&tab=general"
78+
target="_blank"
79+
rel="noreferrer"
80+
onClick={ ( ev ) => {
81+
// Stop propagation is necessary so it doesn't trigger the tooltip click event.
82+
ev.stopPropagation();
83+
} }
84+
/>
85+
),
86+
},
87+
} ) }
88+
/>
89+
</StyledPill>
90+
);
91+
}
92+
93+
return null;
94+
};
95+
96+
export default PaymentMethodUnavailableDueConflictPill;

client/settings/general-settings-section/payment-method-description.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import PaymentMethodMissingCurrencyPill from '../../components/payment-method-mi
44
import RecurringPaymentIcon from '../../components/recurring-payment-icon';
55
import PaymentMethodCapabilityStatusPill from 'wcstripe/components/payment-method-capability-status-pill';
66
import PaymentMethodDeprecationPill from 'wcstripe/components/payment-method-deprecation-pill';
7+
import PaymentMethodUnavailableDueConflictPill from 'wcstripe/components/payment-method-unavailable-due-conflict-pill';
78

89
const Wrapper = styled.div`
910
display: flex;
@@ -69,6 +70,10 @@ const PaymentMethodDescription = ( {
6970
id={ id }
7071
label={ label }
7172
/>
73+
<PaymentMethodUnavailableDueConflictPill
74+
id={ id }
75+
label={ label }
76+
/>
7277
</>
7378
) }
7479
</LabelWrapper>

client/settings/general-settings-section/payment-method.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
PAYMENT_METHOD_AFFIRM,
1313
PAYMENT_METHOD_AFTERPAY_CLEARPAY,
1414
PAYMENT_METHOD_CARD,
15+
PAYMENT_METHOD_KLARNA,
1516
} from 'wcstripe/stripe-utils/constants';
1617
import PaymentMethodFeesPill from 'wcstripe/components/payment-method-fees-pill';
1718
import { usePaymentMethodCurrencies } from 'utils/use-payment-method-currencies';
@@ -127,8 +128,14 @@ const PaymentMethod = ( { method, data } ) => {
127128

128129
const storeCurrency = window?.wcSettings?.currency?.code;
129130
const isDisabled =
130-
paymentMethodCurrencies.length &&
131-
! paymentMethodCurrencies.includes( storeCurrency );
131+
( paymentMethodCurrencies.length &&
132+
! paymentMethodCurrencies.includes( storeCurrency ) ) ||
133+
( PAYMENT_METHOD_AFFIRM === method &&
134+
// eslint-disable-next-line camelcase
135+
wc_stripe_settings_params.has_affirm_gateway_plugin ) ||
136+
( PAYMENT_METHOD_KLARNA === method &&
137+
// eslint-disable-next-line camelcase
138+
wc_stripe_settings_params.has_klarna_gateway_plugin );
132139

133140
return (
134141
<div key={ method }>

includes/admin/class-wc-stripe-settings-controller.php

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -257,15 +257,6 @@ public function admin_scripts( $hook_suffix ) {
257257
// Show the BNPL promotional banner only if no BNPL payment methods are enabled.
258258
&& ! array_intersect( WC_Stripe_Payment_Methods::BNPL_PAYMENT_METHODS, $enabled_payment_methods );
259259

260-
$has_other_bnpl_plugins_active = false;
261-
$available_payment_gateways = WC()->payment_gateways->payment_gateways;
262-
foreach ( $available_payment_gateways as $gateway ) {
263-
if ( ( 'affirm' === $gateway->id || 'klarna_payments' === $gateway->id ) && 'yes' === $gateway->enabled ) {
264-
$has_other_bnpl_plugins_active = true;
265-
break;
266-
}
267-
}
268-
269260
$params = [
270261
'time' => time(),
271262
'i18n_out_of_sync' => $message,
@@ -287,7 +278,9 @@ public function admin_scripts( $hook_suffix ) {
287278
'is_oc_available' => WC_Stripe_Feature_Flags::is_oc_available(),
288279
'oauth_nonce' => wp_create_nonce( 'wc_stripe_get_oauth_urls' ),
289280
'is_sepa_tokens_enabled' => 'yes' === $this->gateway->get_option( 'sepa_tokens_for_other_methods', 'no' ),
290-
'has_other_bnpl_plugins' => $has_other_bnpl_plugins_active,
281+
'has_affirm_gateway_plugin' => WC_Stripe_Helper::has_gateway_plugin_active( WC_Stripe_Helper::OFFICIAL_PLUGIN_ID_AFFIRM ),
282+
'has_klarna_gateway_plugin' => WC_Stripe_Helper::has_gateway_plugin_active( WC_Stripe_Helper::OFFICIAL_PLUGIN_ID_KLARNA ),
283+
'has_other_bnpl_plugins' => WC_Stripe_Helper::has_other_bnpl_plugins_active(),
291284
'is_payments_onboarding_task_completed' => $this->is_payments_onboarding_task_completed(),
292285
];
293286
wp_localize_script(

includes/class-wc-stripe-helper.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,20 @@ class WC_Stripe_Helper {
2020
const META_NAME_STRIPE_CURRENCY = '_stripe_currency';
2121
const PAYMENT_AWAITING_ACTION_META = '_stripe_payment_awaiting_action';
2222

23+
/**
24+
* The identifier for the official Affirm gateway plugin.
25+
*
26+
* @var string
27+
*/
28+
const OFFICIAL_PLUGIN_ID_AFFIRM = 'affirm';
29+
30+
/**
31+
* The identifier for the official Klarna gateway plugin.
32+
*
33+
* @var string
34+
*/
35+
const OFFICIAL_PLUGIN_ID_KLARNA = 'klarna_payments';
36+
2337
/**
2438
* List of legacy Stripe gateways.
2539
*
@@ -1851,4 +1865,35 @@ public static function get_refund_reason_description( $refund_reason_key ) {
18511865
return __( 'Unknown reason', 'woocommerce-gateway-stripe' );
18521866
}
18531867
}
1868+
1869+
/**
1870+
* Checks if there are other Buy Now Pay Later plugins active.
1871+
*
1872+
* @return bool
1873+
*/
1874+
public static function has_other_bnpl_plugins_active() {
1875+
$other_bnpl_gateway_ids = [ self::OFFICIAL_PLUGIN_ID_AFFIRM, self::OFFICIAL_PLUGIN_ID_KLARNA ];
1876+
foreach ( $other_bnpl_gateway_ids as $bnpl_gateway_id ) {
1877+
if ( self::has_gateway_plugin_active( $bnpl_gateway_id ) ) {
1878+
return true;
1879+
}
1880+
}
1881+
return false;
1882+
}
1883+
1884+
/**
1885+
* Checks if a given payment gateway plugin is active.
1886+
*
1887+
* @param string $plugin_id
1888+
* @return bool
1889+
*/
1890+
public static function has_gateway_plugin_active( $plugin_id ) {
1891+
$available_payment_gateways = WC()->payment_gateways->payment_gateways ?? [];
1892+
foreach ( $available_payment_gateways as $available_payment_gateway ) {
1893+
if ( $plugin_id === $available_payment_gateway->id && 'yes' === $available_payment_gateway->enabled ) {
1894+
return true;
1895+
}
1896+
}
1897+
return false;
1898+
}
18541899
}

includes/notes/class-wc-stripe-bnpl-promotion-note.php

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -93,16 +93,7 @@ public static function init( WC_Stripe_Payment_Gateway $gateway ) {
9393
}
9494
}
9595

96-
$has_other_bnpl_plugins_active = false;
97-
$available_payment_gateways = WC()->payment_gateways->payment_gateways;
98-
$other_bnpl_gateway_ids = [ 'affirm', 'klarna_payments' ];
99-
foreach ( $available_payment_gateways as $available_payment_gateway ) {
100-
if ( in_array( $available_payment_gateway->id, $other_bnpl_gateway_ids, true ) && 'yes' === $available_payment_gateway->enabled ) {
101-
$has_other_bnpl_plugins_active = true;
102-
break;
103-
}
104-
}
105-
if ( $has_other_bnpl_plugins_active ) {
96+
if ( WC_Stripe_Helper::has_other_bnpl_plugins_active() ) {
10697
return;
10798
}
10899

includes/payment-methods/class-wc-stripe-upe-payment-gateway.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,10 @@ public function javascript_params() {
557557
// Single Payment Element payment method parent configuration ID
558558
$stripe_params['paymentMethodConfigurationParentId'] = WC_Stripe_Payment_Method_Configurations::get_parent_configuration_id();
559559

560+
// Checking for other BNPL extensions.
561+
$stripe_params['hasAffirmGatewayPlugin'] = WC_Stripe_Helper::has_gateway_plugin_active( WC_Stripe_Helper::OFFICIAL_PLUGIN_ID_AFFIRM );
562+
$stripe_params['hasKlarnaGatewayPlugin'] = WC_Stripe_Helper::has_gateway_plugin_active( WC_Stripe_Helper::OFFICIAL_PLUGIN_ID_KLARNA );
563+
560564
$cart_total = ( WC()->cart ? WC()->cart->get_total( '' ) : 0 );
561565
$currency = get_woocommerce_currency();
562566

0 commit comments

Comments
 (0)