Skip to content

Commit

Permalink
feat: send enrollment/fulfillment failure email
Browse files Browse the repository at this point in the history
  • Loading branch information
syedsajjadkazmii committed Nov 28, 2024
1 parent 2c8885a commit b9d49c6
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 5 deletions.
3 changes: 3 additions & 0 deletions commerce_coordinator/apps/commercetools/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ class OrderFulfillViewInputSerializer(CoordinatorSerializer):
line_item_state_id = serializers.CharField(allow_null=False)
edx_lms_user_id = serializers.IntegerField(allow_null=False)
message_id = serializers.CharField(allow_null=False)
course_title = serializers.CharField(allow_null=False)
user_first_name = serializers.CharField(allow_null=False)
user_email = serializers.EmailField(allow_null=False)


class OrderReturnedViewMessageLineItemReturnItemSerializer(CoordinatorSerializer):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,10 @@ def fulfill_order_placed_message_signal_task(
'course_mode': get_course_mode_from_ct_order(item),
'item_quantity': item.quantity,
'line_item_state_id': line_item_state_id,
'message_id': message_id
'message_id': message_id,
'user_first_name': customer.first_name,
'user_email': customer.email,
'course_title': item.name.get('en-US', '')
})

# the following throws and thus doesn't need to be a conditional
Expand Down
21 changes: 21 additions & 0 deletions commerce_coordinator/apps/commercetools/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,27 @@ def send_order_confirmation_email(
logger.exception(f"Encountered exception sending Order confirmation email. Exception: {exc}")


def send_fulfillment_error_email(
lms_user_id, lms_user_email, canvas_entry_properties
):
""" Sends fulfillment error email via Braze. """
recipients = [{"external_user_id": lms_user_id, "attributes": {
"email": lms_user_email,
}}]
canvas_id = settings.BRAZE_CT_FULFILLMENT_ERROR_CANVAS_ID

try:
braze_client = get_braze_client()
if braze_client:
braze_client.send_canvas_message(
canvas_id=canvas_id,
recipients=recipients,
canvas_entry_properties=canvas_entry_properties,
)
except Exception as exc: # pylint: disable=broad-exception-caught
logger.exception(f"Encountered exception sending Fulfillment Error email. Exception: {exc}")


def format_amount_for_braze_canvas(centAmount):
"""
Utility to convert amount to dollar with 2 decimals percision. Also adds the Dollar signs to resulting value.
Expand Down
5 changes: 4 additions & 1 deletion commerce_coordinator/apps/lms/signal_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ def fulfill_order_placed_send_enroll_in_course(**kwargs):
line_item_id=kwargs['line_item_id'],
item_quantity=kwargs['item_quantity'],
line_item_state_id=kwargs['line_item_state_id'],
message_id=kwargs['message_id']
message_id=kwargs['message_id'],
user_first_name=kwargs['user_first_name'],
user_email=kwargs['user_email'],
course_title=kwargs['course_title']
)
return async_result.id
52 changes: 49 additions & 3 deletions commerce_coordinator/apps/lms/tasks.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,65 @@
"""
LMS Celery tasks
"""
import json

from celery import shared_task
from celery import Task, shared_task
from celery.utils.log import get_task_logger
from django.contrib.auth import get_user_model
from requests import RequestException

from commerce_coordinator.apps.commercetools.catalog_info.constants import TwoUKeys
from commerce_coordinator.apps.commercetools.clients import CommercetoolsAPIClient
from commerce_coordinator.apps.commercetools.utils import send_fulfillment_error_email
from commerce_coordinator.apps.lms.clients import LMSAPIClient

# Use the special Celery logger for our tasks
logger = get_task_logger(__name__)
User = get_user_model()


@shared_task(bind=True, autoretry_for=(RequestException,), retry_kwargs={'max_retries': 5, 'countdown': 3})
class CourseEnrollTaskAfterReturn(Task):
def on_failure(self, exc, task_id, args, kwargs, einfo):
error_message = json.loads(exc.response.text).get('message', '')
edx_lms_user_id = kwargs.get('edx_lms_user_id')
user_email = kwargs.get('user_email')
order_number = kwargs.get('order_number')
user_first_name = kwargs.get('user_first_name')
course_title = kwargs.get('course_title')

logger.error(
f"Task {self.name} failed after max retries with error message: {error_message} "
f"for user with User Id: {edx_lms_user_id}, Email: {user_email}, "
f"Order Number: {order_number}, Course Title: {course_title}"
)

if (
self.request.retries >= self.max_retries
and "course mode is expired or otherwise unavailable for course run" in error_message
):

logger.info(
f"Sending Fulfillment Error Email for user with "
f"User ID: {edx_lms_user_id}, Email: {user_email}, "
f"Order Number: {order_number}, Course Title: {course_title}"
)

canvas_entry_properties = {
'order_number': order_number,
'product_type': 'course',
'product_name': course_title,
'first_name': user_first_name,
}
# Send failure notification email
send_fulfillment_error_email(edx_lms_user_id, user_email, canvas_entry_properties)


@shared_task(
bind=True,
autoretry_for=(RequestException,),
retry_kwargs={'max_retries': 5, 'countdown': 3},
base=CourseEnrollTaskAfterReturn,
)
def fulfill_order_placed_send_enroll_in_course_task(
self,
course_id,
Expand All @@ -32,7 +75,10 @@ def fulfill_order_placed_send_enroll_in_course_task(
line_item_id,
item_quantity,
line_item_state_id,
message_id
message_id,
user_first_name,
user_email,
course_title
):
"""
Celery task for order placed fulfillment and enrollment via LMS Enrollment API.
Expand Down
1 change: 1 addition & 0 deletions commerce_coordinator/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ def root(*path_fragments):
BRAZE_API_KEY = None
BRAZE_API_SERVER = None
BRAZE_CT_ORDER_CONFIRMATION_CANVAS_ID = ''
BRAZE_CT_FULFILLMENT_ERROR_CANVAS_ID = ''

# SEGMENT WRITE KEY
SEGMENT_KEY = None
Expand Down
1 change: 1 addition & 0 deletions commerce_coordinator/settings/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
'host.docker.internal',
'localhost',
'.ngrok-free.app',
'.share.zrok.io',
)

INSTALLED_APPS += (
Expand Down

0 comments on commit b9d49c6

Please sign in to comment.