Skip to content

Conversation

@jono-booth
Copy link
Contributor

Description:
Add a description of your changes here.

Jira:
ENT-10761

Merge checklist:

  • ./manage.py makemigrations has been run
    • Note: This must be run if you modified any models.
      • It may or may not make a migration depending on exactly what you modified, but it should still be run.

Post merge:

  • Ensure that your changes went out to the stage instance
  • Deploy to prod instance

@jono-booth jono-booth changed the title feat: handle payment error on trial WIP: handle payment error on trial Oct 29, 2025
Comment on lines 174 to 190
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)
Copy link
Contributor

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)

Copy link
Contributor Author

@jono-booth jono-booth Oct 30, 2025

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

Copy link
Contributor

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.

@jono-booth jono-booth force-pushed the jono-booth/stripe-payment-error branch from 4fc4868 to 357d021 Compare November 3, 2025 13:02
@jono-booth jono-booth changed the title WIP: handle payment error on trial feat: handle payment error on trial Nov 3, 2025
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:
Copy link
Contributor

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.")

Comment on lines 166 to 171
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.
"""
Copy link
Contributor

@pwnage101 pwnage101 Nov 4, 2025

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):
Copy link
Contributor Author

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.

Copy link
Contributor

@iloveagent57 iloveagent57 Nov 10, 2025

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_item

@jono-booth jono-booth force-pushed the jono-booth/stripe-payment-error branch 2 times, most recently from 1611611 to a026bea Compare November 12, 2025 07:45
@jono-booth jono-booth force-pushed the jono-booth/stripe-payment-error branch from a026bea to cb9765d Compare November 12, 2025 09:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants