Exemplo n.º 1
0
 def test_create_line_reference(self):
     basket = BasketFactory()
     product = ProductFactory(title="A product")
     option = OptionFactory(name="product_option", code="product_option")
     option_product = ProductFactory(title='Asunción')
     options = [{'option': option, 'value': option_product}]
     basket.add_product(product, options=options)
Exemplo n.º 2
0
    def test_description(self):
        basket = BasketFactory()
        product = ProductFactory(title="A product")
        basket.add_product(product)

        line = basket.lines.first()
        self.assertEqual(line.description, "A product")
Exemplo n.º 3
0
def filled_basket():
    basket = BasketFactory()
    product1 = ProductFactory()
    product2 = ProductFactory()
    basket.add_product(product1, quantity=10)
    basket.add_product(product2, quantity=20)
    return basket
Exemplo n.º 4
0
    def test_description_with_attributes(self):
        basket = BasketFactory()
        product = ProductFactory(title="A product")
        basket.add_product(product)

        line = basket.lines.first()
        BasketLineAttributeFactory(line=line, value=u"\u2603", option__name="with")
        self.assertEqual(line.description, u"A product (with = '\u2603')")
Exemplo n.º 5
0
 def test_basket_lines_queryset_is_ordered(self):
     # This is needed to make sure a formset is not performing the query
     # again with an order_by clause (losing all calculated discounts)
     basket = BasketFactory()
     product = ProductFactory(title="A product")
     another_product = ProductFactory(title="Another product")
     basket.add_product(product)
     basket.add_product(another_product)
     queryset = basket.all_lines()
     self.assertTrue(queryset.ordered)
Exemplo n.º 6
0
 def test_apply_voucher_on_basket_and_check_discount_with_multiple_vouchers(
         self):
     """
     Tests apply_voucher_on_basket_and_check_discount when called with a basket already
     containing a valid voucher it only checks the new voucher.
     """
     basket = BasketFactory(owner=self.request.user, site=self.request.site)
     product = ProductFactory(stockrecords__partner__short_code='test1',
                              stockrecords__price_excl_tax=10)
     invalid_voucher, __ = prepare_voucher(code='TEST1')
     valid_voucher, __ = prepare_voucher(
         code='TEST2', _range=RangeFactory(products=[product]))
     basket.add_product(product, 1)
     basket.vouchers.add(valid_voucher)
     applied, msg = apply_voucher_on_basket_and_check_discount(
         invalid_voucher, self.request, basket)
     self.assertEqual(applied, False)
     self.assertEqual(
         msg, 'Basket does not qualify for coupon code {code}.'.format(
             code=invalid_voucher.code))
Exemplo n.º 7
0
    def test_is_satisfied_with_exception_for_enrollments(self):
        """ The method should return True despite having an error at the enrollment check, given 1 course run seat
        corresponding to each course in the program. """
        offer = factories.ProgramOfferFactory(partner=self.partner,
                                              condition=self.condition)
        basket = BasketFactory(site=self.site, owner=UserFactory())
        program = self.mock_program_detail_endpoint(
            self.condition.program_uuid,
            self.site_configuration.discovery_api_url)
        for course in program['courses']:
            course_run = Course.objects.get(id=course['course_runs'][0]['key'])
            for seat in course_run.seat_products:
                if seat.attr.id_verification_required:
                    basket.add_product(seat)

        self.mock_user_data(basket.owner.username,
                            mocked_api='enrollments',
                            owned_products=None,
                            response_code=400)
        self.assertTrue(self.condition.is_satisfied(offer, basket))
Exemplo n.º 8
0
 def test_is_satisfied_contains_content_items_failure(self):
     """ Ensure the condition returns false if the contains_content_item call fails. """
     offer = factories.EnterpriseOfferFactory(partner=self.partner,
                                              condition=self.condition)
     basket = BasketFactory(site=self.site, owner=self.user)
     basket.add_product(self.course_run.seat_products[0])
     self.mock_enterprise_learner_api(
         learner_id=self.user.id,
         enterprise_customer_uuid=str(
             self.condition.enterprise_customer_uuid),
         course_run_id=self.course_run.id,
     )
     self.mock_catalog_contains_course_runs(
         [self.course_run.id],
         self.condition.enterprise_customer_uuid,
         enterprise_customer_catalog_uuid=self.condition.
         enterprise_customer_catalog_uuid,
         contains_content=False,
         raise_exception=True)
     self.assertFalse(self.condition.is_satisfied(offer, basket))
Exemplo n.º 9
0
    def test_voucher_errors(self):
        """ Test data when voucher error happen"""
        basket = BasketFactory(site=self.site)
        voucher, product = prepare_voucher(code='test101')
        basket.vouchers.add(voucher)
        basket.add_product(product)

        with mock.patch(
                'ecommerce.extensions.api.serializers.VoucherSerializer',
                side_effect=ValueError):
            response = self.client.get(self.path,
                                       HTTP_AUTHORIZATION=self.token)
            self.assertIsNone(response.json()['results'][0]['vouchers'])

        with mock.patch(
                'ecommerce.extensions.api.serializers.VoucherSerializer',
                side_effect=AttributeError):
            response = self.client.get(self.path,
                                       HTTP_AUTHORIZATION=self.token)
            self.assertIsNone(response.json()['results'][0]['vouchers'])
Exemplo n.º 10
0
 def test_absolute_benefit_offer_availability(self):
     """
     Verify that enterprise offer condition returns correct result for an absolute benefit with
     discount value greater than course price.
     """
     offer = factories.EnterpriseOfferFactory(
         partner=self.partner,
         benefit=factories.EnterpriseAbsoluteDiscountBenefitFactory(
             value=150),
         max_discount=Decimal(300),
         total_discount=Decimal(200))
     basket = BasketFactory(site=self.site, owner=self.user)
     basket.add_product(self.course_run.seat_products[0])
     self.mock_catalog_contains_course_runs(
         [self.course_run.id],
         self.condition.enterprise_customer_uuid,
         enterprise_customer_catalog_uuid=self.condition.
         enterprise_customer_catalog_uuid,
     )
     self.assertTrue(self.condition.is_satisfied(offer, basket))
Exemplo n.º 11
0
    def test_stop_sailthru_update_on_multi_product_baskets(self, mock_log_error, mock_update_course_enrollment):
        """ Verify Sailthru is not contacted for multi-product baskets. """
        # Create multi-product basket
        seat = self.course.create_or_update_seat('verified', False, 100, None)
        other_course = CourseFactory(partner=self.partner)
        other_seat = other_course.create_or_update_seat('verified', False, 100, None)
        basket = BasketFactory(owner=self.user, site=self.site)
        basket.add_product(seat)
        basket.add_product(other_seat)
        multi_product_order = create_order(number=2, basket=basket, user=self.user, site=self.site)

        # This method takes an argument to determine whether that product is part of a multi-product basket
        process_basket_addition(None, request=self.request, user=self.user, product=seat, is_multi_product_basket=True)
        self.assertFalse(mock_update_course_enrollment.called)
        self.assertFalse(mock_log_error.called)

        # This method looks at the number of lines in the order to determine if the basket has multiple products
        process_checkout_complete(None, order=multi_product_order, request=None)
        self.assertFalse(mock_update_course_enrollment.called)
        self.assertFalse(mock_log_error.called)
Exemplo n.º 12
0
 def test_is_satisfied_true(self):
     """ Ensure the condition returns true if all basket requirements are met. """
     offer = factories.EnterpriseOfferFactory(partner=self.partner,
                                              condition=self.condition)
     basket = BasketFactory(site=self.site, owner=self.user)
     basket.add_product(self.course_run.seat_products[0])
     self.mock_enterprise_learner_api(
         learner_id=self.user.id,
         enterprise_customer_uuid=str(
             self.condition.enterprise_customer_uuid),
         course_run_id=self.course_run.id,
     )
     self.mock_catalog_contains_course_runs(
         [self.course_run.id],
         self.condition.enterprise_customer_uuid,
         self.site.siteconfiguration.enterprise_api_url,
         enterprise_customer_catalog_uuid=self.condition.
         enterprise_customer_catalog_uuid,
     )
     self.assertTrue(self.condition.is_satisfied(offer, basket))
Exemplo n.º 13
0
    def test_is_satisfied_no_enrollments(self):
        """ The method should return True if the basket contains one course run seat corresponding to each
        course in the program. """
        offer = factories.ProgramOfferFactory(partner=self.partner,
                                              condition=self.condition)
        basket = BasketFactory(site=self.site, owner=UserFactory())
        program = self.mock_program_detail_endpoint(
            self.condition.program_uuid,
            self.site_configuration.discovery_api_url)

        # Extract one audit and one verified seat for each course
        audit_seats = []
        verified_seats = []

        for course in program['courses']:
            course_run = Course.objects.get(id=course['course_runs'][0]['key'])
            for seat in course_run.seat_products:
                if seat.attr.id_verification_required:
                    verified_seats.append(seat)
                else:
                    audit_seats.append(seat)

        self.mock_user_data(basket.owner.username)
        # Empty baskets should never be satisfied
        basket.flush()
        self.assertTrue(basket.is_empty)
        self.assertFalse(self.condition.is_satisfied(offer, basket))

        # Adding seats of all the courses with the wrong seat type should NOT satisfy the condition.
        basket.flush()
        for seat in audit_seats:
            basket.add_product(seat)
        self.assertFalse(self.condition.is_satisfied(offer, basket))

        # All courses must be represented in the basket.
        # NOTE: We add all but the first verified seat to ensure complete branch coverage of the method.
        basket.flush()
        for verified_seat in verified_seats[1:len(verified_seats)]:
            basket.add_product(verified_seat)
        self.assertFalse(self.condition.is_satisfied(offer, basket))

        # The condition should be satisfied if one valid course run from each course is in the basket.
        basket.add_product(verified_seats[0])
        self.assertTrue(self.condition.is_satisfied(offer, basket))

        # If the user is enrolled with the wrong seat type for courses missing from their basket that are
        # needed for the program, the condition should NOT be satisfied
        basket.flush()
        for verified_seat in verified_seats[1:len(verified_seats)]:
            basket.add_product(verified_seat)
        self.assertFalse(self.condition.is_satisfied(offer, basket))
Exemplo n.º 14
0
 def test_absolute_benefit_offer_availability_with_max_user_discount(self):
     """
     Verify that enterprise offer condition returns correct result for an absolute benefit with
     discount value greater than course price.
     """
     offer = factories.EnterpriseOfferFactory(
         partner=self.partner,
         benefit=factories.EnterpriseAbsoluteDiscountBenefitFactory(value=150),
         max_user_discount=150
     )
     for _ in range(5):
         order = OrderFactory(user=self.user, status=ORDER.COMPLETE)
         OrderDiscountFactory(order=order, offer_id=offer.id, amount=10)
     basket = BasketFactory(site=self.site, owner=self.user)
     basket.add_product(self.course_run.seat_products[0])
     self.mock_catalog_contains_course_runs(
         [self.course_run.id],
         self.condition.enterprise_customer_uuid,
         enterprise_customer_catalog_uuid=self.condition.enterprise_customer_catalog_uuid,
     )
     self.assertTrue(self.condition.is_satisfied(offer, basket))
Exemplo n.º 15
0
    def test_is_satisfied_with_course_entitlement_request_error(self):
        """ Ensure the condition returns False if an error occurs while fetching course details. """
        offer = factories.EnterpriseOfferFactory(partner=self.partner, condition=self.condition)
        basket = BasketFactory(site=self.site, owner=self.user)
        basket.add_product(self.entitlement)

        self.mock_course_detail_endpoint_error(
            self.entitlement,
            discovery_api_url=self.site_configuration.discovery_api_url,
            error=ReqConnectionError
        )
        self.mock_enterprise_learner_api(
            learner_id=self.user.id,
            enterprise_customer_uuid=str(self.condition.enterprise_customer_uuid),
            course_run_id=self.course_run.id,
        )
        self.mock_catalog_contains_course_runs(
            [self.entitlement.attr.UUID],
            self.condition.enterprise_customer_uuid,
            enterprise_customer_catalog_uuid=self.condition.enterprise_customer_catalog_uuid,
        )
        self.assertFalse(self.condition.is_satisfied(offer, basket))
Exemplo n.º 16
0
    def test_is_satisfied_with_course_entitlement(self):
        """ Ensure the condition returns true if the basket contains a course entitlement. """
        offer = factories.EnterpriseOfferFactory(partner=self.partner, condition=self.condition)
        basket = BasketFactory(site=self.site, owner=self.user)
        basket.add_product(self.entitlement)

        self.mock_course_detail_endpoint(
            discovery_api_url=self.site_configuration.discovery_api_url,
            course=self.entitlement
        )
        self.mock_enterprise_learner_api(
            learner_id=self.user.id,
            enterprise_customer_uuid=str(self.condition.enterprise_customer_uuid),
            course_run_id=self.course_run.id,
        )
        self.mock_catalog_contains_course_runs(
            [self.entitlement.attr.UUID],
            self.condition.enterprise_customer_uuid,
            enterprise_customer_catalog_uuid=self.condition.enterprise_customer_catalog_uuid,
        )

        self.assertTrue(self.condition.is_satisfied(offer, basket))
Exemplo n.º 17
0
    def test_prof_ed_stale_product_removal_with_orders(self):
        """
        Verify that professional education seats are never deleted if they have been purchased.
        """
        user = self.create_user()
        course = CourseFactory()
        professional_product_no_verification = course.create_or_update_seat('professional', False, 0, self.partner)
        self.assertEqual(course.products.count(), 2)

        basket = BasketFactory(owner=user, site=self.site)
        basket.add_product(professional_product_no_verification)
        create_order(basket=basket, user=user)
        course.create_or_update_seat('professional', True, 0, self.partner)
        self.assertEqual(course.products.count(), 3)

        product_mode = course.products.all()[0]
        self.assertEqual(product_mode.attr.id_verification_required, True)
        self.assertEqual(product_mode.attr.certificate_type, 'professional')

        product_mode = course.products.all()[1]
        self.assertEqual(product_mode.attr.id_verification_required, False)
        self.assertEqual(product_mode.attr.certificate_type, 'professional')
Exemplo n.º 18
0
    def test_handle_post_order_for_seat_purchase(self, __):
        """
        Ensure that the single seat purchase order is not linked any business
        client when the method `handle_post_order` is invoked.
        """
        toggle_switch(ENROLLMENT_CODE_SWITCH, False)

        course = CourseFactory(partner=self.partner)
        verified_product = course.create_or_update_seat('verified', True, 50)
        user = UserFactory()
        basket = BasketFactory(owner=user, site=self.site)
        basket.add_product(verified_product, quantity=1)
        order = create_order(number=1, basket=basket, user=user)
        request_data = {'organization': 'Dummy Business Client'}
        # Manually add organization attribute on the basket for testing
        basket_add_organization_attribute(basket, request_data)

        EdxOrderPlacementMixin().handle_post_order(order)

        # Now verify that the single seat order is not linked to business
        # client by checking that there is no record for BusinessClient.
        assert not BusinessClient.objects.all()
Exemplo n.º 19
0
 def test_offer_availability_with_max_user_discount(self, discount_type,
                                                    num_prev_orders,
                                                    benefit_value,
                                                    is_satisfied):
     """
     Verify that enterprise offer with discount type percentage and absolute, condition returns correct result
     based on user limits in the offer.
     """
     benefits = {
         Benefit.PERCENTAGE:
         factories.EnterprisePercentageDiscountBenefitFactory(
             value=benefit_value),
         Benefit.FIXED:
         factories.EnterpriseAbsoluteDiscountBenefitFactory(
             value=benefit_value),
     }
     offer = factories.EnterpriseOfferFactory(
         partner=self.partner,
         benefit=benefits[discount_type],
         max_user_discount=150)
     for _ in range(num_prev_orders):
         order = OrderFactory(user=self.user, status=ORDER.COMPLETE)
         OrderDiscountFactory(order=order, offer_id=offer.id, amount=10)
     basket = BasketFactory(site=self.site, owner=self.user)
     basket.add_product(self.course_run.seat_products[0])
     basket.add_product(self.entitlement)
     self.mock_course_detail_endpoint(
         discovery_api_url=self.site_configuration.discovery_api_url,
         course=self.entitlement)
     self.mock_catalog_contains_course_runs(
         [self.course_run.id],
         self.condition.enterprise_customer_uuid,
         self.site.siteconfiguration.enterprise_api_url,
         enterprise_customer_catalog_uuid=self.condition.
         enterprise_customer_catalog_uuid,
     )
     self.assertEqual(self.condition.is_satisfied(offer, basket),
                      is_satisfied)
Exemplo n.º 20
0
    def test_get_enterprise_customer_from_enterprise_offer(
            self, discount_value):
        """
        Verify that "get_enterprise_customer_from_enterprise_offer" returns `None` if expected conditions are not met.
        """
        course = CourseFactory(name='EnterpriseConsentErrorTest',
                               partner=PartnerFactory())
        product = course.create_or_update_seat('verified', False, 50)

        benefit = EnterprisePercentageDiscountBenefitFactory(
            value=discount_value)
        offer = EnterpriseOfferFactory(benefit=benefit)
        # set wrong priority to invalidate the condition in util
        offer.priority = 111

        self.mock_enterprise_learner_api(
            learner_id=self.learner.id,
            enterprise_customer_uuid=str(
                offer.condition.enterprise_customer_uuid),
            course_run_id=course.id,
        )

        self.mock_catalog_contains_course_runs(
            [course.id],
            str(offer.condition.enterprise_customer_uuid),
            self.site.siteconfiguration.enterprise_api_url,
            enterprise_customer_catalog_uuid=str(
                offer.condition.enterprise_customer_catalog_uuid),
            contains_content=True,
        )

        basket = BasketFactory(site=self.site, owner=self.create_user())
        basket.add_product(product)
        basket.strategy = DefaultStrategy()
        Applicator().apply_offers(basket, [offer])

        self.assertIsNone(
            get_enterprise_customer_from_enterprise_offer(basket))
Exemplo n.º 21
0
    def test_handle_post_order_for_bulk_purchase(self, __):
        """
        Ensure that the bulk purchase order is linked to the provided business
        client when the method `handle_post_order` is invoked.
        """
        toggle_switch(ENROLLMENT_CODE_SWITCH, True)

        course = CourseFactory(partner=self.partner)
        course.create_or_update_seat('verified', True, 50, create_enrollment_code=True)
        enrollment_code = Product.objects.get(product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME)
        user = UserFactory()
        basket = BasketFactory(owner=user, site=self.site)
        basket.add_product(enrollment_code, quantity=1)
        order = create_order(number=1, basket=basket, user=user)
        request_data = {'organization': 'Dummy Business Client'}
        # Manually add organization attribute on the basket for testing
        basket_add_organization_attribute(basket, request_data)

        EdxOrderPlacementMixin().handle_post_order(order)

        # Now verify that a new business client has been created in current
        # order is now linked with that client through Invoice model.
        business_client = BusinessClient.objects.get(name=request_data['organization'])
        assert Invoice.objects.get(order=order).business_client == business_client
Exemplo n.º 22
0
    def test_offer_availability_with_max_discount(self, discount_type,
                                                  total_discount,
                                                  benefit_value, is_satisfied):
        """
        Verify that enterprise offer with discount type percentage and absolute, condition returns correct result
        based on total_discount(consumed discount so far) and discount on course price covered by the offer.
        """
        benefits = {
            Benefit.PERCENTAGE:
            factories.EnterprisePercentageDiscountBenefitFactory(
                value=benefit_value),
            Benefit.FIXED:
            factories.EnterpriseAbsoluteDiscountBenefitFactory(
                value=benefit_value),
        }

        offer = factories.EnterpriseOfferFactory(
            partner=self.partner,
            benefit=benefits[discount_type],
            max_discount=Decimal(5000),
            total_discount=total_discount)
        basket = BasketFactory(site=self.site, owner=self.user)
        basket.add_product(self.course_run.seat_products[0])
        basket.add_product(self.entitlement)
        self.mock_course_detail_endpoint(
            discovery_api_url=self.site_configuration.discovery_api_url,
            course=self.entitlement)
        self.mock_catalog_contains_course_runs(
            [self.course_run.id],
            self.condition.enterprise_customer_uuid,
            self.site.siteconfiguration.enterprise_api_url,
            enterprise_customer_catalog_uuid=self.condition.
            enterprise_customer_catalog_uuid,
        )
        self.assertEqual(self.condition.is_satisfied(offer, basket),
                         is_satisfied)
Exemplo n.º 23
0
    def create_order(self,
                     user=None,
                     credit=False,
                     multiple_lines=False,
                     free=False,
                     entitlement=False,
                     status=ORDER.COMPLETE,
                     id_verification_required=False):
        user = user or self.user
        basket = BasketFactory(owner=user, site=self.site)

        if credit:
            basket.add_product(self.credit_product)
        elif multiple_lines:
            basket.add_product(self.verified_product)
            basket.add_product(self.honor_product)
        elif free:
            basket.add_product(self.honor_product)
        elif entitlement:
            course_entitlement = create_or_update_course_entitlement(
                certificate_type='verified',
                price=100,
                partner=self.partner,
                UUID='111',
                title='Foo',
                id_verification_required=id_verification_required)
            basket.add_product(course_entitlement)
        else:
            basket.add_product(self.verified_product)

        order = create_order(basket=basket, user=user)
        order.status = status
        if entitlement:
            entitlement_option = Option.objects.get(code='course_entitlement')
            line = order.lines.first()
            line.attributes.create(option=entitlement_option, value='111')
        order.save()
        return order
Exemplo n.º 24
0
    def test_offer(self):
        # Our offer is for 100%, so all lines should end up with a price of 0.
        offer = factories.ProgramOfferFactory(
            partner=self.partner,
            benefit=factories.PercentageDiscountBenefitWithoutRangeFactory(
                value=100))
        basket = BasketFactory(site=self.site, owner=self.create_user())

        program_uuid = offer.condition.program_uuid
        program = self.mock_program_detail_endpoint(
            program_uuid, self.site_configuration.discovery_api_url)
        self.mock_user_data(basket.owner.username)

        # Add one course run seat from each course to the basket.
        products = []
        for course in program['courses']:
            course_run = Course.objects.get(id=course['course_runs'][0]['key'])
            for seat in course_run.seat_products:
                if seat.attr.id_verification_required:
                    products.append(seat)
                    basket.add_product(seat)

        # No discounts should be applied, and each line should have a price of 100.00.
        self.assertEqual(len(basket.offer_applications), 0)
        self.assertEqual(basket.total_discount, 0)
        for line in basket.all_lines():
            self.assertEqual(line.line_price_incl_tax_incl_discounts,
                             Decimal(100))

        # Apply the offers as Oscar will in a request
        basket.strategy = DefaultStrategy()
        Applicator().apply(basket, basket.owner, bundle_id=program_uuid)

        # Our discount should be applied, and each line should have a price of 0
        lines = basket.all_lines()
        self.assertEqual(len(basket.offer_applications), 1)
        self.assertEqual(basket.total_discount, Decimal(100) * len(lines))
        for line in lines:
            self.assertEqual(line.line_price_incl_tax_incl_discounts, 0)

        # Reset the basket and add a voucher.
        basket.reset_offer_applications()
        product_range = RangeFactory(products=products)
        voucher, __ = factories.prepare_voucher(_range=product_range,
                                                benefit_value=50)
        self.mock_account_api(self.request,
                              basket.owner.username,
                              data={'is_active': True})
        self.client.login(username=basket.owner.username,
                          password=self.password)
        self.client.post(reverse('basket:vouchers-add'),
                         data={'code': voucher.code})
        response = self.client.get(reverse('basket:summary'))
        basket = response.context['basket']

        # Verify that voucher-based offer takes precedence over program offer.
        actual_offer_discounts = [
            discount['offer'] for discount in basket.offer_discounts
        ]
        actual_voucher_discounts = [
            discount['offer'] for discount in basket.voucher_discounts
        ]
        self.assertEqual(actual_offer_discounts, [])
        self.assertEqual(actual_voucher_discounts, [voucher.offers.first()])
        lines = basket.all_lines()
        self.assertEqual(len(basket.offer_applications), 1)
        self.assertEqual(basket.total_discount, Decimal(50) * len(lines))
        for line in lines:
            self.assertEqual(line.line_price_incl_tax_incl_discounts, 50)
Exemplo n.º 25
0
class DynamicConditionTests(TestCase):
    """
    Tests to make sure that the dynamic discount condition correctly compute whether to give a discount
    """
    def setUp(self):
        super(DynamicConditionTests, self).setUp()
        self.condition = Condition.objects.get(
            proxy_class=
            'ecommerce.extensions.offer.dynamic_conditional_offer.DynamicDiscountCondition'
        ).proxy()
        self.offer = ConditionalOffer.objects.get(
            name='dynamic_conditional_offer')
        self.basket = BasketFactory(site=self.site, owner=self.create_user())
        self.seat_product_class, __ = ProductClass.objects.get_or_create(
            name=SEAT_PRODUCT_CLASS_NAME)

    def test_name(self):
        self.assertTrue(self.condition.name == 'dynamic_discount_condition')

    @override_flag(DYNAMIC_DISCOUNT_FLAG, active=True)
    @patch('crum.get_current_request')
    @patch(
        'ecommerce.extensions.offer.dynamic_conditional_offer.jwt_decode_handler',
        side_effect=_mock_jwt_decode_handler)
    @ddt.data(
        {
            'discount_applicable': True,
            'discount_percent': 15
        },
        {
            'discount_applicable': False,
            'discount_percent': 15
        },
        None,
    )
    def test_is_satisfied_true(self, discount_jwt, jwt_decode_handler,
                               request):  # pylint: disable=unused-argument
        product = ProductFactory(product_class=self.seat_product_class,
                                 stockrecords__price_excl_tax=10,
                                 categories=[])
        self.basket.add_product(product)

        request.return_value = Mock(method='GET',
                                    GET={'discount_jwt': discount_jwt})
        if discount_jwt and discount_jwt.get('discount_applicable') is True:
            self.assertTrue(
                self.condition.is_satisfied(self.offer, self.basket))
        else:
            self.assertFalse(
                self.condition.is_satisfied(self.offer, self.basket))

    @override_flag(DYNAMIC_DISCOUNT_FLAG, active=True)
    @patch('crum.get_current_request')
    def test_is_satisfied_quantity_more_than_1(self, request):  # pylint: disable=unused-argument
        """
        This discount should not apply if are buying more than one of the same course.
        """
        product = ProductFactory(stockrecords__price_excl_tax=10,
                                 categories=[])
        self.basket.add_product(product, quantity=2)
        self.assertFalse(self.condition.is_satisfied(self.offer, self.basket))

    @override_flag(DYNAMIC_DISCOUNT_FLAG, active=True)
    @patch('crum.get_current_request')
    def test_is_satisfied_not_seat_product(self, request):  # pylint: disable=unused-argument
        """
        This discount should not apply if are not purchasing a seat product.
        """
        product = ProductFactory(stockrecords__price_excl_tax=10,
                                 categories=[])
        self.basket.add_product(product)
        self.assertFalse(self.condition.is_satisfied(self.offer, self.basket))
Exemplo n.º 26
0
    def test_is_satisfied_with_entitlements(self):
        """
        The condition should be satisfied if, for each course in the program, their is either an entitlement sku in the
        basket or the user already has an entitlement for the course and the site has enabled partial program offers.
        """
        offer = factories.ProgramOfferFactory(partner=self.partner,
                                              condition=self.condition)
        basket = BasketFactory(site=self.site, owner=UserFactory())
        program = self.mock_program_detail_endpoint(
            self.condition.program_uuid,
            self.site_configuration.discovery_api_url)
        entitlements_response = {
            "count":
            0,
            "num_pages":
            1,
            "current_page":
            1,
            "results": [{
                'mode': 'verified',
                'course_uuid': '268afbfc-cc1e-415b-a5d8-c58d955bcfc3'
            }, {
                'mode': 'verified',
                'course_uuid': '268afbfc-cc1e-415b-a5d8-c58d955bcfc4'
            }],
            "next":
            None,
            "start":
            0,
            "previous":
            None
        }

        # Extract one verified seat for each course
        verified_entitlements = []
        course_uuids = set([course['uuid'] for course in program['courses']])
        for parent_entitlement in Product.objects.filter(
                product_class__name=COURSE_ENTITLEMENT_PRODUCT_CLASS_NAME,
                structure=Product.PARENT):
            for entitlement in Product.objects.filter(
                    parent=parent_entitlement):
                if entitlement.attr.UUID in course_uuids and entitlement.attr.certificate_type == 'verified':
                    verified_entitlements.append(entitlement)

        self.mock_user_data(basket.owner.username,
                            mocked_api='entitlements',
                            owned_products=entitlements_response)
        self.mock_user_data(basket.owner.username)
        # If the user has not added all of the remaining courses in program to their basket,
        # the condition should not be satisfied
        basket.flush()
        for entitlement in verified_entitlements[2:len(verified_entitlements) -
                                                 1]:
            basket.add_product(entitlement)
        self.assertFalse(self.condition.is_satisfied(offer, basket))

        # When all courses in the program that the user is not already enrolled in are in their basket
        # and the site allows partial program completion, the condition should be satisfied
        basket.add_product(verified_entitlements[-1])
        self.assertTrue(self.condition.is_satisfied(offer, basket))

        # If the site does not allow partial program completion and the user does not have all of the program
        # courses in their basket, the condition should not be satisfied
        basket.site.siteconfiguration.enable_partial_program = False
        self.assertFalse(self.condition.is_satisfied(offer, basket))

        # Verify the user enrollments are cached
        basket.site.siteconfiguration.enable_partial_program = True
        httpretty.disable()
        with mock.patch('ecommerce.programs.conditions.get_program',
                        return_value=program):
            self.assertTrue(self.condition.is_satisfied(offer, basket))
Exemplo n.º 27
0
class ManualEnrollmentOrderDiscountConditionTests(TestCase):
    """
    Test the `ManualEnrollmentOrderDiscountCondition` functionality.
    """
    def setUp(self):
        super(ManualEnrollmentOrderDiscountConditionTests, self).setUp()
        self.user = self.create_user(is_staff=True)
        self.learner = self.create_user(username='******', is_staff=False)
        self.condition = ManualEnrollmentOrderDiscountConditionFactory()
        self.basket = BasketFactory(site=self.site, owner=self.learner)
        self.course = CourseFactory(id='course-v1:MAX+CX+Course', partner=self.partner)
        self.course.create_or_update_seat(
            certificate_type='verified',
            id_verification_required=True,
            price=50
        )
        self.course.create_or_update_seat(
            certificate_type='audit',
            id_verification_required=False,
            price=0
        )
        self.seat_product = self.course.seat_products.filter(
            attributes__name='certificate_type'
        ).exclude(
            attribute_values__value_text='audit'
        ).first()

        request_patcher = patch('crum.get_current_request')
        self.request_patcher = request_patcher.start()
        self.request_patcher.return_value = RequestFactory().post(
            reverse('api:v2:manual-course-enrollment-order-list')
        )
        self.addCleanup(request_patcher.stop)

    def test_is_satisfied_with_wrong_offer(self):
        """
        Test `ManualEnrollmentOrderDiscountCondition.is_satisfied` works as expected for wrong offer.
        """
        offer = EnterpriseOfferFactory(partner=self.partner, condition=self.condition)
        status = self.condition.is_satisfied(offer, self.basket)
        assert not status

    def test_is_satisfied_with_wrong_order_lines(self):
        """
        Test `ManualEnrollmentOrderDiscountCondition.is_satisfied` works as expected when there wrong
        number of order lines.
        """
        for seat_product in self.course.seat_products:
            self.basket.add_product(seat_product)

        offer = ManualEnrollmentOrderOfferFactory()
        status = self.condition.is_satisfied(offer, self.basket)
        assert not status

    def test_is_satisfied_with_non_seat_type_product(self):
        """
        Test `ManualEnrollmentOrderDiscountCondition.is_satisfied` works as expected when there basket contains
        non seat type product.
        """
        product = ProductFactory()
        self.basket.add_product(product)

        offer = ManualEnrollmentOrderOfferFactory()
        status = self.condition.is_satisfied(offer, self.basket)
        assert not status

    def test_is_satisfied_with_non_verified_seat_type_product(self):
        """
        Test `ManualEnrollmentOrderDiscountCondition.is_satisfied` works as expected when there basket contains
        seat type product but seat is not verified.
        """
        seat_product = self.course.seat_products.filter(
            attribute_values__value_text='audit'
        ).first()

        self.basket.add_product(seat_product)

        offer = ManualEnrollmentOrderOfferFactory()
        status = self.condition.is_satisfied(offer, self.basket)
        assert not status

    def test_is_satisfied_success(self):
        """
        Test `ManualEnrollmentOrderDiscountCondition.is_satisfied` works as expected when condition satisfies.
        """
        self.basket.add_product(self.seat_product)
        offer = ManualEnrollmentOrderOfferFactory()
        status = self.condition.is_satisfied(offer, self.basket)
        assert status

    def test_is_satisfied_with_wrong_path_info(self):
        """
        Test `ManualEnrollmentOrderDiscountCondition.is_satisfied` works as expected when request path_info is wrong.
        """
        with patch('crum.get_current_request') as request_patcher:
            request_patcher.return_value = RequestFactory().post('some_view_path')
            offer = ManualEnrollmentOrderOfferFactory()
            self.basket.add_product(self.seat_product)
            status = self.condition.is_satisfied(offer, self.basket)
            assert not status
Exemplo n.º 28
0
class JournalBundleConditionTests(TestCase, JournalMixin):
    def setUp(self):
        super(JournalBundleConditionTests, self).setUp()
        user = self.create_user(is_staff=True)
        self.client.login(username=user.username, password=self.password)

        self.condition = factories.JournalConditionFactory()
        self.offer = factories.JournalBundleOfferFactory(
            partner=self.partner, condition=self.condition)
        self.basket = BasketFactory(site=self.site, owner=UserFactory())
        self.basket.add_product(self.create_product(self.client), 1)

    def test_name(self, mocked_journal_api_response):
        """ The name should contain the program's UUID. """
        mocked_journal_api_response.return_value = None
        expected = 'Basket contains every product in bundle {}'.format(
            self.condition.journal_bundle_uuid)
        self.assertEqual(self.condition.name, expected)

    def test_is_satisfied_with_empty_basket(self, mocked_journal_api_response):
        """ Test the 'is_satisfied' with empty basket """
        mocked_journal_api_response.return_value = None
        self.basket.flush()
        self.assertTrue(self.basket.is_empty)
        self.assertFalse(self.condition.is_satisfied(self.offer, self.basket))

    def test_is_satisfied_with_exception(self, mocked_journal_api_response):
        """ Test the 'is_satisfied' with 'HttpNotFoundError' exception  """
        mocked_journal_api_response.side_effect = HttpNotFoundError
        self.assertFalse(self.condition.is_satisfied(self.offer, self.basket))

    def test_is_satisfied_with_slumber_exception(self,
                                                 mocked_journal_api_response):
        """ Test the 'is_satisfied' with 'SlumberBaseException' exception  """
        mocked_journal_api_response.side_effect = SlumberBaseException
        self.assertFalse(self.condition.is_satisfied(self.offer, self.basket))

    def test_is_satisfied_with_timeout(self, mocked_journal_api_response):
        """ Test the 'is_satisfied' with 'Timeout' exception  """
        mocked_journal_api_response.side_effect = Timeout
        self.assertFalse(self.condition.is_satisfied(self.offer, self.basket))

    def test_is_satisfied_without_journal_bundle(self,
                                                 mocked_journal_api_response):
        """ Test the 'is_satisfied' without Journal bundle """
        mocked_journal_api_response.return_value = None
        self.assertFalse(self.condition.is_satisfied(self.offer, self.basket))

    def test_is_satisfied_without_courses(self, mocked_journal_api_response):
        """ Test the 'is_satisfied' without courses in Journal bundle """
        mocked_journal_api_response.return_value = self.get_mocked_discovery_journal_bundle(
            empty_courses=True)
        self.assertFalse(self.condition.is_satisfied(self.offer, self.basket))

    def test_is_satisfied_with_some_but_not_all_courses(
            self, mocked_journal_api_response):
        """ Test the 'is_satisfied' with only some of the courses in the Journal bundle """
        mocked_journal_api_response.return_value = self.get_mocked_discovery_journal_bundle(
            multiple_courses=True)
        self.assertFalse(self.condition.is_satisfied(self.offer, self.basket))

    def test_is_satisfied_with_dummy_product(self,
                                             mocked_journal_api_response):
        """ Test the 'is_satisfied' with dummy product in basket """
        mocked_journal_api_response.return_value = self.get_mocked_discovery_journal_bundle(
        )
        self.basket.flush()
        self.basket.add_product(
            self.create_product(
                self.client, data=self.get_data_for_create(sku="dummy-sku")),
            1)
        self.assertFalse(self.condition.is_satisfied(self.offer, self.basket))

    def test_is_satisfied_with_valid_data(self, mocked_journal_api_response):
        """ Test the 'is_satisfied' with valid Journal bundle """
        mocked_journal_api_response.return_value = self.get_mocked_discovery_journal_bundle(
            empty_journals=True)
        self.assertTrue(self.condition.is_satisfied(self.offer, self.basket))

    def test_get_applicable_lines(self, mocked_journal_api_response):
        """ Test the 'get_applicable_lines' with valid product in basket """
        mocked_journal_api_response.return_value = self.get_mocked_discovery_journal_bundle(
        )
        applicable_lines = [(line.product.stockrecords.first().price_excl_tax,
                             line) for line in self.basket.all_lines()]
        self.assertEqual(
            self.condition.get_applicable_lines(self.offer, self.basket),
            applicable_lines)

    def test_get_applicable_lines_with_empty_basket(
            self, mocked_journal_api_response):
        """ Test the 'get_applicable_lines' with empty basket """
        mocked_journal_api_response.return_value = self.get_mocked_discovery_journal_bundle(
        )
        self.basket.flush()
        self.assertEqual(
            self.condition.get_applicable_lines(self.offer, self.basket), [])

    def test_get_applicable_lines_sku_not_in_basket(
            self, mocked_journal_api_response):
        """ Test the 'get_applicable_lines' where the sku is not in the basket """
        mocked_journal_api_response.return_value = self.get_mocked_discovery_journal_bundle(
        )
        self.basket.flush()
        self.basket.add_product(
            self.create_product(
                self.client, data=self.get_data_for_create(sku="dummy-sku")),
            1)
        self.assertEqual(
            self.condition.get_applicable_lines(self.offer, self.basket), [])

    @mock.patch(
        "ecommerce.extensions.catalogue.models.Product.get_is_discountable")
    def test_get_applicable_lines_product_is_not_discountable(
            self, mocked_product_is_discountable, mocked_journal_api_response):
        """ Test the 'get_applicable_lines' where the product is not discountable """
        mocked_journal_api_response.return_value = self.get_mocked_discovery_journal_bundle(
        )
        mocked_product_is_discountable.return_value = False

        self.assertEqual(
            self.condition.get_applicable_lines(self.offer, self.basket), [])

    @mock.patch("oscar.apps.offer.utils.unit_price")
    def test_get_applicable_lines_no_price(self, mocked_unit_price,
                                           mocked_journal_api_response):
        """ Test the 'get_applicable_lines' where there is no price """
        mocked_journal_api_response.return_value = self.get_mocked_discovery_journal_bundle(
        )
        mocked_unit_price.return_value = None
        self.assertEqual(
            self.condition.get_applicable_lines(self.offer, self.basket), [])

    def test_get_applicable_lines_no_journal_bundle(self,
                                                    mock_journal_api_response):
        """ Test 'get_applicable_lines' where the journal bundle is None """
        mock_journal_api_response.return_value = None
        self.assertEqual(
            self.condition.get_applicable_lines(self.offer, self.basket), [])
Exemplo n.º 29
0
 def test_is_satisfied_site_mismatch(self):
     """ Ensure the condition returns False if the offer partner does not match the basket site partner. """
     offer = factories.EnterpriseOfferFactory(partner=SiteConfigurationFactory().partner, condition=self.condition)
     basket = BasketFactory(site=self.site, owner=self.user)
     basket.add_product(self.test_product)
     self.assertFalse(self.condition.is_satisfied(offer, basket))