def add_variant_to_delivery_group(group, variant, total_quantity, discounts=None, add_to_existing=True): """Adds total_quantity of variant to group. Raises InsufficientStock exception if quantity could not be fulfilled. By default, first adds variant to existing lines with same variant. It can be disabled with setting add_to_existing to False. Order lines are created by increasing quantity of lines, as long as total_quantity of variant will be added. """ quantity_left = (add_variant_to_existing_lines( group, variant, total_quantity) if add_to_existing else total_quantity) price = variant.get_price_per_item(discounts) while quantity_left > 0: stock = variant.select_stockrecord() if not stock: raise InsufficientStock(variant) #satchless quantity = (stock.quantity_available if quantity_left > stock.quantity_available else quantity_left) group.lines.create(product=variant.product, product_name=variant.display_product(), product_sku=variant.sku, quantity=quantity, unit_price_net=price, stock=stock) allocate_stock(stock, quantity) # refresh stock for accessing quantity_allocated stock.refresh_from_db() quantity_left -= quantity
def add_items_to_delivery_group(delivery_group, partition, discounts=None): for item_line in partition: product_variant = item_line.variant price = item_line.get_price_per_item(discounts) total_quantity = item_line.get_quantity() while total_quantity > 0: stock = product_variant.select_stockrecord() if not stock: raise InsufficientStock(product_variant) quantity = (stock.quantity_available if total_quantity > stock.quantity_available else total_quantity) delivery_group.items.create( product=product_variant.product, quantity=quantity, unit_price_net=price.net, product_name=product_variant.display_product(), product_sku=product_variant.sku, unit_price_gross=price.gross, stock=stock, stock_location=stock.location.name) total_quantity -= quantity # allocate quantity to avoid overselling Stock.objects.allocate_stock(stock, quantity) # refresh for reading quantity_available in next select_stockrecord stock.refresh_from_db()
def test_contains_unavailable_variants(): missing_variant = Mock(check_quantity=Mock( side_effect=InsufficientStock(''))) cart = MagicMock() cart.lines.all.return_value = [Mock(variant=missing_variant)] assert utils.contains_unavailable_variants(cart) variant = Mock(check_quantity=Mock()) cart.lines.all.return_value = [Mock(variant=variant)] assert not utils.contains_unavailable_variants(cart)
def test_contains_unavailable_products(): missing_product = Mock(check_quantity=Mock( side_effect=InsufficientStock(''))) cart = MagicMock() cart.__iter__.return_value = [Mock(product=missing_product)] assert utils.contains_unavailable_products(cart) product = Mock(check_quantity=Mock()) cart.__iter__.return_value = [Mock(product=product)] assert not utils.contains_unavailable_products(cart)
def test_add_to_cart_form_when_insufficient_stock(): cart_lines = [] cart = Mock(add=lambda variant, quantity: cart_lines.append(variant), get_line=Mock(return_value=Mock(quantity=1))) form = forms.AddToCartForm(data={'quantity': 1}, cart=cart, product=Mock()) exception_mock = InsufficientStock( Mock(get_stock_quantity=Mock(return_value=4))) product_variant = Mock(check_quantity=Mock(side_effect=exception_mock)) form.get_variant = Mock(return_value=product_variant) assert not form.is_valid()
def add_variant_to_delivery_group(group, variant, total_quantity, discounts=None, add_to_existing=True, package_offer=False): """Adds total_quantity of variant to group. Raises InsufficientStock exception if quantity could not be fulfilled. By default, first adds variant to existing lines with same variant. It can be disabled with setting add_to_existing to False. Order lines are created by increasing quantity of lines, as long as total_quantity of variant will be added. """ quantity_left = (add_variant_to_existing_lines( group, variant, total_quantity) if add_to_existing else total_quantity) # if package_offer: price = variant.get_price_per_item(discounts) while quantity_left > 0: stock = variant.select_stockrecord() if not stock: raise InsufficientStock(variant) quantity = (stock.quantity_available if quantity_left > stock.quantity_available else quantity_left) if package_offer: unit_price_net = 0.00 unit_price_gross = 0.00 else: unit_price_net = price.net unit_price_gross = price.gross group.lines.create( product=variant.product, product_name=variant.display_product() [0:128], # TODO: do something about it product_sku=variant.sku, quantity=quantity, unit_price_net=unit_price_net, unit_price_gross=unit_price_gross, stock=stock, stock_location=stock.location.name) Stock.objects.allocate_stock(stock, quantity) # refresh stock for accessing quantity_allocated stock.refresh_from_db() quantity_left -= quantity
def test_replace_cartline_form_when_insufficient_stock(monkeypatch, cart, variant): initial_quantity = 1 replaced_quantity = 4 cart.add(variant, initial_quantity) exception_mock = InsufficientStock( Mock(get_stock_quantity=Mock(return_value=2))) monkeypatch.setattr('saleor.product.models.ProductVariant.check_quantity', Mock(side_effect=exception_mock)) data = {'quantity': replaced_quantity} form = forms.ReplaceCartLineForm(data=data, cart=cart, product=variant) assert not form.is_valid() with pytest.raises(KeyError): form.save() assert cart.quantity == initial_quantity
def fix_lines_quantities(self): for group in self.groups.all(): for item in group.lines.all(): try: if not item.quantity: raise InsufficientStock(item.variant) item.variant.check_quantity(item.quantity) except InsufficientStock: if item.quantity: item.quantity = item.variant.get_stock() if item.quantity: item.save() else: item.delete() if not group.lines.exists(): group.delete()
def check_quantity(self, quantity): available_quantity = self.get_stock_quantity() if quantity > available_quantity: raise InsufficientStock(self)