Skip to content

Commit 508807e

Browse files
authored
Fix customer not found errors after site migration (#5383)
* Fix customer not found errors after site migration After a site has been migrated to a different WCPay account pre-existing account will be associated with Stripe customer objects that don't exist. This will result in a "No such customer" error in UPE checkouts and a "We're not able to process this request" error in classic checkouts. To fix the issue we make the customer update function synchronous instead of asynchronous. This rolls back a significant performance update, but WCPay stores shouldn't hit this path most of the time anyway, so it shouldn't matter for most stores.
1 parent 36ee47d commit 508807e

5 files changed

+27
-33
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Significance: patch
2+
Type: fix
3+
4+
Prevent 'No such customer' errors after store is migrated to a new WCPay account.

includes/class-wc-payment-gateway-wcpay.php

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ class WC_Payment_Gateway_WCPay extends WC_Payment_Gateway_CC {
7070
Payment_Intent_Status::PROCESSING,
7171
];
7272

73-
const UPDATE_SAVED_PAYMENT_METHOD = 'wcpay_update_saved_payment_method';
74-
const UPDATE_CUSTOMER_WITH_ORDER_DATA = 'wcpay_update_customer_with_order_data';
73+
const UPDATE_SAVED_PAYMENT_METHOD = 'wcpay_update_saved_payment_method';
7574

7675
/**
7776
* Set a large limit argument for retrieving user tokens.
@@ -410,7 +409,6 @@ public function __construct(
410409
add_action( 'set_logged_in_cookie', [ $this, 'set_cookie_on_current_request' ] );
411410

412411
add_action( self::UPDATE_SAVED_PAYMENT_METHOD, [ $this, 'update_saved_payment_method' ], 10, 3 );
413-
add_action( self::UPDATE_CUSTOMER_WITH_ORDER_DATA, [ $this, 'update_customer_with_order_data' ], 10, 4 );
414412

415413
// Update the email field position.
416414
add_filter( 'woocommerce_billing_fields', [ $this, 'checkout_update_email_field_priority' ], 50 );
@@ -830,12 +828,12 @@ protected function prepare_payment_information( $order ) {
830828
/**
831829
* Update the customer details with the incoming order data, in a CRON job.
832830
*
833-
* @param int $order_id WC order id.
834-
* @param string $customer_id The customer id to update details for.
835-
* @param bool $is_test_mode Whether to run the CRON job in test mode.
836-
* @param bool $is_woopay Whether CRON job was queued from WooPay.
831+
* @param \WC_Order $order WC order id.
832+
* @param string $customer_id The customer id to update details for.
833+
* @param bool $is_test_mode Whether to run the CRON job in test mode.
834+
* @param bool $is_woopay Whether CRON job was queued from WooPay.
837835
*/
838-
public function update_customer_with_order_data( $order_id, $customer_id, $is_test_mode = false, $is_woopay = false ) {
836+
public function update_customer_with_order_data( $order, $customer_id, $is_test_mode = false, $is_woopay = false ) {
839837
// Since this CRON job may have been created in test_mode, when the CRON job runs, it
840838
// may lose the test_mode context. So, instead, we pass that context when creating
841839
// the CRON job and apply the context here.
@@ -844,8 +842,7 @@ public function update_customer_with_order_data( $order_id, $customer_id, $is_te
844842
};
845843
add_filter( 'wcpay_test_mode', $apply_test_mode_context );
846844

847-
$order = wc_get_order( $order_id );
848-
$user = $order->get_user();
845+
$user = $order->get_user();
849846
if ( false === $user ) {
850847
$user = wp_get_current_user();
851848
}
@@ -890,16 +887,7 @@ protected function manage_customer_details_for_order( $order, $options = [] ) {
890887
$customer_id = $this->customer_service->create_customer_for_user( $user, $customer_data );
891888
} else {
892889
// Update the customer with order data async.
893-
$this->action_scheduler_service->schedule_job(
894-
time(),
895-
self::UPDATE_CUSTOMER_WITH_ORDER_DATA,
896-
[
897-
'order_id' => $order->get_id(),
898-
'customer_id' => $customer_id,
899-
'is_test_mode' => $this->is_in_test_mode(),
900-
'is_woopay' => $options['is_woopay'] ?? false,
901-
]
902-
);
890+
$this->update_customer_with_order_data( $order, $customer_id, $this->is_in_test_mode(), $options['is_woopay'] ?? false );
903891
}
904892

905893
return [ $user, $customer_id ];

tests/unit/test-class-wc-payment-gateway-wcpay-process-payment.php

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
* WC_Payment_Gateway_WCPay unit tests.
1919
*/
2020
class WC_Payment_Gateway_WCPay_Process_Payment_Test extends WCPAY_UnitTestCase {
21+
const CUSTOMER_ID = 'cus_mock';
22+
2123
/**
2224
* System under test.
2325
*
@@ -1080,20 +1082,10 @@ public function test_updates_customer_with_order_data() {
10801082
->method( 'get_customer_id_by_user_id' )
10811083
->willReturn( $customer_id );
10821084

1083-
// Assert: UPDATE_CUSTOMER_WITH_ORDER_DATA job scheduled correctly.
1084-
$this->mock_action_scheduler_service
1085+
$this->mock_customer_service
10851086
->expects( $this->once() )
1086-
->method( 'schedule_job' )
1087-
->with(
1088-
$this->anything(),
1089-
WC_Payment_Gateway_WCPay::UPDATE_CUSTOMER_WITH_ORDER_DATA,
1090-
[
1091-
'order_id' => $mock_order->get_id(),
1092-
'customer_id' => $customer_id,
1093-
'is_test_mode' => false,
1094-
'is_woopay' => false,
1095-
]
1096-
);
1087+
->method( 'update_customer_for_user' )
1088+
->willReturn( self::CUSTOMER_ID );
10971089

10981090
// Arrange: Create a mock cart.
10991091
$mock_cart = $this->createMock( 'WC_Cart' );

tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions-process-payment.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,11 @@ public function set_up() {
160160
->with( get_current_user_id() )
161161
->willReturn( self::CUSTOMER_ID );
162162

163+
$this->mock_customer_service
164+
->expects( $this->once() )
165+
->method( 'update_customer_for_user' )
166+
->willReturn( self::CUSTOMER_ID );
167+
163168
$this->token = WC_Helper_Token::create_token( self::PAYMENT_METHOD_ID, self::USER_ID );
164169

165170
$_POST = [

tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,11 @@ public function test_scheduled_subscription_payment() {
228228
->with( self::USER_ID )
229229
->willReturn( self::CUSTOMER_ID );
230230

231+
$this->mock_customer_service
232+
->expects( $this->once() )
233+
->method( 'update_customer_for_user' )
234+
->willReturn( self::CUSTOMER_ID );
235+
231236
$this->mock_api_client
232237
->expects( $this->once() )
233238
->method( 'create_and_confirm_intention' )

0 commit comments

Comments
 (0)