def test_add_entitlement_with_support_detail(self): """ Verify that an EntitlementSupportDetail entry is made when the request includes support interaction information. """ course_uuid = uuid.uuid4() entitlement_data = self._get_data_set(self.user, str(course_uuid)) entitlement_data['support_details'] = [ { "action": "CREATE", "comments": "Family emergency." }, ] response = self.client.post( self.entitlements_list_url, data=json.dumps(entitlement_data), content_type='application/json', ) assert response.status_code == 201 results = response.data course_entitlement = CourseEntitlement.objects.get( user=self.user, course_uuid=course_uuid ) assert results == CourseEntitlementSerializer(course_entitlement).data
def test_reinstate_entitlement(self): enrollment = CourseEnrollmentFactory(user=self.user, is_active=True) expired_entitlement = CourseEntitlementFactory.create( user=self.user, enrollment_course_run=enrollment, expired_at=datetime.now() ) url = reverse(self.ENTITLEMENTS_DETAILS_PATH, args=[str(expired_entitlement.uuid)]) update_data = { 'expired_at': None, 'enrollment_course_run': None, 'support_details': [ { 'unenrolled_run': str(enrollment.course.id), 'action': CourseEntitlementSupportDetail.REISSUE, 'comments': 'Severe illness.' } ] } response = self.client.patch( url, data=json.dumps(update_data), content_type='application/json' ) assert response.status_code == 200 results = response.data reinstated_entitlement = CourseEntitlement.objects.get( uuid=expired_entitlement.uuid ) assert results == CourseEntitlementSerializer(reinstated_entitlement).data
def test_add_entitlement_inactive_audit_enrollment(self, mock_get_course_runs): """ Verify that if an entitlement is added for a user, if the user has an inactive audit enrollment that enrollment is NOT upgraded to the mode of the entitlement and linked to the entitlement. """ course_uuid = uuid.uuid4() entitlement_data = self._get_data_set(self.user, str(course_uuid)) mock_get_course_runs.return_value = [{'key': str(self.course.id)}] # Add an audit course enrollment for user. enrollment = CourseEnrollment.enroll(self.user, self.course.id, mode=CourseMode.AUDIT) enrollment.update_enrollment(is_active=False) response = self.client.post( self.entitlements_list_url, data=json.dumps(entitlement_data), content_type='application/json', ) assert response.status_code == 201 results = response.data course_entitlement = CourseEntitlement.objects.get( user=self.user, course_uuid=course_uuid ) # Assert that enrollment mode is now verified enrollment_mode, enrollment_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id) assert enrollment_mode == CourseMode.AUDIT assert enrollment_active is False assert course_entitlement.enrollment_course_run is None assert results == CourseEntitlementSerializer(course_entitlement).data
def create(self, request, *args, **kwargs): support_details = request.data.pop('support_details', []) serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) self.perform_create(serializer) entitlement = serializer.instance set_entitlement_policy(entitlement, request.site) if support_details: for support_detail in support_details: support_detail['entitlement'] = entitlement support_detail['support_user'] = request.user CourseEntitlementSupportDetail.objects.create(**support_detail) else: user = entitlement.user # find all course_runs within the course course_runs = get_course_runs_for_course(entitlement.course_uuid) # check if the user has enrollments for any of the course_runs user_run_enrollments = [ CourseEnrollment.get_enrollment( user, CourseKey.from_string(course_run.get('key'))) for course_run in course_runs if CourseEnrollment.get_enrollment( user, CourseKey.from_string(course_run.get('key'))) ] # filter to just enrollments that can be upgraded. upgradeable_enrollments = [ enrollment for enrollment in user_run_enrollments if enrollment.is_active and enrollment.upgrade_deadline and enrollment.upgrade_deadline > timezone.now() ] # if there is only one upgradeable enrollment, convert it from audit to the entitlement.mode # if there is any ambiguity about which enrollment to upgrade # (i.e. multiple upgradeable enrollments or no available upgradeable enrollment), dont enroll if len(upgradeable_enrollments) == 1: enrollment = upgradeable_enrollments[0] log.info( 'Upgrading enrollment [%s] from %s to %s while adding entitlement for user [%s] for course [%s]', enrollment, enrollment.mode, serializer.data.get('mode'), user.username, serializer.data.get('course_uuid')) enrollment.update_enrollment(mode=entitlement.mode) entitlement.set_enrollment(enrollment) else: log.info( 'No enrollment upgraded while adding entitlement for user [%s] for course [%s] ', user.username, serializer.data.get('course_uuid')) headers = self.get_success_headers(serializer.data) # Note, the entitlement is re-serialized before getting added to the Response, # so that the 'modified' date reflects changes that occur when upgrading enrollment. return Response(CourseEntitlementSerializer(entitlement).data, status=status.HTTP_201_CREATED, headers=headers)
def create(self, request, *args, **kwargs): support_details = request.data.pop('support_details', []) email_opt_in = request.data.pop('email_opt_in', False) serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) self.perform_create(serializer) entitlement = serializer.instance set_entitlement_policy(entitlement, request.site) # The owners for a course are the organizations that own the course. By taking owner.key, # we are able to pass in the organization key for email_opt_in owners = get_owners_for_course(entitlement.course_uuid) for owner in owners: update_email_opt_in(entitlement.user, owner['key'], email_opt_in) if support_details: for support_detail in support_details: support_detail['entitlement'] = entitlement support_detail['support_user'] = request.user CourseEntitlementSupportDetail.objects.create(**support_detail) else: user = entitlement.user upgradeable_enrollments = self.get_upgradeable_enrollments_for_entitlement(entitlement) # if there is only one upgradeable enrollment, update the mode to the paid entitlement.mode # if there is any ambiguity about which enrollment to upgrade # (i.e. multiple upgradeable enrollments or no available upgradeable enrollment), don't alter # the enrollment if len(upgradeable_enrollments) == 1: enrollment = upgradeable_enrollments[0] log.info( 'Upgrading enrollment [%s] from %s to %s while adding entitlement for user [%s] for course [%s]', enrollment, enrollment.mode, serializer.data.get('mode'), user.username, serializer.data.get('course_uuid') ) enrollment.update_enrollment(mode=entitlement.mode) entitlement.set_enrollment(enrollment) else: log.info( 'No enrollment upgraded while adding entitlement for user [%s] for course [%s] ', user.username, serializer.data.get('course_uuid') ) headers = self.get_success_headers(serializer.data) # Note, the entitlement is re-serialized before getting added to the Response, # so that the 'modified' date reflects changes that occur when upgrading enrollment. return Response( CourseEntitlementSerializer(entitlement).data, status=status.HTTP_201_CREATED, headers=headers )
def test_user_can_revoke_and_refund(self, mock_get_course_runs, mock_refund_entitlement): course_entitlement = CourseEntitlementFactory.create(user=self.user) mock_get_course_runs.return_value = self.return_values url = reverse( self.ENTITLEMENTS_ENROLLMENT_NAMESPACE, args=[str(course_entitlement.uuid)] ) assert course_entitlement.enrollment_course_run is None data = { 'course_run_id': str(self.course.id) } response = self.client.post( url, data=json.dumps(data), content_type='application/json', ) course_entitlement.refresh_from_db() assert response.status_code == 201 assert CourseEnrollment.is_enrolled(self.user, self.course.id) # Unenroll with Revoke for refund with patch('lms.djangoapps.commerce.signals.handle_refund_entitlement') as mock_refund_handler: REFUND_ENTITLEMENT.connect(mock_refund_handler) # pre_db_changes_entitlement = course_entitlement revoke_url = url + '?is_refund=true' response = self.client.delete( revoke_url, content_type='application/json', ) assert response.status_code == 204 course_entitlement.refresh_from_db() assert mock_refund_handler.called assert (CourseEntitlementSerializer(mock_refund_handler.call_args[1]['course_entitlement']).data == CourseEntitlementSerializer(course_entitlement).data) assert not CourseEnrollment.is_enrolled(self.user, self.course.id) assert course_entitlement.enrollment_course_run is None assert course_entitlement.expired_at is not None
def test_get_entitlements(self): entitlements = CourseEntitlementFactory.create_batch(2) response = self.client.get( self.entitlements_list_url, content_type='application/json', ) assert response.status_code == 200 results = response.data.get('results', []) assert results == CourseEntitlementSerializer(entitlements, many=True).data
def test_non_staff_get_select_entitlements(self): not_staff_user = UserFactory() self.client.login(username=not_staff_user.username, password=TEST_PASSWORD) CourseEntitlementFactory.create_batch(2) entitlement = CourseEntitlementFactory.create(user=not_staff_user) response = self.client.get( self.entitlements_list_url, content_type='application/json', ) assert response.status_code == 200 results = response.data.get('results', []) # pylint: disable=no-member assert results == CourseEntitlementSerializer([entitlement], many=True).data
def test_get_entitlement_by_uuid(self): entitlement = CourseEntitlementFactory.create() CourseEntitlementFactory.create_batch(2) url = reverse(self.ENTITLEMENTS_DETAILS_PATH, args=[str(entitlement.uuid)]) response = self.client.get( url, content_type='application/json', ) assert response.status_code == 200 results = response.data assert results == CourseEntitlementSerializer(entitlement).data and results.get('expired_at') is None
def test_get_user_entitlements(self): user2 = UserFactory() CourseEntitlementFactory.create() entitlement_user2 = CourseEntitlementFactory.create(user=user2) url = reverse('entitlements_api:v1:entitlements-list') url += '?user={username}'.format(username=user2.username) response = self.client.get( url, content_type='application/json', ) assert response.status_code == 200 results = response.data.get('results', []) assert results == CourseEntitlementSerializer([entitlement_user2], many=True).data
def test_add_entitlement(self): course_uuid = uuid.uuid4() entitlement_data = self._get_data_set(self.user, str(course_uuid)) response = self.client.post( self.entitlements_list_url, data=json.dumps(entitlement_data), content_type='application/json', ) assert response.status_code == 201 results = response.data course_entitlement = CourseEntitlement.objects.get( user=self.user, course_uuid=course_uuid) assert results == CourseEntitlementSerializer(course_entitlement).data
def test_add_entitlement_and_upgrade_audit_enrollment_with_dynamic_deadline( self, mock_get_course_runs): """ Verify that if an entitlement is added for a user, if the user has one upgradeable enrollment that enrollment is upgraded to the mode of the entitlement and linked to the entitlement regardless of dynamic upgrade deadline being set. """ DynamicUpgradeDeadlineConfiguration.objects.create(enabled=True) course = CourseFactory.create(self_paced=True) course_uuid = uuid.uuid4() course_mode = CourseModeFactory( course_id=course.id, mode_slug=CourseMode.VERIFIED, # This must be in the future to ensure it is returned by downstream code. expiration_datetime=now() + timedelta(days=1)) # Set up Entitlement entitlement_data = self._get_data_set(self.user, str(course_uuid)) mock_get_course_runs.return_value = [{'key': str(course.id)}] # Add an audit course enrollment for user. enrollment = CourseEnrollment.enroll(self.user, course.id, mode=CourseMode.AUDIT) # Set an upgrade schedule so that dynamic upgrade deadlines are used ScheduleFactory.create( enrollment=enrollment, upgrade_deadline=course_mode.expiration_datetime + timedelta(days=-3)) # The upgrade should complete and ignore the deadline response = self.client.post( self.entitlements_list_url, data=json.dumps(entitlement_data), content_type='application/json', ) assert response.status_code == 201 results = response.data course_entitlement = CourseEntitlement.objects.get( user=self.user, course_uuid=course_uuid) # Assert that enrollment mode is now verified enrollment_mode = CourseEnrollment.enrollment_mode_for_user( self.user, course.id)[0] assert enrollment_mode == course_entitlement.mode assert course_entitlement.enrollment_course_run == enrollment assert results == CourseEntitlementSerializer(course_entitlement).data
def test_data(self): entitlement = CourseEntitlementFactory() request = RequestFactory().get('') serializer = CourseEntitlementSerializer(entitlement, context={'request': request}) expected = { 'user': entitlement.user.username, 'uuid': str(entitlement.uuid), 'expired_at': entitlement.expired_at, 'course_uuid': str(entitlement.course_uuid), 'mode': entitlement.mode, 'order_number': entitlement.order_number, 'created': entitlement.created.strftime('%Y-%m-%dT%H:%M:%S.%fZ'), 'modified': entitlement.modified.strftime('%Y-%m-%dT%H:%M:%S.%fZ'), } assert serializer.data == expected