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 a non-exclusive offer #1. condition1 = factories.ConditionFactory(range=rng, value=D('1')) benefit1 = factories.BenefitFactory(range=rng, value=D('10')) self.offer1 = factories.ConditionalOfferFactory( condition=condition1, benefit=benefit1, start_datetime=now(), name='Test offer #1', exclusive=False, ) # Create a non-exclusive offer #2. condition2 = factories.ConditionFactory(range=rng, value=D('1')) benefit2 = factories.BenefitFactory(range=rng, value=D('5')) self.offer2 = factories.ConditionalOfferFactory( condition=condition2, benefit=benefit2, start_datetime=now(), name='Test offer #2', exclusive=False, )
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 = 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)
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_range_condition_satisfied(self): """ Verify that a basket satisfies a condition only when all of its products are in its range's catalog queryset. """ valid_user_email = 'valid@{domain}'.format( domain=self.valid_sub_domain) basket = factories.BasketFactory( site=self.site, owner=UserFactory(email=valid_user_email)) product = self.create_entitlement_product() another_product = self.create_entitlement_product() _range = factories.RangeFactory() _range.course_seat_types = ','.join(Range.ALLOWED_SEAT_TYPES) _range.catalog_query = 'uuid:{course_uuid}'.format( course_uuid=product.attr.UUID) benefit = factories.BenefitFactory(range=_range) offer = factories.ConditionalOfferFactory(benefit=benefit) self.mock_access_token_response() self.mock_catalog_query_contains_endpoint( course_run_ids=[], course_uuids=[product.attr.UUID], absent_ids=[another_product.attr.UUID], query=benefit.range.catalog_query, discovery_api_url=self.site_configuration.discovery_api_url) basket.add_product(product) self.assertTrue(offer.is_condition_satisfied(basket)) basket.add_product(another_product) self.assertFalse(offer.is_condition_satisfied(basket)) # Verify that API return values are cached httpretty.disable() self.assertFalse(offer.is_condition_satisfied(basket))
def test_for_multiple_offers_benefits_and_conditions_not_deleted(self): condition = factories.ConditionFactory() condition_id = condition.id benefit = factories.BenefitFactory() benefit_id = benefit.id offer1 = factories.create_offer(name='First test offer', condition=condition) offer2 = factories.create_offer(name='Second test offer', condition=condition, benefit=benefit) offer3 = factories.create_offer(name='Third test offer', benefit=benefit) offer1.delete() self.assertTrue( models.Condition.objects.filter(id=condition_id).exists()) offer2.delete() self.assertFalse( models.Condition.objects.filter(id=condition_id).exists()) self.assertTrue(models.Benefit.objects.filter(id=benefit_id).exists()) offer3.delete() self.assertFalse(models.Benefit.objects.filter(id=benefit_id).exists())
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 = 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)
def test_basket_calculate_site_offer(self): """ Verify successful basket calculation with a site offer """ discount_value = 10.00 benefit = factories.BenefitFactory(type=Benefit.PERCENTAGE, range=self.range, value=discount_value) condition = factories.ConditionFactory(value=3, range=self.range, type=Condition.COVERAGE) factories.ConditionalOfferFactory( name=u'Test Offer', benefit=benefit, condition=condition, offer_type=ConditionalOffer.SITE, start_datetime=datetime.datetime.now() - datetime.timedelta(days=1), end_datetime=datetime.datetime.now() + datetime.timedelta(days=2)) response = self.client.get(self.url) expected = { 'total_incl_tax_excl_discounts': self.product_total, 'total_incl_tax': Decimal('27.00'), 'currency': 'GBP' } self.assertEqual(response.status_code, 200) self.assertEqual(response.data, expected)
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) voucher = factories.VoucherFactory(usage=usage) product_range = factories.RangeFactory(products=products) voucher.offers.add( factories.ConditionalOfferFactory( benefit=factories.BenefitFactory(range=product_range), condition=factories.ConditionFactory(range=product_range))) 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_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 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 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 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_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_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_value(self): with self.assertRaises(ValidationError): factories.BenefitFactory(value=110) with self.assertRaises(ValidationError): factories.BenefitFactory(value=-10)
def test_range(self): with self.assertRaises(ValidationError): factories.BenefitFactory(range=None)
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 = {}