woocommerce / woocommerce-gateway-stripe

The official Stripe Payment Gateway for WooCommerce
https://wordpress.org/plugins/woocommerce-gateway-stripe/
235 stars 206 forks source link

Make sure our code works without issues with WooCommerce's Custom Order Tables #2407

Closed asumaran closed 1 year ago

asumaran commented 2 years ago

For more context visit: p1659937693943169-slack-C9QDV4TL4

As part of WooCommerce's migration to Custom Order Tables (COT) we need to prepare our code to be compatible with it when it's released to everyone.

So far, while testing the critical flows (No UPE) I've found an issue related to refunds.

There are likely more errors than that. We must at least ensure the critical flows (with or without UPE enabled) runs as expected without issues.

Per the COT Recipe Book, these are the functions we need to replace with the new WooCommerce APIs for getting/setting post and post meta data.

We seem affected, given that there are multiple occurrences of some of these functions in our code base.

List of occurrences ``` Searching 249 files for "(get_post)|(get_post_field)|(get_post_status)|(get_post_type)|(get_post_type_object)|(get_posts)|(metadata_exists)|(get_post_meta)|(get_metadata)|(get_metadata_raw)|(get_metadata_default)|(get_metadata_by_mid)|(wp_insert_post)|(add_metadata)|(add_post_meta)|(wp_update_post)|(update_post_meta)|(update_metadata)|(update_metadata_by_mid)|(delete_metadata)|(delete_post_meta)|(delete_metadata_by_mid)|(delete_post_meta_by_key)|(wp_delete_post)|(wp_trash_post)|(wp_untrash_post)|(wp_transition_post_status)|(clean_post_cache)|(update_post_caches)|(update_postmeta_cache)|(post_exists)" (regex) /Users/asumaran/www/woocommerce-gateway-stripe/includes/class-wc-gateway-stripe.php: 861: clean_post_cache( $order->get_id() ); /Users/asumaran/www/woocommerce-gateway-stripe/includes/class-wc-stripe-helper.php: 103: delete_post_meta( $order_id, self::META_NAME_FEE ); 104: delete_post_meta( $order_id, self::LEGACY_META_NAME_FEE ); 162: delete_post_meta( $order_id, self::META_NAME_NET ); 163: delete_post_meta( $order_id, self::LEGACY_META_NAME_NET ); /Users/asumaran/www/woocommerce-gateway-stripe/includes/class-wc-stripe-intent-controller.php: 409: 'metadata' => $gateway->get_metadata_from_order( $order ), /Users/asumaran/www/woocommerce-gateway-stripe/includes/admin/class-wc-stripe-privacy.php: 128: 'value' => get_post_meta( $order->get_id(), '_stripe_source_id', true ), 132: 'value' => get_post_meta( $order->get_id(), '_stripe_customer_id', true ), 193: 'value' => get_post_meta( $subscription->get_id(), '_stripe_source_id', true ), 197: 'value' => get_post_meta( $subscription->get_id(), '_stripe_customer_id', true ), 342: $stripe_source_id = get_post_meta( $subscription_id, '_stripe_source_id', true ); 361: delete_post_meta( $renewal_order_id, '_stripe_source_id' ); 362: delete_post_meta( $renewal_order_id, '_stripe_refund_id' ); 363: delete_post_meta( $renewal_order_id, '_stripe_customer_id' ); 366: delete_post_meta( $subscription_id, '_stripe_source_id' ); 367: delete_post_meta( $subscription_id, '_stripe_refund_id' ); 368: delete_post_meta( $subscription_id, '_stripe_customer_id' ); 381: $stripe_source_id = get_post_meta( $order_id, '_stripe_source_id', true ); 382: $stripe_refund_id = get_post_meta( $order_id, '_stripe_refund_id', true ); 383: $stripe_customer_id = get_post_meta( $order_id, '_stripe_customer_id', true ); 394: delete_post_meta( $order_id, '_stripe_source_id' ); 395: delete_post_meta( $order_id, '_stripe_refund_id' ); 396: delete_post_meta( $order_id, '_stripe_customer_id' ); /Users/asumaran/www/woocommerce-gateway-stripe/includes/compat/trait-wc-stripe-subscriptions.php: 384: update_post_meta( $subscription_id, '_stripe_customer_id', $source->customer ); 387: update_post_meta( $subscription_id, '_stripe_source_id', $source->payment_method ); 389: update_post_meta( $subscription_id, '_stripe_source_id', $source->source ); 400: delete_post_meta( $resubscribe_order->get_id(), '_stripe_customer_id' ); 401: delete_post_meta( $resubscribe_order->get_id(), '_stripe_source_id' ); 403: delete_post_meta( $resubscribe_order->get_id(), '_stripe_card_id' ); 405: delete_post_meta( $resubscribe_order->get_id(), '_stripe_intent_id' ); 419: delete_post_meta( $renewal_order->get_id(), '_stripe_intent_id' ); 433: update_post_meta( $subscription->get_id(), '_stripe_customer_id', $renewal_order->get_meta( '_stripe_customer_id', true ) ); 434: update_post_meta( $subscription->get_id(), '_stripe_source_id', $renewal_order->get_meta( '_stripe_source_id', true ) ); 449: $source_id = get_post_meta( $subscription_id, '_stripe_source_id', true ); 453: $source_id = get_post_meta( $subscription_id, '_stripe_card_id', true ); 456: update_post_meta( $subscription_id, '_stripe_source_id', $source_id ); 457: delete_post_meta( $subscription_id, '_stripe_card_id', $source_id ); 463: 'value' => get_post_meta( $subscription_id, '_stripe_customer_id', true ), 530: $stripe_source_id = get_post_meta( $subscription->get_id(), '_stripe_source_id', true ); 534: $stripe_source_id = get_post_meta( $subscription->get_id(), '_stripe_card_id', true ); 537: update_post_meta( $subscription->get_id(), '_stripe_source_id', $stripe_source_id ); 541: $stripe_customer_id = get_post_meta( $subscription->get_id(), '_stripe_customer_id', true ); 560: $stripe_customer_id = get_post_meta( $subscription->get_parent_id(), '_stripe_customer_id', true ); 561: $stripe_source_id = get_post_meta( $subscription->get_parent_id(), '_stripe_source_id', true ); 565: $stripe_source_id = get_post_meta( $subscription->get_parent_id(), '_stripe_card_id', true ); 568: update_post_meta( $subscription->get_parent_id(), '_stripe_source_id', $stripe_source_id ); /Users/asumaran/www/woocommerce-gateway-stripe/includes/payment-methods/class-wc-gateway-stripe-multibanco.php: 241: $data = get_post_meta( $order_id, '_stripe_multibanco', true ); 292: update_post_meta( $order_id, '_stripe_multibanco', $data ); /Users/asumaran/www/woocommerce-gateway-stripe/includes/payment-methods/class-wc-stripe-payment-request.php: 1556: $posted_data = $wc_checkout->get_posted_data(); /Users/asumaran/www/woocommerce-gateway-stripe/includes/payment-methods/class-wc-stripe-upe-payment-gateway.php: 572: $request['metadata'] = $this->get_metadata_from_order( $order ); 1306: public function get_metadata_from_order( $order ) { /Users/asumaran/www/woocommerce-gateway-stripe/release/woocommerce-gateway-stripe/includes/class-wc-gateway-stripe.php: 860: clean_post_cache( $order->get_id() ); /Users/asumaran/www/woocommerce-gateway-stripe/release/woocommerce-gateway-stripe/includes/class-wc-stripe-helper.php: 103: delete_post_meta( $order_id, self::META_NAME_FEE ); 104: delete_post_meta( $order_id, self::LEGACY_META_NAME_FEE ); 162: delete_post_meta( $order_id, self::META_NAME_NET ); 163: delete_post_meta( $order_id, self::LEGACY_META_NAME_NET ); /Users/asumaran/www/woocommerce-gateway-stripe/release/woocommerce-gateway-stripe/includes/class-wc-stripe-intent-controller.php: 409: 'metadata' => $gateway->get_metadata_from_order( $order ), /Users/asumaran/www/woocommerce-gateway-stripe/release/woocommerce-gateway-stripe/includes/admin/class-wc-stripe-privacy.php: 121: 'value' => get_post_meta( $order->get_id(), '_stripe_source_id', true ), 125: 'value' => get_post_meta( $order->get_id(), '_stripe_customer_id', true ), 186: 'value' => get_post_meta( $subscription->get_id(), '_stripe_source_id', true ), 190: 'value' => get_post_meta( $subscription->get_id(), '_stripe_customer_id', true ), 335: $stripe_source_id = get_post_meta( $subscription_id, '_stripe_source_id', true ); 354: delete_post_meta( $renewal_order_id, '_stripe_source_id' ); 355: delete_post_meta( $renewal_order_id, '_stripe_refund_id' ); 356: delete_post_meta( $renewal_order_id, '_stripe_customer_id' ); 359: delete_post_meta( $subscription_id, '_stripe_source_id' ); 360: delete_post_meta( $subscription_id, '_stripe_refund_id' ); 361: delete_post_meta( $subscription_id, '_stripe_customer_id' ); 374: $stripe_source_id = get_post_meta( $order_id, '_stripe_source_id', true ); 375: $stripe_refund_id = get_post_meta( $order_id, '_stripe_refund_id', true ); 376: $stripe_customer_id = get_post_meta( $order_id, '_stripe_customer_id', true ); 387: delete_post_meta( $order_id, '_stripe_source_id' ); 388: delete_post_meta( $order_id, '_stripe_refund_id' ); 389: delete_post_meta( $order_id, '_stripe_customer_id' ); /Users/asumaran/www/woocommerce-gateway-stripe/release/woocommerce-gateway-stripe/includes/compat/trait-wc-stripe-subscriptions.php: 384: update_post_meta( $subscription_id, '_stripe_customer_id', $source->customer ); 387: update_post_meta( $subscription_id, '_stripe_source_id', $source->payment_method ); 389: update_post_meta( $subscription_id, '_stripe_source_id', $source->source ); 400: delete_post_meta( $resubscribe_order->get_id(), '_stripe_customer_id' ); 401: delete_post_meta( $resubscribe_order->get_id(), '_stripe_source_id' ); 403: delete_post_meta( $resubscribe_order->get_id(), '_stripe_card_id' ); 405: delete_post_meta( $resubscribe_order->get_id(), '_stripe_intent_id' ); 419: delete_post_meta( $renewal_order->get_id(), '_stripe_intent_id' ); 433: update_post_meta( $subscription->get_id(), '_stripe_customer_id', $renewal_order->get_meta( '_stripe_customer_id', true ) ); 434: update_post_meta( $subscription->get_id(), '_stripe_source_id', $renewal_order->get_meta( '_stripe_source_id', true ) ); 449: $source_id = get_post_meta( $subscription_id, '_stripe_source_id', true ); 453: $source_id = get_post_meta( $subscription_id, '_stripe_card_id', true ); 456: update_post_meta( $subscription_id, '_stripe_source_id', $source_id ); 457: delete_post_meta( $subscription_id, '_stripe_card_id', $source_id ); 463: 'value' => get_post_meta( $subscription_id, '_stripe_customer_id', true ), 530: $stripe_source_id = get_post_meta( $subscription->get_id(), '_stripe_source_id', true ); 534: $stripe_source_id = get_post_meta( $subscription->get_id(), '_stripe_card_id', true ); 537: update_post_meta( $subscription->get_id(), '_stripe_source_id', $stripe_source_id ); 541: $stripe_customer_id = get_post_meta( $subscription->get_id(), '_stripe_customer_id', true ); 560: $stripe_customer_id = get_post_meta( $subscription->get_parent_id(), '_stripe_customer_id', true ); 561: $stripe_source_id = get_post_meta( $subscription->get_parent_id(), '_stripe_source_id', true ); 565: $stripe_source_id = get_post_meta( $subscription->get_parent_id(), '_stripe_card_id', true ); 568: update_post_meta( $subscription->get_parent_id(), '_stripe_source_id', $stripe_source_id ); /Users/asumaran/www/woocommerce-gateway-stripe/release/woocommerce-gateway-stripe/includes/payment-methods/class-wc-gateway-stripe-multibanco.php: 237: $data = get_post_meta( $order_id, '_stripe_multibanco', true ); 288: update_post_meta( $order_id, '_stripe_multibanco', $data ); /Users/asumaran/www/woocommerce-gateway-stripe/release/woocommerce-gateway-stripe/includes/payment-methods/class-wc-stripe-payment-request.php: 1584: $posted_data = $wc_checkout->get_posted_data(); /Users/asumaran/www/woocommerce-gateway-stripe/release/woocommerce-gateway-stripe/includes/payment-methods/class-wc-stripe-upe-payment-gateway.php: 534: $request['metadata'] = $this->get_metadata_from_order( $order ); 1268: public function get_metadata_from_order( $order ) { /Users/asumaran/www/woocommerce-gateway-stripe/tests/phpunit/helpers/class-wc-helper-product.php: 394: update_post_meta( $id, '_test2', 'world' ); 103 matches across 17 files ```
asumaran commented 2 years ago

