Merge pull request #21149 from edx/PROD-305/add-credit-mode-enrollment
Add credit mode in support enrollment tool.
This commit is contained in:
@@ -333,7 +333,9 @@ class CourseMode(models.Model):
|
||||
|
||||
@classmethod
|
||||
@request_cached(CACHE_NAMESPACE)
|
||||
def modes_for_course(cls, course_id=None, include_expired=False, only_selectable=True, course=None):
|
||||
def modes_for_course(
|
||||
cls, course_id=None, include_expired=False, only_selectable=True, course=None, exclude_credit=True
|
||||
):
|
||||
"""
|
||||
Returns a list of the non-expired modes for a given course id
|
||||
|
||||
@@ -384,7 +386,7 @@ class CourseMode(models.Model):
|
||||
if only_selectable:
|
||||
if course is not None and hasattr(course, 'selectable_modes'):
|
||||
found_course_modes = course.selectable_modes
|
||||
else:
|
||||
elif exclude_credit:
|
||||
found_course_modes = found_course_modes.exclude(mode_slug__in=cls.CREDIT_MODES)
|
||||
|
||||
modes = ([mode.to_tuple() for mode in found_course_modes])
|
||||
|
||||
@@ -15,13 +15,14 @@ import six
|
||||
from django.contrib.auth.models import User
|
||||
from django.db.models import signals
|
||||
from django.urls import reverse
|
||||
from mock import patch
|
||||
from pytz import UTC
|
||||
|
||||
from common.test.utils import disable_signal
|
||||
from course_modes.models import CourseMode
|
||||
from course_modes.tests.factories import CourseModeFactory
|
||||
from lms.djangoapps.verify_student.models import VerificationDeadline
|
||||
from student.models import ENROLLED_TO_ENROLLED, CourseEnrollment, ManualEnrollmentAudit
|
||||
from student.models import ENROLLED_TO_ENROLLED, CourseEnrollment, CourseEnrollmentAttribute, ManualEnrollmentAudit
|
||||
from student.roles import GlobalStaff, SupportStaffRole
|
||||
from student.tests.factories import CourseEnrollmentFactory, UserFactory
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, SharedModuleStoreTestCase
|
||||
@@ -257,7 +258,8 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase
|
||||
}, data[0])
|
||||
self.assertEqual(
|
||||
{CourseMode.VERIFIED, CourseMode.AUDIT, CourseMode.HONOR,
|
||||
CourseMode.NO_ID_PROFESSIONAL_MODE, CourseMode.PROFESSIONAL},
|
||||
CourseMode.NO_ID_PROFESSIONAL_MODE, CourseMode.PROFESSIONAL,
|
||||
CourseMode.CREDIT_MODE},
|
||||
{mode['slug'] for mode in data[0]['course_modes']}
|
||||
)
|
||||
|
||||
@@ -329,10 +331,9 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase
|
||||
self.assertIsNone(ManualEnrollmentAudit.get_manual_enrollment_by_email(self.student.email))
|
||||
|
||||
@disable_signal(signals, 'post_save')
|
||||
@ddt.data('honor', 'audit', 'verified', 'professional', 'no-id-professional')
|
||||
@ddt.data('honor', 'audit', 'verified', 'professional', 'no-id-professional', 'credit')
|
||||
def test_update_enrollment_for_all_modes(self, new_mode):
|
||||
""" Verify support can changed the enrollment to all available modes
|
||||
except credit. """
|
||||
""" Verify support can changed the enrollment to all available modes"""
|
||||
self.assert_update_enrollment('username', new_mode)
|
||||
|
||||
@disable_signal(signals, 'post_save')
|
||||
@@ -342,10 +343,6 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase
|
||||
self.set_course_end_date_and_expiry()
|
||||
self.assert_update_enrollment('username', new_mode)
|
||||
|
||||
def test_update_enrollment_with_credit_mode_throws_error(self):
|
||||
""" Verify that enrollment cannot be changed to credit mode. """
|
||||
self.assert_update_enrollment('username', CourseMode.CREDIT_MODE)
|
||||
|
||||
@ddt.data('username', 'email')
|
||||
def test_get_enrollments_with_expired_mode(self, search_string_type):
|
||||
""" Verify that page can get the all modes with archived course. """
|
||||
@@ -367,7 +364,7 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase
|
||||
|
||||
def _assert_generated_modes(self, response):
|
||||
"""Dry method to generate course modes dict and test with response data."""
|
||||
modes = CourseMode.modes_for_course(self.course.id, include_expired=True)
|
||||
modes = CourseMode.modes_for_course(self.course.id, include_expired=True, exclude_credit=False)
|
||||
modes_data = []
|
||||
for mode in modes:
|
||||
expiry = mode.expiration_datetime.strftime('%Y-%m-%dT%H:%M:%SZ') if mode.expiration_datetime else None
|
||||
@@ -394,7 +391,7 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase
|
||||
|
||||
self.assertEqual(
|
||||
{CourseMode.VERIFIED, CourseMode.AUDIT, CourseMode.NO_ID_PROFESSIONAL_MODE,
|
||||
CourseMode.PROFESSIONAL, CourseMode.HONOR},
|
||||
CourseMode.PROFESSIONAL, CourseMode.HONOR, CourseMode.CREDIT_MODE},
|
||||
{mode['slug'] for mode in data[0]['course_modes']}
|
||||
)
|
||||
|
||||
@@ -405,19 +402,25 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase
|
||||
'support:enrollment_list',
|
||||
kwargs={'username_or_email': getattr(self.student, search_string_type)}
|
||||
)
|
||||
response = self.client.post(url, data={
|
||||
'course_id': six.text_type(self.course.id),
|
||||
'old_mode': CourseMode.AUDIT,
|
||||
'new_mode': new_mode,
|
||||
'reason': 'Financial Assistance'
|
||||
})
|
||||
# Enrollment cannot be changed to credit mode.
|
||||
if new_mode == CourseMode.CREDIT_MODE:
|
||||
self.assertEqual(response.status_code, 400)
|
||||
else:
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIsNotNone(ManualEnrollmentAudit.get_manual_enrollment_by_email(self.student.email))
|
||||
self.assert_enrollment(new_mode)
|
||||
|
||||
with patch('support.views.enrollments.get_credit_provider_attribute_values') as mock_method:
|
||||
credit_provider = (
|
||||
[u'Arizona State University'], 'You are now eligible for credit from Arizona State University'
|
||||
)
|
||||
mock_method.return_value = credit_provider
|
||||
response = self.client.post(url, data={
|
||||
'course_id': six.text_type(self.course.id),
|
||||
'old_mode': CourseMode.AUDIT,
|
||||
'new_mode': new_mode,
|
||||
'reason': 'Financial Assistance'
|
||||
})
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIsNotNone(ManualEnrollmentAudit.get_manual_enrollment_by_email(self.student.email))
|
||||
self.assert_enrollment(new_mode)
|
||||
if new_mode == 'credit':
|
||||
enrollment_attr = CourseEnrollmentAttribute.objects.first()
|
||||
self.assertEqual(enrollment_attr.value, unicode(credit_provider[0]))
|
||||
|
||||
def set_course_end_date_and_expiry(self):
|
||||
""" Set the course-end date and expire its verified mode."""
|
||||
|
||||
@@ -21,10 +21,11 @@ from edxmako.shortcuts import render_to_response
|
||||
from lms.djangoapps.support.decorators import require_support_permission
|
||||
from lms.djangoapps.support.serializers import ManualEnrollmentSerializer
|
||||
from lms.djangoapps.verify_student.models import VerificationDeadline
|
||||
from openedx.core.djangoapps.credit.email_utils import get_credit_provider_attribute_values
|
||||
from openedx.core.djangoapps.enrollments.api import get_enrollments, update_enrollment
|
||||
from openedx.core.djangoapps.enrollments.errors import CourseModeNotFoundError
|
||||
from openedx.core.djangoapps.enrollments.serializers import ModeSerializer
|
||||
from student.models import ENROLLED_TO_ENROLLED, CourseEnrollment, ManualEnrollmentAudit
|
||||
from student.models import ENROLLED_TO_ENROLLED, CourseEnrollment, CourseEnrollmentAttribute, ManualEnrollmentAudit
|
||||
from util.json_request import JsonResponse
|
||||
|
||||
|
||||
@@ -94,8 +95,6 @@ class EnrollmentSupportListView(GenericAPIView):
|
||||
username=user.username,
|
||||
old_mode=old_mode
|
||||
))
|
||||
if new_mode == CourseMode.CREDIT_MODE:
|
||||
return HttpResponseBadRequest(u'Enrollment cannot be changed to credit mode.')
|
||||
except KeyError as err:
|
||||
return HttpResponseBadRequest(u'The field {} is required.'.format(text_type(err)))
|
||||
except InvalidKeyError:
|
||||
@@ -119,6 +118,16 @@ class EnrollmentSupportListView(GenericAPIView):
|
||||
reason=reason,
|
||||
enrollment=enrollment
|
||||
)
|
||||
if new_mode == CourseMode.CREDIT_MODE:
|
||||
provider_ids = get_credit_provider_attribute_values(course_key, 'id')
|
||||
credit_provider_attr = {
|
||||
'namespace': 'credit',
|
||||
'name': 'provider_id',
|
||||
'value': provider_ids[0],
|
||||
}
|
||||
CourseEnrollmentAttribute.add_enrollment_attr(
|
||||
enrollment=enrollment, data_list=[credit_provider_attr]
|
||||
)
|
||||
return JsonResponse(ManualEnrollmentSerializer(instance=manual_enrollment).data)
|
||||
except CourseModeNotFoundError as err:
|
||||
return HttpResponseBadRequest(text_type(err))
|
||||
@@ -178,7 +187,8 @@ class EnrollmentSupportListView(GenericAPIView):
|
||||
"""
|
||||
course_modes = CourseMode.modes_for_course(
|
||||
course_key,
|
||||
include_expired=True
|
||||
include_expired=True,
|
||||
exclude_credit=False
|
||||
)
|
||||
return [
|
||||
ModeSerializer(mode).data
|
||||
|
||||
Reference in New Issue
Block a user