Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Revise checkout payment statuses to avoid data loss on error #5350

Merged
merged 13 commits into from
Dec 10, 2021

Conversation

mikejolley
Copy link
Member

@mikejolley mikejolley commented Dec 9, 2021

We're seeing errors and inconsistencies with payment method data being lost when errors cause a status change (to pristine) on checkout. On reviewing this, we've also noticed some discrepancies with how statuses (in particular the STARTED status) are used in a non-documented way. It's also confusing how some data is stored in the context provider, some in hooks, and yet it all needs to be kept in sync (currently with useEffect calls).

To solve this, I've taken the following approach:

  • Existing payment statuses are left in place (unlike this PR which added an IDLE status). The main difference here is, like specified in the docs, STARTED is reserved only for Express Payment Methods. Before this PR, saved methods were also using this status to add extra data (tokens).
  • Fixed PRISTINE status so that it only removes errors, not payment method data.
  • Removed the useActivePaymentMethod hook which had methods to set active method, and active token. This has been replaced with data in the context provider.
  • setActivePaymentMethod now accepts payment method data. By consolidating it within this function, saved methods no longer need to use the STARTED status to store data.
  • Consolidated active payment method with active token. The active token can be derived from the active payment method's defined data. Removed setActiveToken.
  • When a different method is made active, all payment data is cleared so that it doesn't linger for other methods.
  • The logic for selecting a default gateway was handled in two places. Saved methods, and the main context provider. I've combined this into one useEffect hook to avoid conflicts.

Fixes #5296
Closes #5318 in favor of this.

Testing

Please smoke test the following:

  1. Payment using a core gateway (BACS, Check)
  2. Payment via Stripe (using a new test card)
  3. Payment via a saved card (with Stripe)
  4. Payment via an express payment method (also Stripe)
  5. Start an express payment and cancel it. Confirm the previously selected gateway is selected after cancellation.

Also, test the case from #5296.

  1. Go to checkout and select a saved method for payment
  2. Leave a required field blank and place order
  3. See error
  4. Correct mistake and place order again. Order should go through.

Changelog

Fixed a case where payments could fail after validation errors when using saved cards.

@mikejolley mikejolley self-assigned this Dec 9, 2021
@mikejolley mikejolley added block: checkout Issues related to the checkout block. type: refactor The issue/PR is related to refactoring. type: bug The issue/PR concerns a confirmed bug. labels Dec 9, 2021
@mikejolley mikejolley requested a review from senadir December 9, 2021 14:53
@rubikuserbot rubikuserbot requested a review from a team December 9, 2021 14:53
@github-actions
Copy link
Contributor

github-actions bot commented Dec 9, 2021

Size Change: +20 B (0%)

Total Size: 840 kB