Tests run with "Use the WooCommerce orders tables" option enabled

-- Starting from here "Keep the posts table and the orders tables synchronized" option was disabled --

asumaran commented 2 years ago

Refund related issues seem to be fixed now after @vedanshujain has merged enhancement/33771 into the cot-main branch.

asumaran commented 2 years ago

So I looked over the code and wanted to see which functions need to be updated or adjusted to work with COT. Here's the list:

So we need to take care of the get_post_meta, update_post_meta, delete_post_meta, and clean_post_cache functions only.

asumaran commented 2 years ago

I went through all the instances where get_post_meta, update_post_meta, delete_post_meta, and clean_post_cache are called and made sure it's working well with COT enabled and "Keep the posts table and the orders tables synchronized" unchecked.

Next step is to create a PR with tweaks for COT compatibility. Unfortunately, all the cases related to subscriptions are not supported for now because COT will not support WC Subscriptions. See pc2DNy-1V1-p2

get_post_meta

includes/admin/class-wc-stripe-privacy.php

includes/compat/trait-wc-stripe-subscriptions.php

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

[x] 1 instance in the get_instructions method.

update_post_meta

includes/compat/trait-wc-stripe-subscriptions.php

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

[x] 1 instance in the save_instructions method.

tests/phpunit/helpers/class-wc-helper-product.php

