def create_paid_but_no_enrollable_run(self, enrollable, in_future, fuzzy):
        """Make paid but not enrolled, with offered currently, in future, and fuzzy """
        self.make_fa_program_enrollment(FinancialAidStatus.AUTO_APPROVED)
        course = Course.objects.get(title='Digital Learning 200')
        course_run = course.courserun_set.order_by('start_date').first()
        # course_run = CourseRunFactory.create(course=course, edx_course_key='course-paid')

        add_paid_order_for_course(user=self.user, course_run=course_run)
        if enrollable:
            course_run = CourseRunFactory.create(course=course, edx_course_key='course-enrollable')
            call_command(
                "alter_data", 'set_to_offered', '--username', 'staff',
                '--course-run-key', course_run.edx_course_key
            )
        if in_future:
            course_run = CourseRunFactory.create(course=course, edx_course_key='course-in-future')
            call_command(
                "alter_data", 'set_to_offered', '--username', 'staff',
                '--course-run-key', course_run.edx_course_key, '--in-future'
            )
        if fuzzy:
            course_run = CourseRunFactory.create(course=course, edx_course_key='course-fuzzy')
            call_command(
                "alter_data", 'set_to_offered', '--username', 'staff',
                '--course-run-key', course_run.edx_course_key, '--fuzzy'
            )
    def two_no_show_exam_attempts(self):
        """Passed and later failed course, and two exam attempts"""
        self.make_fa_program_enrollment(FinancialAidStatus.AUTO_APPROVED)

        course = Course.objects.get(title='Digital Learning 200')
        course_run = CourseRunFactory(course=course, edx_course_key='course-passed')
        call_command(
            "alter_data", 'set_to_passed', '--username', 'staff',
            '--course-run-key', course_run.edx_course_key
        )

        ExamProfileFactory.create(status='success', profile=self.user.profile)
        # run 1
        exam_run = ExamRunFactory.create(course=course, eligibility_past=True, scheduling_past=True)
        ExamAuthorizationFactory.create(
            user=self.user, course=course, exam_run=exam_run, status='success', exam_taken=True, exam_no_show=True
        )
        # run 2
        exam_run = ExamRunFactory.create(course=course, eligibility_past=True, scheduling_past=True)
        ExamAuthorizationFactory.create(
            user=self.user, course=course, exam_run=exam_run, status='success', exam_taken=True, exam_no_show=True
        )
        # another offered
        course_run = CourseRunFactory.create(course=course, edx_course_key='course-enrollable')
        call_command(
            "alter_data", 'set_to_offered', '--username', 'staff',
            '--course-run-key', course_run.edx_course_key
        )
        course_run = CourseRunFactory.create(course=course, edx_course_key='course-failed')
        call_command(
            "alter_data", 'set_to_failed', '--username', 'staff',
            '--course-run-key', course_run.edx_course_key, '--audit',
        )
Beispiel #3
0
def base_test_data():
    """
    Fixture for test data that should be available to any test case in the suite
    """
    # Create a live program with valid prices and financial aid
    program = ProgramFactory.create(
        live=True,
        financial_aid_availability=True,
        price=1000,
    )
    CourseRunFactory.create(course__program=program)
    TierProgramFactory.create_properly_configured_batch(2, program=program)
    # Create users
    staff_user, student_user = (create_user_for_login(is_staff=True), create_user_for_login(is_staff=False))
    ProgramEnrollment.objects.create(program=program, user=staff_user)
    ProgramEnrollment.objects.create(program=program, user=student_user)
    Role.objects.create(
        role=Staff.ROLE_ID,
        user=staff_user,
        program=program,
    )
    return SimpleNamespace(
        staff_user=staff_user,
        student_user=student_user,
        program=program
    )
 def missed_payment_can_reenroll(self):
     """User has missed payment but they can re-enroll"""
     call_command(
         "alter_data", 'set_to_needs_upgrade', '--username', 'staff',
         '--course-title', 'Analog Learning 200', '--missed-deadline',
     )
     course = Course.objects.get(title='Analog Learning 200')
     CourseRunFactory.create(course=course)
 def failed_run_missed_payment_can_reenroll(self):
     """Failed User has missed payment but they can re-enroll"""
     call_command(
         "alter_data", 'set_to_failed', '--username', 'staff',
         '--course-title', 'Analog Learning 200', '--grade', '0', '--audit'
     )
     course = Course.objects.get(title='Analog Learning 200')
     CourseRunFactory.create(course=course)
Beispiel #6
0
 def test_course_fuzzy_start_date(self):
     """Test course with promised course run"""
     CourseRunFactory.create(
         course=self.course,
         fuzzy_start_date="Fall 2017",
         start_date=None,
         end_date=None,
         enrollment_start=None,
         enrollment_end=None,
     )
     assert self.course.enrollment_text == 'Coming Fall 2017'
Beispiel #7
0
 def setUpTestData(cls):
     """Create a set of course runs for testing"""
     super().setUpTestData()
     cls.run1 = CourseRunFactory.create(
         course__program__live=True,
         course__program__financial_aid_availability=True,
     )
     cls.program = cls.run1.course.program
     cls.run2 = CourseRunFactory.create(course=cls.run1.course)
     cls.runs = [cls.run1, cls.run2]
     cls.user = UserFactory.create()
     ProgramEnrollment.objects.create(user=cls.user, program=cls.run1.course.program)
Beispiel #8
0
    def test_course_run_finder_success(self):
        """Tests that CourseRunFinder will return a desired course run"""
        course_run = CourseRunFactory.create(title='courserun1', edx_course_key='coursekey1')
        CourseRunFactory.create(title='courserun2', edx_course_key='coursekey2')

        found_course_runs = [
            CourseRunFinder.find(course_run_title='courserun1'),
            CourseRunFinder.find(course_run_title='run1'),
            CourseRunFinder.find(course_run_key='coursekey1'),
            CourseRunFinder.find(course_run_key='key1')
        ]
        assert all([course_run == found_course_run for found_course_run in found_course_runs])
