示例#1
0
    def test_provider_fields(self, benefit_type, discount):
        code = 'TEST'
        seat = self.course.create_or_update_seat(
            'credit',
            True,
            self.price,
            self.provider,
            credit_hours=self.credit_hours)
        new_range = RangeFactory(products=[
            seat,
        ])
        prepare_voucher(code=code,
                        _range=new_range,
                        benefit_value=100,
                        benefit_type=benefit_type)
        self.mock_access_token_response()
        self._mock_eligibility_api(body=self.eligibilities)
        self._mock_providers_api(body=self.provider_data)

        response = self.client.get('{}?code={}'.format(self.path, code))
        self.assertEqual(response.status_code, 200)
        provider_info = response.context['providers'][0]

        self.assertEqual(provider_info['new_price'], '0.00')
        self.assertEqual(provider_info['discount'], discount)
示例#2
0
    def test_get_offers_for_single_course_voucher(self):
        """ Verify that the course offers data is returned for a single course voucher. """
        self.mock_access_token_response()
        course, seat = self.create_course_and_seat()
        new_range = RangeFactory(products=[seat, ])
        voucher, __ = prepare_voucher(_range=new_range, benefit_value=10)
        benefit = voucher.offers.first().benefit
        request = self.prepare_offers_listing_request(voucher.code)
        self.mock_course_run_detail_endpoint(
            course, discovery_api_url=self.site_configuration.discovery_api_url
        )
        offers = VoucherViewSet().get_offers(request=request, voucher=voucher)['results']
        first_offer = offers[0]

        self.assertEqual(len(offers), 1)
        self.assertDictEqual(first_offer, {
            'benefit': {
                'type': benefit.type,
                'value': benefit.value
            },
            'contains_verified': True,
            'course_start_date': '2013-02-05T05:00:00Z',
            'id': course.id,
            'image_url': '/path/to/image.jpg',
            'multiple_credit_providers': False,
            'organization': CourseKey.from_string(course.id).org,
            'credit_provider_price': None,
            'seat_type': course.type,
            'stockrecords': serializers.StockRecordSerializer(seat.stockrecords.first()).data,
            'title': course.name,
            'voucher_end_date': voucher.end_datetime,
        })
示例#3
0
 def test_no_product(self):
     """ Verify an error is returned for voucher with no product. """
     no_product_range = RangeFactory()
     prepare_voucher(code='NOPRODUCT', _range=no_product_range)
     url = self.path + '?code={}'.format('NOPRODUCT')
     response = self.client.get(url)
     self.assertEqual(response.context['error'], _('The voucher is not applicable to your current basket.'))
示例#4
0
    def create_benefits(self):
        """
        Create all Benefit permutations
            - Benefit type: Percentage, Benefit value: 100%
            - Benefit type: Percentage, Benefit value: 50%
            - Benefit type: Value, Benefit value: seat price
            - Benefit type: Value, Benefit value: half the seat price
        """
        _range = RangeFactory(products=[
            self.verified_seat,
        ])

        benefit_percentage_all = BenefitFactory(type=Benefit.PERCENTAGE,
                                                range=_range,
                                                value=100.00)
        benefit_percentage_half = BenefitFactory(type=Benefit.PERCENTAGE,
                                                 range=_range,
                                                 value=50.00)
        benefit_value_all = BenefitFactory(type=Benefit.FIXED,
                                           range=_range,
                                           value=self.seat_price)
        benefit_value_half = BenefitFactory(type=Benefit.FIXED,
                                            range=_range,
                                            value=self.seat_price / 2)

        return [
            benefit_percentage_all, benefit_percentage_half, benefit_value_all,
            benefit_value_half
        ]
示例#5
0
    def test_proper_code(self):
        """ Verify that proper information is returned when a valid code is provided. """
        course = CourseFactory()
        seat = course.create_or_update_seat('verified', True, 50, self.partner)
        sr = StockRecord.objects.get(product=seat)
        catalog = Catalog.objects.create(name='Test catalog',
                                         partner=self.partner)
        catalog.stock_records.add(sr)
        range_ = RangeFactory(catalog=catalog)
        self.prepare_voucher(range_=range_)

        course_info = {
            "media": {
                "course_image": {
                    "uri":
                    "/asset-v1:edX+DemoX+Demo_Course+type@asset+block@images_course_image.jpg"
                }
            },
            "name": "edX Demonstration Course",
        }
        course_info_json = json.dumps(course_info)
        course_url = get_lms_url('api/courses/v1/courses/{}/'.format(
            course.id))
        httpretty.register_uri(httpretty.GET,
                               course_url,
                               body=course_info_json,
                               content_type='application/json')

        url = self.offer_url + '?code={}'.format('COUPONTEST')
        response = self.client.get(url)
        self.assertEqual(response.context['course']['name'],
                         _('edX Demonstration Course'))
        self.assertEqual(response.context['code'], _('COUPONTEST'))
