-
Notifications
You must be signed in to change notification settings - Fork 336
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(stripe): Fix the bug when there's failed payment we charge customer extra amount #8072
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really appreciate the testing steps with screenshots! It made my life as a reviewer really easy. It works, and LGTM!
I wonder which tune it sings |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good and it's the best type of fix where we just remove broken code 😎
However the changes in terminateSubscription appear wrong, are these covered by the test case?
@@ -18,7 +18,7 @@ const terminateSubscription = async (orgId: string) => { | |||
stripeSubscriptionId: null | |||
}, | |||
{returnChanges: true} | |||
)('changes')(0)('old_val') | |||
)('changes')(0)('old_val')('stripeSubscriptionId') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-1 this seems to contradict how we're reading the rethinkResult
in line l26
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't sure what you meant by contradiction, but I made a few changes to make it more clear & easy to read. Let me know if that's what you were thinking?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the change, now I understand what you were doing.
@@ -32,7 +32,7 @@ const terminateSubscription = async (orgId: string) => { | |||
try { | |||
await manager.deleteSubscription(stripeSubscriptionId) | |||
} catch (e) { | |||
// noop | |||
console.error(`cannot delete subscription ${stripeSubscriptionId}`, e) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 Reading the comment in l28 it appears as if we intentionally do not track errors here. Are you sure this is necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would highly suspect that it never did what it was supposed to do... the issue was hidden as we didn't have that many self upgrades in the past, let alone the even rare cases where the payment failed.
As a quick test, I commented out this part as the comment seemed to indicate, i.e., it wouldn't harm if the deletion failed or not even performed, as Stripe is configured to do so automatically. Well, not the case here. If the customer failed to perform the first payment and just did nothing, this is gonna happen:
- A failed payment notification was sent
- The invoice stays in PENDING state
- The org still stays in the Team tier, i.e., the customer is enjoying the Team tier for free
Looking at Stripe side, after 24 hours, this is going to happen:
- The invoice is void
- The payment was cancelled
- The subscription was incomplete
But again, none of those prevent us from giving the customers Team tier for free, from the app side.
So, all in all, we definitely need that subscription deletion to finish and succeed, in order for the app to cancel that upgrade. Therefore, we should capture the error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for investigating this and removing the comment!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did not test again, but looks good now!
@@ -32,7 +32,7 @@ const terminateSubscription = async (orgId: string) => { | |||
try { | |||
await manager.deleteSubscription(stripeSubscriptionId) | |||
} catch (e) { | |||
// noop | |||
console.error(`cannot delete subscription ${stripeSubscriptionId}`, e) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for investigating this and removing the comment!
@@ -18,7 +18,7 @@ const terminateSubscription = async (orgId: string) => { | |||
stripeSubscriptionId: null | |||
}, | |||
{returnChanges: true} | |||
)('changes')(0)('old_val') | |||
)('changes')(0)('old_val')('stripeSubscriptionId') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the change, now I understand what you were doing.
Description
Fixes #8061. To reproduce the bug, on
master
branch:stripe listen --forward-to localhost:3000/stripe
, and copy the webhook singing secret to replace the one in your .env4000 0000 0000 3063
, expiration date any month in the future, CVC can be anythingNow update the credit card number to
4242 4242 4242 4242
Wait a moment and then refresh the page, you should see a new invoice generated and paid with 2x of the amount, indicating the customer has been double charged.
Testing scenarios
With this branch pulled and server started, repeat the above-mentioned steps 3 - 5.
4242 4242 4242 4242
Final checklist
One Review Required
if the PR introduces only minor changes, does not contain any architectural changes or does not introduce any new patterns and I think one review is sufficient'