Beispiel #9
0
    def setUpTestData(cls):
        super().setUpTestData()
        # create an user
        cls.user = UserFactory.create()
        cls.cached_edx_user_data = MagicMock(
            spec=CachedEdxUserData,
            enrollments=CachedEnrollment.deserialize_edx_data(cls.enrollments_json),
            certificates=CachedCertificate.deserialize_edx_data(cls.certificates_json),
            current_grades=CachedCurrentGrade.deserialize_edx_data(cls.current_grades_json),
        )

        # create the programs
        cls.program = ProgramFactory.create(live=True, financial_aid_availability=False, price=1000)
        cls.program_financial_aid = ProgramFactory.create(live=True, financial_aid_availability=True, price=1000)

        # create course runs for the normal program
        cls.course = CourseFactory.create(program=cls.program)
        expected_course_keys = [
            "course-v1:edX+DemoX+Demo_Course",
            "course-v1:MITx+8.MechCX+2014_T1",
            '',
            None,
            'course-v1:odl+FOO102+CR-FALL16'
        ]

        cls.cruns = []
        for course_key in expected_course_keys:
            course_run = CourseRunFactory.create(
                course=cls.course,
                edx_course_key=course_key
            )
            if course_key:
                cls.cruns.append(course_run)

        # and the program with financial aid
        finaid_course = CourseFactory.create(program=cls.program_financial_aid)
        cls.now = now_in_utc()
        cls.end_date = cls.now - timedelta(weeks=45)
        cls.crun_fa = CourseRunFactory.create(
            course=finaid_course,
            start_date=cls.now-timedelta(weeks=52),
            end_date=cls.end_date,
            enrollment_start=cls.now-timedelta(weeks=62),
            enrollment_end=cls.now-timedelta(weeks=53),
            edx_course_key="course-v1:odl+FOO101+CR-FALL15"
        )
        cls.crun_fa2 = CourseRunFactory.create(
            course=finaid_course
        )
        CourseRunFactory.create(
            course=finaid_course,
            edx_course_key=None
        )
Beispiel #10
0
    def setUpTestData(cls):
        cls.user = SocialUserFactory.create()

        cls.run_fa = CourseRunFactory.create(
            freeze_grade_date=now_in_utc()-timedelta(days=1),
            course__program__financial_aid_availability=True,
        )
        cls.run_fa_with_cert = CourseRunFactory.create(
            freeze_grade_date=None,
            course__program=cls.run_fa.course.program,
        )

        cls.run_no_fa = CourseRunFactory.create(
            freeze_grade_date=now_in_utc()+timedelta(days=1),
            course__program__financial_aid_availability=False,
        )
        cls.run_no_fa_with_cert = CourseRunFactory.create(
            course__program=cls.run_no_fa.course.program,
        )

        all_course_runs = (cls.run_fa, cls.run_fa_with_cert, cls.run_no_fa, cls.run_no_fa_with_cert, )

        for run in all_course_runs:
            if run.course.program.financial_aid_availability:
                FinancialAidFactory.create(
                    user=cls.user,
                    tier_program=TierProgramFactory.create(
                        program=run.course.program, income_threshold=0, current=True
                    ),
                    status=FinancialAidStatus.RESET,
                )

        cls.enrollments = {
            course_run.edx_course_key: CachedEnrollmentFactory.create(
                user=cls.user, course_run=course_run) for course_run in all_course_runs
        }

        cls.current_grades = {
            course_run.edx_course_key: CachedCurrentGradeFactory.create(
                user=cls.user, course_run=course_run) for course_run in all_course_runs
        }

        cls.certificates = {
            course_run.edx_course_key: CachedCertificateFactory.create(
                user=cls.user, course_run=course_run) for course_run in (cls.run_fa_with_cert, cls.run_no_fa_with_cert)
        }

        cls.user_edx_data = CachedEdxUserData(cls.user)
Beispiel #11
0
    def test_course_keys(self):
        """
        Coupon.course_keys should return a list of all course run keys in a program, course, or course run
        """
        run1 = CourseRunFactory.create(course__program__financial_aid_availability=True)
        run2 = CourseRunFactory.create(course=run1.course)
        run3 = CourseRunFactory.create(course__program=run1.course.program)
        run4 = CourseRunFactory.create(course=run3.course)

        coupon_program = CouponFactory.create(
            content_object=run1.course.program,
        )
        assert sorted(coupon_program.course_keys) == sorted([run.edx_course_key for run in [run1, run2, run3, run4]])

        coupon_course = CouponFactory.create(content_object=run1.course)
        assert sorted(coupon_course.course_keys) == sorted([run.edx_course_key for run in [run1, run2]])
Beispiel #12
0
    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 create_missed_payment_for_exam(self, enrollable, future_exam, current):
        """Passed course but missed deadline to pay to take exam"""
        self.make_fa_program_enrollment(FinancialAidStatus.AUTO_APPROVED)
        if current:
            call_command(
                "alter_data", 'set_to_enrolled', '--username', 'staff',
                '--course-title', 'Digital Learning 200',
                '--missed-deadline'
            )
        else:
            call_command(
                "alter_data", 'set_past_run_to_passed', '--username', 'staff',
                '--course-title', 'Digital Learning 200', '--grade', '87', '--audit',
                '--missed-deadline'
            )
        course = Course.objects.get(title='Digital Learning 200')
        ExamProfileFactory.create(status='success', profile=self.user.profile)
        ExamRunFactory.create(course=course, eligibility_past=True, scheduling_past=True)

        if enrollable:
            course_run = CourseRunFactory.create(course=course, edx_course_key='course-enrollable')
            call_command(
                "alter_data", 'set_to_offered', '--username', 'staff',
                '--course-run-key', course_run.edx_course_key
            )
        if future_exam:
            ExamRunFactory.create(
                scheduling_past=False,
                scheduling_future=True,
                authorized=True,
                course=course
            )
Beispiel #14
0
    def test_user_has_redemptions_left(self, order_status, has_unpurchased_run, another_already_redeemed, expected):
        """
        Coupon.user_has_redemptions_left should be true if user has not yet purchased all course runs
        """
        run1 = CourseRunFactory.create(course__program__financial_aid_availability=True)
        if has_unpurchased_run:
            CourseRunFactory.create(course__program=run1.course.program)

        line = LineFactory.create(course_key=run1.edx_course_key, order__status=order_status)
        coupon = CouponFactory.create(content_object=run1.course.program)
        with patch(
            'ecommerce.models.Coupon.another_user_already_redeemed',
            autospec=True,
        ) as _already_redeemed:
            _already_redeemed.return_value = another_already_redeemed
            assert coupon.user_has_redemptions_left(line.order.user) is expected
        _already_redeemed.assert_called_with(coupon, line.order.user)
    def create_passed_and_offered_course_run(self, grades_frozen, with_certificate):
        """Make passed and currently offered course run, and see the View Certificate and Re-Enroll"""
        self.make_fa_program_enrollment(FinancialAidStatus.AUTO_APPROVED)
        call_command(
            "alter_data", 'set_to_passed', '--username', 'staff',
            '--course-title', 'Digital Learning 200', '--grade', '89',
        )
        course = Course.objects.get(title='Digital Learning 200')
        # create another currently offered run
        CourseRunFactory.create(course=course)

        if grades_frozen:
            final_grade = FinalGrade.objects.filter(user=self.user, course_run__course=course, passed=True).first()
            CourseRunGradingStatus.objects.create(course_run=final_grade.course_run, status='complete')
            if with_certificate:
                MicromastersCourseCertificate.objects.create(user=self.user, course=course)
                CourseCertificateSignatoriesFactory.create(course=course)
Beispiel #16
0
 def setUpTestData(cls):
     cls.user = SocialUserFactory.create()
     cls.run_1 = CourseRunFactory.create(
         freeze_grade_date=now_in_utc()-timedelta(days=1),
         course__program__financial_aid_availability=True,
     )
     CourseRunGradingStatus.objects.create(course_run=cls.run_1, status='complete')
     cls.program = cls.run_1.course.program
Beispiel #17
0
    def setUpTestData(cls):
        cls.users = [UserFactory.create() for _ in range(35)]

        freeze_date = now_in_utc()-timedelta(days=1)
        future_freeze_date = now_in_utc()+timedelta(days=1)
        cls.course_run1 = CourseRunFactory.create(freeze_grade_date=freeze_date)
        cls.course_run2 = CourseRunFactory.create(freeze_grade_date=freeze_date)
        cls.all_freezable_runs = [cls.course_run1, cls.course_run2]

        cls.course_run_future = CourseRunFactory.create(freeze_grade_date=future_freeze_date)
        cls.course_run_frozen = CourseRunFactory.create(freeze_grade_date=freeze_date)

        CourseRunGradingStatus.objects.create(course_run=cls.course_run_frozen, status=FinalGradeStatus.COMPLETE)

        for user in cls.users:
            CachedEnrollmentFactory.create(user=user, course_run=cls.course_run1)
            CachedCurrentGradeFactory.create(user=user, course_run=cls.course_run1)
Beispiel #18
0
    def setUpTestData(cls):
        cls.user = SocialUserFactory.create()

        cls.run_1 = CourseRunFactory.create(
            freeze_grade_date=now_in_utc()-timedelta(days=1),
            course__program__financial_aid_availability=True,
        )
        cls.program = cls.run_1.course.program
Beispiel #19
0
 def test_create_final_grade_fa(self, generate_letter_mock, update_grade_mock, mock_on_commit):
     """
     Test that final grades created for non-FA courses will try to update combined final grades.
     """
     fa_course_run = CourseRunFactory.create(course__program__financial_aid_availability=True)
     FinalGradeFactory.create(user=self.user, course_run=fa_course_run, grade=0.9)
     update_grade_mock.assert_called_once_with(self.user, fa_course_run.course)
     generate_letter_mock.assert_not_called()
Beispiel #20
0
 def test_course_with_run(self):
     """
     Make sure the course URL serializes properly
     """
     course_run = CourseRunFactory.create()
     course = course_run.course
     data = CourseSerializer(course).data
     assert data['url'] == course_run.enrollment_url
     assert data['enrollment_text'] == course.enrollment_text
Beispiel #21
0
 def setUpTestData(cls):
     """
     Create user, run, and coupons for testing
     """
     super().setUpTestData()
     cls.user = SocialProfileFactory.create().user
     UserSocialAuthFactory.create(user=cls.user, provider='not_edx')
     run = CourseRunFactory.create(course__program__financial_aid_availability=True)
     cls.coupon = CouponFactory.create(content_object=run.course.program)
     UserCoupon.objects.create(coupon=cls.coupon, user=cls.user)
Beispiel #22
0
 def test_coupon_allowed_course(self):
     """
     Assert that the price is not adjusted if the coupon is for a different course in the same program
     """
     course_run, _ = create_purchasable_course_run()
     other_course = CourseRunFactory.create(course__program=course_run.course.program).course
     price = Decimal('0.3')
     coupon = CouponFactory.create(content_object=other_course)
     assert coupon.content_object != course_run
     assert calculate_coupon_price(coupon, price, course_run.edx_course_key) == price
Beispiel #23
0
    def test_another_user_already_redeemed(self, order_status, other_user_redeemed, is_automatic, expected):
        """
        Tests for Coupon.another_user_already_redeemed
        """
        run1 = CourseRunFactory.create(course__program__financial_aid_availability=True)
        run2 = CourseRunFactory.create(course=run1.course)
        coupon = CouponFactory.create(
            content_object=run1.course,
            coupon_type=Coupon.DISCOUNTED_PREVIOUS_COURSE if is_automatic else Coupon.STANDARD,
        )

        line1 = LineFactory.create(course_key=run1.edx_course_key, order__status=Order.FULFILLED)
        RedeemedCoupon.objects.create(order=line1.order, coupon=coupon)

        if other_user_redeemed:
            line2 = LineFactory.create(course_key=run2.edx_course_key, order__status=order_status)
            RedeemedCoupon.objects.create(order=line2.order, coupon=coupon)

        assert coupon.another_user_already_redeemed(line1.order.user) is expected
Beispiel #24
0
 def test_deserialize_user_data(self):
     """Test that user data is correctly deserialized"""
     new_course_run = CourseRunFactory.create(edx_course_key='course-v1:MITx+Analog+Learning+100+Aug_2015')
     new_program = new_course_run.course.program
     with mute_signals(post_save):
         user = deserialize_user_data(self.USER_DATA, [new_program])
     assert user.username == '{}mario.medina'.format(FAKE_USER_USERNAME_PREFIX)
     assert user.profile.first_name == 'Mario'
     assert user.profile.date_of_birth == '1961-04-29'
     assert CachedEnrollment.objects.filter(user=user, course_run=new_course_run).count() == 1
Beispiel #25
0
    def setUpTestData(cls):
        super().setUpTestData()
        # create a user
        cls.user = SocialUserFactory.create()

        # create the course run
        cls.course_id = "edx+fake+key"
        cls.course_run = CourseRunFactory.create(edx_course_key=cls.course_id)

        # url for the dashboard
        cls.url = reverse('user_course_enrollments')
Beispiel #26
0
 def test_course_run(self):
     """
     Make sure course run serializer correctly
     """
     course_run = CourseRunFactory.create()
     data = CourseRunSerializer(course_run).data
     expected = {
         'edx_course_key': course_run.edx_course_key,
         'program_title': course_run.course.program.title,
     }
     assert data == expected
Beispiel #27
0
    def create_frozen_run(self, course):
        """helper function to create frozen course runs"""

        now = now_in_utc()
        run = CourseRunFactory.create(
            course=course,
            title="Title Run",
            freeze_grade_date=now - timedelta(weeks=1),
        )
        CourseRunGradingStatus.objects.create(course_run=run, status='complete')
        return run
Beispiel #28
0
 def test_validate_discount_prev_run_coupon_type(self):
     """Coupon must be for a course if Coupon.coupon_type is DISCOUNTED_PREVIOUS_RUN"""
     run = CourseRunFactory.create()
     with self.assertRaises(ValidationError) as ex:
         CouponFactory.create(
             coupon_type=Coupon.DISCOUNTED_PREVIOUS_COURSE,
             content_object=run.course.program,
         )
     assert ex.exception.args[0]['__all__'][0].args[0] == (
         'coupon must be for a course if coupon_type is discounted-previous-course'
     )
Beispiel #29
0
 def test_is_automatic(self):
     """
     Coupon.is_automatic_qset should be true if the coupon type is DISCOUNTED_PREVIOUS_COURSE
     """
     coupon_not_automatic = CouponFactory.create(coupon_type=Coupon.STANDARD)
     assert Coupon.is_automatic_qset().filter(id=coupon_not_automatic.id).exists() is False
     run = CourseRunFactory.create(course__program__financial_aid_availability=True)
     coupon_is_automatic = CouponFactory.create(
         coupon_type=Coupon.DISCOUNTED_PREVIOUS_COURSE,
         content_object=run.course,
     )
     assert Coupon.is_automatic_qset().filter(id=coupon_is_automatic.id).exists() is True
Beispiel #30
0
 def test_enrollment_url(self):
     """If both enrollment_url and edx_course_key are available, use enrollment_url"""
     course_run = CourseRunFactory.create(
         course=self.course,
         start_date=self.from_weeks(-1),
         end_date=None,
         enrollment_start=self.from_weeks(-1),
         enrollment_end=None,
         enrollment_url="http://enrollment.url/",
         edx_course_key="course_key"
     )
     assert course_run.course.url == "http://enrollment.url/"
Beispiel #31
0
    def create_paid_failed_course_run(self, *, current, in_future, fuzzy):
        """Make paid failed course run, and offer another run"""
        self.make_fa_program_enrollment(FinancialAidStatus.AUTO_APPROVED)
        call_command(
            "alter_data", 'set_to_failed', '--username', 'staff',
            '--course-title', 'Digital Learning 200', '--grade', '45',
        )
        course = Course.objects.get(title='Digital Learning 200')

        if current:
            CourseRunFactory.create(course=course)

        if in_future:
            course_run = CourseRunFactory.create(course=course, edx_course_key='course-in-future')
            call_command(
                "alter_data", 'set_to_offered', '--username', 'staff',
                '--course-run-key', course_run.edx_course_key, '--in-future'
            )
        if fuzzy:
            course_run = CourseRunFactory.create(course=course, edx_course_key='course-fuzzy')
            call_command(
                "alter_data", 'set_to_offered', '--username', 'staff',
                '--course-run-key', course_run.edx_course_key, '--fuzzy'
            )
 def test_create_final_grade_non_fa(self, generate_letter_mock,
                                    update_grade_mock, mock_on_commit):
     """
     Test that final grades created for non-FA courses will try to update combined final grades and
     generate a program commendation letter.
     """
     non_fa_course_run = CourseRunFactory.create(
         course__program__financial_aid_availability=False)
     FinalGradeFactory.create(user=self.user,
                              course_run=non_fa_course_run,
                              grade=0.9)
     update_grade_mock.assert_called_once_with(self.user,
                                               non_fa_course_run.course)
     generate_letter_mock.assert_called_once_with(
         self.user, non_fa_course_run.course.program)
Beispiel #33
0
def test_serialize_course_run_detail():
    """Test CourseRunDetailSerializer serialization"""
    course_run = CourseRunFactory.create()
    data = CourseRunDetailSerializer(course_run).data
    assert data == {
        "course": BaseCourseSerializer(course_run.course).data,
        "title": course_run.title,
        "courseware_id": course_run.courseware_id,
        "courseware_url": course_run.courseware_url,
        "start_date": drf_datetime(course_run.start_date),
        "end_date": drf_datetime(course_run.end_date),
        "enrollment_start": drf_datetime(course_run.enrollment_start),
        "enrollment_end": drf_datetime(course_run.enrollment_end),
        "expiration_date": drf_datetime(course_run.expiration_date),
        "id": course_run.id,
    }
