コード例 #1
0
 def test_validate_coupon_type(self):
     """Coupon.coupon_type must be one of Coupon.COUPON_TYPES"""
     with self.assertRaises(ValidationError) as ex:
         CouponFactory.create(coupon_type='xyz')
     assert ex.exception.args[0]['__all__'][0].args[0] == (
         'coupon_type must be one of {}'.format(", ".join(Coupon.COUPON_TYPES))
     )
コード例 #2
0
 def test_coupon_run(self):
     """
     Test coupon serializer
     """
     course_run = CourseRunFactory.create(course__program__financial_aid_availability=True)
     with self.assertRaises(ValidationError) as ex:
         CouponFactory.create(content_object=course_run)
     assert ex.exception.args[0]['__all__'][0].args[0] == 'content_object must be of type Course or Program'
コード例 #3
0
def basket_and_coupons():
    """
    Sample basket and coupon
    """
    basket_item = BasketItemFactory()

    # Some prices for the basket item product
    ProductVersionFactory(product=basket_item.product, price=Decimal("15.00"))
    product_version = ProductVersionFactory(
        product=basket_item.product, price=Decimal("25.00")
    )

    run = basket_item.product.content_object
    CourseRunSelection.objects.create(run=run, basket=basket_item.basket)

    payment_worst = CouponPaymentFactory()
    payment_best = CouponPaymentFactory()
    coupon_worst = CouponFactory(payment=payment_worst, coupon_code="WORST")
    coupon_best = CouponFactory(payment=payment_best, coupon_code="BEST")

    # Coupon payment for worst coupon, with lowest discount
    civ_worst = CouponPaymentVersionFactory(
        payment=payment_worst, amount=Decimal("0.10000"), automatic=True
    )
    # Coupon payment for best coupon, with highest discount
    civ_best_old = CouponPaymentVersionFactory(
        payment=payment_best, amount=Decimal("0.50000")
    )
    # Coupon payment for best coupon, more recent than previous so takes precedence
    civ_best = CouponPaymentVersionFactory(
        payment=payment_best, amount=Decimal("1.00000")
    )

    # Coupon version for worst coupon
    cv_worst = CouponVersionFactory(payment_version=civ_worst, coupon=coupon_worst)
    # Coupon version for best coupon
    CouponVersionFactory(payment_version=civ_best_old, coupon=coupon_best)
    # Most recent coupon version for best coupon
    cv_best = CouponVersionFactory(payment_version=civ_best, coupon=coupon_best)

    # Both best and worst coupons eligible for the product
    CouponEligibilityFactory(coupon=coupon_best, product=basket_item.product)
    CouponEligibilityFactory(coupon=coupon_worst, product=basket_item.product)

    # Apply one of the coupons to the basket
    CouponSelectionFactory.create(basket=basket_item.basket, coupon=coupon_best)

    coupongroup_worst = CouponGroup(coupon_worst, cv_worst, payment_worst, civ_worst)
    coupongroup_best = CouponGroup(coupon_best, cv_best, payment_best, civ_best)

    return SimpleNamespace(
        basket=basket_item.basket,
        basket_item=basket_item,
        product_version=product_version,
        coupongroup_best=coupongroup_best,
        coupongroup_worst=coupongroup_worst,
        run=run,
    )
コード例 #4
0
 def test_validate_amount_type(self):
     """
     Coupon.amount_type should be one of Coupon.AMOUNT_TYPES
     """
     with self.assertRaises(ValidationError) as ex:
         CouponFactory.create(amount_type='xyz')
     assert ex.exception.args[0]['__all__'][0].args[0] == (
         'amount_type must be one of percent-discount, fixed-discount, fixed-price'
     )
コード例 #5
0
 def test_validate_amount(self):
     """
     Coupon.amount should be between 0 and 1 if amount_type is percent-discount
     """
     with self.assertRaises(ValidationError) as ex:
         CouponFactory.create(amount=3, amount_type=Coupon.PERCENT_DISCOUNT)
     assert ex.exception.args[0]['__all__'][0].args[0] == (
         'amount must be between 0 and 1 if amount_type is percent-discount'
     )
