Exemple #1
0
def test_create_run_enrollments_enroll_api_fail(mocker, user,
                                                keep_failed_enrollments,
                                                exception_cls,
                                                inner_exception):
    """
    create_run_enrollments should log a message and still create local enrollment records when an enrollment exception
    is raised if a flag is set to true
    """
    num_runs = 3
    runs = CourseRunFactory.create_batch(num_runs)
    patched_edx_enroll = mocker.patch(
        "courses.api.enroll_in_edx_course_runs",
        side_effect=exception_cls(user, runs[2], inner_exception),
    )
    patched_log_exception = mocker.patch("courses.api.log.exception")
    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=None,
        company=None,
        keep_failed_enrollments=keep_failed_enrollments,
    )
    patched_edx_enroll.assert_called_once_with(user, runs)
    patched_log_exception.assert_called_once()
    patched_send_enrollment_email.assert_not_called()
    expected_enrollments = 0 if not keep_failed_enrollments else num_runs
    assert len(successful_enrollments) == expected_enrollments
    assert edx_request_success is False
Exemple #2
0
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)
Exemple #3
0
def enroll_user_in_order_items(order):
    """
    Enroll the user in the CourseRuns associated with their Order, and create local records of their
    enrollments.

    Args:
        order (Order): An order
    """
    order_line = Line.objects.prefetch_related("line_selections__run").get(
        order=order)
    runs = [
        line_selection.run
        for line_selection in order_line.line_selections.all()
    ]
    programs = get_order_programs(order)
    company = get_company_affiliation(order)

    if programs and not runs:
        log.error(
            "An order is being completed for a program, but does not have any course run selections. "
            "(Order: %d, purchaser: '%s', program(s): %s)",
            order.id,
            order.purchaser.email,
            [program.readable_id for program in programs],
        )

    successful_run_enrollments = []
    if runs:
        successful_run_enrollments, _ = create_run_enrollments(
            order.purchaser,
            runs,
            order=order,
            company=company,
            keep_failed_enrollments=True,
        )

    voucher = (order.purchaser.vouchers.filter(product_id__in=order.lines.all(
    ).values_list("product_version__product__id", flat=True)).order_by(
        "uploaded").last())
    voucher_target = None
    if (voucher and voucher.is_redeemed() and voucher.product is not None
            and voucher.enrollment is None):
        voucher_target = voucher.product.content_object
    voucher_enrollment = first_or_none(
        (enrollment for enrollment in successful_run_enrollments
         if enrollment.run == voucher_target))
    if voucher_enrollment is not None:
        voucher.enrollment = voucher_enrollment
        voucher.save()

    if programs:
        create_program_enrollments(order.purchaser,
                                   programs,
                                   order=order,
                                   company=company)
Exemple #4
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
Exemple #5
0
def test_create_run_enrollments_creation_fail(mocker, user):
    """
    create_run_enrollments should log a message and send an admin email if there's an error during the
    creation of local enrollment records
    """
    runs = CourseRunFactory.create_batch(2)
    enrollment = CourseRunEnrollmentFactory.build(run=runs[1])
    mocker.patch(
        "courses.api.CourseRunEnrollment.all_objects.get_or_create",
        side_effect=[Exception(), (enrollment, True)],
    )
    patched_edx_enroll = mocker.patch("courses.api.enroll_in_edx_course_runs")
    patched_log_exception = mocker.patch("courses.api.log.exception")
    patched_mail_api = mocker.patch("courses.api.mail_api")

    successful_enrollments, edx_request_success = create_run_enrollments(
        user, runs, order=None, company=None)
    patched_edx_enroll.assert_called_once_with(user, runs)
    patched_log_exception.assert_called_once()
    patched_mail_api.send_course_run_enrollment_email.assert_not_called()
    patched_mail_api.send_enrollment_failure_message.assert_called_once()
    assert successful_enrollments == [enrollment]
    assert edx_request_success is True
Exemple #6
0
    def handle(self, *args, **options):
        """Handle command execution"""

        user = fetch_user(options["user"])

        run = CourseRun.objects.filter(courseware_id=options["run"]).first()
        if run is None:
            raise CommandError(
                "Could not find course run with courseware_id={}".format(
                    options["run"]))

        product = Product.objects.filter(
            courseruns__courseware_id=options["run"]).first()
        if product is None:
            raise CommandError(
                "No product found for that course with courseware_id={}".
                format(options["run"]))

        coupon = Coupon.objects.filter(coupon_code=options["code"]).first()
        if not coupon:
            raise CommandError("That enrollment code {} does not exist".format(
                options["code"]))

        # Check if the coupon is valid for the product
        coupon_version = best_coupon_for_product(product,
                                                 user,
                                                 code=coupon.coupon_code)
        if coupon_version is None:
            raise CommandError({
                "coupons":
                "Enrollment code {} is invalid for course run {}".format(
                    options["code"], options["run"])
            })
        # Fetch the latest product version.
        product_version = latest_product_version(product)

        # Calculate the total paid price after applying coupon.
        total_price_paid = get_product_version_price_with_discount(
            coupon_version=coupon_version, product_version=product_version)

        with transaction.atomic():
            # Create an order.
            order = Order.objects.create(
                status=Order.FULFILLED,
                purchaser=user,
                total_price_paid=total_price_paid,
            )

            successful_enrollments, edx_request_success = create_run_enrollments(
                user,
                [run],
                keep_failed_enrollments=options["keep_failed_enrollments"],
                order=order,
            )
            if not successful_enrollments:
                raise CommandError("Failed to create the enrollment record")

        ProductCouponAssignment.objects.filter(
            email__iexact=user.email,
            redeemed=False,
            product_coupon__coupon=coupon).update(redeemed=True)

        self.stdout.write(
            self.style.SUCCESS(
                "Enrollment created for user {} in {} (edX enrollment success: {})"
                .format(user, options["run"], edx_request_success)))

        line = Line.objects.create(order=order,
                                   product_version=product_version,
                                   quantity=1)

        redeem_coupon(coupon_version=coupon_version, order=order)

        self.stdout.write(
            self.style.SUCCESS(
                "Order {} with line {} is created for user {} ".format(
                    order, line, user)))