Beispiel #34
0
def test_run_queryset(is_program):
    """
    run_queryset should return all runs related to the product
    """
    program = ProgramFactory.create()
    runs = [CourseRunFactory.create(course__program=program) for _ in range(4)]
    run = runs[2]
    obj = program if is_program else run
    product = ProductFactory.create(content_object=obj)

    def key_func(_run):
        return _run.id

    assert sorted(product.run_queryset,
                  key=key_func) == sorted(runs if is_program else [run],
                                          key=key_func)
 def test_update_edx_record(self):
     """
     Test that a cached edX record is reindexed after being updated
     """
     program_enrollment = ProgramEnrollmentFactory.create()
     for edx_cached_model_factory in [
             CachedCertificateFactory, CachedEnrollmentFactory
     ]:
         assert es.search()['total'] == 1
         course_run = CourseRunFactory.create(
             program=program_enrollment.program)
         edx_record = edx_cached_model_factory.create(
             user=program_enrollment.user, course_run=course_run)
         edx_record.data.update({'new': 'data'})
         edx_record.save()
         assert_search(es.search(), [program_enrollment])
Beispiel #36
0
    def setUpTestData(cls):
        cls.user = SocialUserFactory.create()

        cls.course_run = CourseRunFactory.create(
            course__program__financial_aid_availability=True
        )
        cls.exam_run = ExamRunFactory.create(
            course=cls.course_run.course,
            date_grades_available=now_in_utc() - timedelta(weeks=1)
        )
        cls.not_passing_final_grade = FinalGradeFactory.create(
            user=cls.user,
            course_run=cls.course_run,
            grade=0.5,
            passed=False
        )
    def test_not_live_program(self):
        """
        An order is created using create_unfulfilled_order and a payload
        is generated using generate_cybersource_sa_payload
        """
        user = UserFactory.create()
        self.client.force_login(user)
        course_run = CourseRunFactory.create(
            course__program__live=False,
            course__program__financial_aid_availability=True,
        )

        resp = self.client.post(reverse('checkout'),
                                {'course_id': course_run.edx_course_key},
                                format='json')
        assert resp.status_code == status.HTTP_404_NOT_FOUND
 def test_url_with_course_key(self):
     """Test course url with a course key and no enrollment_url"""
     course_run = CourseRunFactory.create(
         course=self.course,
         start_date=self.from_weeks(-1),
         end_date=None,
         enrollment_start=self.from_weeks(-1),
         enrollment_end=None,
         enrollment_url=None,
         edx_course_key="course_key"
     )
     expected = urljoin(
         BASE_URL,
         'courses/{key}/about'.format(key=course_run.edx_course_key)
     )
     assert course_run.course.url == expected
    def setUpTestData(cls):
        """
        Set up data
        """
        cls.user = UserFactory.create()
        cls.user.social_auth.create(
            provider=EdxOrgOAuth2.name,
            uid="{}_edx".format(cls.user.username),
            extra_data={"access_token": "fooooootoken"})

        certificates_json = load_json_from_file(
            'dashboard/fixtures/certificates.json')
        cls.certificates = Certificates(
            [Certificate(cert_json) for cert_json in certificates_json])

        enrollments_json = load_json_from_file(
            'dashboard/fixtures/user_enrollments.json')
        cls.enrollments = Enrollments(enrollments_json)

        # the grades need to have all the same usernames
        current_grades_json = []
        for grade in load_json_from_file(
                'dashboard/fixtures/current_grades.json'):
            grade.update({'username': cls.user.username})
            current_grades_json.append(grade)
        cls.current_grades = CurrentGrades(
            [CurrentGrade(grade_json) for grade_json in current_grades_json])

        cls.certificates_ids = set(cls.certificates.all_courses_certs)
        cls.verified_certificates_ids = set(
            cls.certificates.all_courses_verified_certs)
        cls.enrollment_ids = set(cls.enrollments.get_enrolled_course_ids())
        cls.grades_ids = set(cls.current_grades.all_course_ids)
        cls.all_course_run_ids = list(cls.certificates_ids | cls.enrollment_ids
                                      | cls.grades_ids)
        cls.all_runs = []
        for course_id in cls.all_course_run_ids:
            cls.all_runs.append(
                CourseRunFactory.create(
                    edx_course_key=course_id,
                    course__program__live=True,
                ))

        cls.edx_client = MagicMock()
        cls.edx_client.enrollments.get_student_enrollments.return_value = cls.enrollments
        cls.edx_client.certificates.get_student_certificates.return_value = cls.certificates
        cls.edx_client.current_grades.get_student_current_grades.return_value = cls.current_grades