コード例 #6
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'
     )
コード例 #7
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
コード例 #8
0
 def test_validate_coupon_program(self):
     """Coupons should fail to validate for non-financial aid programs"""
     run = CourseRunFactory.create(
         course__program__financial_aid_availability=False,
     )
     with self.assertRaises(ValidationError) as ex:
         CouponFactory.create(
             coupon_type=Coupon.STANDARD,
             content_object=run.course,
         )
     assert ex.exception.args[0]['__all__'][0].args[0] == (
         "coupons are only allowed for programs with financial aid"
     )
コード例 #9
0
    def test_validate_content_object(self):
        """
        Coupon.content_object should only accept Course, CourseRun, or Program
        """
        course_run = CourseRunFactory.create(course__program__financial_aid_availability=True)
        coupons = []
        for obj in (course_run.course, course_run.course.program):
            coupons.append(CouponFactory.create(content_object=obj))

        with self.assertRaises(ValidationError) as ex:
            CouponFactory.create(content_object=course_run)
        assert ex.exception.args[0]['__all__'][0].args[0] == (
            'content_object must be of type Course or Program'
        )
コード例 #10
0
ファイル: api_test.py プロジェクト: mitodl/micromasters
 def test_prev_course_user_not_verified(self):
     """If a user is not verified, they should not get a coupon for the course"""
     coupon = CouponFactory.create(
         coupon_type=Coupon.DISCOUNTED_PREVIOUS_COURSE,
         content_object=self.run1.course,
     )
     assert is_coupon_redeemable(coupon, self.user) is False
コード例 #11
0
ファイル: basic_test.py プロジェクト: mitodl/micromasters
def test_zero_price_purchase(browser, base_test_data, logged_in_student, mocker):
    """
    Test that a course can be purchased with a 100%-off coupon
    """
    mocker.patch('ecommerce.views.enroll_user_on_success')
    # Make a 100% off coupon. By setting the price to $0 we can avoid dealing with Cybersource
    coupon = CouponFactory.create(
        amount=1,
        amount_type=Coupon.PERCENT_DISCOUNT,
        coupon_type=Coupon.STANDARD,
        content_object=base_test_data.program
    )
    UserCoupon.objects.create(coupon=coupon, user=logged_in_student)

    browser.get("/")
    # Click the dashboard link on the upper right of the homepage
    browser.click_when_loaded(By.CLASS_NAME, "header-dashboard-link")
    browser.assert_no_console_errors()

    browser.click_when_loaded(By.CLASS_NAME, "enroll-button")
    browser.wait_until_loaded(By.CLASS_NAME, "continue-payment")

    # Click back then click the enroll now button again to assert back button behavior
    browser.driver.back()
    browser.click_when_loaded(By.CLASS_NAME, "enroll-button")
    browser.assert_no_console_errors()

    # Click 'Continue' on the order summary page
    browser.click_when_loaded(By.CLASS_NAME, "continue-payment")
    browser.assert_no_console_errors()
    browser.wait_until_loaded(By.CLASS_NAME, "toast-message")

    # No status message is shown here since this is FA program
    browser.assert_no_console_errors()
コード例 #12
0
def test_zero_price_purchase(browser, base_test_data, logged_in_student,
                             mocker):
    """
    Test that a course can be purchased with a 100%-off coupon
    """
    mocker.patch('ecommerce.views.enroll_user_on_success')
    # Make a 100% off coupon. By setting the price to $0 we can avoid dealing with Cybersource
    coupon = CouponFactory.create(amount=1,
                                  amount_type=Coupon.PERCENT_DISCOUNT,
                                  coupon_type=Coupon.STANDARD,
                                  content_object=base_test_data.program)
    UserCoupon.objects.create(coupon=coupon, user=logged_in_student)

    browser.get("/")
    # Click the dashboard link on the upper right of the homepage
    browser.click_when_loaded(By.CLASS_NAME, "header-dashboard-link")
    browser.assert_no_console_errors()

    browser.click_when_loaded(By.CLASS_NAME, "enroll-button")
    browser.wait_until_loaded(By.CLASS_NAME, "continue-payment")

    # Click back then click the enroll now button again to assert back button behavior
    browser.driver.back()
    browser.click_when_loaded(By.CLASS_NAME, "enroll-button")
    browser.assert_no_console_errors()

    # Click 'Continue' on the order summary page
    browser.click_when_loaded(By.CLASS_NAME, "continue-payment")
    browser.assert_no_console_errors()
    browser.wait_until_loaded(By.CLASS_NAME, "toast-message")

    # No status message is shown here since this is FA program
    browser.assert_no_console_errors()
