Skip to content

Commit 965a67a

Browse files
diegocurbeloMayishadaledupreez
committed
Disable Settings Sync when no valid PMC is available (#4334)
* Disable Sync if no PMC with the WooPlatform parent_id is returned by Stripe --------- Co-authored-by: Mayisha <[email protected]> Co-authored-by: Dale du Preez <[email protected]>
1 parent bc6035f commit 965a67a

9 files changed

+215
-5
lines changed

changelog.txt

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

33
= 9.5.2 - xxxx-xx-xx =
44
* Add - Implement custom database cache for persistent caching with in-memory optimization.
5+
* Fix - Disable payment settings sync when we receive unsupported payment method configurations.
56

67
= 9.5.1 - 2025-05-17 =
78
* Fix - Add a fetch cooldown to the payment method configuration retrieval endpoint to prevent excessive requests.

includes/admin/class-wc-rest-stripe-account-keys-controller.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ public function set_account_keys( WP_REST_Request $request ) {
272272
if ( $is_deleting_account ) {
273273
$settings['enabled'] = 'no';
274274
$settings['connection_type'] = '';
275+
$settings['pmc_enabled'] = '';
275276
$settings['test_connection_type'] = '';
276277
$settings['refresh_token'] = '';
277278
$settings['test_refresh_token'] = '';

includes/class-wc-stripe-payment-method-configurations.php

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ private static function get_payment_method_configuration_from_stripe() {
159159
}
160160
}
161161

162+
// If we don't have a Payment Method Configuration that inherits from the WooCommerce Platform, disable Payment Method Configuration sync.
163+
self::disable_payment_method_configuration_sync();
162164
return null;
163165
}
164166

@@ -327,9 +329,21 @@ function ( $id ) use ( $is_test_mode ) {
327329
* @return bool
328330
*/
329331
public static function is_enabled() {
330-
$stripe_settings = WC_Stripe_Helper::get_stripe_settings();
331-
$key = WC_Stripe_Mode::is_test() ? 'test_connection_type' : 'connection_type';
332-
return isset( $stripe_settings[ $key ] ) && 'connect' === $stripe_settings[ $key ];
332+
$stripe_settings = WC_Stripe_Helper::get_stripe_settings();
333+
$connection_type_key = WC_Stripe_Mode::is_test() ? 'test_connection_type' : 'connection_type';
334+
335+
// If the account is not a Connect OAuth account, we can't use the payment method configurations API.
336+
if ( ! isset( $stripe_settings[ $connection_type_key ] ) || 'connect' !== $stripe_settings[ $connection_type_key ] ) {
337+
return false;
338+
}
339+
340+
// If we have the pmc_enabled flag, and it is set to no, we should not use the payment method configurations API.
341+
// We only disable the PMC if the flag is set to no explicitly, an empty value means the migration has not been attempted yet.
342+
if ( isset( $stripe_settings['pmc_enabled'] ) && 'no' === $stripe_settings['pmc_enabled'] ) {
343+
return false;
344+
}
345+
346+
return true;
333347
}
334348

335349
/**
@@ -338,7 +352,7 @@ public static function is_enabled() {
338352
public static function maybe_migrate_payment_methods_from_db_to_pmc() {
339353
$stripe_settings = WC_Stripe_Helper::get_stripe_settings();
340354

341-
// Skip if PMC is not enabled or migration already done
355+
// Skip if PMC is not enabled or migration already done (pmc_enabled is set).
342356
if ( ! self::is_enabled() || ! empty( $stripe_settings['pmc_enabled'] ) ) {
343357
return;
344358
}
@@ -394,4 +408,14 @@ public static function maybe_migrate_payment_methods_from_db_to_pmc() {
394408
$stripe_settings['pmc_enabled'] = 'yes';
395409
WC_Stripe_Helper::update_main_stripe_settings( $stripe_settings );
396410
}
411+
412+
/**
413+
* Disables the payment method configuration sync by setting pmc_enabled to 'no' in the Stripe settings.
414+
* This is called when no Payment Method Configuration is found that inherits from the WooCommerce Platform.
415+
*/
416+
private static function disable_payment_method_configuration_sync() {
417+
$stripe_settings = WC_Stripe_Helper::get_stripe_settings();
418+
$stripe_settings['pmc_enabled'] = 'no';
419+
WC_Stripe_Helper::update_main_stripe_settings( $stripe_settings );
420+
}
397421
}

includes/connect/class-wc-stripe-connect.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ private function save_stripe_keys( $result, $type = 'connect', $mode = 'live' )
163163
$options[ $prefix . 'publishable_key' ] = $publishable_key;
164164
$options[ $prefix . 'secret_key' ] = $secret_key;
165165
$options[ $prefix . 'connection_type' ] = $type;
166-
166+
$options['pmc_enabled'] = 'connect' === $type ? '' : 'no'; // When not connected via oauth, the PMC is disabled. Otherwise, set to empty string which will be set to 'yes' after the migration in 'maybe_migrate_payment_methods_from_db_to_pmc'.
167167
if ( 'app' === $type ) {
168168
$options[ $prefix . 'refresh_token' ] = $result->refreshToken; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
169169
}

readme.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,6 @@ If you get stuck, you can ask for help in the [Plugin Forum](https://wordpress.o
112112

113113
= 9.5.2 - xxxx-xx-xx =
114114
* Add - Implement custom database cache for persistent caching with in-memory optimization.
115+
* Fix - Disable payment settings sync when we receive unsupported payment method configurations.
115116

116117
[See changelog for full details across versions](https://raw.githubusercontent.com/woocommerce/woocommerce-gateway-stripe/trunk/changelog.txt).

tests/phpunit/admin/test-wc-stripe-admin-notices.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ public function set_up() {
2020
'test' => 'test',
2121
]
2222
);
23+
$this->mock_payment_method_configurations(
24+
[
25+
WC_Stripe_Payment_Methods::CARD,
26+
WC_Stripe_Payment_Methods::BANCONTACT,
27+
WC_Stripe_Payment_Methods::EPS,
28+
]
29+
);
2330
}
2431

2532
public function test_no_notices_are_shown_when_user_is_not_admin() {

tests/phpunit/test-class-wc-stripe-payment-method-configurations.php

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,172 @@ class WC_Stripe_Payment_Method_Configurations_Test extends WP_UnitTestCase {
1111
public function test_get_parent_configuration_id() {
1212
$this->assertNull( WC_Stripe_Payment_Method_Configurations::get_parent_configuration_id() );
1313
}
14+
15+
/**
16+
* Tests the disable_payment_method_configuration_sync method.
17+
*
18+
* @return void
19+
*/
20+
public function test_disable_payment_method_configuration_sync() {
21+
// Get initial settings
22+
$initial_settings = WC_Stripe_Helper::get_stripe_settings();
23+
24+
// Use reflection to access the private method
25+
$reflection = new ReflectionClass( 'WC_Stripe_Payment_Method_Configurations' );
26+
$method = $reflection->getMethod( 'disable_payment_method_configuration_sync' );
27+
$method->setAccessible( true );
28+
// Call the method
29+
$method->invoke( null );
30+
31+
// Get updated settings
32+
$updated_settings = WC_Stripe_Helper::get_stripe_settings();
33+
34+
// Verify pmc_enabled is set to 'no'
35+
$this->assertEquals( 'no', $updated_settings['pmc_enabled'] );
36+
37+
// Restore original settings
38+
WC_Stripe_Helper::update_main_stripe_settings( $initial_settings );
39+
}
40+
41+
/**
42+
* Tests that disable_payment_method_configuration_sync is called when no PMC is found.
43+
*
44+
* @return void
45+
*/
46+
public function test_disable_payment_method_configuration_sync_on_no_pmc() {
47+
// Mock the Stripe API response to return no configurations
48+
$mock_api = $this->getMockBuilder( 'WC_Stripe_API' )
49+
->disableOriginalConstructor()
50+
->getMock();
51+
52+
$mock_api->expects( $this->once() )
53+
->method( 'get_payment_method_configurations' )
54+
->willReturn( (object) [ 'data' => [] ] );
55+
56+
// Set the mock API instance
57+
$reflection = new ReflectionClass( 'WC_Stripe_API' );
58+
$property = $reflection->getProperty( 'instance' );
59+
$property->setAccessible( true );
60+
$property->setValue( null, $mock_api );
61+
62+
// Get initial settings
63+
$initial_settings = WC_Stripe_Helper::get_stripe_settings();
64+
65+
// Call get_primary_configuration which should trigger disable_payment_method_configuration_sync
66+
// Use reflection to access the private method
67+
$reflection = new ReflectionClass( 'WC_Stripe_Payment_Method_Configurations' );
68+
$method = $reflection->getMethod( 'get_primary_configuration' );
69+
$method->setAccessible( true );
70+
// Call the method
71+
$method->invoke( null );
72+
73+
// Get updated settings
74+
$updated_settings = WC_Stripe_Helper::get_stripe_settings();
75+
76+
// Verify pmc_enabled is set to 'no'
77+
$this->assertEquals( 'no', $updated_settings['pmc_enabled'] );
78+
79+
// Restore original settings and API instance
80+
WC_Stripe_Helper::update_main_stripe_settings( $initial_settings );
81+
$property->setValue( null, null );
82+
}
83+
84+
/**
85+
* Tests that pmc_enabled is not set to 'no' when valid PMC data exists.
86+
*
87+
* @return void
88+
*/
89+
public function test_pmc_enabled_not_disabled_with_valid_data() {
90+
// Get initial settings
91+
$initial_settings = WC_Stripe_Helper::get_stripe_settings();
92+
93+
// Mock the Stripe API response to return a valid configuration
94+
$mock_api = $this->getMockBuilder( 'WC_Stripe_API' )
95+
->disableOriginalConstructor()
96+
->getMock();
97+
98+
$mock_configuration = (object) [
99+
'id' => 'test_config_id',
100+
'parent' => WC_Stripe_Payment_Method_Configurations::TEST_MODE_CONFIGURATION_PARENT_ID,
101+
];
102+
103+
$mock_api->expects( $this->once() )
104+
->method( 'get_payment_method_configurations' )
105+
->willReturn( (object) [ 'data' => [ $mock_configuration ] ] );
106+
107+
// Set the mock API instance
108+
$reflection = new ReflectionClass( 'WC_Stripe_API' );
109+
$property = $reflection->getProperty( 'instance' );
110+
$property->setAccessible( true );
111+
$property->setValue( null, $mock_api );
112+
113+
// Call get_primary_configuration which should NOT trigger disable_payment_method_configuration_sync
114+
// Use reflection to access the private method
115+
$reflection = new ReflectionClass( 'WC_Stripe_Payment_Method_Configurations' );
116+
$method = $reflection->getMethod( 'get_primary_configuration' );
117+
$method->setAccessible( true );
118+
// Call the method
119+
$method->invoke( null );
120+
121+
// Get the updated settings
122+
$updated_settings = WC_Stripe_Helper::get_stripe_settings();
123+
124+
// Verify pmc_enabled is not set to 'no'
125+
$this->assertNotEquals( 'no', $updated_settings['pmc_enabled'] ?? null );
126+
127+
// Restore original settings and API instance
128+
WC_Stripe_Helper::update_main_stripe_settings( $initial_settings );
129+
$property->setValue( null, null );
130+
}
131+
132+
/**
133+
* Tests that disable_payment_method_configuration_sync is called when there is a valid PMC in the responmse but is not valid.
134+
*
135+
* @return void
136+
*/
137+
public function test_disable_payment_method_configuration_sync_on_not_valid_pmc() {
138+
// Mock the Stripe API response to return no configurations
139+
$mock_api = $this->getMockBuilder( 'WC_Stripe_API' )
140+
->disableOriginalConstructor()
141+
->getMock();
142+
143+
$mock_configuration = (object) [
144+
'id' => 'test_config_id',
145+
'parent' => 'pmc_from_another_platform_id',
146+
];
147+
148+
$mock_api->expects( $this->once() )
149+
->method( 'get_payment_method_configurations' )
150+
->willReturn( (object) [ 'data' => [ $mock_configuration ] ] );
151+
152+
// Set the mock API instance
153+
$reflection = new ReflectionClass( 'WC_Stripe_API' );
154+
$property = $reflection->getProperty( 'instance' );
155+
$property->setAccessible( true );
156+
$property->setValue( null, $mock_api );
157+
158+
// Get initial settings
159+
$initial_settings = WC_Stripe_Helper::get_stripe_settings();
160+
161+
// Call get_payment_method_configuration_from_stripe which should trigger disable_payment_method_configuration_sync
162+
// We could use get_primary_configuration, but it has a cooldown cache; we can remove the option for the test, but
163+
// we want to test the function get_payment_method_configuration_from_stripe that is the one processing the response
164+
// from the Stripe API call.
165+
// Use reflection to access the private method
166+
$reflection = new ReflectionClass( 'WC_Stripe_Payment_Method_Configurations' );
167+
$method = $reflection->getMethod( 'get_payment_method_configuration_from_stripe' );
168+
$method->setAccessible( true );
169+
// Call the method
170+
$method->invoke( null );
171+
172+
// Get updated settings
173+
$updated_settings = WC_Stripe_Helper::get_stripe_settings();
174+
175+
// Verify pmc_enabled is set to 'no'
176+
$this->assertEquals( 'no', $updated_settings['pmc_enabled'] );
177+
178+
// Restore original settings and API instance
179+
WC_Stripe_Helper::update_main_stripe_settings( $initial_settings );
180+
$property->setValue( null, null );
181+
}
14182
}

tests/phpunit/test-wc-rest-stripe-account-keys-controller.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ public function set_up() {
4141
->getMock();
4242

4343
$this->controller = new WC_REST_Stripe_Account_Keys_Controller( $mock_account );
44+
$this->mock_payment_method_configurations(
45+
[
46+
WC_Stripe_Payment_Methods::CARD,
47+
WC_Stripe_Payment_Methods::LINK,
48+
]
49+
);
4450
}
4551

4652
public function test_get_account_keys_returns_status_code_200() {
@@ -154,6 +160,7 @@ public function test_changing_keys_resets_payment_methods() {
154160
'secret_key' => 'sk_live-key',
155161
'testmode' => 'no',
156162
'connection_type' => 'connect',
163+
'pmc_enabled' => 'yes',
157164
WC_Stripe_Feature_Flags::UPE_CHECKOUT_FEATURE_ATTRIBUTE_NAME => 'yes',
158165
]
159166
);

uninstall.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
// Live keys
2929
unset( $settings['publishable_key'], $settings['secret_key'] );
3030
unset( $settings['connection_type'], $settings['refresh_token'] );
31+
unset( $settings['pmc_enabled'] );
3132
unset( $settings['webhook_data'] );
3233
unset( $settings['webhook_secret'] );
3334
// Test keys

0 commit comments

Comments
 (0)