Skip to content

Commit df621a2

Browse files
jajjibhai008iloveagent57
authored andcommitted
feat: send trial cancelation confirmation braze email
1 parent 99086c6 commit df621a2

File tree

3 files changed

+27
-18
lines changed

3 files changed

+27
-18
lines changed

enterprise_access/apps/customer_billing/stripe_event_handlers.py

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -240,25 +240,31 @@ def subscription_updated(event: stripe.Event) -> None:
240240
)
241241

242242
# Handle trial subscription cancellation
243-
# TODO: Check that status wasn't already canceled to avoid duplicate emails.
244-
# This will be easier to implement once StripeEventSummary changes land,
245-
# which will provide easier querying of prior subscription states.
246-
if subscription.get("status") == "canceled":
247-
trial_end = subscription.get("trial_end")
248-
if trial_end:
249-
logger.info(
250-
f"Queuing trial cancellation email for subscription {subscription.id}, "
251-
f"checkout_intent_id={checkout_intent_id}"
252-
)
253-
254-
# Queue the async task to send the email
255-
send_trial_cancellation_email_task.delay(
256-
checkout_intent_id=checkout_intent.id,
257-
trial_end_timestamp=trial_end,
258-
)
243+
# Check if status changed to canceled to avoid duplicate emails
244+
current_status = subscription.get("status")
245+
if current_status == "canceled":
246+
prior_status = getattr(checkout_intent.previous_summary(event), 'subscription_status', None)
247+
248+
# Only send email if status changed from non-canceled to canceled
249+
if prior_status != 'canceled':
250+
trial_end = subscription.get("trial_end")
251+
if trial_end:
252+
logger.info(
253+
f"Subscription {subscription.id} status changed from '{prior_status}' to 'canceled'. "
254+
f"Queuing trial cancellation email for checkout_intent_id={checkout_intent_id}"
255+
)
256+
257+
send_trial_cancellation_email_task.delay(
258+
checkout_intent_id=checkout_intent.id,
259+
trial_end_timestamp=trial_end,
260+
)
261+
else:
262+
logger.info(
263+
f"Subscription {subscription.id} canceled but has no trial_end, skipping cancellation email"
264+
)
259265
else:
260266
logger.info(
261-
f"Subscription {subscription.id} canceled but has no trial_end, skipping cancellation email"
267+
f"Subscription {subscription.id} already canceled (status unchanged), skipping cancellation email"
262268
)
263269

264270
@on_stripe_event("customer.subscription.deleted")

enterprise_access/apps/customer_billing/tasks.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,6 @@ def send_trial_cancellation_email_task(
253253
lms_user_id=admin.get("lms_user_id"),
254254
)
255255
recipients.append(recipient)
256-
257256
except Exception as exc: # pylint: disable=broad-exception-caught
258257
logger.warning(
259258
"Failed to create Braze recipient for admin email %s: %s",

enterprise_access/apps/customer_billing/tests/test_stripe_event_handlers.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Unit tests for Stripe event handlers.
33
"""
44
from contextlib import nullcontext
5+
from datetime import timedelta
56
from random import randint
67
from typing import Type, cast
78
from unittest import mock
@@ -10,6 +11,7 @@
1011
import stripe
1112
from django.contrib.auth.models import AbstractUser
1213
from django.test import TestCase
14+
from django.utils import timezone
1315

1416
from enterprise_access.apps.core.tests.factories import UserFactory
1517
from enterprise_access.apps.customer_billing.constants import CheckoutIntentState
@@ -66,6 +68,8 @@ def tearDown(self):
6668
def _create_mock_stripe_event(self, event_type, event_data):
6769
"""Helper to create a mock Stripe event."""
6870
mock_event = mock.MagicMock(spec=stripe.Event)
71+
created_at = timezone.now() - timedelta(seconds=randint(1, 30))
72+
mock_event.created = int(created_at.timestamp())
6973
mock_event.type = event_type
7074
numeric_id = str(randint(1, 100000)).zfill(6)
7175
mock_event.id = f'evt_test_{event_type.replace(".", "_")}_{numeric_id}'

0 commit comments

Comments
 (0)