-
Notifications
You must be signed in to change notification settings - Fork 85
Handle customer.subscription.deleted webhook #513
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
Conversation
sbatson5
left a 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.
Just a couple of questions and comments. This is looking good 👍
| {:ok, subscription} | ||
| else | ||
| {:error, :project_not_ready} -> {:error, :project_not_ready} | ||
| {:error, :user_not_ready} -> {:error, :user_not_ready} |
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.
It seems that all these cases return what we are matching against. What are your thoughts on just matching on nil and then returning everything else.
nil -> {:error, :not_found}
error_tuple -> error_tuple
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'd like to keep it explicit because I'm expecting we might be doing custom handling/errors at some point. I can move that into a comment above the line, though.
| defp to_create_attributes(%StripeConnectCard{} = card, %StripeConnectCustomer{} = customer, %StripeConnectPlan{} = plan, quantity) do | ||
| defp to_create_attributes( | ||
| %StripeConnectCard{} = card, %StripeConnectCustomer{} = customer, | ||
| %StripeConnectPlan{} = plan, %{"quantity" => quantity} |
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.
Do we need to pattern match here for StripeConnectCard and StripeConnectPlan etc? This is the only method we have by this name, so the pattern matching seems unnecessary when we could simply do:
defp to_create_attributes(card, customer, plan, %{"quantity" => quantity)
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.
Good catch. The validate call at the start of the process actually does all the pattern matching required.
| defp retrieve_connect_account(connect_customer_id) do | ||
| customer = StripeConnectCustomer | ||
| |> Repo.get_by(id_from_stripe: connect_customer_id) | ||
| |> Repo.preload(:stripe_connect_account) |
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.
Can we indent here?
|
|
||
| defp load_subscription(id_from_stripe) do | ||
| subscription = StripeConnectSubscription | ||
| |> Repo.get_by(id_from_stripe: id_from_stripe) |
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.
Same as above. I believe the style is to indent when we are assigning
| updated_account = | ||
| StripeConnectAccount | ||
| |> Repo.get_by(id_from_stripe: stripe_id) | ||
| updated_account = StripeConnectAccount |> Repo.get_by(id_from_stripe: stripe_id) |
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.
Thoughts on not piping here? updated_account = Repo.get_by(StripeConnectAccount, id_from_stripe: stripe_id)
|
|
||
| conn = post conn, stripe_connect_events_path(conn, :create), event | ||
|
|
||
| assert response(conn, 200) |
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.
Thoughts on piping this block?
assert conn |> post(stripe_connect_events_path(conn, :create), event) |> response(200)
|
@begedin feel free to merge when you're comfortable making any changes you'd like in response to code review comments. Don't await another review. |
a88bb45 to
259de3b
Compare
…able, by adding validators
259de3b to
cc9313d
Compare
cc9313d to
c0e2dc7
Compare
What's in this PR?
This PR adds handling of the
customer.subscription.deletedevent.Since the actual subscription stripe record is not deleted, instead simply removed from the customer account, and it's status set to cancelled, the solution was to simply handle it identically to
customer.subscription.updated.This raises a question, though.
Should our API, when requesting a user's subscriptions, only return those that are active, or all of them?
If the answer is all of them, then we need to modify our client logic so that the donate UI is hidden/redirected from only if there is an active subscription, not just any subscription as it is right now.
If the answer is only those that are active, then we need to modify our user/project views.
Implementation
The logical place to put the update code was
CodeCorps.StripeService.StripeConnectSubscriptionService.However, I found the code there difficult to understand and manage, so adding additional code there would make it even worse.
In an attempt to remedy this, I refactored the module:
I rewrote a few methods
I added validator modules -
ProjectSubscribableandUserCanSubscribe.These both have a
validate/1method, which receives aProjectorUserrecord respectively. It either returns back an{:ok, record}or an{:error, :project_not_ready}/{:error, :user_not_ready}if the two records do not have the necessary stripe relationships set up.The idea is that these validators are a simple blackbox that determines if a user or a project is able to participate in the donation system. It allows us to have less checks in the subscription creation process reduces the required size of method signatures there, making the code more readable.
Once that was in, I cleaned up further and then moved the logic from
Events.CustomerSubscriptionUpdatedintoStripeConnectSubscriptionService.update_from_stripe/2. This same method is then used byEvents.CustomerSubscriptionDeleted.References
Fixes #509
Progress on: #