-
Notifications
You must be signed in to change notification settings - Fork 16
feat: handle payment error on trial #910
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
base: main
Are you sure you want to change the base?
feat: handle payment error on trial #910
Conversation
| current_list = client.list_subscriptions(enterprise_uuid, current=True) | ||
| current_results = (current_list or {}).get('results', []) | ||
| current_plan = current_results[0] if current_results else None | ||
| if not current_plan: | ||
| logger.warning( | ||
| "No current subscription plan found for enterprise %s when canceling future plans (subscription %s)", | ||
| enterprise_uuid, subscription_id_for_logs, | ||
| ) | ||
| return deactivated | ||
|
|
||
| current_plan_uuid = str(current_plan.get('uuid')) | ||
|
|
||
| # Fetch all active plans for enterprise | ||
| all_list = client.list_subscriptions(enterprise_uuid) | ||
| all_plans = (all_list or {}).get('results', []) | ||
|
|
||
| future_plans = future_plans_of_current(current_plan_uuid, all_plans) |
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.
One possible area for improvement:
As written, this will make two API calls, but we could make it only 1 with something like this:
all_enterprise_subscriptions = client.list_subscriptions(enterprise_uuid)
current_plans, other_plans = [], []
for sub in all_enterprise_subscriptions:
if sub.get('is_current'):
current_plans.append(sub)
else:
other_plans.append(sub)
if not current_plans:
return
current_plan_uuid = str(current_plan.get('uuid'))
future_plans = future_plans_of_current(current_plan_uuid, other_plans)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 @iloveagent57, makes sense. I still have a bit of clean up work to do.
I just wanted to get the PR up so I could get your input on the email task. You mentioned you were looking into a wrapper for Braze, which seems a bit overkill. Seeing as the emails tend to have different logic it makes sense to keep the logic separate for each. But in this case the 2 functions are very similar.
Do you prefer I:
A) Keep the duplication
B) DRY up just these methods in this class
C) Look at a better wrapper solution for this and other emails
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.
Ah, I see what you're saying. Yeah, wrapper might be overkill. If there's easy/obvious opportunities to DRY stuff up, go ahead and do that, otherwise don't worry about it.
4fc4868 to
357d021
Compare
| prior_status = getattr(checkout_intent.previous_summary(event), 'subscription_status', None) | ||
| if current_status == "canceled" and prior_status != "canceled": | ||
| trial_end = subscription.get("trial_end") | ||
| if trial_end: |
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.
[request] Add an else block to this with logger.warn("cancellation code branch reached, but handler not yet implemented.")
| def cancel_all_future_plans(enterprise_uuid: str, reason: str = 'delayed_payment', subscription_id_for_logs: str | None = None) -> list[str]: | ||
| """ | ||
| Deactivate (cancel) all future plans for the current plan of the given enterprise. | ||
| Returns list of deactivated plan UUIDs. Logs warnings/info for observability. | ||
| """ |
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.
This approach exposes us to liability because it is sensitive to any future change we might make to allow multiple current SubscriptionPlans to exist aside from the stripe-managed one, or any change to allow multiple Stripe Subscriptions per customer. I'd recommend taking into account some other data to join to make sure the plans being deactivated are somehow related to the stripe Subscription.
I don't have a tested recommendation, but maybe there's something you can do with the CheckoutIntent. E.g. get the CheckoutIntent ID from the subscription object, then get the subscription plan lineage from the CheckoutIntent record.
| ) | ||
| raise | ||
|
|
||
| def update_subscription_plan(self, subscription_uuid, **payload): |
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.
@pwnage101 I've got a few merge conflicts around this function, I need to use it too just to set the status and reason. Any reason you have explicit arguments inside the current function on main? I normally exclude any logic from the update function and keep it more loosely coupled and have a single responsibility.
FYI, I have not merged your most recent work yet, you've release more changes on Friday since my last rebase.
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.
FWIW, I would change the signature and logic of the update payload to accomodate this like so:
def update_subscription_plan(self, subscription_uuid, salesforce_opportunity_line_item=None, **kwargs):
payload = {**kwargs)
if salesforce_opportunity_line_item:
payload['salesforce_opportunity_line_item'] = salesforce_opportunity_line_item1611611 to
a026bea
Compare
a026bea to
cb9765d
Compare
Description:
Add a description of your changes here.
Jira:
ENT-10761
Merge checklist:
./manage.py makemigrationshas been runPost merge: