Example #1
0
def test_add_invalid_product():
    shop = get_default_shop()
    supplier = get_default_supplier()
    request = get_request_with_basket()
    basket = request.basket

    # cannot add simple/variable variation parent to the basket
    parent = create_product("parent", shop=shop, supplier=supplier)
    child = create_product("child", shop=shop, supplier=supplier)
    child.link_to_parent(parent)
    parent.refresh_from_db()
    assert parent.mode == ProductMode.SIMPLE_VARIATION_PARENT

    with pytest.raises(ValidationError) as excinfo:
        basket_commands.handle_add(request, basket, product_id=parent.pk, quantity=2)
    assert excinfo.value.code == 'invalid_product'

    child.unlink_from_parent()
    child.link_to_parent(parent, variables={"size": "XXL"})
    parent.refresh_from_db()
    assert parent.mode == ProductMode.VARIABLE_VARIATION_PARENT

    with pytest.raises(ValidationError) as excinfo:
        basket_commands.handle_add(request, basket, product_id=parent.pk, quantity=3)
    assert excinfo.value.code == 'invalid_product'
Example #2
0
    def create(self, request, *args, **kwargs):
        basket = self.get_basket()
        serializer = self.get_serializer_class()(data=request.data)
        serializer.is_valid(raise_exception=True)
        try:
            product = serializer.validated_data['product']
            product.get_shop_instance(shop=self.request.shop)
        except ObjectDoesNotExist:
            return ValidationError({
                'code': 'product_not_available',
                'error': [_('The requested product does not exists or is not available in the current store')]
            })
        try:
            handle_add(PricingContext(self.request.shop, basket.customer),
                       basket, product.id, serializer.validated_data['quantity'])
            basket.save()
        except ShopMismatchBasketCompatibilityError:
            raise ValidationError({
                'code': 'shop_mismatch',
                'error': _('The requested belongs to another shop')
            })

        # trigger reload, otherwise we have a cached version
        new_basket = self.get_basket()
        return Response(APIBasketSerializer(new_basket, context={'request': self.request}).data)
Example #3
0
def test_parallel_baskets(rf):
    request = get_request_with_basket()
    shop = get_default_shop()
    customer = create_random_person()

    request = rf.get("/")
    request.shop = shop
    apply_request_middleware(request)
    request.customer = customer

    basket_one = get_basket(request, basket_name="basket_one")
    basket_two = get_basket(request, basket_name="basket_two")

    product_one = get_default_product()
    product_two = get_default_product()
    product_two.sku = "derpy-hooves"
    sales_unit = SalesUnit.objects.create(identifier="test-sales-partial", decimals=2, name="Partial unit")
    product_two.sales_unit = sales_unit  # Set the sales unit for the product
    product_two.save()

    basket_commands.handle_add(request, basket_one, product_id=product_one.pk, quantity=1)
    basket_commands.handle_add(request, basket_two, product_id=product_two.pk, quantity=3.5)

    assert basket_one.product_count == 1
    assert basket_two.product_count == 3.5
Example #4
0
def test_add_and_remove_and_clear():
    product = create_product('fractionable', fractional=True)
    complete_product(product)
    supplier = get_default_supplier()
    request = get_request_with_basket()
    basket = request.basket

    with pytest.raises(ValidationError):
        # Ordering antimatter is not supported
        basket_commands.handle_add(request, basket, product_id=product.pk, quantity=-3)

    # These will get merged into one line...
    basket_commands.handle_add(request, basket, **{"product_id": product.pk, "quantity": 1, "supplier_id": supplier.pk})
    basket_commands.handle_add(request, basket, **{"product_id": product.pk, "quantity": 2})

    # Fractions should also be supported
    basket_commands.handle_add(request, basket, **{"product_id": product.pk, "quantity": 0.75})

    # ... so there will be 3 products but one line
    assert basket.product_count == 3.75
    lines = basket.get_lines()
    assert len(lines) == 1
    # ... and deleting that line will clear the basket...
    basket_commands.handle_del(request, basket, lines[0].line_id)
    assert basket.product_count == 0
    # ... and adding another product will create a new line...
    basket_commands.handle_add(request, basket, product_id=product.pk, quantity=1)
    assert basket.product_count == 1
    # ... that can be cleared.
    basket_commands.handle_clear(request, basket)
    assert basket.product_count == 0
