diff --git a/openedx/core/djangoapps/programs/tests/test_utils.py b/openedx/core/djangoapps/programs/tests/test_utils.py index 9bca686466..eb177703a8 100644 --- a/openedx/core/djangoapps/programs/tests/test_utils.py +++ b/openedx/core/djangoapps/programs/tests/test_utils.py @@ -416,6 +416,30 @@ class TestProgramProgressMeter(TestCase): meter = ProgramProgressMeter(self.user) self.assertEqual(meter.completed_programs, program_uuids) + @mock.patch(UTILS_MODULE + '.ProgramProgressMeter.completed_course_runs', new_callable=mock.PropertyMock) + def test_completed_programs_no_id_professional(self, mock_completed_course_runs, mock_get_programs): + """ Verify the method treats no-id-professional enrollments as professional enrollments. """ + course_runs = CourseRunFactory.create_batch(2, type='no-id-professional') + program = ProgramFactory(courses=[CourseFactory(course_runs=course_runs)]) + mock_get_programs.return_value = [program] + + # Verify that no programs are complete. + meter = ProgramProgressMeter(self.user) + self.assertEqual(meter.completed_programs, []) + + # Complete all programs. + for course_run in course_runs: + CourseEnrollmentFactory(user=self.user, course_id=course_run['key'], mode='no-id-professional') + + mock_completed_course_runs.return_value = [ + {'course_run_id': course_run['key'], 'type': MODES.professional} + for course_run in course_runs + ] + + # Verify that all programs are complete. + meter = ProgramProgressMeter(self.user) + self.assertEqual(meter.completed_programs, [program['uuid']]) + @mock.patch(UTILS_MODULE + '.certificate_api.get_certificates_for_user') def test_completed_course_runs(self, mock_get_certificates_for_user, _mock_get_programs): """ diff --git a/openedx/core/djangoapps/programs/utils.py b/openedx/core/djangoapps/programs/utils.py index 9de403e602..6f510ff34d 100644 --- a/openedx/core/djangoapps/programs/utils.py +++ b/openedx/core/djangoapps/programs/utils.py @@ -257,6 +257,12 @@ class ProgramProgressMeter(object): Modify the structure of a course run dict to facilitate comparison with course run certificates. """ + course_run_type = course_run['type'] + + # Treat no-id-professional enrollments as professional + if course_run_type == CourseMode.NO_ID_PROFESSIONAL_MODE: + course_run_type = CourseMode.PROFESSIONAL + return { 'course_run_id': course_run['key'], # A course run's type is assumed to indicate which mode must be @@ -266,7 +272,7 @@ class ProgramProgressMeter(object): # count towards completion of a course in a program). This may change # in the future to make use of the more rigid set of "applicable seat # types" associated with each program type in the catalog. - 'type': course_run['type'], + 'type': course_run_type, } return any(reshape(course_run) in self.completed_course_runs for course_run in course['course_runs'])