W-21372336: Fail Order for redirect based payments#3707
W-21372336: Fail Order for redirect based payments#3707rasbhat merged 3 commits intot/team404/sfp-on-pwafrom
Conversation
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
packages/template-retail-react-app/app/pages/checkout/payment-processing.jsx
Show resolved
Hide resolved
|
|
||
| const isError = !isValidReturnUrl() | ||
| const isHandled = useRef(false) | ||
| const failOrderCalledRef = useRef(false) |
There was a problem hiding this comment.
If there's an easy way to combine this with isHandled I think it would be more readable. If no easy way, then we can save that for a later refactor.
There was a problem hiding this comment.
Tested it. Seems like isHandled is already handling it. failOrderCalledRef was redundant. removed it.
| } | ||
| }) | ||
| } catch { | ||
| // Order may already be failed by webhook; avoid hanging |
There was a problem hiding this comment.
Do we only have a catch block to contain the comment describing why we don't need a catch block?
There was a problem hiding this comment.
Might need the catch to handle a few scenarios for us to avoid hanging. Listed the possible scenarios in a comment here.
| // Navigate back to the checkout page to try again | ||
| navigate('/checkout') | ||
| // Redirect to cart when payment fails | ||
| navigate('/cart') |
There was a problem hiding this comment.
When we hit this case it's because a gateway redirected the shopper back to the storefront, and the payment failed. We would like to navigate the shopper back to the start of the redirect which is the checkout page.
There was a problem hiding this comment.
Makes sense, reverted back to navigate to checkout. Updated the screenshot in description that reflects it.
packages/template-retail-react-app/app/pages/checkout/payment-processing.jsx
Outdated
Show resolved
Hide resolved
| expect(mockNavigate).toHaveBeenCalledWith('/cart') | ||
| }) | ||
|
|
||
| test('does not call failOrder when order already failed by webhook (e.g. 3DS declined)', async () => { |
There was a problem hiding this comment.
Do we need a test for scenario of the race condition that I think the catch block covers in the component code? e.g. the failOrder API fails because it's already in failed state.
There was a problem hiding this comment.
Seems like that might be a scenario too! Good catch! Listed it in the catch block comment and added a test for the same.
|
|
||
| try { | ||
| const token = await getTokenWhenReady() | ||
| const currentOrder = await api.shopperOrders.getOrder({ |
There was a problem hiding this comment.
There is a useOrder hook. Can we use that or is specific way to do it the way you are doing it here? Having to get and set bearer token in the component seems off
There was a problem hiding this comment.
Makes sense. used useOrder. I was referring to express payments implementataion, where token is manually set.
There was a problem hiding this comment.
If express is wrong then should we update it?
323c664 to
5f0e22f
Compare
| } | ||
| }) | ||
| } catch (error) { | ||
| // Swallow so flow continues (invalidate, navigate). Causes: (1) Race: refetch |
There was a problem hiding this comment.
Thanks for this comment. IMO the fact the framework level design decisions bring us to this scenario where swallowing an error is the right path, implicates those decisions not our code as a consumer. I'm ok with this.
There was a problem hiding this comment.
If there was a way to recover the basket even when fail order fails (and not just when it passes) then it might be consistent. That reopen flag isn't really reopening in a failure case.
The only difference is Express is throwing some toast, so doing nothing in catch is fine here
const basketRecovered = await attemptFailOrder(createdOrderNo)
if (basketRecovered) {
showErrorMessage(ERROR_MESSAGE_KEYS.FAIL_ORDER)
} else {
showErrorMessage(ERROR_MESSAGE_KEYS.ORDER_RECOVERY_FAILED)
if (usage !== EXPRESS_BUY_NOW) {
navigate('/cart')
}
}
…/fail-order-on-redirect W-21372336: Fail Order for redirect based payments
…/fail-order-on-redirect W-21372336: Fail Order for redirect based payments
…/fail-order-on-redirect W-21372336: Fail Order for redirect based payments
Description
When we have a failed order on redirect based payments, checkout page just kept loading indefinitely.
Cause:
Previously, the code always called failOrder when payment failed or the return URL was invalid. But this caused an issue when either payment already failed on provider's end, or a webhook already failed it : the user landed on the checkout page, and tried to fail the same order again which caused the load indefinitely.
Fix: We try to fail an order if the order is still in a state we can fail. We also attempt to fail the order only once per page load (guardrail against multiple failOrders)
Testing:
Types of Changes
Changes
How to Test-Drive This PR
Checklists
General
Accessibility Compliance
You must check off all items in one of the follow two lists:
or...
Localization