Example #5
0
def test_basket_update_errors():
    request = get_request_with_basket()
    basket = request.basket
    product = get_default_product()
    basket_commands.handle_add(request, basket, product_id=product.pk, quantity=1)

    # Hide product and now updating quantity should give errors
    shop_product = product.get_shop_instance(request.shop)
    shop_product.suppliers.clear()

    line_id = basket.get_lines()[0].line_id
    basket_commands.handle_update(request, basket, **{"q_%s" % line_id: "2"})
    error_messages = messages.get_messages(request)
    # One warning is added to messages
    assert len(error_messages) == 1
    assert any("not supplied" in msg.message for msg in error_messages)

    shop_product.visible = False
    shop_product.save()

    basket_commands.handle_update(request, basket, **{"q_%s" % line_id: "2"})

    error_messages = messages.get_messages(request)
    # Two warnings is added to messages
    assert len(error_messages) == 3
    assert any("not visible" in msg.message for msg in error_messages)
    assert all("[" not in msg.message for msg in error_messages)
Example #6
0
def test_basket_partial_quantity_update():
    request = get_request_with_basket()
    basket = request.basket
    product = get_default_product()

    sales_unit = SalesUnit.objects.create(identifier="test-sales-partial", decimals=2, name="Partial unit")
    product.sales_unit = sales_unit  # Set the sales unit for the product
    product.save()

    basket_commands.handle_add(request, basket, product_id=product.pk, quantity=1.5)
    assert basket.product_count == 1.5
    line_id = basket.get_lines()[0].line_id
    basket_commands.handle_update(request, basket, **{"q_%s" % line_id: "1.5"})
    assert basket.product_count == 1.5

    basket_commands.handle_update(request, basket, **{"q_%s" % line_id: "3.5"})
    assert basket.product_count == 3.5

    basket_commands.handle_update(request, basket, **{"q_%s" % line_id: "3.0"})
    assert basket.product_count == 3.0

    basket_commands.handle_update(request, basket, **{"q_%s" % line_id: "4"})
    assert basket.product_count == 4

    basket_commands.handle_update(request, basket, **{"delete_%s" % line_id: "1"})
    assert basket.product_count == 0
Example #7
0
def test_basket_partial_quantity_update():
    request = get_request_with_basket()
    basket = request.basket
    product = get_default_product()

    sales_unit = SalesUnit.objects.create(identifier="test-sales-partial", decimals=2, name="Partial unit")
    product.sales_unit = sales_unit  # Set the sales unit for the product
    product.save()

    basket_commands.handle_add(request, basket, product_id=product.pk, quantity=1.5)
    assert basket.product_count == 1.5
    line_id = basket.get_lines()[0].line_id
    basket_commands.handle_update(request, basket, **{"q_%s" % line_id: "1.5"})
    assert basket.product_count == 1.5

    basket_commands.handle_update(request, basket, **{"q_%s" % line_id: "3.5"})
    assert basket.product_count == 3.5

    basket_commands.handle_update(request, basket, **{"q_%s" % line_id: "3.0"})
    assert basket.product_count == 3.0

    basket_commands.handle_update(request, basket, **{"q_%s" % line_id: "4"})
    assert basket.product_count == 4

    basket_commands.handle_update(request, basket, **{"delete_%s" % line_id: "1"})
    assert basket.product_count == 0
Example #8
0
def test_parallel_baskets(rf):
    request = get_request_with_basket()
    shop = get_default_shop()
    customer = create_random_person()

    request = rf.get("/")
    request.shop = shop
    apply_request_middleware(request)
    request.customer = customer

    basket_one = get_basket(request, basket_name="basket_one")
    basket_two = get_basket(request, basket_name="basket_two")

    product_one = get_default_product()
    product_two = get_default_product()
    product_two.sku = "derpy-hooves"
    sales_unit = SalesUnit.objects.create(identifier="test-sales-partial", decimals=2, name="Partial unit")
    product_two.sales_unit = sales_unit  # Set the sales unit for the product
    product_two.save()

    basket_commands.handle_add(request, basket_one, product_id=product_one.pk, quantity=1)
    basket_commands.handle_add(request, basket_two, product_id=product_two.pk, quantity=3.5)

    assert basket_one.product_count == 1
    assert basket_two.product_count == 3.5
Example #9
0
def test_add_and_remove_and_clear():
    product = create_product('fractionable', fractional=True)
    complete_product(product)
    supplier = get_default_supplier()
    request = get_request_with_basket()
    basket = request.basket

    with pytest.raises(ValidationError):
        # Ordering antimatter is not supported
        basket_commands.handle_add(request, basket, product_id=product.pk, quantity=-3)

    # These will get merged into one line...
    basket_commands.handle_add(request, basket, **{"product_id": product.pk, "quantity": 1, "supplier_id": supplier.pk})
    basket_commands.handle_add(request, basket, **{"product_id": product.pk, "quantity": 2})

    # Fractions should also be supported
    basket_commands.handle_add(request, basket, **{"product_id": product.pk, "quantity": 0.75})

    # ... so there will be 3 products but one line
    assert basket.product_count == 3.75
    lines = basket.get_lines()
    assert len(lines) == 1
    # ... and deleting that line will clear the basket...
    basket_commands.handle_del(request, basket, lines[0].line_id)
    assert basket.product_count == 0
    # ... and adding another product will create a new line...
    basket_commands.handle_add(request, basket, product_id=product.pk, quantity=1)
    assert basket.product_count == 1
    # ... that can be cleared.
    basket_commands.handle_clear(request, basket)
    assert basket.product_count == 0
Example #10
0
def test_add_invalid_product():
    shop = get_default_shop()
    supplier = get_default_supplier()
    request = get_request_with_basket()
    basket = request.basket

    # cannot add simple/variable variation parent to the basket
    parent = create_product("parent", shop=shop, supplier=supplier)
    child = create_product("child", shop=shop, supplier=supplier)
    child.link_to_parent(parent)
    parent.refresh_from_db()
    assert parent.mode == ProductMode.SIMPLE_VARIATION_PARENT

    with pytest.raises(ValidationError) as excinfo:
        basket_commands.handle_add(request,
                                   basket,
                                   product_id=parent.pk,
                                   quantity=2)
    assert excinfo.value.code == "invalid_product"

    child.unlink_from_parent()
    child.link_to_parent(parent, variables={"size": "XXL"})
    parent.refresh_from_db()
    assert parent.mode == ProductMode.VARIABLE_VARIATION_PARENT

    with pytest.raises(ValidationError) as excinfo:
        basket_commands.handle_add(request,
                                   basket,
                                   product_id=parent.pk,
                                   quantity=3)
    assert excinfo.value.code == "invalid_product"
Example #11
0
def test_basket_update_errors():
    request = get_request_with_basket()
    basket = request.basket
    product = get_default_product()
    basket_commands.handle_add(request,
                               basket,
                               product_id=product.pk,
                               quantity=1)

    # Hide product and now updating quantity should give errors
    shop_product = product.get_shop_instance(request.shop)
    shop_product.suppliers.clear()

    line_id = basket.get_lines()[0].line_id
    basket_commands.handle_update(request, basket, **{"q_%s" % line_id: "2"})
    error_messages = messages.get_messages(request)
    # One warning is added to messages
    assert len(error_messages) == 1
    assert any("not supplied" in msg.message for msg in error_messages)

    shop_product.visible = False
    shop_product.save()

    basket_commands.handle_update(request, basket, **{"q_%s" % line_id: "2"})

    error_messages = messages.get_messages(request)
    # Two warnings is added to messages
    assert len(error_messages) == 3
    assert any("not visible" in msg.message for msg in error_messages)
    assert all("[" not in msg.message for msg in error_messages)
Example #12
0
def test_basket_update():
    request = get_request_with_basket()
    basket = request.basket
    product = get_default_product()
    basket_commands.handle_add(request, basket, product_id=product.pk, quantity=1)
    assert basket.product_count == 1
    line_id = basket.get_lines()[0].line_id
    basket_commands.handle_update(request, basket, **{"q_%s" % line_id: "2"})
    assert basket.product_count == 2
    basket_commands.handle_update(request, basket, **{"delete_%s" % line_id: "1"})
    assert basket.product_count == 0
Example #13
0
def test_basket_update():
    request = get_request_with_basket()
    basket = request.basket
    product = get_default_product()
    basket_commands.handle_add(request, basket, product_id=product.pk, quantity=1)
    assert basket.product_count == 1
    line_id = basket.get_lines()[0].line_id
    basket_commands.handle_update(request, basket, **{"q_%s" % line_id: "2"})
    assert basket.product_count == 2
    basket_commands.handle_update(request, basket, **{"delete_%s" % line_id: "1"})
    assert basket.product_count == 0
Example #14
0
def test_basket_update():
    request = get_request_with_basket()
    basket = request.basket
    product = create_product('fractionable', fractional=True)
    complete_product(product)
    basket_commands.handle_add(request, basket, product_id=product.pk, quantity=1.75)
    assert basket.product_count == 1.75
    line_id = basket.get_lines()[0].line_id
    basket_commands.handle_update(request, basket, **{"q_%s" % line_id: "2"})
    assert basket.product_count == 2
    basket_commands.handle_update(request, basket, **{"delete_%s" % line_id: "1"})
    assert basket.product_count == 0
Example #15
0
def test_basket_update():
    request = get_request_with_basket()
    basket = request.basket
    product = create_product('fractionable', fractional=True)
    complete_product(product)
    basket_commands.handle_add(request, basket, product_id=product.pk, quantity=1.75)
    assert basket.product_count == 1.75
    line_id = basket.get_lines()[0].line_id
    basket_commands.handle_update(request, basket, **{"q_%s" % line_id: "2"})
    assert basket.product_count == 2
    basket_commands.handle_update(request, basket, **{"delete_%s" % line_id: "1"})
    assert basket.product_count == 0
Example #16
0
def test_add_and_invalid_product():
    shop = get_default_shop()
    product = create_product('fractionable', fractional=True)
    complete_product(product)
    supplier = get_default_supplier()
    request = get_request_with_basket()
    basket = request.basket

    # remove the shop product
    product.get_shop_instance(shop).delete()

    with pytest.raises(ValidationError) as exc:
        basket_commands.handle_add(request, basket, **{
            "product_id": product.pk, "quantity": 1, "supplier_id": supplier.pk
        })
    assert "Product not available in this shop" in exc.value.message
Example #17
0
def test_add_and_invalid_product():
    shop = get_default_shop()
    product = create_product('fractionable', fractional=True)
    complete_product(product)
    supplier = get_default_supplier()
    request = get_request_with_basket()
    basket = request.basket

    # remove the shop product
    product.get_shop_instance(shop).delete()

    with pytest.raises(ValidationError) as exc:
        basket_commands.handle_add(request, basket, **{
            "product_id": product.pk, "quantity": 1, "supplier_id": supplier.pk
        })
    assert "Product not available in this shop" in exc.value.message
Example #18
0
def test_basket_update_with_package_product():
    if "shuup.simple_supplier" not in settings.INSTALLED_APPS:
        pytest.skip("Need shuup.simple_supplier in INSTALLED_APPS")
    from shuup_tests.simple_supplier.utils import get_simple_supplier

    request = get_request_with_basket()
    basket = request.basket
    shop = get_default_shop()
    supplier = get_simple_supplier()
    parent, child = get_unstocked_package_product_and_stocked_child(shop, supplier, child_logical_quantity=2)

    # There should be enough stock for 1 parent and 1 extra child, each of quantity 1
    basket_commands.handle_add(request, basket, product_id=parent.pk, quantity=1)
    assert basket.product_count == 1
    basket_commands.handle_add(request, basket, product_id=child.pk, quantity=1)
    assert basket.product_count == 2
    assert not messages.get_messages(request)

    basket_lines = {line.product.id: line for line in basket.get_lines()}
    package_line = basket_lines[parent.id]
    extra_child_line = basket_lines[child.id]

    # Trying to increase package product line quantity should fail, with error message
    basket_commands.handle_update(request, basket, **{"q_%s" % package_line.line_id: "2"})
    assert basket.product_count == 2
    assert len(messages.get_messages(request)) == 1

    # So should increasing the extra child line quantity
    basket_commands.handle_update(request, basket, **{"q_%s" % extra_child_line.line_id: "2"})
    assert basket.product_count == 2
    assert len(messages.get_messages(request)) == 2

    # However, if we delete the parent line, we can increase the extra child
    basket_commands.handle_update(request, basket, **{"delete_%s" % package_line.line_id: "1"})
    assert basket.product_count == 1
    basket_commands.handle_update(request, basket, **{"q_%s" % extra_child_line.line_id: "2"})
    assert basket.product_count == 2

    # Resetting to original basket contents
    basket_commands.handle_update(request, basket, **{"q_%s" % extra_child_line.line_id: "1"})
    basket_commands.handle_add(request, basket, product_id=parent.pk, quantity=1)
    basket_lines = {line.product.id: line for line in basket.get_lines()}
    package_line = basket_lines[parent.id]  # Package line will have a new ID
    assert basket.product_count == 2

    # Like above, delete the child line and we can now increase the parent
    basket_commands.handle_update(request, basket, **{"delete_%s" % extra_child_line.line_id: "1"})
    assert basket.product_count == 1
    basket_commands.handle_update(request, basket, **{"q_%s" % package_line.line_id: "2"})
    assert basket.product_count == 2
Example #19
0
def test_basket_update_with_package_product():
    if "shuup.simple_supplier" not in settings.INSTALLED_APPS:
        pytest.skip("Need shuup.simple_supplier in INSTALLED_APPS")
    from shuup_tests.simple_supplier.utils import get_simple_supplier

    request = get_request_with_basket()
    basket = request.basket
    shop = get_default_shop()
    supplier = get_simple_supplier()
    parent, child = get_unstocked_package_product_and_stocked_child(shop, supplier, child_logical_quantity=2)

    # There should be enough stock for 1 parent and 1 extra child, each of quantity 1
    basket_commands.handle_add(request, basket, product_id=parent.pk, quantity=1)
    assert basket.product_count == 1
    basket_commands.handle_add(request, basket, product_id=child.pk, quantity=1)
    assert basket.product_count == 2
    assert not messages.get_messages(request)

    basket_lines = {line.product.id: line for line in basket.get_lines()}
    package_line = basket_lines[parent.id]
    extra_child_line = basket_lines[child.id]

    # Trying to increase package product line quantity should fail, with error message
    basket_commands.handle_update(request, basket, **{"q_%s" % package_line.line_id: "2"})
    assert basket.product_count == 2
    assert len(messages.get_messages(request)) == 1

    # So should increasing the extra child line quantity
    basket_commands.handle_update(request, basket, **{"q_%s" % extra_child_line.line_id: "2"})
    assert basket.product_count == 2
    assert len(messages.get_messages(request)) == 2

    # However, if we delete the parent line, we can increase the extra child
    basket_commands.handle_update(request, basket, **{"delete_%s" % package_line.line_id: "1"})
    assert basket.product_count == 1
    basket_commands.handle_update(request, basket, **{"q_%s" % extra_child_line.line_id: "2"})
    assert basket.product_count == 2

    # Resetting to original basket contents
    basket_commands.handle_update(request, basket, **{"q_%s" % extra_child_line.line_id: "1"})
    basket_commands.handle_add(request, basket, product_id=parent.pk, quantity=1)
    basket_lines = {line.product.id: line for line in basket.get_lines()}
    package_line = basket_lines[parent.id]  # Package line will have a new ID
    assert basket.product_count == 2

    # Like above, delete the child line and we can now increase the parent
    basket_commands.handle_update(request, basket, **{"delete_%s" % extra_child_line.line_id: "1"})
    assert basket.product_count == 1
    basket_commands.handle_update(request, basket, **{"q_%s" % package_line.line_id: "2"})
    assert basket.product_count == 2
