Example #1
0
    def test_checks_if_purchase_is_permitted(self):
        basket = factories.BasketFactory()
        product = factories.ProductFactory()

        # Build a 4-level mock monster so we can force the return value of
        # whether the product is available to buy. This is a serious code smell
        # and needs to be remedied.
        info = mock.Mock()
        info.availability = mock.Mock()
        info.availability.is_purchase_permitted = mock.Mock(
            return_value=(False, "Not on your nelly!"))
        basket.strategy.fetch_for_product = mock.Mock(return_value=info)

        data = {'quantity': 1}
        form = forms.AddToBasketForm(basket=basket, product=product, data=data)
        self.assertFalse(form.is_valid())
        self.assertEqual('Not on your nelly!', form.errors['__all__'][0])
Example #2
0
 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
Example #3
0
    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)
            place_order(creator,
                        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
Example #4
0
    def test_cancel_stock_allocations_track_stock_on(self):
        product_class = factories.ProductClassFactory(requires_shipping=False,
                                                      track_stock=True)
        product = factories.ProductFactory(product_class=product_class)
        basket = factories.create_basket(empty=True)
        add_product(basket, D('10.00'), 5, product=product)
        order = factories.create_order(basket=basket)

        stockrecord = product.stockrecords.get()
        num_allocated = stockrecord.num_allocated

        lines = order.lines.all()
        self.handler.cancel_stock_allocations(
            order, lines, [line.quantity for line in lines])

        stockrecord.refresh_from_db()
        self.assertEqual(stockrecord.num_allocated, num_allocated - 5,
                         "Allocated stock should have decreased, but didn't.")
Example #5
0
    def test_mixed_currency_baskets_are_not_permitted(self):
        # Ensure basket is one currency
        basket = mock.Mock()
        basket.currency = 'GBP'
        basket.num_items = 1

        # Ensure new product has different currency
        info = mock.Mock()
        info.price.currency = 'EUR'
        basket.strategy.fetch_for_product = mock.Mock(
            return_value=info)

        product = factories.ProductFactory()

        data = {'quantity': 1}
        form = forms.AddToBasketForm(
            basket=basket, product=product, data=data)
        self.assertFalse(form.is_valid())
Example #6
0
    def test_consume_stock_allocations_without_line_arguments(self):
        product_class = factories.ProductClassFactory(requires_shipping=False,
                                                      track_stock=True)
        product = factories.ProductFactory(product_class=product_class)
        basket = factories.create_basket(empty=True)
        add_product(basket, D('10.00'), 5, product=product)
        order = factories.create_order(basket=basket)

        stockrecord = product.stockrecords.get()
        num_in_stock = stockrecord.num_in_stock
        num_allocated = stockrecord.num_allocated

        self.handler.consume_stock_allocations(order)

        stockrecord.refresh_from_db()
        self.assertEqual(stockrecord.num_allocated, num_allocated - 5,
                         "Allocated stock should have decreased, but didn't.")
        self.assertEqual(stockrecord.num_in_stock, num_in_stock - 5,
                         "Stock should have decreased, but didn't.")
    def test_attributes_initialised_before_write(self):
        # Regression test for https://github.com/django-oscar/django-oscar/issues/3258
        product_class = factories.ProductClassFactory()
        product_class.attributes.create(name='a1', code='a1', required=True)
        product_class.attributes.create(name='a2', code='a2', required=False)
        product_class.attributes.create(name='a3', code='a3', required=True)
        product = factories.ProductFactory(product_class=product_class)
        product.attr.a1 = "v1"
        product.attr.a3 = "v3"
        product.attr.save()

        product = Product.objects.get(pk=product.pk)
        product.attr.a1 = "v2"
        product.attr.a3 = "v6"
        product.attr.save()

        product = Product.objects.get(pk=product.pk)
        assert product.attr.a1 == "v2"
        assert product.attr.a3 == "v6"
Example #8
0
 def test_voucher_not_valid_for_bundle(self):
     """ Verify correct error message is returned when voucher is used against a bundle. """
     self.mock_access_token_response()
     self.mock_account_api(self.request,
                           self.user.username,
                           data={'is_active': True})
     voucher, product = prepare_voucher(code=COUPON_CODE, benefit_value=0)
     new_product = factories.ProductFactory(
         categories=[], stockrecords__partner__short_code='second')
     self.basket.add_product(product)
     self.basket.add_product(new_product)
     BasketAttributeType.objects.get_or_create(name=BUNDLE)
     BasketAttribute.objects.update_or_create(
         basket=self.basket,
         attribute_type=BasketAttributeType.objects.get(name=BUNDLE),
         value_text='test_bundle')
     self.assert_form_valid_message(
         "Coupon code '{code}' is not valid for this basket.".format(
             code=voucher.code))
Example #9
0
    def test_are_stock_allocations_available(self):
        product_class = factories.ProductClassFactory(requires_shipping=False,
                                                      track_stock=True)
        product = factories.ProductFactory(product_class=product_class)

        basket = factories.create_basket(empty=True)
        add_product(basket, D('10.00'), 5, product=product)
        order = factories.create_order(basket=basket)

        line = order.lines.get()
        self.assertEqual(
            self.handler.are_stock_allocations_available([line],
                                                         [line.quantity]),
            True,
        )

        self.assertEqual(
            self.handler.are_stock_allocations_available([line], [105]),
            False,
        )
Example #10
0
    def setUp(self):
        super(TestProductClass, self).setUp()
        self.pclass = ProductClassFactory(name='T-Shirts', slug='tshirts')

        for attribute_type, __ in ProductAttribute.TYPE_CHOICES:
            values = {
                'type': attribute_type,
                'code': attribute_type,
                'product_class': self.pclass,
                'name': attribute_type,
            }
            if attribute_type == ProductAttribute.OPTION:
                option_group = factories.AttributeOptionGroupFactory()
                self.option = factories.AttributeOptionFactory(
                    group=option_group)
                values['option_group'] = option_group
            ProductAttributeFactory(**values)
        self.product = factories.ProductFactory(product_class=self.pclass)
        self.url = reverse('dashboard:catalogue-product',
                           kwargs={'pk': self.product.id})
    def test_single_usage(self):
        user = AnonymousUser()
        creator = OrderCreator()
        product = factories.ProductFactory(stockrecords__num_in_stock=1000)

        # 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

        # Start 5 threads to place an order concurrently
        def worker():
            order_number = threading.current_thread().name

            basket = factories.BasketFactory()
            basket.add_product(product)
            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)

        assert all(isinstance(x, ValueError) for x in exceptions), exceptions
        assert len(exceptions) == 0
        assert Order.objects.count() == 5

        stockrecord = product.stockrecords.first()
        assert stockrecord.num_allocated == 5
    def _create_program_with_courses_and_offer(self):
        offer = ProgramOfferFactory(
            site=self.site,
            partner=self.site.siteconfiguration.partner,
            benefit=PercentageDiscountBenefitWithoutRangeFactory(value=20))
        program_uuid = offer.condition.program_uuid
        program_data = self.mock_program_detail_endpoint(
            program_uuid, self.site_configuration.discovery_api_url)
        self.mock_user_data(self.user.username)

        sku_list = []
        products = []
        for course in program_data['courses']:
            sku_list.append(course['entitlements'][0]['sku'])

        for sku in sku_list:
            products.append(
                factories.ProductFactory(
                    stockrecords__partner=self.partner,
                    stockrecords__price_excl_tax=Decimal('10.00'),
                    stockrecords__partner_sku=sku,
                ))
        return products, program_uuid
 def test_validates_that_child_products_dont_need_a_title(self):
     parent = factories.ProductFactory(product_class=self.product_class,
                                       structure='parent')
     form = self.submit({'structure': 'child'}, parent=parent)
     self.assertTrue(form.is_valid())
Example #14
0
 def setUp(self):
     product_class = factories.ProductClassFactory(
         requires_shipping=False, track_stock=False)
     self.product = factories.ProductFactory(product_class=product_class)
     self.stockrecord = factories.create_stockrecord(
         self.product, price_excl_tax=D('10.00'), num_in_stock=10)
Example #15
0
 def setUp(self):
     super(InvoiceManagementCommandExceptionsTest, self).setUp()
     self.product = factories.ProductFactory(product_class=ProductClass.objects.get(name='Coupon'))
     self.basket = factories.BasketFactory()
     self.basket.add_product(self.product, 1)
     self.basket.submit()
    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 = {}
Example #17
0
 def test_pricing_policy_unavailable_if_no_price_excl_tax(self):
     product = factories.ProductFactory(stockrecords=[])
     factories.StockRecordFactory(price_excl_tax=None, product=product)
     info = strategy.US().fetch_for_product(product)
     self.assertFalse(info.price.exists)
Example #18
0
 def test_product_with_empty_price(self):
     product_class = factories.ProductClassFactory(track_stock=False)
     product = factories.ProductFactory(product_class=product_class, stockrecords=[])
     factories.StockRecordFactory(price_excl_tax=None, product=product)
     info = self.strategy.fetch_for_product(product)
     self.assertFalse(info.availability.is_available_to_buy)
 def test_save_multi_option_value(self):
     product = factories.ProductFactory()
     # We'll save two out of the three available options
     self.attr.save_value(product, [self.options[0], self.options[2]])
     product = Product.objects.get(pk=product.pk)
     self.assertEqual(list(product.attr.sizes), [self.options[0], self.options[2]])
 def test_option_value_as_text(self):
     product = factories.ProductFactory()
     option_2 = self.options[1]
     self.attr.save_value(product, option_2)
     attr_val = product.attribute_values.get(attribute=self.attr)
     assert attr_val.value_as_text == str(option_2)
Example #21
0
    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 test_multi_option_value_as_text(self):
     product = factories.ProductFactory()
     self.attr.save_value(product, self.options)
     attr_val = product.attribute_values.get(attribute=self.attr)
     self.assertEqual(attr_val.value_as_text, ", ".join(o.option for o in self.options))
 def setUp(self):
     super().setUp()
     self.product = factories.ProductFactory()
     self.url = reverse('dashboard:catalogue-product',
                        kwargs={'pk': self.product.id})