コード例 #13
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]])
コード例 #14
0
 def test_is_not_valid(self):
     """If a Coupon is not valid it should not be redeemable"""
     coupon = CouponFactory.create(content_object=self.program)
     with patch('ecommerce.api.Coupon.is_valid',
                new_callable=PropertyMock) as is_valid:
         is_valid.return_value = False
         assert is_coupon_redeemable(coupon, self.user) is False
コード例 #15
0
    def test_program(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)
        CourseRunFactory.create(course=run1.course)
        run3 = CourseRunFactory.create(course__program=run1.course.program)
        CourseRunFactory.create(course=run3.course)

        coupon_program = CouponFactory.create(
            content_object=run1.course.program,
        )
        assert coupon_program.program == run1.course.program

        coupon_course = CouponFactory.create(content_object=run1.course)
        assert coupon_course.program == run1.course.program
コード例 #16
0
 def test_prev_course_user_not_verified(self):
     """If a user is not verified, they should not get a coupon for the course"""
     coupon = CouponFactory.create(
         coupon_type=Coupon.DISCOUNTED_PREVIOUS_COURSE,
         content_object=self.run1.course,
     )
     assert is_coupon_redeemable(coupon, self.user) is False
コード例 #17
0
ファイル: api_test.py プロジェクト: mitodl/micromasters
    def test_attached_to_other_user(self):
        """
        Coupons only attached to another user should not be shown
        """
        UserCoupon.objects.all().delete()
        UserCoupon.objects.create(user=UserFactory.create(), coupon=CouponFactory.create())

        assert pick_coupons(self.user) == []
コード例 #18
0
 def test_is_coupon_redeemable_for_run(self):
     """Happy case for is_coupon_redeemable_for_run"""
     coupon = CouponFactory.create(content_object=self.run1.course)
     with patch('ecommerce.api.is_coupon_redeemable', autospec=True) as _is_coupon_redeemable:
         _is_coupon_redeemable.return_value = True
         assert is_coupon_redeemable_for_run(coupon, self.user, self.run1.edx_course_key) is True
     assert _is_coupon_redeemable.call_count == 1
     _is_coupon_redeemable.assert_called_with(coupon, self.user)
コード例 #19
0
 def test_is_not_redeemable(self):
     """If is_coupon_redeemable returns False, is_coupon_redeemable_for_run should also return False"""
     coupon = CouponFactory.create(content_object=self.run1.course)
     with patch('ecommerce.api.is_coupon_redeemable', autospec=True) as _is_coupon_redeemable:
         _is_coupon_redeemable.return_value = False
         assert is_coupon_redeemable_for_run(coupon, self.user, self.run1.edx_course_key) is False
     assert _is_coupon_redeemable.call_count == 1
     _is_coupon_redeemable.assert_called_with(coupon, self.user)
コード例 #20
0
ファイル: api_test.py プロジェクト: mitodl/micromasters
 def test_no_more_coupons(self):
     """If user has no redemptions left the coupon should not be redeemable"""
     coupon = CouponFactory.create(content_object=self.program)
     with patch('ecommerce.api.Coupon.user_has_redemptions_left', autospec=True) as _user_has_redemptions:
         _user_has_redemptions.return_value = False
         assert is_coupon_redeemable(coupon, self.user) is False
     assert _user_has_redemptions.call_count == 1
     _user_has_redemptions.assert_called_with(coupon, self.user)
コード例 #21
0
ファイル: api_test.py プロジェクト: mitodl/micromasters
 def test_is_not_redeemable(self):
     """If is_coupon_redeemable returns False, is_coupon_redeemable_for_run should also return False"""
     coupon = CouponFactory.create(content_object=self.run1.course)
     with patch('ecommerce.api.is_coupon_redeemable', autospec=True) as _is_coupon_redeemable:
         _is_coupon_redeemable.return_value = False
         assert is_coupon_redeemable_for_run(coupon, self.user, self.run1.edx_course_key) is False
     assert _is_coupon_redeemable.call_count == 1
     _is_coupon_redeemable.assert_called_with(coupon, self.user)
コード例 #22
0
ファイル: api_test.py プロジェクト: mitodl/micromasters
 def test_is_coupon_redeemable_for_run(self):
     """Happy case for is_coupon_redeemable_for_run"""
     coupon = CouponFactory.create(content_object=self.run1.course)
     with patch('ecommerce.api.is_coupon_redeemable', autospec=True) as _is_coupon_redeemable:
         _is_coupon_redeemable.return_value = True
         assert is_coupon_redeemable_for_run(coupon, self.user, self.run1.edx_course_key) is True
     assert _is_coupon_redeemable.call_count == 1
     _is_coupon_redeemable.assert_called_with(coupon, self.user)
コード例 #23
0
 def test_no_more_coupons(self):
     """If user has no redemptions left the coupon should not be redeemable"""
     coupon = CouponFactory.create(content_object=self.program)
     with patch('ecommerce.api.Coupon.user_has_redemptions_left', autospec=True) as _user_has_redemptions:
         _user_has_redemptions.return_value = False
         assert is_coupon_redeemable(coupon, self.user) is False
     assert _user_has_redemptions.call_count == 1
     _user_has_redemptions.assert_called_with(coupon, self.user)
コード例 #24
0
    def test_attached_to_other_user(self):
        """
        Coupons only attached to another user should not be shown
        """
        UserCoupon.objects.all().delete()
        UserCoupon.objects.create(user=UserFactory.create(), coupon=CouponFactory.create())

        assert pick_coupons(self.user) == []
コード例 #25
0
 def test_coupon_allowed_program(self):
     """
     Assert that the price is not adjusted if the coupon is for a different program
     """
     course_run, _ = create_purchasable_course_run()
     price = Decimal('0.3')
     coupon = CouponFactory.create()
     assert coupon.content_object != course_run
     assert calculate_coupon_price(coupon, price, course_run.edx_course_key) == price
コード例 #26
0
ファイル: api_test.py プロジェクト: mitodl/micromasters
 def test_coupon_allowed_program(self):
     """
     Assert that the price is not adjusted if the coupon is for a different program
     """
     course_run, _ = create_purchasable_course_run()
     price = Decimal('0.3')
     coupon = CouponFactory.create()
     assert coupon.content_object != course_run
     assert calculate_coupon_price(coupon, price, course_run.edx_course_key) == price
コード例 #27
0
ファイル: views_test.py プロジェクト: mitodl/micromasters
 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)
コード例 #28
0
ファイル: api_test.py プロジェクト: mitodl/micromasters
 def test_capped_coupon_price_above_full(self):
     """
     Assert that the adjusted price cannot go above the full price
     """
     course_run, _ = create_purchasable_course_run()
     price = course_run.course.program.price
     coupon = CouponFactory.create(
         content_object=course_run.course, amount_type=Coupon.FIXED_DISCOUNT, amount=-(price + 50),
     )
     assert calculate_coupon_price(coupon, price, course_run.edx_course_key) == price
コード例 #29
0
ファイル: api_test.py プロジェクト: mitodl/micromasters
 def test_fixed_discount(self):
     """
     Assert the price with a fixed discount
     """
     course_run, _ = create_purchasable_course_run()
     price = Decimal(5)
     coupon = CouponFactory.create(
         content_object=course_run.course, amount_type=Coupon.FIXED_DISCOUNT, amount=Decimal("1.5")
     )
     assert calculate_coupon_price(coupon, price, course_run.edx_course_key) == price - coupon.amount
コード例 #30
0
 def test_fixed_discount(self):
     """
     Assert the price with a fixed discount
     """
     course_run, _ = create_purchasable_course_run()
     price = Decimal(5)
     coupon = CouponFactory.create(
         content_object=course_run.course, amount_type=Coupon.FIXED_DISCOUNT, amount=Decimal("1.5")
     )
     assert calculate_coupon_price(coupon, price, course_run.edx_course_key) == price - coupon.amount
コード例 #31
0
 def test_capped_coupon_price_above_full(self):
     """
     Assert that the adjusted price cannot go above the full price
     """
     course_run, _ = create_purchasable_course_run()
     price = course_run.course.program.price
     coupon = CouponFactory.create(
         content_object=course_run.course, amount_type=Coupon.FIXED_DISCOUNT, amount=-(price + 50),
     )
     assert calculate_coupon_price(coupon, price, course_run.edx_course_key) == price
コード例 #32
0
ファイル: conftest.py プロジェクト: mitodl/mitxpro
def redeemed_voucher_and_user_client(voucher_and_user, client):
    """
    Returns a voucher, user, and authenticated client
    """
    user = voucher_and_user.user
    voucher = voucher_and_user.voucher
    client.force_login(user)
    voucher.coupon = CouponFactory()
    voucher.save()
    CouponRedemptionFactory(coupon_version__coupon=voucher.coupon)
    return SimpleNamespace(**vars(voucher_and_user), client=client)
コード例 #33
0
ファイル: api_test.py プロジェクト: mitodl/micromasters
 def test_fixed_price(self):
     """
     Assert a fixed price coupon
     """
     course_run, _ = create_purchasable_course_run()
     price = Decimal(5)
     amount = Decimal("1.5")
     coupon = CouponFactory.create(
         content_object=course_run.course, amount_type=Coupon.FIXED_PRICE, amount=amount
     )
     assert calculate_coupon_price(coupon, price, course_run.edx_course_key) == amount
コード例 #34
0
ファイル: api_test.py プロジェクト: mitodl/micromasters
 def test_calculate_coupon_price(self):
     """
     Assert that the price is not adjusted if the amount type is unknown
     """
     course_run, _ = create_purchasable_course_run()
     price = Decimal('0.3')
     coupon = CouponFactory.create(content_object=course_run.course)
     # Use manager to skip validation, which usually prevents setting content_object to an arbitrary object
     Coupon.objects.filter(id=coupon.id).update(amount_type='xyz')
     coupon.refresh_from_db()
     assert calculate_coupon_price(coupon, price, course_run.edx_course_key) == price
コード例 #35
0
 def test_prev_course(self):
     """
     A coupon for a previously purchased course should be redeemable if
     it applies to the course which is being purchased
     """
     coupon = CouponFactory.create(
         coupon_type=Coupon.DISCOUNTED_PREVIOUS_COURSE,
         content_object=self.run1.course,
     )
     CachedEnrollmentFactory.create(user=self.user, course_run=self.run1)
     assert is_coupon_redeemable(coupon, self.user) is True
コード例 #36
0
ファイル: api_test.py プロジェクト: mitodl/micromasters
 def test_prev_course(self):
     """
     A coupon for a previously purchased course should be redeemable if
     it applies to the course which is being purchased
     """
     coupon = CouponFactory.create(
         coupon_type=Coupon.DISCOUNTED_PREVIOUS_COURSE,
         content_object=self.run1.course,
     )
     CachedEnrollmentFactory.create(user=self.user, course_run=self.run1)
     assert is_coupon_redeemable(coupon, self.user) is True