Example #20
0
def test_basket_update_with_package_product():
    if "shuup.simple_supplier" not in settings.INSTALLED_APPS:
        pytest.skip("Need shuup.simple_supplier in INSTALLED_APPS")
    from shuup_tests.simple_supplier.utils import get_simple_supplier

    request = get_request_with_basket()
    basket = request.basket
    shop = get_default_shop()
    supplier = get_simple_supplier()
    parent, child = get_unstocked_package_product_and_stocked_child(shop, supplier, child_logical_quantity=2)

    # There should be enough stock for 1 parent and 1 extra child, each of quantity 1
    basket_commands.handle_add(request, basket, product_id=parent.pk, quantity=1)
    assert basket.product_count == 1
    basket_commands.handle_add(request, basket, product_id=child.pk, quantity=1)
    assert basket.product_count == 2
    assert not messages.get_messages(request)

    basket_lines = {line.product.id: line for line in basket.get_lines()}
    package_line = basket_lines[parent.id]
    extra_child_line = basket_lines[child.id]

    # Trying to increase package product line quantity should fail, with error message
    basket_commands.handle_update(request, basket, **{"q_%s" % package_line.line_id: "2"})
    assert basket.product_count == 2
    assert len(messages.get_messages(request)) == 1

    # So should increasing the extra child line quantity
    basket_commands.handle_update(request, basket, **{"q_%s" % extra_child_line.line_id: "2"})
    assert basket.product_count == 2
    assert len(messages.get_messages(request)) == 2

    # However, if we delete the parent line, we can increase the extra child
    basket_commands.handle_update(request, basket, **{"delete_%s" % package_line.line_id: "1"})
    assert basket.product_count == 1
    basket_commands.handle_update(request, basket, **{"q_%s" % extra_child_line.line_id: "2"})
    assert basket.product_count == 2

    # Resetting to original basket contents
    basket_commands.handle_update(request, basket, **{"q_%s" % extra_child_line.line_id: "1"})
    basket_commands.handle_add(request, basket, product_id=parent.pk, quantity=1)
    basket_lines = {line.product.id: line for line in basket.get_lines()}
    package_line = basket_lines[parent.id]  # Package line will have a new ID
    assert basket.product_count == 2

    # Like above, delete the child line and we can now increase the parent
    basket_commands.handle_update(request, basket, **{"delete_%s" % extra_child_line.line_id: "1"})
    assert basket.product_count == 1
    basket_commands.handle_update(request, basket, **{"q_%s" % package_line.line_id: "2"})
    assert basket.product_count == 2

    # Clear basket
    basket_commands.handle_clear(request, basket)
    assert basket.product_count == 0

    # Remove the Shop Product from the child
    child.get_shop_instance(shop).delete()

    # Child not available for this shop
    with pytest.raises(ProductNotOrderableProblem):
        basket_commands.handle_add(request, basket, product_id=parent.pk, quantity=1)

    # use the update methods object to check orderability errors
    update_methods = BasketUpdateMethods(request, basket)
    errors = update_methods._get_orderability_errors(parent, supplier, 1)
    assert len(errors) == 2
    assert any(["product_not_available_in_shop" in error.code for error in errors])
Example #21
0
def test_basket_update_with_package_product():
    if "shuup.simple_supplier" not in settings.INSTALLED_APPS:
        pytest.skip("Need shuup.simple_supplier in INSTALLED_APPS")
    from shuup_tests.simple_supplier.utils import get_simple_supplier

    request = get_request_with_basket()
    basket = request.basket
    shop = get_default_shop()
    supplier = get_simple_supplier()
    parent, child = get_unstocked_package_product_and_stocked_child(
        shop, supplier, child_logical_quantity=2)

    # There should be enough stock for 1 parent and 1 extra child, each of quantity 1
    basket_commands.handle_add(request,
                               basket,
                               product_id=parent.pk,
                               quantity=1)
    assert basket.product_count == 1
    basket_commands.handle_add(request,
                               basket,
                               product_id=child.pk,
                               quantity=1)
    assert basket.product_count == 2
    assert not messages.get_messages(request)

    basket_lines = {line.product.id: line for line in basket.get_lines()}
    package_line = basket_lines[parent.id]
    extra_child_line = basket_lines[child.id]

    # Trying to increase package product line quantity should fail, with error message
    basket_commands.handle_update(request, basket,
                                  **{"q_%s" % package_line.line_id: "2"})
    assert basket.product_count == 2
    assert len(messages.get_messages(request)) == 1

    # So should increasing the extra child line quantity
    basket_commands.handle_update(request, basket,
                                  **{"q_%s" % extra_child_line.line_id: "2"})
    assert basket.product_count == 2
    assert len(messages.get_messages(request)) == 2

    # However, if we delete the parent line, we can increase the extra child
    basket_commands.handle_update(request, basket,
                                  **{"delete_%s" % package_line.line_id: "1"})
    assert basket.product_count == 1
    basket_commands.handle_update(request, basket,
                                  **{"q_%s" % extra_child_line.line_id: "2"})
    assert basket.product_count == 2

    # Resetting to original basket contents
    basket_commands.handle_update(request, basket,
                                  **{"q_%s" % extra_child_line.line_id: "1"})
    basket_commands.handle_add(request,
                               basket,
                               product_id=parent.pk,
                               quantity=1)
    basket_lines = {line.product.id: line for line in basket.get_lines()}
    package_line = basket_lines[parent.id]  # Package line will have a new ID
    assert basket.product_count == 2

    # Like above, delete the child line and we can now increase the parent
    basket_commands.handle_update(
        request, basket, **{"delete_%s" % extra_child_line.line_id: "1"})
    assert basket.product_count == 1
    basket_commands.handle_update(request, basket,
                                  **{"q_%s" % package_line.line_id: "2"})
    assert basket.product_count == 2

    # Clear basket
    basket_commands.handle_clear(request, basket)
    assert basket.product_count == 0

    # Remove the Shop Product from the child
    child.get_shop_instance(shop).delete()

    # Child not available for this shop
    with pytest.raises(ProductNotOrderableProblem):
        basket_commands.handle_add(request,
                                   basket,
                                   product_id=parent.pk,
                                   quantity=1)

    # use the update methods object to check orderability errors
    update_methods = BasketUpdateMethods(request, basket)
    errors = update_methods._get_orderability_errors(parent, supplier, 1)
    assert len(errors) == 2
    assert any(
        ["product_not_available_in_shop" in error.code for error in errors])