Beispiel #40
0
def test_course_run_not_beyond_enrollment(end_days, enroll_start_days,
                                          enroll_end_days, expected):
    """
    Test that CourseRun.is_beyond_enrollment returns the expected boolean value
    """
    now = now_in_utc()
    end_date = None if end_days is None else now + timedelta(days=end_days)
    enr_end_date = (None if enroll_end_days is None else now +
                    timedelta(days=enroll_end_days))
    enr_start_date = (None if enroll_start_days is None else now +
                      timedelta(days=enroll_start_days))

    assert (CourseRunFactory.create(
        end_date=end_date,
        enrollment_end=enr_end_date,
        enrollment_start=enr_start_date,
    ).is_not_beyond_enrollment is expected)
    def test_creates_order(self):
        """
        An order is created using create_unfulfilled_order and a payload
        is generated using generate_cybersource_sa_payload
        """
        user = UserFactory.create()
        self.client.force_login(user)

        course_run = CourseRunFactory.create(
            course__program__live=True,
            course__program__financial_aid_availability=True,
        )
        order = LineFactory.create(order__status=Order.CREATED).order
        fake_ip = "195.0.0.1"
        payload = {
            'a': 'payload',
        }
        with patch(
                'ecommerce.views.create_unfulfilled_order',
                autospec=True,
                return_value=order,
        ) as create_mock, patch(
                'ecommerce.views.generate_cybersource_sa_payload',
                autospec=True,
                return_value=payload,
        ) as generate_mock, patch("ecommerce.views.get_client_ip",
                                  return_value=(fake_ip,
                                                True)) as mock_ip_call:
            resp = self.client.post(reverse('checkout'),
                                    {'course_id': course_run.edx_course_key},
                                    format='json')

        assert mock_ip_call.call_count == 1
        assert resp.status_code == status.HTTP_200_OK
        assert resp.json() == {
            'payload': payload,
            'url': CYBERSOURCE_SECURE_ACCEPTANCE_URL,
            'method': 'POST',
        }

        assert create_mock.call_count == 1
        assert create_mock.call_args[0] == (course_run.edx_course_key, user)
        assert generate_mock.call_count == 1
        assert generate_mock.call_args[0] == (order,
                                              'http://testserver/dashboard/',
                                              fake_ip)
 def test_add_edx_record(self, index_type, mock_on_commit):
     """
     Test that cached edX records are indexed after being added
     """
     program_enrollment = ProgramEnrollmentFactory.create()
     for edx_cached_model_factory in [
             CachedCertificateFactory, CachedEnrollmentFactory,
             CachedCurrentGradeFactory
     ]:
         assert es.search(index_type)['total'] == DOC_TYPES_PER_ENROLLMENT
         course = CourseFactory.create(program=program_enrollment.program)
         course_run = CourseRunFactory.create(course=course)
         edx_cached_model_factory.create(user=program_enrollment.user,
                                         course_run=course_run)
         index_program_enrolled_users([program_enrollment])
         assert_search(es.search(index_type), [program_enrollment],
                       index_type=index_type)
Beispiel #43
0
def test_instructors(has_page):
    """CourseRun.instructors should list instructors from the related CMS page, or provide an empty list"""
    faculty_names = ["Teacher One", "Teacher Two"]
    course_run = CourseRunFactory.create(course__page=None)
    if has_page:
        course_page = CoursePageFactory.create(course=course_run.course)
        FacultyMembersPageFactory.create(
            parent=course_page,
            **{
                f"members__{idx}__member__name": name
                for idx, name in enumerate(faculty_names)
            },
        )

    assert course_run.instructors == ([{
        "name": name
    } for name in faculty_names] if has_page else [])
Beispiel #44
0
def test_basket_thumbnail_courserun(basket_and_coupons, mock_context):
    """Basket thumbnail should be serialized for a courserun"""
    thumbnail_filename = "abcde.jpg"
    course_page = CoursePageFactory.create(
        thumbnail_image__file__filename=thumbnail_filename
    )
    run = CourseRunFactory.create(course=course_page.course)
    product_version = ProductVersionFactory.create(product__content_object=run)
    data = FullProductVersionSerializer(
        instance=product_version, context=mock_context
    ).data
    assert (
        data["thumbnail_url"]
        == course_page.thumbnail_image.get_rendition(
            CATALOG_COURSE_IMG_WAGTAIL_FILL
        ).url
    )
Beispiel #45
0
 def test_course_enrollments_serialized_unique(self):
     """
     Tests that enrollments in multiple runs of the same course won't result in multiple serializations
     """
     # Create an enrollment for a different course run of an already-enrolled course
     serialized_program_user = UserProgramSearchSerializer.serialize(
         self.non_fa_program_enrollment)
     serialized_count_before_addition = len(
         serialized_program_user['courses'])
     first_enrollment = self.non_fa_enrollments[0]
     new_course_run = CourseRunFactory.create(
         course=first_enrollment.course_run.course)
     self.verified_enroll(self.user, course_run=new_course_run)
     serialized_program_user = UserProgramSearchSerializer.serialize(
         self.non_fa_program_enrollment)
     # Number of serialized enrollments should be unaffected
     assert len(serialized_program_user['courses']
                ) == serialized_count_before_addition
 def test_calculate_run_price_other_run(self):
     """
     If the coupon is for another course in this program it should not be returned here
     """
     course_run, user = create_purchasable_course_run()
     other_course = CourseRunFactory.create(
         course__program=course_run.course.program).course
     coupon = CouponFactory.create(content_object=other_course)
     UserCoupon.objects.create(coupon=coupon, user=user)
     discounted_price = 5
     program_enrollment = course_run.course.program.programenrollment_set.first(
     )
     fa_price = get_formatted_course_price(program_enrollment)['price']
     with patch('ecommerce.api.calculate_coupon_price',
                autospec=True) as _calculate_coupon_price:
         _calculate_coupon_price.return_value = discounted_price
         assert calculate_run_price(course_run, user) == (fa_price, None)
     assert _calculate_coupon_price.called is False
Beispiel #47
0
def test_create_run_enrollments_api_fail(mocker, user, exception_cls):
    """
    create_run_enrollments should log a message and still create local enrollment records when certain exceptions
    are raised if a flag is set to true
    """
    patched_edx_enroll = mocker.patch("courses.api.enroll_in_edx_course_runs",
                                      side_effect=exception_cls)
    patched_log_exception = mocker.patch("courses.api.log.exception")
    patched_send_enrollment_email = mocker.patch(
        "courses.api.mail_api.send_course_run_enrollment_email")
    run = CourseRunFactory.create()
    successful_enrollments, edx_request_success = create_run_enrollments(
        user, [run], order=None, company=None, keep_failed_enrollments=True)
    patched_edx_enroll.assert_called_once_with(user, [run])
    patched_log_exception.assert_called_once()
    patched_send_enrollment_email.assert_not_called()
    assert len(successful_enrollments) == 1
    assert edx_request_success is False
 def setUpTestData(cls):
     with mute_signals(post_save):
         cls.profile = ProfileFactory.create()
     EducationFactory.create(profile=cls.profile)
     EmploymentFactory.create(profile=cls.profile)
     EmploymentFactory.create(profile=cls.profile, end_date=None)
     program = ProgramFactory.create()
     course = CourseFactory.create(program=program)
     course_runs = [
         CourseRunFactory.create(course=course) for _ in range(2)
     ]
     for course_run in course_runs:
         CachedCertificateFactory.create(user=cls.profile.user,
                                         course_run=course_run)
         CachedEnrollmentFactory.create(user=cls.profile.user,
                                        course_run=course_run)
     cls.program_enrollment = ProgramEnrollment.objects.create(
         user=cls.profile.user, program=program)