示例#6
0
    def prepare_url_for_credit_seat(self,
                                    code='CREDIT',
                                    enterprise_customer=None):
        """Helper method for creating a credit seat and construct the URL to its offer landing page.

        Returns:
            URL to its offer landing page.
        """
        __, credit_seat = self.create_course_and_seat(seat_type='credit')
        self.credit_seat = credit_seat
        # Make sure to always pair `course_seat_types` and `catalog_query` parameters because
        # if one of them is missing it could result in a SEGFAULT error when running tests
        # with migrations enabled.
        range_kwargs = {
            'products': [
                credit_seat,
            ],
            'course_seat_types': 'credit',
            'catalog_query': '*:*',
        }
        if enterprise_customer:
            range_kwargs['enterprise_customer'] = enterprise_customer
        _range = RangeFactory(**range_kwargs)
        prepare_voucher(code=code, _range=_range)

        url = '{path}?code={code}'.format(path=self.path, code=code)
        return url
示例#7
0
    def test_prepare_basket_with_bundle_voucher(self):
        """
        Test prepare_basket clears vouchers for a bundle
        """
        product = ProductFactory(stockrecords__price_excl_tax=100)
        new_range = RangeFactory(products=[
            product,
        ])
        voucher, __ = prepare_voucher(_range=new_range, benefit_value=10)

        request = self.request
        basket = prepare_basket(request, [product], voucher)
        self.assertTrue(basket.vouchers.all())
        request.GET = {'bundle': TEST_BUNDLE_ID}
        program_data = {
            'marketing_slug': 'program-slug',
            'title': 'program title',
            'type_attrs': {
                'slug': 'micromasters'
            }
        }
        with mock.patch('ecommerce.extensions.basket.utils.get_program',
                        return_value=program_data):
            basket = prepare_basket(request, [product])
        self.assertFalse(basket.vouchers.all())
示例#8
0
    def test_success(self):
        product_price = 100
        percentage_discount = 10
        product = ProductFactory(stockrecords__price_excl_tax=product_price)
        voucher, product = prepare_voucher(
            _range=RangeFactory(products=[product]),
            benefit_value=percentage_discount)
        self.request.user = UserFactory()
        basket = prepare_basket(self.request, [product], voucher)

        ppr = PaymentProcessorResponse.objects.create(basket=basket,
                                                      transaction_id='abc',
                                                      processor_name='paypal')
        with mock.patch.object(Paypal, 'issue_credit') as mock_issue_credit:
            mock_issue_credit.return_value = None

            assert refund_basket_transactions(self.site, [basket.id]) == (
                1,
                0,
            )
            total = product_price * (100 - percentage_discount) / 100.
            mock_issue_credit.assert_called_once_with(basket.order_number,
                                                      basket,
                                                      ppr.transaction_id,
                                                      total, basket.currency)
示例#9
0
    def test_prepare_basket_applies_valid_voucher_argument(self):
        """
            Tests that prepare_basket applies a valid voucher passed as an
            an argument, even when there is also a valid voucher already on
            the basket.
        """
        product = ProductFactory(stockrecords__partner__short_code='test1',
                                 stockrecords__price_excl_tax=100)
        new_range = RangeFactory(products=[product])
        new_voucher, __ = prepare_voucher(code='xyz',
                                          _range=new_range,
                                          benefit_value=10)
        existing_voucher, __ = prepare_voucher(code='test',
                                               _range=new_range,
                                               benefit_value=50)

        basket = BasketFactory(owner=self.request.user, site=self.request.site)
        basket.vouchers.add(existing_voucher)
        self.assertEqual(basket.vouchers.count(), 1)

        basket = prepare_basket(self.request, [product], new_voucher)
        self.assertIsNotNone(basket)
        self.assertEqual(basket.vouchers.count(), 1)
        self.assertEqual(basket.vouchers.first().code, 'XYZ')
        self.assertEqual(basket.total_discount, 10.00)
示例#10
0
 def prepare_course_information(self):
     """ Helper function to prepare an API endpoint that provides course information. """
     course, __, stock_record = self.prepare_stock_record()
     catalog = Catalog.objects.create(name='Test catalog', partner=self.partner)
     catalog.stock_records.add(stock_record)
     _range = RangeFactory(catalog=catalog)
     self.mock_course_api_response(course=course)
     return _range
示例#11
0
    def test_offer(self):
        # Our offer is for 100%, so all lines should end up with a price of 0.
        offer = factories.ProgramOfferFactory(
            site=self.site,
            benefit=factories.PercentageDiscountBenefitWithoutRangeFactory(value=100)
        )
        basket = factories.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)

        # 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)
示例#12
0
    def test_no_product(self):
        """ Verify an error is returned for voucher with no product. """
        code = FuzzyText().fuzz()
        no_product_range = RangeFactory()
        prepare_voucher(code=code, _range=no_product_range)
        url = format_url(path=self.path, params={'code': code})

        response = self.client.get(url)
        self.assertEqual(response.context['error'], 'The voucher is not applicable to your current basket.')
示例#13
0
def prepare_voucher(code='COUPONTEST',
                    _range=None,
                    start_datetime=None,
                    end_datetime=None,
                    benefit_value=100,
                    benefit_type=Benefit.PERCENTAGE,
                    usage=Voucher.SINGLE_USE,
                    max_usage=None,
                    email_domains=None,
                    enterprise_customer=None,
                    site=None):
    """ Helper function to create a voucher and add an offer to it that contains a product. """

    # NOTE (CCB): We use empty categories here to avoid unique-constraint issues that occur when we use
    # ProductCategoryFactory in conjunction with pre-created Category objects.
    if _range is None:
        product = ProductFactory(categories=[])
        _range = RangeFactory(products=[product],
                              enterprise_customer=enterprise_customer)
    elif _range.num_products() > 0:
        product = _range.all_products()[0]
    else:
        product = ProductFactory(categories=[])

    if start_datetime is None:
        start_datetime = now() - timedelta(days=1)

    if end_datetime is None:
        end_datetime = now() + timedelta(days=10)

    voucher = VoucherFactory(code=code,
                             start_datetime=start_datetime,
                             end_datetime=end_datetime,
                             usage=usage)
    benefit = BenefitFactory(type=benefit_type,
                             range=_range,
                             value=benefit_value)
    condition = ConditionFactory(value=1,
                                 range=_range,
                                 enterprise_customer_uuid=enterprise_customer)
    if max_usage:
        offer = ConditionalOfferFactory(offer_type=ConditionalOffer.VOUCHER,
                                        benefit=benefit,
                                        condition=condition,
                                        max_global_applications=max_usage,
                                        email_domains=email_domains,
                                        priority=OFFER_PRIORITY_VOUCHER)
    else:
        offer = ConditionalOfferFactory(
            offer_type=ConditionalOffer.VOUCHER,
            benefit=benefit,
            condition=condition,
            email_domains=email_domains,
            partner=site.siteconfiguration.partner if site else None,
            priority=OFFER_PRIORITY_VOUCHER)
    voucher.offers.add(offer)
    return voucher, product
 def setUp(self):
     self.basket = create_basket(empty=True)
     self.product = create_product(price=100)
     range = RangeFactory(products=[self.product])
     condition = ConditionFactory(range=range, value=2)
     self.voucher = VoucherFactory()
     self.voucher.offers.add(
         create_offer(offer_type='Voucher',
                      range=range,
                      condition=condition))
示例#15
0
 def setUp(self):
     self.applicator = Applicator()
     self.basket = BasketFactory()
     rng = RangeFactory(includes_all_products=True)
     self.condition = ConditionFactory(
         range=rng, type=ConditionFactory._meta.model.VALUE,
         value=D('100'), proxy_class=None)
     self.benefit = BenefitFactory(
         range=rng, type=BenefitFactory._meta.model.FIXED,
         value=D('10'))
示例#16
0
    def test_voucher_offers_listing_product_found(self):
        """ Verify the endpoint returns offers data for single product range. """
        course, seat = self.create_course_and_seat()
        self.mock_dynamic_catalog_single_course_runs_api(course)

        new_range = RangeFactory(products=[seat, ])
        voucher, __ = prepare_voucher(_range=new_range, benefit_value=10)
        request = self.prepare_offers_listing_request(voucher.code)
        response = self.endpointView(request)

        self.assertEqual(response.status_code, 200)
示例#17
0
 def prepare_course_information(self):
     """ Helper function to prepare an API endpoint that provides course information. """
     course = CourseFactory(name='Test course')
     seat = course.create_or_update_seat('verified', True, 50, self.partner)
     stock_record = StockRecord.objects.get(product=seat)
     catalog = Catalog.objects.create(name='Test catalog',
                                      partner=self.partner)
     catalog.stock_records.add(stock_record)
     _range = RangeFactory(catalog=catalog)
     self.mock_course_api_response(course=course)
     return _range
示例#18
0
 def setUp(self):
     self.applicator = Applicator()
     rng = RangeFactory(includes_all_products=True)
     self.condition = ConditionFactory(
         range=rng, type=ConditionFactory._meta.model.VALUE,
         value=D('100'), proxy_class=None)
     self.benefit = BenefitFactory(
         range=rng, type=BenefitFactory._meta.model.FIXED,
         value=D('10'), max_affected_items=1)
     self.basket = factories.create_basket()
     self.line = self.basket.all_lines()[0]
示例#19
0
    def test_voucher_offers_listing_product_found(self):
        """ Verify the endpoint returns offers data for single product range. """
        self.mock_dynamic_catalog_course_runs_api()
        product = ProductFactory(stockrecords__price_excl_tax=100)
        new_range = RangeFactory(products=[
            product,
        ])
        voucher, __ = prepare_voucher(_range=new_range, benefit_value=10)
        request = self.prepare_offers_listing_request(voucher.code)
        response = self.endpointView(request)

        self.assertEqual(response.status_code, 200)
示例#20
0
    def test_voucher_offers_listing_api_exception_caught(self, exception):
        """ Verify the endpoint returns status 400 Bad Request when ConnectionError occurs """
        __, seat = self.create_course_and_seat()
        new_range = RangeFactory(products=[seat, ])
        voucher, __ = prepare_voucher(_range=new_range, benefit_value=10)

        with mock.patch(
                'ecommerce.extensions.api.v2.views.vouchers.VoucherViewSet.get_offers',
                mock.Mock(side_effect=exception)):
            request = self.prepare_offers_listing_request(voucher.code)
            response = self.endpointView(request)

            self.assertEqual(response.status_code, 400)
示例#21
0
 def test_apply_voucher_on_basket_and_check_discount_with_invalid_product(self):
     """
     Tests apply_voucher_on_basket_and_check_discount when called with invalid product
     does not apply voucher and returns the correct values.
     """
     basket = BasketFactory(owner=self.request.user, site=self.request.site)
     product = ProductFactory(stockrecords__partner__short_code='test1', stockrecords__price_excl_tax=0)
     voucher, __ = prepare_voucher(_range=RangeFactory(products=[product]))
     basket.add_product(product, 1)
     applied, msg = apply_voucher_on_basket_and_check_discount(voucher, self.request, basket)
     self.assertEqual(applied, False)
     self.assertEqual(basket.applied_offers(), {})
     self.assertEqual(msg, 'Basket does not qualify for coupon code {code}.'.format(code=voucher.code))
示例#22
0
    def test_get_offers_object_not_found(self):
        """ Verify the endpoint returns status 404 Not Found when product Course or Stock Record is not found """
        __, seat = self.create_course_and_seat()
        new_range = RangeFactory(products=[seat, ])
        voucher, __ = prepare_voucher(_range=new_range)

        with mock.patch(
                'ecommerce.extensions.api.v2.views.vouchers.VoucherViewSet.get_offers',
                mock.Mock(side_effect=Http404)):
            request = self.prepare_offers_listing_request(voucher.code)
            response = self.endpointView(request)

            self.assertEqual(response.status_code, 404)
示例#23
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))
示例#24
0
    def test_prepare_basket_with_bundle_voucher(self):
        """
        Test prepare_basket clears vouchers for a bundle
        """
        product = ProductFactory(stockrecords__price_excl_tax=100)
        new_range = RangeFactory(products=[product, ])
        voucher, __ = prepare_voucher(_range=new_range, benefit_value=10)

        request = self.request
        basket = prepare_basket(request, [product], voucher)
        self.assertTrue(basket.vouchers.all())
        request.GET = {'bundle': TEST_BUNDLE_ID}
        basket = prepare_basket(request, [product])
        self.assertFalse(basket.vouchers.all())
