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 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_transfers_vouchers_to_new_basket(self): baskets = [factories.BasketFactory(), factories.BasketFactory()] voucher = factories.VoucherFactory() baskets[0].vouchers.add(voucher) baskets[1].merge(baskets[0]) self.assertEqual(1, baskets[1].vouchers.all().count())
def test_single_usage(self): user = AnonymousUser() basket = factories.create_basket() creator = OrderCreator() voucher = factories.VoucherFactory(usage=Voucher.SINGLE_USE) voucher.offers.add(factories.create_offer(offer_type='Voucher')) basket.vouchers.add(voucher) surcharges = SurchargeApplicator().get_applicable_surcharges(basket) place_order(creator, surcharges=surcharges, basket=basket, order_number='12346', user=user) assert voucher.applications.count() == 1 # Make sure the voucher usage is rechecked with pytest.raises(ValueError): place_order(creator, surcharges=surcharges, basket=basket, order_number='12347', user=user)
def test_expired_voucher(self): user = AnonymousUser() basket = factories.create_basket() creator = OrderCreator() voucher = factories.VoucherFactory(usage=Voucher.SINGLE_USE) voucher.offers.add(factories.create_offer(offer_type='Voucher')) basket.vouchers.add(voucher) voucher.end_datetime = timezone.now() - datetime.timedelta(days=100) voucher.save() place_order(creator, basket=basket, order_number='12346', user=user) assert voucher.applications.count() == 0
def _create_coupon_product_with_note_attribute(self, note): """Helper method that creates a coupon product with note attribute set.""" coupon_product = factories.ProductFactory( title=self.COUPON_PRODUCT_TITLE, product_class=self.coupon_product_class) voucher = factories.VoucherFactory() coupon_vouchers = CouponVouchers.objects.create(coupon=coupon_product) coupon_vouchers.vouchers.add(voucher) coupon_product.attr.coupon_vouchers = coupon_vouchers coupon_product.attr.note = note coupon_product.save() return coupon_product
def _create_coupon_and_voucher(self, enterprise_contract_metadata=None): """ Create and link the coupon product and voucher, and return the coupon_code and voucher. """ coupon = self.create_coupon_product() voucher = factories.VoucherFactory() voucher.offers.add(self.discount_offer) coupon_vouchers = CouponVouchers.objects.create(coupon=coupon) coupon_vouchers.vouchers.add(voucher) coupon.attr.enterprise_contract_metadata = enterprise_contract_metadata coupon.attr.coupon_vouchers = coupon_vouchers coupon.save() return coupon.attr.coupon_vouchers.vouchers.first().code, voucher
def test_post_valid(self): voucher = factories.VoucherFactory(num_basket_additions=5) data = {'code': voucher.code} request = RequestFactory().post('/', data=data) request.basket.save() request.basket.vouchers.add(voucher) view = views.VoucherRemoveView.as_view() response = view(request, pk=voucher.pk) self.assertEqual(response.status_code, 302) voucher = voucher.__class__.objects.get(pk=voucher.pk) self.assertEqual(voucher.num_basket_additions, 4)
def test_voucher_single_usage(self): user = AnonymousUser() creator = OrderCreator() product = factories.ProductFactory() voucher = factories.VoucherFactory(usage=Voucher.SINGLE_USE) voucher.offers.add(factories.create_offer(offer_type='Voucher')) # Make the order creator a bit more slow too reliable trigger # concurrency issues org_create_order_model = OrderCreator.create_order_model def new_create_order_model(*args, **kwargs): time.sleep(0.5) return org_create_order_model(creator, *args, **kwargs) creator.create_order_model = new_create_order_model org_record_voucher_usage = OrderCreator.record_voucher_usage def record_voucher_usage(*args, **kwargs): time.sleep(0.5) return org_record_voucher_usage(creator, *args, **kwargs) creator.record_voucher_usage = record_voucher_usage # Start 5 threads to place an order concurrently def worker(): order_number = threading.current_thread().name basket = factories.BasketFactory() basket.add_product(product) basket.vouchers.add(voucher) surcharges = SurchargeApplicator().get_applicable_surcharges( basket) place_order(creator, surcharges=surcharges, basket=basket, order_number=order_number, user=user) exceptions = run_concurrently(worker, num_threads=5) voucher.refresh_from_db() assert all(isinstance(x, ValueError) for x in exceptions), exceptions assert len(exceptions) == 4 assert voucher.applications.count() == 1 assert Order.objects.count() == 1
def test_post_valid(self): voucher = factories.VoucherFactory() self.assertTrue(voucher.is_active()) data = { 'code': voucher.code } request = RequestFactory().post('/', data=data) request.basket.save() view = views.VoucherAddView.as_view() response = view(request) self.assertEqual(response.status_code, 302) voucher = voucher.__class__.objects.get(pk=voucher.pk) self.assertEqual(voucher.num_basket_additions, 1, msg=self._get_voucher_message(request))
def _create_coupon_product_with_attributes(self, note='note', notify_email=None): """Helper method that creates a coupon product with note and notify_email attributes.""" coupon_product = factories.ProductFactory( title=self.COUPON_PRODUCT_TITLE, product_class=self.coupon_product_class, categories=[]) voucher = factories.VoucherFactory() coupon_vouchers = CouponVouchers.objects.create(coupon=coupon_product) coupon_vouchers.vouchers.add(voucher) coupon_product.attr.coupon_vouchers = coupon_vouchers coupon_product.attr.note = note if notify_email: coupon_product.attr.notify_email = notify_email coupon_product.save() return coupon_product