コード例 #37
0
 def test_calculate_coupon_price(self):
     """
     Assert that the price is not adjusted if the amount type is unknown
     """
     course_run, _ = create_purchasable_course_run()
     price = Decimal('0.3')
     coupon = CouponFactory.create(content_object=course_run.course)
     # Use manager to skip validation, which usually prevents setting content_object to an arbitrary object
     Coupon.objects.filter(id=coupon.id).update(amount_type='xyz')
     coupon.refresh_from_db()
     assert calculate_coupon_price(coupon, price, course_run.edx_course_key) == price
コード例 #38
0
 def test_fixed_price(self):
     """
     Assert a fixed price coupon
     """
     course_run, _ = create_purchasable_course_run()
     price = Decimal(5)
     amount = Decimal("1.5")
     coupon = CouponFactory.create(
         content_object=course_run.course, amount_type=Coupon.FIXED_PRICE, amount=amount
     )
     assert calculate_coupon_price(coupon, price, course_run.edx_course_key) == amount
コード例 #39
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)
コード例 #40
0
ファイル: api_test.py プロジェクト: mitodl/micromasters
 def test_course_key_not_in_list(self):
     """run is not in the course keys listed by Coupon"""
     coupon = CouponFactory.create(content_object=self.program)
     with patch('ecommerce.api.is_coupon_redeemable', autospec=True) as _is_coupon_redeemable, patch(
         'ecommerce.api.Coupon.course_keys', new_callable=PropertyMock
     ) as _course_keys:
         _is_coupon_redeemable.return_value = True
         _course_keys.return_value = ['missing']
         assert is_coupon_redeemable_for_run(coupon, self.user, self.run1.edx_course_key) is False
     assert _is_coupon_redeemable.call_count == 1
     _is_coupon_redeemable.assert_called_with(coupon, self.user)
     assert _course_keys.call_count == 1
コード例 #41
0
ファイル: api_test.py プロジェクト: mitodl/micromasters
 def test_percent_discount(self):
     """
     Assert the price with a percent discount
     """
     course_run, _ = create_purchasable_course_run()
     price = Decimal(5)
     coupon = CouponFactory.create(
         content_object=course_run.course,
         amount_type=Coupon.PERCENT_DISCOUNT,
         amount=Decimal("0.3"),
     )
     assert calculate_coupon_price(coupon, price, course_run.edx_course_key) == price * (1 - coupon.amount)
コード例 #42
0
 def test_percent_discount(self):
     """
     Assert the price with a percent discount
     """
     course_run, _ = create_purchasable_course_run()
     price = Decimal(5)
     coupon = CouponFactory.create(
         content_object=course_run.course,
         amount_type=Coupon.PERCENT_DISCOUNT,
         amount=Decimal("0.3"),
     )
     assert calculate_coupon_price(coupon, price, course_run.edx_course_key) == price * (1 - coupon.amount)
コード例 #43
0
 def test_program_invalid_content_object(self):
     """
     program should error if we set content_object to an invalid value
     """
     coupon = CouponFactory.create()
     profile_content_type = ContentType.objects.get_for_model(Profile)
     # bypass clean()
     Coupon.objects.filter(id=coupon.id).update(content_type=profile_content_type)
     coupon.refresh_from_db()
     with self.assertRaises(ImproperlyConfigured) as ex:
         _ = coupon.program
     assert ex.exception.args[0] == "content_object expected to be one of Program, Course, CourseRun"
コード例 #44
0
 def test_course_key_not_in_list(self):
     """run is not in the course keys listed by Coupon"""
     coupon = CouponFactory.create(content_object=self.program)
     with patch('ecommerce.api.is_coupon_redeemable', autospec=True) as _is_coupon_redeemable, patch(
         'ecommerce.api.Coupon.course_keys', new_callable=PropertyMock
     ) as _course_keys:
         _is_coupon_redeemable.return_value = True
         _course_keys.return_value = ['missing']
         assert is_coupon_redeemable_for_run(coupon, self.user, self.run1.edx_course_key) is False
     assert _is_coupon_redeemable.call_count == 1
     _is_coupon_redeemable.assert_called_with(coupon, self.user)
     assert _course_keys.call_count == 1
