def test_serialize_order(status): """Test that OrderToDealSerializer produces the correct serialized data""" order = OrderFactory.create(status=status) line = LineFactory.create(order=order) serialized_data = OrderToDealSerializer(instance=order).data assert serialized_data == { "id": order.id, "name": f"XPRO-ORDER-{order.id}", "purchaser": format_hubspot_id(order.purchaser.id), "stage": ORDER_STATUS_MAPPING[status], "amount": line.product_version.price.to_eng_string(), "discount_amount": "0.0000", "close_date": ( int(order.updated_on.timestamp() * 1000) if status == Order.FULFILLED else None ), "coupon_code": None, "company": None, "payment_type": None, "payment_transaction": None, "discount_percent": "0", "order_type": ORDER_TYPE_B2C, "lines": [LineSerializer(instance=line).data], "status": order.status, }
def test_create_run_enrollments(mocker, user): """ create_run_enrollments should call the edX API to create enrollments, create or reactivate local enrollment records, and notify enrolled users via email """ num_runs = 3 order = OrderFactory.create() company = CompanyFactory.create() runs = CourseRunFactory.create_batch(num_runs) # Create an existing deactivate enrollment to test that it gets reactivated CourseRunEnrollmentFactory.create( user=user, run=runs[0], order=order, change_status=ENROLL_CHANGE_STATUS_REFUNDED, active=False, ) patched_edx_enroll = mocker.patch("courses.api.enroll_in_edx_course_runs") patched_send_enrollment_email = mocker.patch( "courses.api.mail_api.send_course_run_enrollment_email") successful_enrollments, edx_request_success = create_run_enrollments( user, runs, order=order, company=company) patched_edx_enroll.assert_called_once_with(user, runs) assert patched_send_enrollment_email.call_count == num_runs assert edx_request_success is True assert len(successful_enrollments) == num_runs enrollments = CourseRunEnrollment.objects.order_by("run__id").all() for (run, enrollment) in zip(runs, enrollments): assert enrollment.change_status is None assert enrollment.active is True assert enrollment.edx_enrolled is True assert enrollment.run == run patched_send_enrollment_email.assert_any_call(enrollment)
def test_create_program_enrollments(user): """ create_program_enrollments should create or reactivate local enrollment records """ num_programs = 2 order = OrderFactory.create() company = CompanyFactory.create() programs = ProgramFactory.create_batch(num_programs) # Create an existing deactivate enrollment to test that it gets reactivated ProgramEnrollmentFactory.create( user=user, program=programs[0], order=order, change_status=ENROLL_CHANGE_STATUS_REFUNDED, active=False, ) successful_enrollments = create_program_enrollments(user, programs, order=order, company=company) assert len(successful_enrollments) == num_programs enrollments = ProgramEnrollment.objects.order_by("program__id").all() assert len(enrollments) == len(programs) for (program, enrollment) in zip(programs, enrollments): assert enrollment.change_status is None assert enrollment.active is True assert enrollment.program == program
def test_update_exam_authorization_order(self, order_status): """ Verify that update_exam_authorization_final_grade is called when a fulfilled Order saves """ with mute_signals(post_save): # muted because enrollment also trigger signal for profile creation. right now we are just # looking final grades CachedEnrollmentFactory.create(user=self.profile.user, course_run=self.course_run) FinalGradeFactory.create( user=self.profile.user, course_run=self.course_run, passed=True, ) order = OrderFactory.create(user=self.profile.user, fulfilled=False) LineFactory.create(course_key=self.course_run.edx_course_key, order=order) # There is no ExamProfile or ExamAuthorization before creating the FinalGrade. assert ExamProfile.objects.filter(profile=self.profile).exists() is False assert ExamAuthorization.objects.filter( user=self.profile.user, course=self.course_run.course ).exists() is False order.status = order_status order.save() # assert Exam Authorization and profile created. assert ExamProfile.objects.filter(profile=self.profile).exists() is True assert ExamAuthorization.objects.filter( user=self.profile.user, course=self.course_run.course ).exists() is True
def test_reference_number(settings): """ order.reference_number should concatenate the reference prefix and the order id """ settings.ENVIRONMENT = "test" order = OrderFactory.create() assert (f"{REFERENCE_NUMBER_PREFIX}{settings.ENVIRONMENT}-{order.id}" == order.reference_number)
def test_to_dict(self): """ Test Order.to_dict() """ order = OrderFactory.create() lines = [LineFactory.create(order=order) for _ in range(5)] data = order.to_dict() lines_data = data.pop('lines') assert serialize_model_object(order) == data assert lines_data == [serialize_model_object(line) for line in lines]
def pay_for_fa_course(self, course_id, status=Order.FULFILLED): """ Helper function to pay for a financial aid course """ order = OrderFactory.create( user=self.user, status=status ) return LineFactory.create( order=order, course_key=course_id )
def test_create_hubspot_line_resync(settings, mock_hubspot_line_error, mock_retry_lines): """Test that lines are re-synced if the error is INVALID_ASSOCIATION_PROPERTY and the order has since been synced""" HubspotErrorCheckFactory.create(checked_on=TIMESTAMPS[0]) order = OrderFactory(id=FAKE_OBJECT_ID) line = LineFactory(order=order, id=FAKE_OBJECT_ID) settings.HUBSPOT_API_KEY = "dkfjKJ2jfd" check_hubspot_api_errors() assert mock_hubspot_line_error.call_count == 2 assert mock_retry_lines.call_count == 1 assert HubspotLineResync.objects.count() == 1 assert HubspotLineResync.objects.first().line == line
def test_save_and_log_model(mocker): """ Tests that the save_model() function on OrderAdmin creates an OrderAudit entry """ assert OrderAudit.objects.count() == 0 order = OrderFactory.create() admin = OrderAdmin(model=order, admin_site=mocker.Mock()) mock_request = mocker.Mock(user=UserFactory.create()) admin.save_model(request=mock_request, obj=admin.model, form=mocker.Mock(), change=mocker.Mock()) assert OrderAudit.objects.count() == 1
def test_hubspot_syncs(mock_hubspot_syncs, settings, hubspot_api_key): """ Test that hubspot sync tasks are called only if API key is set""" settings.HUBSPOT_API_KEY = hubspot_api_key order = OrderFactory.create() order.save_and_log(None) if hubspot_api_key is not None: for line in order.lines.all(): mock_hubspot_syncs.line.assert_called_with(line.id) mock_hubspot_syncs.product.assert_called_with( line.product_version.product.id) else: mock_hubspot_syncs.line.assert_not_called() mock_hubspot_syncs.product.assert_not_called()
def test_save_and_log_model(self): """ Tests that the save_model() function on OrderAdmin creates an OrderAudit entry """ assert OrderAudit.objects.count() == 0 order = OrderFactory.create() admin = OrderAdmin(model=order, admin_site=Mock()) mock_request = Mock(user=UserFactory.create()) admin.save_model( request=mock_request, obj=admin.model, form=Mock(), change=Mock() ) assert OrderAudit.objects.count() == 1
def test_defer_enrollment(mocker, keep_failed_enrollments): """ defer_enrollment should deactivate a user's existing enrollment and create an enrollment in another course run """ course = CourseFactory.create() course_runs = CourseRunFactory.create_batch(3, course=course) order = OrderFactory.create() company = CompanyFactory.create() existing_enrollment = CourseRunEnrollmentFactory.create(run=course_runs[0], order=order, company=company) target_run = course_runs[1] mock_new_enrollment = mocker.Mock() patched_create_enrollments = mocker.patch( "courses.api.create_run_enrollments", autospec=True, return_value=([ mock_new_enrollment if keep_failed_enrollments else None ], True), ) patched_deactivate_enrollments = mocker.patch( "courses.api.deactivate_run_enrollment", autospec=True, return_value=existing_enrollment if keep_failed_enrollments else None, ) returned_from_enrollment, returned_to_enrollment = defer_enrollment( existing_enrollment.user, existing_enrollment.run.courseware_id, course_runs[1].courseware_id, keep_failed_enrollments=keep_failed_enrollments, ) assert returned_from_enrollment == patched_deactivate_enrollments.return_value assert returned_to_enrollment == patched_create_enrollments.return_value[ 0][0] patched_create_enrollments.assert_called_once_with( existing_enrollment.user, [target_run], order=order, company=company, keep_failed_enrollments=keep_failed_enrollments, ) patched_deactivate_enrollments.assert_called_once_with( existing_enrollment, ENROLL_CHANGE_STATUS_DEFERRED, keep_failed_enrollments=keep_failed_enrollments, )
def setUpTestData(cls): super().setUpTestData() cls.user = UserFactory() cls.user.social_auth.create( provider='not_edx', ) cls.user.social_auth.create( provider=EdxOrgOAuth2.name, uid="{}_edx".format(cls.user.username), ) cls.order = OrderFactory.create(status=Order.CREATED, user=cls.user) cls.line1 = LineFactory.create(order=cls.order) cls.line2 = LineFactory.create(order=cls.order) cls.course_run1 = CourseRunFactory.create(edx_course_key=cls.line1.course_key) cls.course_run2 = CourseRunFactory.create(edx_course_key=cls.line2.course_key)
def test_deactivate_program_enrollment(self, user, patches): """ deactivate_program_enrollment set the local program enrollment record to inactive as well as all associated course run enrollments """ order = OrderFactory.create() program_enrollment = ProgramEnrollmentFactory.create(user=user, order=order) course = CourseFactory.create(program=program_enrollment.program) course_run_enrollments = CourseRunEnrollmentFactory.create_batch( 3, user=user, run__course=course, active=True, order=factory.Iterator([order, order, None]), ) expected_inactive_run_enrollments = course_run_enrollments[0:2] expected_ignored_run_enrollment = course_run_enrollments[2] returned_program_enrollment, returned_run_enrollments = deactivate_program_enrollment( program_enrollment, change_status=ENROLL_CHANGE_STATUS_REFUNDED) program_enrollment.refresh_from_db() assert program_enrollment.change_status == ENROLL_CHANGE_STATUS_REFUNDED assert program_enrollment.active is False assert returned_program_enrollment == program_enrollment assert {e.id for e in returned_run_enrollments } == {e.id for e in expected_inactive_run_enrollments} assert patches.edx_unenroll.call_count == len( expected_inactive_run_enrollments) assert patches.send_unenrollment_email.call_count == len( expected_inactive_run_enrollments) for run_enrollment in expected_inactive_run_enrollments: run_enrollment.refresh_from_db() assert run_enrollment.change_status == ENROLL_CHANGE_STATUS_REFUNDED assert run_enrollment.active is False assert expected_ignored_run_enrollment.active is True
def test_update_exam_authorization_order(self, order_status): """ Verify that update_exam_authorization_final_grade is called when a fulfilled Order saves """ with mute_signals(post_save): # muted because enrollment also trigger signal for profile creation. right now we are just # looking final grades CachedEnrollmentFactory.create(user=self.profile.user, course_run=self.course_run) FinalGradeFactory.create( user=self.profile.user, course_run=self.course_run, passed=True, ) order = OrderFactory.create(user=self.profile.user, fulfilled=False) LineFactory.create(course_key=self.course_run.edx_course_key, order=order) # There is no ExamProfile or ExamAuthorization before creating the FinalGrade. assert ExamProfile.objects.filter( profile=self.profile).exists() is False assert ExamAuthorization.objects.filter( user=self.profile.user, course=self.course_run.course).exists() is False order.status = order_status order.save() # assert Exam Authorization and profile created. assert ExamProfile.objects.filter( profile=self.profile).exists() is True assert ExamAuthorization.objects.filter( user=self.profile.user, course=self.course_run.course).exists() is True
def setUpTestData(cls): with mute_signals(post_save): cls.profile = profile = ProfileFactory.create() cls.user = profile.user EducationFactory.create(profile=profile) EmploymentFactory.create(profile=profile) # create a normal program program = ProgramFactory.create() cls.enrollments = cls._generate_cached_enrollments(cls.user, program, num_course_runs=2) certificate_grades_vals = [0.7, 0.8] cls.current_grades_vals = [0.9, 1.0] cls.certificates = [] cls.current_grades = [] for i, enrollment in enumerate(cls.enrollments): cls.certificates.append( CachedCertificateFactory.create( user=cls.user, course_run=enrollment.course_run, data={ "grade": certificate_grades_vals[i], "certificate_type": "verified", "course_id": enrollment.course_run.edx_course_key, "status": "downloadable", } ) ) cls.current_grades.append( CachedCurrentGradeFactory.create( user=cls.user, course_run=enrollment.course_run, data={ "passed": True, "percent": cls.current_grades_vals[i], "course_key": enrollment.course_run.edx_course_key, } ) ) FinalGradeFactory.create( user=cls.user, course_run=enrollment.course_run, grade=certificate_grades_vals[i], passed=True, ) non_fa_cached_edx_data = CachedEdxUserData(cls.user, program=program) non_fa_mmtrack = MMTrack(cls.user, program, non_fa_cached_edx_data) cls.serialized_enrollments = UserProgramSearchSerializer.serialize_enrollments(non_fa_mmtrack) cls.serialized_course_enrollments = UserProgramSearchSerializer.serialize_course_enrollments(non_fa_mmtrack) cls.semester_enrollments = UserProgramSearchSerializer.serialize_course_runs_enrolled(non_fa_mmtrack) cls.program_enrollment = ProgramEnrollment.objects.create(user=cls.user, program=program) # create a financial aid program cls.fa_program, _ = create_program() cls.fa_program_enrollment = ProgramEnrollment.objects.create(user=cls.user, program=cls.fa_program) cls.fa_enrollments = cls._generate_cached_enrollments(cls.user, cls.fa_program, num_course_runs=2) cls.current_grades = [] for i, enrollment in enumerate(cls.fa_enrollments): order = OrderFactory.create(user=cls.user, status='fulfilled') LineFactory.create(order=order, course_key=enrollment.course_run.edx_course_key) cls.current_grades.append( CachedCurrentGradeFactory.create( user=cls.user, course_run=enrollment.course_run, data={ "passed": True, "percent": cls.current_grades_vals[i], "course_key": enrollment.course_run.edx_course_key, } ) ) FinalGradeFactory.create( user=cls.user, course_run=enrollment.course_run, grade=cls.current_grades_vals[i], passed=True, ) fa_cached_edx_data = CachedEdxUserData(cls.user, program=cls.fa_program) fa_mmtrack = MMTrack(cls.user, cls.fa_program, fa_cached_edx_data) cls.fa_serialized_course_enrollments = ( UserProgramSearchSerializer.serialize_course_enrollments(fa_mmtrack) ) cls.fa_serialized_enrollments = ( UserProgramSearchSerializer.serialize_enrollments(fa_mmtrack) )
def setUpTestData(cls): with mute_signals(post_save): cls.profile = profile = ProfileFactory.create() cls.user = profile.user EducationFactory.create(profile=profile) EmploymentFactory.create(profile=profile) # create a normal program program = ProgramFactory.create() cls.enrollments = cls._generate_cached_enrollments(cls.user, program, num_course_runs=2) certificate_grades_vals = [0.7, 0.8] cls.current_grades_vals = [0.9, 1.0] cls.certificates = [] cls.current_grades = [] for i, enrollment in enumerate(cls.enrollments): cls.certificates.append( CachedCertificateFactory.create( user=cls.user, course_run=enrollment.course_run, data={ "grade": certificate_grades_vals[i], "certificate_type": "verified", "course_id": enrollment.course_run.edx_course_key, "status": "downloadable", })) cls.current_grades.append( CachedCurrentGradeFactory.create( user=cls.user, course_run=enrollment.course_run, data={ "passed": True, "percent": cls.current_grades_vals[i], "course_key": enrollment.course_run.edx_course_key, })) FinalGradeFactory.create( user=cls.user, course_run=enrollment.course_run, grade=certificate_grades_vals[i], passed=True, ) non_fa_cached_edx_data = CachedEdxUserData(cls.user, program=program) non_fa_mmtrack = MMTrack(cls.user, program, non_fa_cached_edx_data) cls.serialized_enrollments = UserProgramSearchSerializer.serialize_enrollments( non_fa_mmtrack) cls.serialized_course_enrollments = UserProgramSearchSerializer.serialize_course_enrollments( non_fa_mmtrack) cls.semester_enrollments = UserProgramSearchSerializer.serialize_course_runs_enrolled( non_fa_mmtrack) cls.program_enrollment = ProgramEnrollment.objects.create( user=cls.user, program=program) # create a financial aid program cls.fa_program, _ = create_program() cls.fa_program_enrollment = ProgramEnrollment.objects.create( user=cls.user, program=cls.fa_program) cls.fa_enrollments = cls._generate_cached_enrollments( cls.user, cls.fa_program, num_course_runs=2) cls.current_grades = [] for i, enrollment in enumerate(cls.fa_enrollments): order = OrderFactory.create(user=cls.user, status='fulfilled') LineFactory.create(order=order, course_key=enrollment.course_run.edx_course_key) cls.current_grades.append( CachedCurrentGradeFactory.create( user=cls.user, course_run=enrollment.course_run, data={ "passed": True, "percent": cls.current_grades_vals[i], "course_key": enrollment.course_run.edx_course_key, })) FinalGradeFactory.create( user=cls.user, course_run=enrollment.course_run, grade=cls.current_grades_vals[i], passed=True, ) fa_cached_edx_data = CachedEdxUserData(cls.user, program=cls.fa_program) fa_mmtrack = MMTrack(cls.user, cls.fa_program, fa_cached_edx_data) cls.fa_serialized_course_enrollments = ( UserProgramSearchSerializer.serialize_course_enrollments( fa_mmtrack)) cls.fa_serialized_enrollments = ( UserProgramSearchSerializer.serialize_enrollments(fa_mmtrack))