From 7e3e3a30495061816a0d2af5a74794311cf517ab Mon Sep 17 00:00:00 2001 From: Troy Sankey Date: Thu, 14 Mar 2024 16:30:36 -0700 Subject: [PATCH] feat: support the core enrollment API's force_enrollment flag from enterprise_support This enables enterprise-specific callers trying to create lms enrollments to be able to create enrollments even after the enrollment deadline. The target use case for this feature is the enterprise bulk enrollment endpoint in edx-enterprise. ENT-8525 --- .../enrollments/tests/test_utils.py | 39 +++++++++++++++++++ .../enterprise_support/enrollments/utils.py | 5 +++ 2 files changed, 44 insertions(+) diff --git a/openedx/features/enterprise_support/enrollments/tests/test_utils.py b/openedx/features/enterprise_support/enrollments/tests/test_utils.py index 35a93311866a..f9233c3724c8 100644 --- a/openedx/features/enterprise_support/enrollments/tests/test_utils.py +++ b/openedx/features/enterprise_support/enrollments/tests/test_utils.py @@ -139,6 +139,45 @@ def test_calls_enrollment_and_cohort_apis( is_active=True, enrollment_attributes=None, enterprise_uuid=ENTERPRISE_UUID, + force_enrollment=False, + ) + mock_get_enrollment_api.assert_called_once_with(USERNAME, str(COURSE_ID)) + + @mock.patch('openedx.features.enterprise_support.enrollments.utils.enrollment_api.add_enrollment') + @mock.patch('openedx.features.enterprise_support.enrollments.utils.enrollment_api.get_enrollment') + @mock.patch('openedx.features.enterprise_support.enrollments.utils.User.objects.get') + @mock.patch('openedx.features.enterprise_support.enrollments.utils.transaction') + def test_passes_force_enrollment_flag( + self, + mock_tx, + mock_user_model, + mock_get_enrollment_api, + mock_add_enrollment_api, + ): + """ + Everything about this test is the same as the standard happy case, except we're just making sure the + force_enrollment flag gets passed to add_enrollment(). + """ + expected_response = {'mode': COURSE_MODE, 'is_active': True} + + mock_add_enrollment_api.return_value = expected_response + mock_tx.return_value.atomic.side_effect = None + + mock_user_model.return_value = self.a_user + mock_get_enrollment_api.return_value = None + + response = lms_update_or_create_enrollment( + USERNAME, COURSE_ID, COURSE_MODE, is_active=True, enterprise_uuid=ENTERPRISE_UUID, force_enrollment=True + ) + assert response == expected_response + mock_add_enrollment_api.assert_called_once_with( + USERNAME, + str(COURSE_ID), + mode=COURSE_MODE, + is_active=True, + enrollment_attributes=None, + enterprise_uuid=ENTERPRISE_UUID, + force_enrollment=True, # Literally the only purpose of this test. ) mock_get_enrollment_api.assert_called_once_with(USERNAME, str(COURSE_ID)) diff --git a/openedx/features/enterprise_support/enrollments/utils.py b/openedx/features/enterprise_support/enrollments/utils.py index 1a8a105f4b34..b64ff971b769 100644 --- a/openedx/features/enterprise_support/enrollments/utils.py +++ b/openedx/features/enterprise_support/enrollments/utils.py @@ -28,6 +28,7 @@ def lms_update_or_create_enrollment( desired_mode, is_active, enterprise_uuid=None, + force_enrollment=False, ): """ Update or create the user's course enrollment based on the existing enrollment mode. @@ -50,6 +51,9 @@ def lms_update_or_create_enrollment( - is_active (bool): A Boolean value that indicates whether the enrollment is to be set to inactive (if False). Usually we want a True if enrolling anew. - enterprise_uuid (str): Optional. id to identify the enterprise to enroll under + - force_enrollment (bool): + Enroll user even if course enrollment_end date is expired (default False). This only has an effect when the + enrollment is being created, not when it is only updated. Returns: A serializable dictionary of the new or updated course enrollment. If it hits CourseEnrollmentError or CourseEnrollmentNotUpdatableError, it raises those exceptions. @@ -105,6 +109,7 @@ def lms_update_or_create_enrollment( is_active=is_active, enrollment_attributes=None, enterprise_uuid=enterprise_uuid, + force_enrollment=force_enrollment, ) if not response: log.exception(