示例#25
0
    def test_multiple_vouchers(self):
        """ Verify only the last entered voucher is contained in the basket. """
        product = ProductFactory(stockrecords__price_excl_tax=100)
        new_range = RangeFactory(products=[product, ])
        voucher1, __ = prepare_voucher(code='TEST1', _range=new_range, benefit_value=10)
        basket = prepare_basket(self.request, [product], voucher1)
        self.assertEqual(basket.vouchers.count(), 1)
        self.assertEqual(basket.vouchers.first(), voucher1)

        voucher2, __ = prepare_voucher(code='TEST2', _range=new_range, benefit_value=20)
        new_basket = prepare_basket(self.request, [product], voucher2)
        self.assertEqual(basket, new_basket)
        self.assertEqual(new_basket.vouchers.count(), 1)
        self.assertEqual(new_basket.vouchers.first(), voucher2)
示例#26
0
    def prepare_url_for_credit_seat(self, code='CREDIT'):
        """Helper method for creating a credit seat and construct the URL to its offer landing page.
        Returns:
            URL to its offer landing page.
        """
        __, credit_seat = self.create_course_and_seat(seat_type='credit')
        # Make sure to always pair `course_seat_types` and `catalog_query` parameters because
        # if one of them is missing it could result in a SEGFAULT error when running tests
        # with migrations enabled.
        _range = RangeFactory(products=[credit_seat, ], course_seat_types='credit', catalog_query='*:*')
        prepare_voucher(code=code, _range=_range)

        url = '{path}?code={code}'.format(path=self.path, code=code)
        return url
    def test_is_voucher_applied(self):
        """
        Verify is_voucher_applied return correct value.
        """
        product = ProductFactory(stockrecords__price_excl_tax=100)
        voucher, product = prepare_voucher(
            _range=RangeFactory(products=[product]), benefit_value=10)
        basket = prepare_basket(self.request, [product], voucher)

        # Verify is_voucher_applied returns True when voucher is applied to the basket.
        self.assertTrue(is_voucher_applied(basket, voucher))

        # Verify is_voucher_applied returns False when voucher can not be applied to the basket.
        self.assertFalse(is_voucher_applied(basket, VoucherFactory()))
示例#28
0
    def test_voucher_offers_listing_product_found(self):
        """ Verify the endpoint returns offers data for single product range. """
        self.mock_access_token_response()
        course, seat = self.create_course_and_seat()
        self.mock_course_run_detail_endpoint(
            course, discovery_api_url=self.site_configuration.discovery_api_url
        )

        new_range = RangeFactory(products=[seat, ])
        voucher, __ = prepare_voucher(_range=new_range, benefit_value=10)
        request = self.prepare_offers_listing_request(voucher.code)
        response = self.endpointView(request)

        self.assertEqual(response.status_code, 200)
示例#29
0
    def test_voucher_offers_listing_for_a_single_course_voucher(self):
        """ Verify the endpoint returns offers data when a single product is in voucher range. """
        course, seat = self.create_course_and_seat()
        self.mock_dynamic_catalog_single_course_runs_api(course)
        new_range = RangeFactory(products=[seat, ])
        new_range.catalog = Catalog.objects.create(partner=self.partner)
        new_range.catalog.stock_records.add(StockRecord.objects.get(product=seat))
        voucher, __ = prepare_voucher(_range=new_range, benefit_value=10)
        request = self.prepare_offers_listing_request(voucher.code)
        response = self.endpointView(request)
        self.assertEqual(response.status_code, 200)

        new_range.remove_product(seat)
        response = self.endpointView(request)
        self.assertEqual(response.status_code, 404)
示例#30
0
    def prepare_voucher(self, range_=None, start_datetime=None, benefit_value=100, benefit_type='Percentage'):
        """ Create a voucher and add an offer to it that contains a created product. """
        if range_ is None:
            product = ProductFactory(title='Test product')
            range_ = RangeFactory(products=[product, ])
        else:
            product = range_.all_products()[0]

        if start_datetime is None:
            start_datetime = now() - datetime.timedelta(days=1)

        voucher = VoucherFactory(code='COUPONTEST', start_datetime=start_datetime, usage=Voucher.SINGLE_USE)
        benefit = BenefitFactory(type=benefit_type, range=range_, value=benefit_value)
        offer = ConditionalOfferFactory(benefit=benefit)
        voucher.offers.add(offer)
        return voucher, product