Filename Size Change
build/all-products-frontend.js 18.6 kB -6 B (0%)
build/all-products.js 34.4 kB -20 B (0%)
build/atomic-block-components/add-to-cart--atomic-block-components/button--atomic-block-components/image---a7e2bb9b.js 2.76 kB -1 B (0%)
build/atomic-block-components/add-to-cart.js 6.42 kB -1 B (0%)
build/atomic-block-components/button-frontend.js 1.48 kB +2 B (0%)
build/atomic-block-components/button.js 849 B +1 B (0%)
build/atomic-block-components/image-frontend.js 1.38 kB +1 B (0%)
build/atomic-block-components/image.js 1.05 kB +1 B (0%)
build/atomic-block-components/price-frontend.js 1.74 kB -1 B (0%)
build/atomic-block-components/title.js 1.1 kB +1 B (0%)
build/attribute-filter-frontend.js 16.6 kB +4 B (0%)
build/cart-blocks/express-payment-frontend.js 4.84 kB -22 B (0%)
build/cart-blocks/order-summary-frontend.js 8.97 kB +5 B (0%)
build/cart-frontend.js 45.5 kB +30 B (0%)
build/cart.js 44 kB +43 B (0%)
build/checkout-blocks/contact-information-frontend.js 2.94 kB -2 B (0%)
build/checkout-blocks/express-payment-frontend.js 5.14 kB -23 B (0%)
build/checkout-blocks/order-summary-frontend.js 11.5 kB +9 B (0%)
build/checkout-blocks/payment-frontend.js 7.43 kB -49 B (-1%)
build/checkout-blocks/shipping-methods-frontend.js 4.81 kB +3 B (0%)
build/checkout-frontend.js 47.6 kB +31 B (0%)
build/checkout.js 47 kB -19 B (0%)
build/handpicked-products.js 7.33 kB -1 B (0%)
build/mini-cart-component-frontend.js 37.6 kB +17 B (0%)
build/mini-cart.js 6.66 kB +1 B (0%)
build/price-filter-frontend.js 12.4 kB +7 B (0%)
build/product-category.js 8.36 kB +1 B (0%)
build/product-new.js 7.67 kB +1 B (0%)
build/product-tag.js 7.77 kB +1 B (0%)
build/products-by-attribute.js 8.49 kB +1 B (0%)
build/reviews-by-category.js 11.9 kB +1 B (0%)
build/reviews-by-product.js 12.9 kB +1 B (0%)
build/reviews-frontend.js 7.23 kB +1 B (0%)
build/single-product-frontend.js 22 kB -5 B (0%)
build/stock-filter-frontend.js 6.81 kB +8 B (0%)
build/vendors--atomic-block-components/add-to-cart--cart-blocks/order-summary--checkout-blocks/billing-ad--c5eb4dcd-frontend.js 18.9 kB -1 B (0%)
ℹ️ View Unchanged
Filename Size
build/active-filters-frontend.js 6.21 kB
build/active-filters.js 7.06 kB
build/all-reviews.js 8.35 kB
build/atomic-block-components/add-to-cart--atomic-block-components/button.js 1.48 kB
build/atomic-block-components/add-to-cart-frontend.js 6.88 kB
build/atomic-block-components/category-list-frontend.js 458 B
build/atomic-block-components/category-list.js 458 B
build/atomic-block-components/price.js 1.69 kB
build/atomic-block-components/rating-frontend.js 553 B
build/atomic-block-components/rating.js 553 B
build/atomic-block-components/sale-badge-frontend.js 626 B
build/atomic-block-components/sale-badge.js 622 B
build/atomic-block-components/sku-frontend.js 386 B
build/atomic-block-components/sku.js 385 B
build/atomic-block-components/stock-indicator-frontend.js 585 B
build/atomic-block-components/stock-indicator.js 586 B
build/atomic-block-components/summary-frontend.js 875 B
build/atomic-block-components/summary.js 872 B
build/atomic-block-components/tag-list-frontend.js 459 B
build/atomic-block-components/tag-list.js 458 B
build/atomic-block-components/title-frontend.js 1.11 kB
build/attribute-filter.js 12.7 kB
build/blocks-checkout.js 17.6 kB
build/cart-blocks/accepted-payment-methods-frontend.js 1.14 kB
build/cart-blocks/checkout-button-frontend.js 1.14 kB
build/cart-blocks/empty-cart-frontend.js 345 B
build/cart-blocks/filled-cart-frontend.js 767 B
build/cart-blocks/items-frontend.js 297 B
build/cart-blocks/line-items-frontend.js 5.14 kB
build/cart-blocks/totals-frontend.js 320 B
build/checkout-blocks/actions-frontend.js 1.45 kB
build/checkout-blocks/billing-address--checkout-blocks/shipping-address-frontend.js 4.25 kB
build/checkout-blocks/billing-address-frontend.js 887 B
build/checkout-blocks/fields-frontend.js 343 B
build/checkout-blocks/order-note-frontend.js 1.13 kB
build/checkout-blocks/shipping-address-frontend.js 973 B
build/checkout-blocks/terms-frontend.js 1.22 kB
build/checkout-blocks/totals-frontend.js 323 B
build/featured-category.js 8.55 kB
build/featured-product.js 9.9 kB
build/legacy-template.js 2.05 kB
build/mini-cart-contents.js 3.46 kB
build/mini-cart-frontend.js 1.76 kB
build/price-filter.js 8.61 kB
build/price-format.js 1.18 kB
build/product-best-sellers.js 7.51 kB
build/product-categories.js 3.47 kB
build/product-on-sale.js 8.05 kB
build/product-search.js 2.47 kB
build/product-top-rated.js 7.63 kB
build/single-product.js 10.4 kB
build/stock-filter.js 6.83 kB
build/vendors--atomic-block-components/add-to-cart-frontend.js 6.81 kB
build/vendors--atomic-block-components/price--cart-blocks/line-items--cart-blocks/order-summary--checkout--8a3571de-frontend.js 5.71 kB
build/vendors--cart-blocks/line-items--checkout-blocks/order-summary-frontend.js 3.14 kB
build/vendors--cart-blocks/order-summary--checkout-blocks/billing-address--checkout-blocks/order-summary---eb4d2cec-frontend.js 4.74 kB
build/wc-blocks-data.js 8.84 kB
build/wc-blocks-editor-style-rtl.css 4.27 kB
build/wc-blocks-editor-style.css 4.28 kB
build/wc-blocks-google-analytics.js 1.56 kB
build/wc-blocks-middleware.js 949 B
build/wc-blocks-registry.js 2.7 kB
build/wc-blocks-shared-context.js 1.51 kB
build/wc-blocks-shared-hocs.js 1.14 kB
build/wc-blocks-style-rtl.css 21.1 kB
build/wc-blocks-style.css 21.1 kB
build/wc-blocks-vendors-style-rtl.css 1.28 kB
build/wc-blocks-vendors-style.css 1.28 kB
build/wc-blocks-vendors.js 65.4 kB
build/wc-blocks.js 2.96 kB
build/wc-payment-method-bacs.js 820 B
build/wc-payment-method-cheque.js 816 B
build/wc-payment-method-cod.js 912 B
build/wc-payment-method-paypal.js 838 B
build/wc-payment-method-stripe.js 11.1 kB
build/wc-settings.js 2.6 kB

