def setUp(self): self.condition_product = factories.ProductFactory() condition_range = factories.RangeFactory() condition_range.add_product(self.condition_product) self.condition = models.CountCondition.objects.create( range=condition_range, type=models.Condition.COUNT, value=2) self.benefit_product = factories.ProductFactory() benefit_range = factories.RangeFactory() benefit_range.add_product(self.benefit_product) self.benefit = models.AbsoluteDiscountBenefit.objects.create( range=benefit_range, type=models.Benefit.FIXED, value=D('3.00')) self.offer = models.ConditionalOffer(id=1, condition=self.condition, benefit=self.benefit) self.basket = factories.create_basket(empty=True) self.applicator = Applicator()
def setUp(self): super(BenefitTests, self).setUp() _range = factories.RangeFactory( course_seat_types=','.join(Range.ALLOWED_SEAT_TYPES[1:]), catalog_query='uuid:*' ) self.benefit = factories.BenefitFactory(range=_range) self.offer = factories.ConditionalOfferFactory(benefit=self.benefit) self.user = UserFactory()
def create_and_apply_benefit_to_basket(self, basket, product, benefit_type, benefit_value): _range = factories.RangeFactory(products=[ product, ]) voucher, __ = prepare_voucher(_range=_range, benefit_type=benefit_type, benefit_value=benefit_value) basket.vouchers.add(voucher) Applicator().apply(basket)
def setUp(self): super(BasketCalculateViewTests, self).setUp() self.products = ProductFactory.create_batch( 3, stockrecords__partner=self.partner, categories=[]) self.path = reverse('api:v2:baskets:calculate') self.range = factories.RangeFactory(includes_all_products=True) self.product_total = sum(product.stockrecords.first().price_excl_tax for product in self.products) self.user = self._login_as_user(is_staff=True) self.url = self._generate_sku_url(self.products, username=self.user.username)
def setUp(self): super(BasketCalculateViewTests, self).setUp() self.products = ProductFactory.create_batch(3, stockrecords__partner=self.partner) qs = urllib.urlencode({'sku': [product.stockrecords.first().partner_sku for product in self.products]}, True) self.path = reverse('api:v2:baskets:calculate') self.url = '{root}?{qs}'.format(root=self.path, qs=qs) self.range = factories.RangeFactory(includes_all_products=True) self.product_total = sum(product.stockrecords.first().price_excl_tax for product in self.products) self.user = self.create_user(is_staff=True) self.client.login(username=self.user.username, password=self.password)
def setUp(self): super(ConditionalOfferTests, self).setUp() self.email_domains = 'example.com' self.product = factories.ProductFactory() _range = factories.RangeFactory(products=[ self.product, ]) self.offer = ConditionalOffer.objects.create( condition=factories.ConditionFactory(value=1, range=_range), benefit=factories.BenefitFactory(), email_domains=self.email_domains)
def test_condition_not_satisfied_for_enterprise(self): """Verify a condition is not satisfied.""" valid_user_email = 'valid@{domain}'.format(domain=self.valid_sub_domain) basket = factories.BasketFactory(site=self.site, owner=UserFactory(email=valid_user_email)) _range = factories.RangeFactory( products=[self.product, ], course_seat_types='verified', enterprise_customer=str(uuid4()), catalog_query='*:*' ) benefit = factories.BenefitFactory(range=_range) offer = factories.ConditionalOfferFactory(benefit=benefit) basket.add_product(self.product) self.assertFalse(offer.is_condition_satisfied(basket))
def test_name_and_description(self): """ Tests that the condition proxy classes all return a name and description. Unfortunately, the current implementations means a valid range and value are required. This test became necessary because the complex name/description logic broke with the python_2_unicode_compatible decorator. """ range = factories.RangeFactory() for type, __ in models.Condition.TYPE_CHOICES: condition = models.Condition(type=type, range=range, value=5) self.assertTrue( all([ condition.name, condition.description, six.text_type(condition) ]))
def test_add_multiple_products_and_use_voucher(self, usage): """ Verify the basket accepts multiple products and a single use voucher. """ products = ProductFactory.create_batch(3, stockrecords__partner=self.partner) product_range = factories.RangeFactory(products=products) voucher, __ = prepare_voucher(_range=product_range, usage=usage) qs = urllib.urlencode({ 'sku': [product.stockrecords.first().partner_sku for product in products], 'code': voucher.code }, True) url = '{root}?{qs}'.format(root=self.path, qs=qs) response = self.client.get(url) self.assertEqual(response.status_code, 303) basket = response.wsgi_request.basket self.assertEqual(basket.status, Basket.OPEN) self.assertTrue(basket.contains_voucher(voucher.code))
def test_name_and_description(self): """ Tests that the benefit proxy classes all return a name and description. Unfortunately, the current implementations means a valid range is required. This test became necessary because the complex name/description logic broke with the python_2_unicode_compatible decorator. """ range = factories.RangeFactory() for type, __ in Benefit.TYPE_CHOICES: benefit = Benefit(type=type, range=range) self.assertTrue( all([ benefit.name, benefit.description, six.text_type(benefit) ]))
def setUp(self): super(ConditionalOfferTests, self).setUp() self.valid_domain = 'example.com' self.valid_sub_domain = 'sub.example2.com' self.email_domains = '{domain1},{domain2}'.format( domain1=self.valid_domain, domain2=self.valid_sub_domain) self.product = factories.ProductFactory() _range = factories.RangeFactory(products=[ self.product, ]) self.offer = ConditionalOffer.objects.create( condition=factories.ConditionFactory(value=1, range=_range), benefit=factories.BenefitFactory(), email_domains=self.email_domains)
def test_track_completed_discounted_order_with_voucher(self): """ An event including coupon information should be sent to Segment""" with mock.patch('ecommerce.extensions.checkout.signals.track_segment_event') as mock_track: # Orders may be discounted by percent percent_benefit = 66 product = ProductFactory(categories=[], stockrecords__price_currency='USD') _range = factories.RangeFactory(products=[product], ) voucher, product = prepare_voucher(_range=_range, benefit_value=percent_benefit) basket = factories.BasketFactory(owner=self.user, site=self.site) basket.add_product(product) basket.vouchers.add(voucher) Applicator().apply(basket, user=basket.owner, request=self.request) order = factories.create_order(basket=basket, user=self.user) track_completed_order(None, order) properties = self._generate_event_properties(order, voucher) mock_track.assert_called_once_with(order.site, order.user, 'Order Completed', properties, traits=properties)
def test_track_completed_discounted_order_with_offer(self): """ An event including a discount but no coupon should be sent to Segment""" with mock.patch('ecommerce.extensions.checkout.signals.track_segment_event') as mock_track: # Orders may be discounted by a fixed value offer_discount = 5 product = ProductFactory(categories=[], stockrecords__price_currency='USD') _range = factories.RangeFactory(products=[product], ) site_offer = factories.ConditionalOfferFactory( offer_type=ConditionalOffer.SITE, benefit=factories.BenefitFactory(range=_range, value=offer_discount), condition=factories.ConditionFactory(type=Condition.COVERAGE, value=1, range=_range) ) basket = factories.BasketFactory(owner=self.user, site=self.site) basket.add_product(product) Applicator().apply_offers(basket, [site_offer]) order = factories.create_order(basket=basket, user=self.user) track_completed_order(None, order) properties = self._generate_event_properties(order) mock_track.assert_called_once_with(order.site, order.user, 'Order Completed', properties, traits=properties)
def test_condition_not_satisfied_for_enterprise_switch_on(self): """Verify a condition is not satisfied.""" Switch.objects.update_or_create( name=ENTERPRISE_OFFERS_FOR_COUPONS_SWITCH, defaults={'active': True}) valid_user_email = 'valid@{domain}'.format( domain=self.valid_sub_domain) basket = factories.BasketFactory( site=self.site, owner=factories.UserFactory(email=valid_user_email)) _range = factories.RangeFactory(products=[ self.product, ], course_seat_types='verified', enterprise_customer=str( uuid4()).decode('utf-8'), catalog_query='*:*') benefit = factories.BenefitFactory(range=_range) offer = factories.ConditionalOfferFactory(benefit=benefit) basket.add_product(self.product) self.assertFalse(offer.is_condition_satisfied(basket))
def test_track_completed_discounted_order_with_voucher_with_offer(self): with mock.patch('ecommerce.extensions.checkout.signals.track_segment_event') as mock_track: # Orders may be discounted by a fixed value fixed_benefit = 5.00 offer_discount = 6 product = ProductFactory(categories=[], stockrecords__price_currency='USD') _range = factories.RangeFactory(products=[product], ) voucher, product = prepare_voucher(_range=_range, benefit_value=fixed_benefit, benefit_type=Benefit.FIXED) factories.ConditionalOfferFactory( offer_type=ConditionalOffer.SITE, benefit=factories.BenefitFactory(range=_range, value=offer_discount), condition=factories.ConditionFactory(type=Condition.COVERAGE, value=1, range=_range) ) basket = factories.BasketFactory(owner=self.user, site=self.site) basket.add_product(product) basket.vouchers.add(voucher) Applicator().apply(basket, user=basket.owner, request=self.request) order = factories.create_order(basket=basket, user=self.user) track_completed_order(None, order) properties = self._generate_event_properties(order, voucher) mock_track.assert_called_once_with(order.site, order.user, 'Order Completed', properties, traits=properties)
def test_coupon_applied_on_site_offer(self): """Coupon offer supersedes site offer.""" self.mock_access_token_response() self.mock_account_api(self.request, self.user.username, data={'is_active': True}) product_price = 100 site_offer_discount = 20 voucher_discount = 10 voucher, product = prepare_voucher(benefit_value=voucher_discount) stockrecord = product.stockrecords.first() stockrecord.price_excl_tax = product_price stockrecord.save() _range = factories.RangeFactory(includes_all_products=True) site_offer = factories.ConditionalOfferFactory( offer_type=ConditionalOffer.SITE, benefit=factories.BenefitFactory(range=_range, value=site_offer_discount), condition=factories.ConditionFactory(type=Condition.COVERAGE, value=1, range=_range)) self.basket.add_product(product) # Only site offer is applied to the basket. self.assert_basket_discounts([site_offer]) # Only the voucher offer is applied to the basket. self.client.post(reverse('basket:vouchers-add'), data={'code': voucher.code}) self.assert_basket_discounts( expected_voucher_discounts=[voucher.offers.first()]) # Site offer discount is still present after removing voucher. self.client.post( reverse('basket:vouchers-remove', kwargs={'pk': voucher.id})) self.assert_basket_discounts([site_offer])
def test_is_single_use_range_condition_satisfied(self): """ Verify that the condition for a single use coupon is only satisfied by single-product baskets. """ valid_user_email = 'valid@{domain}'.format( domain=self.valid_sub_domain) basket = factories.BasketFactory( site=self.site, owner=factories.UserFactory(email=valid_user_email)) product1 = self.create_entitlement_product() product2 = self.create_entitlement_product() _range = factories.RangeFactory() _range.course_seat_types = ','.join(Range.ALLOWED_SEAT_TYPES) _range.catalog_query = 'uuid:*' benefit = factories.BenefitFactory(range=_range) offer = factories.ConditionalOfferFactory(benefit=benefit) offer.set_voucher(factories.VoucherFactory(usage='Single-use')) self.mock_access_token_response() self.mock_catalog_query_contains_endpoint( course_run_ids=[], course_uuids=[product1.attr.UUID, product2.attr.UUID], absent_ids=[], query=benefit.range.catalog_query, discovery_api_url=self.site_configuration.discovery_api_url) # Verify that each product individually satisfies the condition basket.add_product(product1) self.assertTrue(offer.is_condition_satisfied(basket)) basket.flush() basket.add_product(product2) self.assertTrue(offer.is_condition_satisfied(basket)) # Verify that the offer cannot be applied to a multi-product basket basket.add_product(product1) self.assertFalse(offer.is_condition_satisfied(basket))
def range(): return factories.RangeFactory()
def setUp(self): super().setUp() self.basket = factories.create_basket(empty=True) # Create range and add one product to it. rng = factories.RangeFactory(name='All products', includes_all_products=True) self.product = factories.ProductFactory() rng.add_product(self.product) # Create offer #1. condition1 = factories.ConditionFactory( range=rng, type=factories.ConditionFactory._meta.model.COUNT, value=D('2'), ) benefit1 = factories.BenefitFactory( range=rng, type=factories.BenefitFactory._meta.model.MULTIBUY, value=None, ) self.offer1 = factories.ConditionalOfferFactory( condition=condition1, benefit=benefit1, slug='offer-1', start_datetime=now(), name='Test offer #1', priority=1, ) # Create offer #2. condition2 = factories.ConditionFactory( range=rng, type=factories.ConditionFactory._meta.model.COUNT, value=D('1'), ) benefit2 = factories.BenefitFactory( range=rng, type=factories.BenefitFactory._meta.model.PERCENTAGE, value=D('5'), ) self.offer2 = factories.ConditionalOfferFactory( condition=condition2, benefit=benefit2, slug='offer-2', start_datetime=now(), name='Test offer #2', ) # Create offer #3. condition3 = factories.ConditionFactory( range=rng, type=factories.ConditionFactory._meta.model.COUNT, value=D('1'), ) benefit3 = factories.BenefitFactory( range=rng, type=factories.BenefitFactory._meta.model.MULTIBUY, value=None, ) self.offer3 = factories.ConditionalOfferFactory( condition=condition3, benefit=benefit3, slug='offer-3', start_datetime=now(), name='Test offer #3', exclusive=False, ) # Create offer #4. condition4 = factories.ConditionFactory( range=rng, type=factories.ConditionFactory._meta.model.COUNT, value=D('1'), ) benefit4 = factories.BenefitFactory( range=rng, type=factories.BenefitFactory._meta.model.MULTIBUY, value=None, ) self.offer4 = factories.ConditionalOfferFactory( condition=condition4, benefit=benefit4, slug='offer-4', start_datetime=now(), name='Test offer #4', exclusive=False, priority=3, )
def setUp(self): super().setUp() self.basket = factories.create_basket(empty=True) # Create range and add one product to it. rng = factories.RangeFactory(name='All products', includes_all_products=True) self.product = factories.ProductFactory() rng.add_product(self.product) # Create offer #1. condition1 = factories.ConditionFactory( range=rng, type=factories.ConditionFactory._meta.model.COUNT, value=D('2'), ) benefit1 = factories.BenefitFactory( range=rng, type=factories.BenefitFactory._meta.model.MULTIBUY, value=None, ) self.offer1 = factories.ConditionalOfferFactory( condition=condition1, benefit=benefit1, slug='offer-1', start_datetime=now(), name='Test offer #1', priority=1, ) # Create offer #2. condition2 = factories.ConditionFactory( range=rng, type=factories.ConditionFactory._meta.model.VALUE, value=D('1.99'), ) benefit2 = factories.BenefitFactory( range=rng, type=factories.BenefitFactory._meta.model.MULTIBUY, value=None, ) self.offer2 = factories.ConditionalOfferFactory( condition=condition2, benefit=benefit2, slug='offer-2', start_datetime=now(), name='Test offer #2', ) # Create offer #3. condition3 = factories.ConditionFactory( range=rng, type=factories.ConditionFactory._meta.model.COVERAGE, value=1, ) benefit3 = factories.BenefitFactory( range=rng, type=factories.BenefitFactory._meta.model.MULTIBUY, value=None, ) self.offer3 = factories.ConditionalOfferFactory( condition=condition3, benefit=benefit3, slug='offer-3', start_datetime=now(), name='Test offer #3', ) # Prepare `BasketView` to use `get_upsell_messages` method in tests. self.view = BasketView() self.view.request = RequestFactory().get(reverse('basket:summary')) self.view.request.user = factories.UserFactory() self.view.args = [] self.view.kwargs = {}
def range_some(products_some): return factories.RangeFactory(name="Some products", products=products_some)
def range_all(): return factories.RangeFactory(name="All products range", includes_all_products=True)