コード例 #45
0
ファイル: api_test.py プロジェクト: mitodl/micromasters
    def _create_coupons(cls, user):
        """Create some coupons"""
        course_run = CourseRunFactory.create(
            course__program__financial_aid_availability=True,
            course__program__live=True,
        )
        course = course_run.course
        ProgramEnrollment.objects.create(program=course.program, user=user)
        coupon1_auto = CouponFactory.create(
            coupon_type=Coupon.DISCOUNTED_PREVIOUS_COURSE,
            content_object=course,
        )
        coupon2_auto = CouponFactory.create(
            coupon_type=Coupon.DISCOUNTED_PREVIOUS_COURSE,
            content_object=course,
        )
        coupon1_attached = CouponFactory.create(content_object=course)
        UserCoupon.objects.create(user=user, coupon=coupon1_attached)
        coupon2_attached = CouponFactory.create(content_object=course)
        UserCoupon.objects.create(user=user, coupon=coupon2_attached)

        return coupon1_attached, coupon2_attached, coupon1_auto, coupon2_auto
コード例 #46
0
ファイル: views_test.py プロジェクト: mitodl/micromasters
 def test_list_coupons(self):
     """
     Test that we use pick_coupon to get the list of coupons
     """
     # Despite enabled=False, the API returns this coupon because we patched pick_coupons
     coupon = CouponFactory.create(enabled=False)
     with patch('ecommerce.views.pick_coupons', autospec=True) as _pick_coupons:
         _pick_coupons.return_value = [coupon]
         resp = self.client.get(reverse('coupon-list'))
     assert resp.status_code == status.HTTP_200_OK
     assert resp.json() == [CouponSerializer(coupon).data]
     assert _pick_coupons.call_count == 1
     _pick_coupons.assert_called_with(self.user)
コード例 #47
0
    def _create_coupons(cls, user):
        """Create some coupons"""
        course_run = CourseRunFactory.create(
            course__program__financial_aid_availability=True,
            course__program__live=True,
        )
        course = course_run.course
        ProgramEnrollment.objects.create(program=course.program, user=user)
        coupon1_auto = CouponFactory.create(
            coupon_type=Coupon.DISCOUNTED_PREVIOUS_COURSE,
            content_object=course,
        )
        coupon2_auto = CouponFactory.create(
            coupon_type=Coupon.DISCOUNTED_PREVIOUS_COURSE,
            content_object=course,
        )
        coupon1_attached = CouponFactory.create(content_object=course)
        UserCoupon.objects.create(user=user, coupon=coupon1_attached)
        coupon2_attached = CouponFactory.create(content_object=course)
        UserCoupon.objects.create(user=user, coupon=coupon2_attached)

        return coupon1_attached, coupon2_attached, coupon1_auto, coupon2_auto
コード例 #48
0
ファイル: api_test.py プロジェクト: mitodl/micromasters
 def test_calculate_run_price_coupon(self):
     """
     If there is a coupon calculate_run_price should use calculate_coupon_price to get the discounted price
     """
     course_run, user = create_purchasable_course_run()
     coupon = CouponFactory.create(content_object=course_run.course)
     UserCoupon.objects.create(coupon=coupon, user=user)
     discounted_price = 5
     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) == (discounted_price, coupon)
     program_enrollment = course_run.course.program.programenrollment_set.first()
     fa_price = get_formatted_course_price(program_enrollment)['price']
     _calculate_coupon_price.assert_called_with(coupon, fa_price, course_run.edx_course_key)
コード例 #49
0
ファイル: api_test.py プロジェクト: mitodl/micromasters
 def test_calculate_run_price_no_coupons(self):
     """
     If there are no coupons for this program the price should be what get_formatted_course_price returned
     """
     course_run, user = create_purchasable_course_run()
     # This coupon is for a different program
     coupon = CouponFactory.create()
     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
コード例 #50
0
ファイル: api_test.py プロジェクト: mitodl/micromasters
 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