Beispiel #49
0
 def setUpTestData(cls):
     super().setUpTestData()
     with mute_signals(post_save):
         staff_profile = ProfileFactory.create()
     cls.staff_user = staff_profile.user
     cls.course = CourseFactory.create(
         contact_email='*****@*****.**',
         program__financial_aid_availability=False)
     course_run = CourseRunFactory.create(course=cls.course)
     ProgramEnrollmentFactory.create(user=cls.staff_user,
                                     program=cls.course.program)
     CachedEnrollmentFactory.create(user=cls.staff_user,
                                    course_run=course_run)
     cls.url_name = 'course_team_mail_api'
     cls.request_data = {
         'email_subject': 'email subject',
         'email_body': 'email body'
     }
Beispiel #50
0
    def create_passed_enrolled_again(self):
        """Make course passed and user retaking/auditing the course again"""
        self.make_fa_program_enrollment(FinancialAidStatus.AUTO_APPROVED)
        course = Course.objects.get(title='Digital Learning 200')
        CourseCertificateSignatoriesFactory.create(course=course)

        call_command(
            "alter_data", 'set_past_run_to_passed', '--username', 'staff',
            '--course-title', 'Digital Learning 200', '--grade', '87',
        )
        final_grade = FinalGrade.objects.filter(
            course_run__course__title='Digital Learning 200', user=self.user
        ).first()
        CourseRunGradingStatus.objects.create(course_run=final_grade.course_run, status='complete')
        MicromastersCourseCertificateFactory.create(user=self.user, course=course)

        course_run = CourseRunFactory.create(course=course)
        set_course_run_current(course_run, upgradeable=True, save=True)
        CachedEnrollmentHandler(self.user).set_or_create(course_run, verified=False)
Beispiel #51
0
def create_purchasable_course_run():
    """
    Creates a purchasable course run and an associated user
    """
    course_run = CourseRunFactory.create(
        course__program__live=True,
        course__program__financial_aid_availability=True,
    )
    price = course_run.course.program.price
    user = UserFactory.create()
    FinancialAidFactory.create(
        tier_program__current=True,
        tier_program__program=course_run.course.program,
        tier_program__discount_amount=price/2,
        user=user,
        status=FinancialAidStatus.APPROVED,
    )
    ProgramEnrollment.objects.create(user=user, program=course_run.course.program)
    return course_run, user
Beispiel #52
0
    def test_get_best_final_grade_for_course(self):
        """
        Test for get_best_final_grade_for_course to return the highest grade over all course runs
        """
        mmtrack = MMTrack(
            user=self.user,
            program=self.program_financial_aid,
            edx_user_data=self.cached_edx_user_data
        )
        finaid_course = self.crun_fa.course

        FinalGradeFactory.create(user=self.user, course_run=self.crun_fa, grade=0.3, passed=False)
        assert mmtrack.get_best_final_grade_for_course(finaid_course) is None

        for grade in [0.3, 0.5, 0.8]:
            course_run = CourseRunFactory.create(
                course=finaid_course,
            )
            FinalGradeFactory.create(user=self.user, course_run=course_run, grade=grade, passed=True)
        assert mmtrack.get_best_final_grade_for_course(finaid_course).grade == 0.8
Beispiel #53
0
 def create_run(self,
                course=None,
                start=None,
                end=None,
                enr_start=None,
                enr_end=None,
                upgrade_deadline=None,
                freeze_grade_date=None):
     """helper function to create course runs"""
     # pylint: disable=too-many-arguments
     return CourseRunFactory.create(
         course=course or self.course,
         title="Title Run",
         start_date=start,
         end_date=end,
         enrollment_start=enr_start,
         enrollment_end=enr_end,
         upgrade_deadline=upgrade_deadline,
         freeze_grade_date=freeze_grade_date,
     )
Beispiel #54
0
def test_course_certificate_view(user_client, user, wagtail_basics):
    """
    Test that certificate page show correctly
    """
    home = HomePageFactory.create(parent=wagtail_basics.root, slug="home")
    home.save_revision().publish()

    course_page = CoursePageFactory.create(parent=home)
    course_page.save_revision().publish()

    course_run = CourseRunFactory.create(course=course_page.course)

    course_run_certificate = CourseRunCertificateFactory.create(
        user=user, course_run=course_run
    )

    resp = user_client.get(course_run_certificate.link)
    assert resp.status_code == status.HTTP_200_OK
    assert resp.context_data["page"] == course_page.certificate_page
    assert resp.context_data["page"].certificate == course_run_certificate
 def test_delete_edx_record(self, index_type, mock_on_commit):
     """
     Test that a cached edX record is removed from index after being deleted
     """
     program_enrollment = ProgramEnrollmentFactory.create()
     for edx_cached_model_factory in [
             CachedCertificateFactory, CachedEnrollmentFactory,
             CachedCurrentGradeFactory
     ]:
         course = CourseFactory.create(program=program_enrollment.program)
         course_run = CourseRunFactory.create(course=course)
         edx_record = edx_cached_model_factory.create(
             user=program_enrollment.user, course_run=course_run)
         index_program_enrolled_users([program_enrollment])
         assert_search(es.search(index_type), [program_enrollment],
                       index_type=index_type)
         edx_record.delete()
         index_program_enrolled_users([program_enrollment])
         assert_search(es.search(index_type), [program_enrollment],
                       index_type=index_type)
    def test_update_exam_authorization_cached_enrollment_when_no_exam_run(
            self):
        """
        Test no exam profile created when course has no ExamRun
        """
        self.exam_run.delete()
        course = CourseFactory.create(program=self.program)
        course_run = CourseRunFactory.create(
            end_date=now_in_utc() - timedelta(days=100),
            enrollment_end=now_in_utc() + timedelta(hours=1),
            course=course)
        create_order(self.profile.user, course_run)

        # exam profile before enrollment.
        assert ExamProfile.objects.filter(
            profile=self.profile).exists() is False
        CachedEnrollmentFactory.create(user=self.profile.user,
                                       course_run=course_run)
        assert ExamProfile.objects.filter(
            profile=self.profile).exists() is False
