diff --git a/common/djangoapps/entitlements/models.py b/common/djangoapps/entitlements/models.py index 735933bf79..9bce945d15 100644 --- a/common/djangoapps/entitlements/models.py +++ b/common/djangoapps/entitlements/models.py @@ -260,13 +260,29 @@ class CourseEntitlement(TimeStampedModel): @classmethod def get_entitlement_if_active(cls, user, course_uuid): """ - Returns an entitlement for a given course uuid if an active entitlement exists, otherwise returns None. + Retrieves the active entitlement for the course_uuid and User. + An active entitlement is defined as an entitlement that has not yet expired or has a currently enrolled session. + If there is more than one entitlement, return the most recently created active entitlement. + + Arguments: + user: User that owns the Course Entitlement + course_uuid: The Course UUID for a Course that we are retrieving active entitlements for. + + Returns: + CourseEntitlement: Returns the most recently created entitlement for a given course uuid if an + active entitlement exists, otherwise returns None """ - return cls.objects.filter( - user=user, - course_uuid=course_uuid - ).exclude(expired_at__isnull=False, enrollment_course_run=None).first() + try: + return cls.objects.filter( + user=user, + course_uuid=course_uuid + ).exclude( + expired_at__isnull=False, + enrollment_course_run=None + ).latest('created') + except CourseEntitlement.DoesNotExist: + return None @classmethod def get_active_entitlements_for_user(cls, user): diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index 1adde03085..309cb495eb 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -800,12 +800,11 @@ def dashboard(request): urls, program_data = {}, {} bundles_on_dashboard_flag = WaffleFlag(WaffleFlagNamespace(name=u'student.experiments'), u'bundles_on_dashboard') - if (bundles_on_dashboard_flag.is_enabled()): + if bundles_on_dashboard_flag.is_enabled(): programs_data = meter.programs if programs_data: program_data = meter.programs[0] program_data = ProgramDataExtender(program_data, request.user).extend() - course_data = meter.progress(programs=[program_data], count_only=False)[0] program_data.pop('courses') skus = program_data.get('skus') diff --git a/openedx/core/djangoapps/programs/tests/test_utils.py b/openedx/core/djangoapps/programs/tests/test_utils.py index 0d481284c6..b123f02a45 100644 --- a/openedx/core/djangoapps/programs/tests/test_utils.py +++ b/openedx/core/djangoapps/programs/tests/test_utils.py @@ -179,6 +179,54 @@ class TestProgramProgressMeter(TestCase): program = data[0] self.assertEqual(meter.engaged_programs, [program]) + def test_single_program_multiple_entitlements(self, mock_get_programs): + """ + Verify that the most recent entitlement is returned when a user has multiple for the same course + """ + course_uuid = uuid.uuid4() + data = [ + ProgramFactory(courses=[CourseFactory(uuid=str(course_uuid))]), + ProgramFactory(), + ] + mock_get_programs.return_value = data + course_run_key = generate_course_run_key() + course_run_key2 = generate_course_run_key() + + enrollment = CourseEnrollmentFactory( + user=self.user, + course_id=course_run_key, + mode=CourseMode.VERIFIED, + is_active=False + ) + enrollment2 = CourseEnrollmentFactory( + user=self.user, + course_id=course_run_key2, + mode=CourseMode.VERIFIED + ) + + CourseEntitlementFactory.create( + user=self.user, + course_uuid=course_uuid, + expired_at=datetime.datetime.now(utc), + mode=CourseMode.VERIFIED, + enrollment_course_run=enrollment + + ) + CourseEntitlementFactory.create( + user=self.user, + course_uuid=course_uuid, + mode=CourseMode.VERIFIED, + enrollment_course_run=enrollment2 + ) + + meter = ProgramProgressMeter(self.site, self.user) + self._attach_detail_url(data) + self.assertEqual(len(meter.entitlements), 1) + + entitlement = meter.entitlements[0] + self.assertIsNone(entitlement.expired_at) + self.assertEqual(entitlement.enrollment_course_run.course_id, enrollment2.course_id) + def test_course_progress(self, mock_get_programs): """ Verify that the progress meter can represent progress in terms of diff --git a/openedx/core/djangoapps/programs/utils.py b/openedx/core/djangoapps/programs/utils.py index 8447dbd8d8..ccae2ddaa2 100644 --- a/openedx/core/djangoapps/programs/utils.py +++ b/openedx/core/djangoapps/programs/utils.py @@ -237,7 +237,10 @@ class ProgramProgressMeter(object): elif self._is_course_enrolled(course) or active_entitlement: # Show all currently enrolled courses and active entitlements as in progress if active_entitlement: - course['course_runs'] = get_fulfillable_course_runs_for_entitlement(active_entitlement, course['course_runs']) + course['course_runs'] = get_fulfillable_course_runs_for_entitlement( + active_entitlement, + course['course_runs'] + ) course['user_entitlement'] = active_entitlement.to_dict() course['enroll_url'] = reverse( 'entitlements_api:v1:enrollments',