compressed-size-action

[ savedTokenKey ]: token.toString(),
isSavedToken: true,
} );
removeNotice(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was previously handled in the context provider via useEffect, but because we want the token and method ID it seemed best to move it all to the onClick handler.

@@ -79,10 +80,10 @@ const ExpressPaymentMethods = () => {
( errorMessage ) => {
setPaymentStatus().error( errorMessage );
setExpressPaymentError( errorMessage );
setActivePaymentMethod( previousActivePaymentMethod.current );
if ( previousPaymentMethodData.current.isSavedToken ) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code appears to have been added as a workaround for started/pristine data resetting. Saved methods should not be using STARTED so I've removed it.

};
setActivePaymentMethod: (
paymentMethod: string,
paymentMethodData?: ObjectType | EmptyObjectType
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Data can now be set at the same time as setting an active payment method. This removes the need to use STARTED status to set data.

type: STATUS.SUCCESS,
paymentMethodData,
} as const ),
started: ( {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we can no longer dispatch started?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's dispatched as statusOnly now like pristine. That's all express methods need. The data addition was added for saved payment methods - with the new setActivePaymentMethod method that's no longer a requirement. They can stay pristine.

if (
! activePaymentMethod &&
paymentMethod.is_default &&
activeSavedToken === ''
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why we were handling defaults here. I moved it to context with the other default setter.

Copy link
Member

@senadir senadir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests and works very well!

@github-actions github-actions bot added this to the 6.6.0 milestone Dec 10, 2021
@senadir senadir merged commit eb607e8 into trunk Dec 10, 2021
@senadir senadir deleted the fix/5296-missing-payment-method-data branch December 10, 2021 15:26
jonny-bull pushed a commit to jonny-bull/woocommerce-gutenberg-products-block that referenced this pull request Dec 14, 2021
…erce#5350)

* Clarify docs for STARTED

* Clarify docs for setActivePaymentMethod

* Remove useActivePaymentMethod hook (this held state for active methods and tokens)

* Update type defs

* Enhance setActivePaymentMethod action to accept method data

* SET_ACTIVE_PAYMENT_METHOD action

* Add setActivePaymentMethod dispatcher and make "started" status only

* Update setActivePaymentMethod usage in express methods

* Set radio control defaults

* Consolodate tokens and methods

* Update assets/js/base/context/providers/cart-checkout/payment-methods/reducer.ts

Co-authored-by: Seghir Nadir <[email protected]>

* Spacing

* Split saved cards tests from regular, since saved cards are checked by default

Co-authored-by: Seghir Nadir <[email protected]>
@chrism245
Copy link

Issue reported here as as well 4580573-zen.

jonny-bull pushed a commit to jonny-bull/woocommerce-gutenberg-products-block that referenced this pull request Dec 16, 2021
…erce#5350)

* Clarify docs for STARTED

* Clarify docs for setActivePaymentMethod

* Remove useActivePaymentMethod hook (this held state for active methods and tokens)

* Update type defs

* Enhance setActivePaymentMethod action to accept method data

* SET_ACTIVE_PAYMENT_METHOD action

* Add setActivePaymentMethod dispatcher and make "started" status only

* Update setActivePaymentMethod usage in express methods

* Set radio control defaults

* Consolodate tokens and methods

* Update assets/js/base/context/providers/cart-checkout/payment-methods/reducer.ts

Co-authored-by: Seghir Nadir <[email protected]>

* Spacing

* Split saved cards tests from regular, since saved cards are checked by default

Co-authored-by: Seghir Nadir <[email protected]>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
block: checkout Issues related to the checkout block. type: bug The issue/PR concerns a confirmed bug. type: refactor The issue/PR is related to refactoring.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Checkout: Selected payment method token gets out of sync with paymentMethodData
3 participants