Skip to content

Commit

Permalink
feat: Add OrderFulfill endpoint and LMS enrollment signal (#47)
Browse files Browse the repository at this point in the history
REV-2847
  • Loading branch information
julianajlk authored Sep 12, 2022
1 parent ebefa7b commit b475a5a
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 6 deletions.
28 changes: 28 additions & 0 deletions commerce_coordinator/apps/lms/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""
LMS app signals and receivers.
"""
import logging

from commerce_coordinator.apps.core.signal_helpers import CoordinatorSignal, coordinator_receiver
from commerce_coordinator.apps.lms.tasks import fulfill_order_placed_send_enroll_in_course_task

logger = logging.getLogger(__name__)

fulfill_order_placed_signal = CoordinatorSignal()


@coordinator_receiver(logger)
def fulfill_order_placed_send_enroll_in_course(**kwargs):
"""
Fulfill the order placed in Titan with a Celery task to LMS to enroll a user in a single course.
"""
fulfill_order_placed_send_enroll_in_course_task.delay(
coupon_code=kwargs['coupon_code'],
course_id=kwargs['course_id'],
date_placed=kwargs['date_placed'],
edx_lms_user_id=kwargs['edx_lms_user_id'],
edx_lms_username=kwargs['edx_lms_username'],
mode=kwargs['mode'],
partner_sku=kwargs['partner_sku'],
titan_order_uuid=kwargs['titan_order_uuid'],
)
35 changes: 35 additions & 0 deletions commerce_coordinator/apps/lms/tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""
LMS Celery tasks
"""
from celery import shared_task
from celery.utils.log import get_task_logger

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


@shared_task()
def fulfill_order_placed_send_enroll_in_course_task(
coupon_code,
course_id,
date_placed,
edx_lms_user_id,
edx_lms_username,
mode,
partner_sku,
titan_order_uuid,
):
"""
Celery task for order placed fulfillment and enrollment via LMS Enrollment API.
"""
logger.info(
f'LMS fulfill_order_placed_send_enroll_in_course_task fired with coupon {coupon_code},'
f'course ID {course_id}, on {date_placed}, for LMS user ID {edx_lms_user_id}, with mode {mode},'
f'SKU {partner_sku}, for Titan Order: {titan_order_uuid}.'
)

# TODO: make the API call to LMS here.
# Temporary if statement below since username is PII and cannot
# be logged but will be used as enrollment data in the next commit
if edx_lms_username:
logger.info('Calling LMS enrollment API...')
2 changes: 0 additions & 2 deletions commerce_coordinator/apps/lms/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import logging

from edx_rest_framework_extensions.permissions import LoginRedirectIfUnauthenticated
from rest_framework.authentication import BasicAuthentication, SessionAuthentication
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView

Expand All @@ -17,7 +16,6 @@ class EnrollmentView(APIView):
API for LMS enrollment.
"""
permission_classes = [LoginRedirectIfUnauthenticated]
authentication_classes = [SessionAuthentication, BasicAuthentication]
throttle_classes = [UserRateThrottle]

logger.info('LMS app views')
4 changes: 3 additions & 1 deletion commerce_coordinator/apps/titan/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@

import logging

from commerce_coordinator.apps.core.signal_helpers import coordinator_receiver
from commerce_coordinator.apps.core.signal_helpers import CoordinatorSignal, coordinator_receiver
from commerce_coordinator.apps.titan.tasks import (
enrollment_code_redemption_requested_create_order_oauth_task,
enrollment_code_redemption_requested_create_order_task
)

logger = logging.getLogger(__name__)

fulfill_order_placed_signal = CoordinatorSignal()


@coordinator_receiver(logger)
def enrollment_code_redemption_requested_create_order(**kwargs):
Expand Down
10 changes: 9 additions & 1 deletion commerce_coordinator/apps/titan/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,12 @@
URLS for the titan app
"""

# from django.urls import include, path
from django.urls import path

from .views import OrderFulfillView

app_name = 'titan'

urlpatterns = [
path('fulfill/', OrderFulfillView.as_view(), name='order_fulfill'),
]
83 changes: 81 additions & 2 deletions commerce_coordinator/apps/titan/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,85 @@
Views for the titan app
"""

# from django.shortcuts import render
import logging

# Create your views here.
from rest_framework.permissions import IsAdminUser
from rest_framework.response import Response
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView

from commerce_coordinator.apps.core.signal_helpers import format_signal_results

from .signals import fulfill_order_placed_signal

logger = logging.getLogger(__name__)


class OrderFulfillView(APIView):
"""
API for order fulfillment that is called from Titan.
"""
permission_classes = [IsAdminUser]
throttle_classes = [UserRateThrottle]

def post(self, request):
"""
POST request handler for /order/fulfill
Requires a JSON object of the following format:
{
"coupon_code": "WELCOME100",
"course_id": "course-v1:edX+DemoX+Demo_Course",
"date_placed": "2022-08-24T16:57:00.127327+00:00",
"edx_lms_user_id": 1,
"edx_lms_username": "test-user",
"mode": "verified",
"partner_sku": "test-sku",
"titan_order_uuid": "123-abc",
}
Returns a JSON object of the following format:
{
"<function fulfill_order_placed_send_enroll_in_course at 0x105088700>": {
"response": "",
"error": false,
},
}
"""
coupon_code = request.data.get('coupon_code')
course_id = request.data.get('course_id')
date_placed = request.data.get('date_placed')
edx_lms_user_id = request.data.get('edx_lms_user_id')
edx_lms_username = request.data.get('edx_lms_username')
mode = request.data.get('mode')
partner_sku = request.data.get('partner_sku')
titan_order_uuid = request.data.get('titan_order_uuid')

# TODO: add enterprise data for enrollment API here

# TODO: add credit_provider data here
# /ecommerce/extensions/fulfillment/modules.py#L315

logger.info(
'Attempting to fulfill Titan order ID [%s] for user ID [%s], course ID [%s], on [%s]',
titan_order_uuid,
edx_lms_user_id,
course_id,
date_placed,
)

results = fulfill_order_placed_signal.send_robust(
sender=self.__class__,
date_placed=date_placed,
edx_lms_user_id=edx_lms_user_id,
edx_lms_username=edx_lms_username,
course_id=course_id,
coupon_code=coupon_code,
mode=mode,
partner_sku=partner_sku,
titan_order_uuid=titan_order_uuid,
)
return Response(format_signal_results(results))
3 changes: 3 additions & 0 deletions commerce_coordinator/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,9 @@ def root(*x):
'commerce_coordinator.apps.ecommerce.signals.enrollment_code_redemption_requested_signal': [
'commerce_coordinator.apps.titan.signals.enrollment_code_redemption_requested_create_order',
],
'commerce_coordinator.apps.titan.signals.fulfill_order_placed_signal': [
'commerce_coordinator.apps.lms.signals.fulfill_order_placed_send_enroll_in_course',
],
}

# Default timeouts for requests
Expand Down
2 changes: 2 additions & 0 deletions commerce_coordinator/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from commerce_coordinator.apps.ecommerce import urls as ecommerce_urls
from commerce_coordinator.apps.frontend_app_ecommerce import urls as orders_urls
from commerce_coordinator.apps.lms import urls as lms_urls
from commerce_coordinator.apps.titan import urls as titan_urls

admin.autodiscover()

Expand All @@ -46,6 +47,7 @@
path('ecommerce/', include(ecommerce_urls), name='ecommerce'),
path('lms/', include(lms_urls), name='lms'),
path('health/', core_views.health, name='health'),
path('titan/', include(titan_urls), name='titan'),
path('orders/', include(orders_urls)),
# DEMO: Currently this is only test code, we may want to decouple LMS code here at some point...
path('demo_lms/', include(demo_lms_urls))
Expand Down

0 comments on commit b475a5a

Please sign in to comment.