[x] 1 instance in the save_post_test_update_meta_data_direct method

delete_post_meta

includes/class-wc-stripe-helper.php

includes/admin/class-wc-stripe-privacy.php

includes/compat/trait-wc-stripe-subscriptions.php

clean_post_cache

includes/class-wc-gateway-stripe.php

cesarcosta99 commented 1 year ago

Doing another battery of tests with “Use the WooCommerce orders tables” option enabled:

Store setup:

  1. WordPress 6.1.1
  2. WooCommerce 7.2.2
  3. WooCommerce Blocks 9.3.0
  4. WooCommerce Stripe trunk (7f3cbdd9)
  5. WooCommerce Subscriptions 4.7.0

Starting from here “Keep the posts table and the orders tables synchronized” option was disabled.

Result:

No issues related to COT were found. When “Keep the posts table and the orders tables synchronized” was enabled, both wp_posts and wp_wc_orders have stayed in sync; after disabling it, only wp_wc_orders was having information being set – as expected.

Bugs found:

To do:

reykjalin commented 1 year ago

I switched my local dev store to HPOS and subscriptions don't seem to work for me.

Store setup

  1. WordPress v6.1.1
  2. WooCommerce v7.3.0
  3. WooCommerce Stripe develop (https://github.com/woocommerce/woocommerce-gateway-stripe/commit/d9ed8a9be5f67c6c4290032fea30b67d6617b46f) with the following patch applied:
diff --git a/woocommerce-gateway-stripe.php b/woocommerce-gateway-stripe.php
index 6a0a76c8..8b2a9359 100644
--- a/woocommerce-gateway-stripe.php
+++ b/woocommerce-gateway-stripe.php
@@ -777,7 +777,7 @@ add_action(
        'before_woocommerce_init',
        function() {
                if ( class_exists( '\Automattic\WooCommerce\Utilities\FeaturesUtil' ) ) {
-                       \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', __FILE__, false );
+                       \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', __FILE__, true );
                }
        }
 );
  1. WooCommerce Blocks v9.3.0 (Although I used the shortcode checkout)
  2. WooCommerce Subscriptions v4.7.0 with the following patch applied:
--- a/woocommerce-subscriptions.php
+++ b/woocommerce-subscriptions.php
add_action(
    'before_woocommerce_init',
    function() {
        if ( class_exists( '\Automattic\WooCommerce\Utilities\FeaturesUtil' ) ) {
-           \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', __FILE__, false );
+           \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', __FILE__, true );
        }
    }
);
  1. UPE is enabled in Stripe.

Testing flow

  1. Add a single (simple) subscription product with no free trial period to the cart.
  2. Go to the shortcode checkout.
  3. Complete checkout with the non-3DS test card 4242 4242 4242 4242.
  4. Go to wp-admin > WooCommerce > Orders and open the order details for the order.
  5. Order contains a subscription and was successfully processed. Overall looks normal.
  6. Stripe dashboard shows the payment was collected successfully.
  7. Go to wp-admin > WooCommerce > Subscriptions and notice the subscription is missing.
Order details Subscriptions list
image image
  1. Go to wp-admin > WooCommerce > Orders and open the order details for the order. From there open the details for the subscription order. Everything looks normal.
  2. Go to wp-admin > Tools > Scheduled Actions. Search for the renewal action and run it.
  3. Renewal action for the order fails.
Logs ``` 2023-01-17T00:57:17+00:00 DEBUG ====Stripe Version: 7.0.2==== ====Start Log==== Info: Begin processing subscription payment for order 191 for the amount of 10.00 ====End Log==== 2023-01-17T00:57:17+00:00 DEBUG ====Stripe Version: 7.0.2==== ====Start Log==== payment_intents request: Array ( [amount] => 1000 [currency] => usd [description] => Stripe - Order 191 [metadata] => Array ( [customer_name] => Tester Testerson [customer_email] => any@example.com [order_id] => 191 [site_url] => http://stripe.test [payment_type] => recurring ) [payment_method_types] => Array ( [0] => card [1] => link ) [off_session] => true [confirm] => true [confirmation_method] => automatic [statement_descriptor] => THRLKSN [customer] => cus_N7lr0MremTl2lc [shipping] => Array ( [name] => Tester Testerson [address] => Array ( [line1] => 60 29th St [line2] => #343 [city] => San Francisco [country] => US [postal_code] => 94110 [state] => CA ) ) ) ====End Log==== 2023-01-17T00:57:19+00:00 DEBUG ====Stripe Version: 7.0.2==== ====Start Log==== Info: Begin processing subscription payment for order 191 for the amount of 10.00 ====End Log==== 2023-01-17T00:57:19+00:00 DEBUG ====Stripe Version: 7.0.2==== ====Start Log==== payment_intents request: Array ( [amount] => 1000 [currency] => usd [description] => Stripe - Order 191 [metadata] => Array ( [customer_name] => Tester Testerson [customer_email] => any@example.com [order_id] => 191 [site_url] => http://stripe.test [payment_type] => recurring ) [payment_method_types] => Array ( [0] => card [1] => link ) [off_session] => true [confirm] => true [confirmation_method] => automatic [statement_descriptor] => THRLKSN [customer] => cus_N7lr0MremTl2lc [shipping] => Array ( [name] => Tester Testerson [address] => Array ( [line1] => 60 29th St [line2] => #343 [city] => San Francisco [country] => US [postal_code] => 94110 [state] => CA ) ) ) ====End Log==== 2023-01-17T00:57:21+00:00 DEBUG ====Stripe Version: 7.0.2==== ====Start Log==== Info: Begin processing subscription payment for order 191 for the amount of 10.00 ====End Log==== 2023-01-17T00:57:21+00:00 DEBUG ====Stripe Version: 7.0.2==== ====Start Log==== payment_intents request: Array ( [amount] => 1000 [currency] => usd [description] => Stripe - Order 191 [metadata] => Array ( [customer_name] => Tester Testerson [customer_email] => any@example.com [order_id] => 191 [site_url] => http://stripe.test [payment_type] => recurring ) [payment_method_types] => Array ( [0] => card [1] => link ) [off_session] => true [confirm] => true [confirmation_method] => automatic [statement_descriptor] => THRLKSN [customer] => cus_N7lr0MremTl2lc [shipping] => Array ( [name] => Tester Testerson [address] => Array ( [line1] => 60 29th St [line2] => #343 [city] => San Francisco [country] => US [postal_code] => 94110 [state] => CA ) ) ) ====End Log==== 2023-01-17T00:57:25+00:00 DEBUG ====Stripe Version: 7.0.2==== ====Start Log==== Info: Begin processing subscription payment for order 191 for the amount of 10.00 ====End Log==== 2023-01-17T00:57:25+00:00 DEBUG ====Stripe Version: 7.0.2==== ====Start Log==== payment_intents request: Array ( [amount] => 1000 [currency] => usd [description] => Stripe - Order 191 [metadata] => Array ( [customer_name] => Tester Testerson [customer_email] => any@example.com [order_id] => 191 [site_url] => http://stripe.test [payment_type] => recurring ) [payment_method_types] => Array ( [0] => card [1] => link ) [off_session] => true [confirm] => true [confirmation_method] => automatic [statement_descriptor] => THRLKSN [customer] => cus_N7lr0MremTl2lc [shipping] => Array ( [name] => Tester Testerson [address] => Array ( [line1] => 60 29th St [line2] => #343 [city] => San Francisco [country] => US [postal_code] => 94110 [state] => CA ) ) ) ====End Log==== 2023-01-17T00:57:30+00:00 DEBUG ====Stripe Version: 7.0.2==== ====Start Log==== Info: Begin processing subscription payment for order 191 for the amount of 10.00 ====End Log==== 2023-01-17T00:57:30+00:00 DEBUG ====Stripe Version: 7.0.2==== ====Start Log==== payment_intents request: Array ( [amount] => 1000 [currency] => usd [description] => Stripe - Order 191 [metadata] => Array ( [customer_name] => Tester Testerson [customer_email] => any@example.com [order_id] => 191 [site_url] => http://stripe.test [payment_type] => recurring ) [payment_method_types] => Array ( [0] => card [1] => link ) [off_session] => true [confirm] => true [confirmation_method] => automatic [statement_descriptor] => THRLKSN [customer] => cus_N7lr0MremTl2lc [shipping] => Array ( [name] => Tester Testerson [address] => Array ( [line1] => 60 29th St [line2] => #343 [city] => San Francisco [country] => US [postal_code] => 94110 [state] => CA ) ) ) ====End Log==== 2023-01-17T00:57:30+00:00 DEBUG ====Stripe Version: 7.0.2==== ====Start Log==== Info: Begin processing subscription payment for order 191 for the amount of 10.00 ====End Log==== 2023-01-17T00:57:30+00:00 DEBUG ====Stripe Version: 7.0.2==== ====Start Log==== payment_intents request: Array ( [amount] => 1000 [currency] => usd [description] => Stripe - Order 191 [metadata] => Array ( [customer_name] => Tester Testerson [customer_email] => any@example.com [order_id] => 191 [site_url] => http://stripe.test [payment_type] => recurring ) [payment_method_types] => Array ( [0] => card [1] => link ) [off_session] => true [confirm] => true [confirmation_method] => automatic [statement_descriptor] => THRLKSN [customer] => cus_N7lr0MremTl2lc [shipping] => Array ( [name] => Tester Testerson [address] => Array ( [line1] => 60 29th St [line2] => #343 [city] => San Francisco [country] => US [postal_code] => 94110 [state] => CA ) ) ) ====End Log==== 2023-01-17T00:57:31+00:00 DEBUG ====Stripe Version: 7.0.2==== ====Start Log==== Error: stdClass Object ( [error] => stdClass Object ( [code] => payment_intent_unexpected_state [doc_url] => https://stripe.com/docs/error-codes/payment-intent-unexpected-state [message] => You cannot confirm this PaymentIntent because it's missing a payment method. You can either update the PaymentIntent with a payment method and then confirm it again, or confirm it again directly with a payment method. [request_log_url] => https://dashboard.stripe.com/test/logs/req_eDMB8MdnINP1i4?t=1673917055 [type] => invalid_request_error ) ) ====End Log==== ```

The most relevant bit from the logs is this:

Error: stdClass Object
(
    [error] => stdClass Object
        (
            [code] => payment_intent_unexpected_state
            [doc_url] => https://stripe.com/docs/error-codes/payment-intent-unexpected-state
            [message] => You cannot confirm this PaymentIntent because it's missing a payment method. You can either update the PaymentIntent with a payment method and then confirm it again, or confirm it again directly with a payment method.
            [request_log_url] => https://dashboard.stripe.com/test/logs/req_eDMB8MdnINP1i4?t=1673917055
            [type] => invalid_request_error
        )

)

So it looks like there is no payment method assigned to the renewal payments? Not sure exactly what's going on.

  1. The new order in wp-admin > WooCommerce > Orders is Pending payment.
  2. There is now a subscription that's set to On Hold in wp-admin > WooCommerce > Subscriptions.
  3. Stripe dashboard shows no attempt at creating any sort of payment intent in the Payments List.
  4. The logs in the Stripe dashboard show 6 failed attempts:
image
reykjalin commented 1 year ago

Same thing happens on a fresh store, except now renewals work but there's no Subscription added to wp-admin > WooCommerce > Subscription 🤔

reykjalin commented 1 year ago

Hmmm, after I deleted the payment methods that were initially saved during the first few subscription trials to reduce the list of payment methods in the database the renewals started failing again, likely because no payment method was saved:

image

This is with UPE enabled. It seems like UPE + HPOS doesn't save payment methods? Even when I checkout with a simple product and tick "save payment method" there is still no payment method added.

Adding a payment method through the payment method screen caused them all the previous trial attempts to appear:

image
reykjalin commented 1 year ago

Switching back to the non-UPE checkout has renewals working again, but there are still no Subscriptions showing up in the subscriptions list.

reykjalin commented 1 year ago

Using UPE with Blocks checkout works the same as non-UPE with the blocks checkout, i.e. payments and renewals successful, but no Subscriptions show up in the subscriptions list.

So in my tests I think this is the array of support for subs, at least as long as the Subs plugin wraps up the support by making sure the Subscriptions show up in the Subscriptions list:

Shortcode Blocks
Non-UPE Checkout
UPE Checkout

The UPE Checkout with the shortcode block is likely failing because the payment method is not being saved for some reason, which I think is a problem I've seen before sometime 🤔

reykjalin commented 1 year ago

When I use the latest subs testing release from pdjTHR-1Fu-p2#comment-2572 everything seems to work actually, so the issue is only present with v4.7.0 of subs (which we already knew to be incompatible).

I'm just glad the shortcode+UPE issue is an issue in subs, not Stripe 😌

cesarcosta99 commented 1 year ago

@reykjalin In a fresh store using the very same setup you used, except Stripe, where I used 7.0.2, I could reproduce partially what you described here. I got the same until step 9 – the action runs fine and the order is processed and paid correctly, although, no subscriptions show up still.

After using the test release you mentioned it worked well 🙌 Replacing the subs 4.7.0 plugin with the test version in the same store step fixes the subscription list as well.

reykjalin commented 1 year ago

Doing another battery of tests with “Use the WooCommerce orders tables” option enabled:

Store setup

  1. WordPress 6.1.1
  2. WooCommerce 7.3.0
  3. WooCommerce Stripe develop (1c36361ad485c962f5c7d27578a1ae8f8d2c9356)
  4. WooCommerce Subscriptions Test Release from pdjTHR-1Fu-p2#comment-2572

Flows

Note All tests done with HPOS enabled and “Keep the posts table and the orders tables synchronized" disabled.

Note Testing was done on a fresh store, but before starting the flows I processed 1 payment with HPOS turned off in an attempt to simulate a store that's migrating from WP tables to HPOS.

Result

There seems to be an issue with saving cards when UPE is enabled causing cascading issues for subscriptions. The first payment seems to work, subscriptions are created correctly, and renewal jobs are properly instantiated. The only thing missing is payment method saving functionality.

Bugs found

  1. Saving cards is flaky at best. For some reason it was working for me last night but is not today. I'm not sure why.
    • This consequently makes it so subscriptions don't work. Not sure if the fault is with the plugin, subscriptions, HPOS, or any combination of all three.

To do

cesarcosta99 commented 1 year ago

@reykjalin I retested all of the items that failed for you. The following worked for me under the same store setup (with Stripe 7.0.2):

Can you double-check the ones above in a fresh store to confirm?

I spun up a new store with Stripe 7.0.2 and HPOS disabled and all tests under "Shopper - Subscriptions" that failed with HPOS enabled passed in this store. I'm investigating this.

cesarcosta99 commented 1 year ago

Created #2531 to track failing critical flows.

asumaran commented 1 year ago

@reykjalin I retested all of the items that failed for you. The following worked for me under the same store setup (with Stripe 7.0.2):

  • Shopper - Checkout - Save card at checkout

    • UPE: ❌ This did not work; the card wasn't saved.
    • No UPE: ❌ This did not work; the card wasn't saved.
  • Shopper - WooCommerce Blocks - Save card at checkout

    • UPE: ❌ This did not work; the card wasn't saved.

@cesarcosta99 @reykjalin This worked for me as well. With HPOS enabled and UPE enabled/disabled and using shortcode based checkout or checkout block.