Beispiel #57
0
def test_build_digital_credential_course_run(settings, mocker):
    "Verify build_digital_credential works correctly for a course run"
    mock_build_course_run_credential = mocker.patch(
        "courses.credentials.build_course_run_credential", autospec=True)
    course_run = CourseRunFactory.create()
    learner_did = LearnerDIDFactory.create()
    certificate = CourseRunCertificateFactory.create(user=learner_did.learner,
                                                     course_run=course_run)

    assert build_digital_credential(certificate, learner_did) == {
        "credential": {
            "@context": [
                "https://www.w3.org/2018/credentials/v1",
                "https://w3id.org/security/suites/ed25519-2020/v1",
                "https://w3id.org/dcc/v1"
            ],
            "id":
            urljoin(settings.SITE_BASE_URL, certificate.link),
            "type": ["VerifiableCredential", "LearningCredential"],
            "issuer": {
                "type": "Issuer",
                "id": settings.DIGITAL_CREDENTIALS_ISSUER_ID,
                "name": settings.SITE_NAME,
                "url": settings.SITE_BASE_URL,
            },
            "issuanceDate":
            any_instance_of(str),
            "credentialSubject": {
                "type": "schema:Person",
                "id": learner_did.did,
                "name": learner_did.learner.name,
                "hasCredential": mock_build_course_run_credential.return_value,
            },
        },
        "options": {
            "verificationMethod":
            settings.DIGITAL_CREDENTIALS_VERIFICATION_METHOD
        },
    }

    mock_build_course_run_credential.assert_called_once_with(certificate)
def test_create_combined_final_grade(mocker):
    """
    Test create_combined_final_grade creates the grade when it is missing
    """
    update_mock = mocker.patch(
        'grades.api.update_or_create_combined_final_grade', autospec=True)
    course_run = CourseRunFactory.create(
        freeze_grade_date=now_in_utc() - timedelta(days=1),
        course__program__financial_aid_availability=True,
        course__program__live=True)
    course = course_run.course
    CourseRunGradingStatus.objects.create(course_run=course_run,
                                          status='complete')
    # Create exam run for course with date_grades_available True
    exam_run_grades_available = ExamRunFactory.create(
        course=course, date_grades_available=now_in_utc() - timedelta(weeks=1))

    exam_grades = ProctoredExamGradeFactory.create_batch(
        5,
        course=course,
        exam_run=exam_run_grades_available,
        passed=True,
    )
    for exam_grade in exam_grades[:3]:
        CombinedFinalGrade.objects.create(user=exam_grade.user,
                                          course=course,
                                          grade=0.7)
    # Only 3 users will have combined grades
    for exam_grade in exam_grades[3:]:
        FinalGradeFactory.create(user=exam_grade.user,
                                 course_run=course_run,
                                 passed=True)

    tasks.create_combined_final_grades.delay()

    assert update_mock.call_count == 2

    update_mock.assert_has_calls(
        [call(exam_grades[3].user, course),
         call(exam_grades[4].user, course)],
        any_order=True)
    def test_zero_price_checkout(self):
        """
        If the order total is $0, we should just fulfill the order and direct the user to our order receipt page
        """
        user = UserFactory.create()
        self.client.force_login(user)

        course_run = CourseRunFactory.create(
            course__program__live=True,
            course__program__financial_aid_availability=True,
        )
        order = LineFactory.create(
            order__status=Order.CREATED,
            order__total_price_paid=0,
            price=0,
        ).order
        with patch(
                'ecommerce.views.create_unfulfilled_order',
                autospec=True,
                return_value=order,
        ) as create_mock, patch('ecommerce.views.enroll_user_on_success',
                                autospec=True) as enroll_user_mock:
            resp = self.client.post(reverse('checkout'),
                                    {'course_id': course_run.edx_course_key},
                                    format='json')

        assert resp.status_code == status.HTTP_200_OK
        assert resp.json() == {
            'payload': {},
            'url':
            'http://testserver/dashboard/?status=receipt&course_key={}'.format(
                quote_plus(course_run.edx_course_key)),
            'method':
            'GET',
        }

        assert create_mock.call_count == 1
        assert create_mock.call_args[0] == (course_run.edx_course_key, user)

        assert enroll_user_mock.call_count == 1
        assert enroll_user_mock.call_args[0] == (order, )
 def test_decimal(self):
     """
     Test that a model with a decimal field is handled correctly
     """
     course_run = CourseRunFactory.create()
     assert serialize_model_object(course_run) == {
         'course': course_run.course.id,
         'edx_course_key': course_run.edx_course_key,
         'end_date': format_as_iso8601(course_run.end_date),
         'enrollment_end': format_as_iso8601(course_run.enrollment_end),
         'enrollment_start': format_as_iso8601(course_run.enrollment_start),
         'enrollment_url': course_run.enrollment_url,
         'freeze_grade_date': format_as_iso8601(course_run.freeze_grade_date),
         'fuzzy_enrollment_start_date': course_run.fuzzy_enrollment_start_date,
         'fuzzy_start_date': course_run.fuzzy_start_date,
         'id': course_run.id,
         'prerequisites': course_run.prerequisites,
         'start_date': format_as_iso8601(course_run.start_date),
         'title': course_run.title,
         'upgrade_deadline': format_as_iso8601(course_run.upgrade_deadline),
     }