Commit ab52966f by Clinton Blackburn Committed by Clinton Blackburn

Updated Enrollment API to always store enrollment attributes

Enrollment attributes are now always stored, regardless of whether an enrollment is being created or updated. This will ensure that learners who purchase paid modes, without first enrolling in a non-paid mode, can request refunds if they choose to un-enroll from a course run within the refund window.

LEARNER-1282
parent f95c30af
......@@ -142,7 +142,7 @@ def get_enrollment(user_id, course_id):
return _data_api().get_course_enrollment(user_id, course_id)
def add_enrollment(user_id, course_id, mode=None, is_active=True):
def add_enrollment(user_id, course_id, mode=None, is_active=True, enrollment_attributes=None):
"""Enrolls a user in a course.
Enrolls a user in a course. If the mode is not specified, this will default to `CourseMode.DEFAULT_MODE_SLUG`.
......@@ -150,12 +150,11 @@ def add_enrollment(user_id, course_id, mode=None, is_active=True):
Arguments:
user_id (str): The user to enroll.
course_id (str): The course to enroll the user in.
Keyword Arguments:
mode (str): Optional argument for the type of enrollment to create. Ex. 'audit', 'honor', 'verified',
'professional'. If not specified, this defaults to the default course mode.
is_active (boolean): Optional argument for making the new enrollment inactive. If not specified, is_active
defaults to True.
enrollment_attributes (list): Attributes to be set the enrollment.
Returns:
A serializable dictionary of the new course enrollment.
......@@ -194,7 +193,12 @@ def add_enrollment(user_id, course_id, mode=None, is_active=True):
if mode is None:
mode = _default_course_mode(course_id)
validate_course_mode(course_id, mode, is_active=is_active)
return _data_api().create_course_enrollment(user_id, course_id, mode, is_active)
enrollment = _data_api().create_course_enrollment(user_id, course_id, mode, is_active)
if enrollment_attributes is not None:
set_enrollment_attributes(user_id, course_id, enrollment_attributes)
return enrollment
def update_enrollment(user_id, course_id, mode=None, is_active=None, enrollment_attributes=None, include_expired=False):
......
......@@ -19,6 +19,8 @@ from mock import patch
from nose.plugins.attrib import attr
from rest_framework import status
from rest_framework.test import APITestCase
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, check_mongo_calls_range
from course_modes.models import CourseMode
from enrollment import api
......@@ -35,8 +37,6 @@ from student.roles import CourseStaffRole
from student.tests.factories import AdminFactory, CourseModeFactory, UserFactory
from util.models import RateLimitConfiguration
from util.testing import UrlResetMixin
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, check_mongo_calls_range
class EnrollmentTestMixin(object):
......@@ -997,6 +997,55 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
'No request was made to the mocked enterprise-course-enrollment API'
)
def test_enrollment_attributes_always_written(self):
""" Enrollment attributes should always be written, regardless of whether
the enrollment is being created or updated.
"""
course_key = self.course.id
for mode in [CourseMode.DEFAULT_MODE_SLUG, CourseMode.VERIFIED]:
CourseModeFactory.create(
course_id=course_key,
mode_slug=mode,
mode_display_name=mode,
)
# Creating a new enrollment should write attributes
order_number = 'EDX-1000'
enrollment_attributes = [{
'namespace': 'order',
'name': 'order_number',
'value': order_number,
}]
mode = CourseMode.VERIFIED
self.assert_enrollment_status(
as_server=True,
is_active=True,
mode=mode,
enrollment_attributes=enrollment_attributes
)
enrollment = CourseEnrollment.objects.get(user=self.user, course_id=course_key)
self.assertTrue(enrollment.is_active)
self.assertEqual(enrollment.mode, CourseMode.VERIFIED)
self.assertEqual(enrollment.attributes.get(namespace='order', name='order_number').value, order_number)
# Updating an enrollment should update attributes
order_number = 'EDX-2000'
enrollment_attributes = [{
'namespace': 'order',
'name': 'order_number',
'value': order_number,
}]
mode = CourseMode.DEFAULT_MODE_SLUG
self.assert_enrollment_status(
as_server=True,
mode=mode,
enrollment_attributes=enrollment_attributes
)
enrollment.refresh_from_db()
self.assertTrue(enrollment.is_active)
self.assertEqual(enrollment.mode, mode)
self.assertEqual(enrollment.attributes.get(namespace='order', name='order_number').value, order_number)
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
class EnrollmentEmbargoTest(EnrollmentTestMixin, UrlResetMixin, ModuleStoreTestCase):
......
......@@ -641,7 +641,13 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
)
else:
# Will reactivate inactive enrollments.
response = api.add_enrollment(username, unicode(course_id), mode=mode, is_active=is_active)
response = api.add_enrollment(
username,
unicode(course_id),
mode=mode,
is_active=is_active,
enrollment_attributes=enrollment_attributes
)
email_opt_in = request.data.get('email_opt_in', None)
if email_opt_in is not None:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment