Пример #1
0
def test_formatted_decimal_field():
    """
    Test that FormattedDecimalField doesn't return value in scientific
    notation.
    """
    class TestModelForm(ModelForm):
        class Meta:
            model = Product
            fields = ["width"]

    values = [
        "0E-9", "0E-30", "1E-9", "123E-10", "-123E-10", "1.12345666666666E20"
    ]

    for value in values:
        product = Product(width=Decimal(value))
        form = TestModelForm(instance=product)
        rendered_form = force_text(form)
        rendered_value = re.search('value="(.*?)"', rendered_form).group(1)
        rendered_step = re.search('step="(.*?)"', rendered_form).group(1)
        assert rendered_value and "E" not in rendered_value
        assert rendered_step and "E" not in rendered_step

    # Extremely large exponents should raise an exception so as not to
    # produce excessively large files
    large_value = "1.23E-10000"
    product = Product(width=Decimal(large_value))
    with pytest.raises(ValueError):
        form = TestModelForm(instance=product)
Пример #2
0
def create_product(sku, shop=None, supplier=None, default_price=None, **attrs):
    if default_price is not None:
        default_price = shop.create_price(default_price)

    product_attrs = dict(
        type=get_default_product_type(),
        tax_class=get_default_tax_class(),
        sku=sku,
        name=sku.title(),
        width=100,
        height=100,
        depth=100,
        net_weight=100,
        gross_weight=100,
        sales_unit=get_default_sales_unit(),
        stock_behavior=StockBehavior.UNSTOCKED
    )
    product_attrs.update(attrs)
    product = Product(**product_attrs)
    product.full_clean()
    product.save()
    if shop:
        sp = ShopProduct.objects.create(
            product=product, shop=shop, default_price=default_price,
            visibility=ShopProductVisibility.ALWAYS_VISIBLE
        )
        if supplier:
            sp.suppliers.add(supplier)
        sp.save()

    return product
Пример #3
0
def test_model_url():
    with admin_only_urls():
        with pytest.raises(NoModelUrl):
            get_model_url(Counter)  # That's silly!
        p = Product()
        p.pk = 3
        assert get_model_url(p)
Пример #4
0
def test_model_url_with_permissions():
    permissions = set(
        ["shuup.add_product", "shuup.delete_product", "shuup.change_product"])
    p = Product()
    p.pk = 3

    # If no user is given, don't check for permissions
    assert get_model_url(p)

    # If a user is given and no permissions are provided, check for default model permissions
    user = StaffUser()
    with pytest.raises(NoModelUrl):
        assert get_model_url(p, user=user)

    # If a user is given and permissions are provided, check for those permissions
    assert get_model_url(p, user=user, required_permissions=())
    with pytest.raises(NoModelUrl):
        assert get_model_url(p,
                             user=user,
                             required_permissions=["shuup.add_product"])

    # Confirm that url is returned with correct permissions
    user.permissions = permissions
    assert get_model_url(p, user=user)
    assert get_model_url(p, user=user, required_permissions=permissions)
Пример #5
0
def test_applied_attributes():
    product = get_default_product()
    for spec in ATTR_SPECS:  # This loop sets each attribute twice. That's okay.
        attr = Attribute.objects.get(identifier=spec["identifier"])
        pa, _ = ProductAttribute.objects.get_or_create(product=product, attribute=attr)
        _populate_applied_attribute(pa)
        pa.save()
        if not attr.is_translated:
            product.set_attribute_value(attr.identifier, pa.value)

    assert product.get_attribute_value("bogomips") == 320, "integer attribute loaded neatly"
    product.set_attribute_value("bogomips", 480)
    assert product.get_attribute_value("bogomips") == 480, "integer attribute updated neatly"
    Product.cache_attributes_for_targets(
        applied_attr_cls=ProductAttribute,
        targets=[product],
        attribute_identifiers=[a["identifier"] for a in ATTR_SPECS],
        language=get_language()
    )
    assert (get_language(), "bogomips",) in product._attr_cache, "integer attribute in cache"
    assert product.get_attribute_value("bogomips") == 480, "integer attribute value in cache"
    assert product.get_attribute_value("ba:gelmips", default="Britta") == "Britta", "non-existent attributes return default value"
    assert product._attr_cache[(get_language(), "ba:gelmips")] is NoSuchAttributeHere, "cache miss saved"
    attr_info = product.get_all_attribute_info(language=get_language(), visibility_mode=AttributeVisibility.SHOW_ON_PRODUCT_PAGE)
    assert set(attr_info.keys()) <= set(a["identifier"] for a in ATTR_SPECS), "get_all_attribute_info gets all attribute info"
Пример #6
0
def test_model_url():
    with admin_only_urls():
        with pytest.raises(NoModelUrl):
            get_model_url(Counter)  # That's silly!
        p = Product()
        p.pk = 3
        assert get_model_url(p)
Пример #7
0
def test_applied_attributes():
    product = get_default_product()
    for spec in ATTR_SPECS:  # This loop sets each attribute twice. That's okay.
        attr = Attribute.objects.get(identifier=spec["identifier"])
        pa, _ = ProductAttribute.objects.get_or_create(product=product, attribute=attr)
        _populate_applied_attribute(pa)
        pa.save()
        if not attr.is_translated:
            product.set_attribute_value(attr.identifier, pa.value)

    assert product.get_attribute_value("bogomips") == 320, "integer attribute loaded neatly"
    product.set_attribute_value("bogomips", 480)
    assert product.get_attribute_value("bogomips") == 480, "integer attribute updated neatly"
    Product.cache_attributes_for_targets(
        applied_attr_cls=ProductAttribute,
        targets=[product],
        attribute_identifiers=[a["identifier"] for a in ATTR_SPECS],
        language=get_language()
    )
    assert (get_language(), "bogomips",) in product._attr_cache, "integer attribute in cache"
    assert product.get_attribute_value("bogomips") == 480, "integer attribute value in cache"
    assert product.get_attribute_value("ba:gelmips", default="Britta") == "Britta", "non-existent attributes return default value"
    assert product._attr_cache[(get_language(), "ba:gelmips")] is NoSuchAttributeHere, "cache miss saved"
    attr_info = product.get_all_attribute_info(language=get_language(), visibility_mode=AttributeVisibility.SHOW_ON_PRODUCT_PAGE)
    assert set(attr_info.keys()) <= set(a["identifier"] for a in ATTR_SPECS), "get_all_attribute_info gets all attribute info"
Пример #8
0
def test_modelform_persistence():
    with translation.override("en"):
        test_product = Product(barcode="666")
        test_product.set_current_language("en")
        test_product.name = "foo"
        frm = MultiProductForm(languages=["en"], instance=test_product, default_language="en")
        assert frm["barcode"].value() == test_product.barcode
        assert frm.initial["name"] == test_product.name
Пример #9
0
def cache_product_things(request, products, language=None, attribute_identifiers=("author",)):
    # Cache necessary things for products. WARNING: This will cause queryset iteration.
    language = language or get_language()
    # TODO: Should we cache prices here?
    if attribute_identifiers:
        Product.cache_attributes_for_targets(
            ProductAttribute, products, attribute_identifiers=attribute_identifiers, language=language
        )
    products = cache_translations(products, (language,))
    return products
Пример #10
0
def test_modelform_persistence():
    with translation.override("en"):
        test_product = Product(barcode="666")
        test_product.set_current_language("en")
        test_product.name = "foo"
        frm = MultiProductForm(languages=["en"],
                               instance=test_product,
                               default_language="en")
        assert frm["barcode"].value() == test_product.barcode
        assert frm.initial["name"] == test_product.name
Пример #11
0
def cache_product_things(request, products, language=None, attribute_identifiers=("author",)):
    # Cache necessary things for products. WARNING: This will cause queryset iteration.
    language = language or get_language()
    # TODO: Should we cache prices here?
    if attribute_identifiers:
        Product.cache_attributes_for_targets(
            ProductAttribute, products,
            attribute_identifiers=attribute_identifiers,
            language=language)
    products = cache_translations(products, (language,))
    return products
Пример #12
0
def test_modelform_persistence():
    with translation.override("en"):
        test_product = Product(barcode="666", stock_behavior=StockBehavior.STOCKED)
        test_product.set_current_language("en")
        test_product.name = "foo"
        frm = MultiProductForm(languages=["en"], instance=test_product, default_language="en")
        assert frm["barcode"].value() == test_product.barcode
        stock_behavior_field = Product._meta.get_field_by_name("stock_behavior")[0]
        assert stock_behavior_field.to_python(frm["stock_behavior"].value()) is test_product.stock_behavior
        assert 'value="1" selected="selected"' in six.text_type(frm["stock_behavior"].as_widget())
        assert frm.initial["name"] == test_product.name
Пример #13
0
def test_modelform_persistence():
    with translation.override("en"):
        test_product = Product(barcode="666", stock_behavior=StockBehavior.STOCKED)
        test_product.set_current_language("en")
        test_product.name = "foo"
        frm = MultiProductForm(languages=["en"], instance=test_product, default_language="en")
        assert frm["barcode"].value() == test_product.barcode
        stock_behavior_field = Product._meta.get_field("stock_behavior")
        assert stock_behavior_field.to_python(frm["stock_behavior"].value()) is test_product.stock_behavior
        assert 'value="1" selected' in six.text_type(frm["stock_behavior"].as_widget())
        assert frm.initial["name"] == test_product.name
Пример #14
0
 def get_object(self, queryset=None):
     if not self.kwargs.get(self.pk_url_kwarg):
         instance = self.model()
         instance.shop = self.request.shop
         instance.product = Product()
         return instance
     return super(ProductEditView, self).get_object(queryset)
Пример #15
0
def _get_template_engine_and_context():
    engine = django.template.engines['jinja2']
    assert isinstance(engine, django_jinja.backend.Jinja2)

    request = RequestFactory().get('/')
    request.shop = Shop(currency='USD', prices_include_tax=False)
    request.customer = AnonymousContact()
    request.person = request.customer
    PriceDisplayOptions(include_taxes=False).set_for_request(request)
    tax = get_default_tax()
    create_default_tax_rule(tax)
    tax_class = get_default_tax_class()
    order, order_line = _get_order_and_order_line(request)

    context = {
        'request': request,
        'prod': Product(sku='6.0745', tax_class=tax_class),
        # TODO: Test also with variant products
        'sline': _get_source_line(request),
        'bline': _get_basket_line(request),
        'oline': order_line,
        'order': order
    }

    return (engine, context)
Пример #16
0
def test_formatted_decimal_field_default():
    class TestModelForm(ModelForm):
        class Meta:
            model = Product
            fields = ["width"]

    rendered_form = force_text(TestModelForm(instance=Product()))
    rendered_value = re.search('value="(.*?)"', rendered_form).group(1)
    assert rendered_value == "0"
Пример #17
0
def test_pricing_module_is_active():
    """
    Make sure that our custom pricing module is active.
    """
    shop = Shop(currency="USD", prices_include_tax=False)
    customer = AnonymousContact()
    product = Product(sku="6.0745")

    pricing_mod = get_pricing_module()
    pricing_ctx = pricing_mod.get_context_from_data(shop, customer)

    pi = product.get_price_info(pricing_ctx, quantity=2)

    price = shop.create_price
    assert pi.price == price("12.149")
    assert pi.base_price == price("48.596")
    assert pi.quantity == 2
    assert pi.discounted_unit_price == price("6.0745")
    assert pi.base_unit_price == price("24.298")
    assert pi.discount_rate == Decimal("0.75")
Пример #18
0
def test_pricing_module_is_active():
    """
    Make sure that our custom pricing module is active.
    """
    shop = Shop(currency='USD', prices_include_tax=False)
    customer = AnonymousContact()
    product = Product(sku='6.0745')

    pricing_mod = get_pricing_module()
    pricing_ctx = pricing_mod.get_context_from_data(shop, customer)

    pi = product.get_price_info(pricing_ctx, quantity=2)

    price = shop.create_price
    assert pi.price == price('12.149')
    assert pi.base_price == price('48.596')
    assert pi.quantity == 2
    assert pi.discounted_unit_price == price('6.0745')
    assert pi.base_unit_price == price('24.298')
    assert pi.discount_rate == Decimal('0.75')
Пример #19
0
def test_convert_taxness_without_conversion(taxes, price_cls):
    request = get_request()
    item = Product()
    priceful = _get_price_info(price_cls)
    calcs_done_before = DummyTaxModule.calculations_done
    result = convert_taxness(request, item, priceful, with_taxes=taxes)
    calcs_done_after = DummyTaxModule.calculations_done
    assert result == priceful
    assert result.price == price_cls(480, 'USD')
    assert result.base_price == price_cls(660, 'USD')
    assert result.quantity == 2
    assert calcs_done_after == calcs_done_before
Пример #20
0
def test_product_caching_object_type_validation():
    with pytest.raises(TypeError):
        pco = ProductCachingObject()
        pco.product_id = "yeah"

    with pytest.raises(TypeError):
        pco = ProductCachingObject()
        pco.product = "yeahhh"

    with pytest.raises(ValueError):
        pco = ProductCachingObject()
        pco.product = Product()
Пример #21
0
def create_product(sku, shop=None, supplier=None, default_price=None, **attrs):
    if default_price is not None:
        default_price = shop.create_price(default_price)

    product_attrs = dict(type=get_default_product_type(),
                         tax_class=get_default_tax_class(),
                         sku=sku,
                         name=sku.title(),
                         width=100,
                         height=100,
                         depth=100,
                         net_weight=100,
                         gross_weight=100,
                         sales_unit=get_default_sales_unit(),
                         stock_behavior=StockBehavior.UNSTOCKED)
    product_attrs.update(attrs)
    product = Product(**product_attrs)
    product.full_clean()
    product.save()
    if shop:
        sp = ShopProduct.objects.create(product=product,
                                        shop=shop,
                                        default_price=default_price)
        if supplier:
            sp.suppliers.add(supplier)
        sp.save()

    return product
Пример #22
0
def create_product(sku, shop=None, supplier=None, default_price=None, **attrs):
    if default_price is not None:
        default_price = shop.create_price(default_price)
    if "fractional" in attrs:
        attrs.pop("fractional")
        get_sales_unit = get_fractional_sales_unit
    else:
        get_sales_unit = get_default_sales_unit

    product_attrs = dict(
        type=get_default_product_type(),
        tax_class=get_default_tax_class(),
        sku=sku,
        name=sku.title(),
        width=100,
        height=100,
        depth=100,
        net_weight=100,
        gross_weight=100,
        sales_unit=get_sales_unit(),
    )
    product_attrs.update(attrs)
    product = Product(**product_attrs)
    product.full_clean()
    product.save()
    if shop:
        sp = ShopProduct.objects.create(
            product=product, shop=shop, default_price=default_price, visibility=ShopProductVisibility.ALWAYS_VISIBLE
        )
        if supplier:
            sp.suppliers.add(supplier)
        sp.save()

    return product
Пример #23
0
def test_model_url_with_permissions():
    permissions = set(["shuup.add_product", "shuup.delete_product", "shuup.change_product"])
    p = Product()
    p.pk = 3

    # If no user is given, don't check for permissions
    assert get_model_url(p)

    # If a user is given and no permissions are provided, check for default model permissions
    user = StaffUser()
    with pytest.raises(NoModelUrl):
        assert get_model_url(p, user=user)

    # If a user is given and permissions are provided, check for those permissions
    assert get_model_url(p, user=user, required_permissions=())
    with pytest.raises(NoModelUrl):
        assert get_model_url(p, user=user, required_permissions=["shuup.add_product"])

    # Confirm that url is returned with correct permissions
    user.permissions = permissions
    assert get_model_url(p, user=user)
    assert get_model_url(p, user=user, required_permissions=permissions)
Пример #24
0
def _get_order_line(request):
    order = Order(
        shop=request.shop,
        currency=request.shop.currency,
        prices_include_tax=request.shop.prices_include_tax,
    )
    pi = _get_price_info(request.shop, Product(sku='6.0745'), quantity=2)
    return OrderLine(
        order=order,
        base_unit_price=pi.base_unit_price,
        discount_amount=pi.discount_amount,
        quantity=pi.quantity,
    )
Пример #25
0
def _get_order_and_order_line(request):
    order = Order(
        shop=request.shop,
        currency=request.shop.currency,
        prices_include_tax=request.shop.prices_include_tax,
    )
    order.taxful_total_price = TaxfulPrice("100", request.shop.currency)
    order.taxless_total_price = TaxlessPrice("50", request.shop.currency)
    pi = _get_price_info(request.shop, Product(sku='6.0745'), quantity=2)
    return (order, OrderLine(
        order=order,
        base_unit_price=pi.base_unit_price,
        discount_amount=pi.discount_amount,
        quantity=pi.quantity,
    ))
Пример #26
0
def test_convert_taxness_taxless_to_taxful():
    request = get_request()
    tax_class = TaxClass()
    item = Product(tax_class=tax_class)
    priceful = _get_price_info(TaxlessPrice)
    calcs_done_before = DummyTaxModule.calculations_done
    result = convert_taxness(request, item, priceful, with_taxes=True)
    calcs_done_after = DummyTaxModule.calculations_done
    assert result != priceful
    assert result.price == TaxfulPrice(576, 'USD')
    assert result.base_price == TaxfulPrice(792, 'USD')
    assert result.quantity == 2
    assert result.tax_amount == Money(96, 'USD')
    assert result.taxful_price == result.price
    assert result.taxless_price == priceful.price
    assert calcs_done_after == calcs_done_before + 2
Пример #27
0
def test_convert_taxness_taxful_to_taxless():
    request = get_request()
    tax_class = TaxClass()
    item = Product(tax_class=tax_class)
    priceful = _get_price_info(TaxfulPrice)
    calcs_done_before = DummyTaxModule.calculations_done
    result = convert_taxness(request, item, priceful, with_taxes=False)
    calcs_done_after = DummyTaxModule.calculations_done
    assert result != priceful
    assert (result.price - TaxlessPrice(400, "USD")).value < 0.00001
    assert result.base_price == TaxlessPrice(550, "USD")
    assert result.quantity == 2
    assert result.tax_amount == Money(80, "USD")
    assert result.taxless_price == result.price
    assert result.taxful_price == priceful.price
    assert calcs_done_after == calcs_done_before + 2
Пример #28
0
def _get_cross_sell_products(
    context,
    product: Product,
    types: Iterable[ProductCrossSellType],
    count=5,
    orderable_only=True,
    use_variation_parents=False,
):
    related_product_cross_sells = ProductCrossSell.objects.filter(
        type__in=types)
    # if this product is parent, then use all children instead
    if product.is_variation_parent():
        # Remember to exclude relations with the same parent
        related_product_cross_sells = related_product_cross_sells.filter(
            product1__in=product.variation_children.all()).exclude(
                product2__in=product.variation_children.all())
    else:
        related_product_cross_sells = ProductCrossSell.objects.filter(
            product1=product)

    if use_variation_parents:
        related_product_cross_sells = set(
            related_product_cross_sells.order_by("-weight").values_list(
                Coalesce("product2__variation_parent_id", "product2_id"),
                "weight").distinct())
    else:
        related_product_cross_sells = set(
            related_product_cross_sells.order_by("-weight").values_list(
                "product2_id", "weight").distinct())

    products_ids = [pcs[0] for pcs in related_product_cross_sells]

    request = context["request"]
    customer = get_person_contact(request.user)
    catalog = ProductCatalog(
        ProductCatalogContext(
            shop=request.shop,
            user=getattr(request, "user", None),
            contact=customer,
            purchasable_only=orderable_only,
            visibility=ShopProductVisibility.LISTED,
        ))
    products = catalog.get_products_queryset().filter(
        pk__in=products_ids).distinct()[:count]
    return sorted(products, key=lambda product: products_ids.index(product.id))
Пример #29
0
def _get_template_engine_and_context():
    engine = django.template.engines['jinja2']
    assert isinstance(engine, django_jinja.backend.Jinja2)

    request = RequestFactory().get('/')
    request.shop = Shop(currency='USD', prices_include_tax=False)
    request.customer = AnonymousContact()
    request.person = request.customer

    context = {
        'request': request,
        'prod': Product(sku='6.0745'),
        # TODO: Test also with variant products
        'sline': _get_source_line(request),
        'bline': _get_basket_line(request),
        'oline': _get_order_line(request),
    }

    return (engine, context)
Пример #30
0
def create_variation_product(parent_product: Product, shop: Shop, sku: str,
                             combination: Combination,
                             combination_hash: str) -> Product:
    variation_child = Product(
        name=get_variation_product_name(parent_product, combination),
        tax_class=parent_product.tax_class,
        sales_unit=parent_product.sales_unit,
        sku=sku,
        shipping_mode=parent_product.shipping_mode,
        type=parent_product.type,
        manufacturer=parent_product.manufacturer,
        height=parent_product.height,
        depth=parent_product.depth,
        net_weight=parent_product.net_weight,
        gross_weight=parent_product.gross_weight,
    )
    variation_child.full_clean()
    variation_child.save()
    variation_child.link_to_parent(parent_product,
                                   combination_hash=combination_hash)
    return variation_child
Пример #31
0
def _get_price_info(shop, product=None, quantity=2):
    if not product:
        product = Product(sku="6.0745")
    # SKU of product defines the price :)
    price = shop.create_price(product.sku)
    return PriceInfo(quantity * price, quantity * 4 * price, quantity)
Пример #32
0
def _get_basket_line(request):
    basket = BaseBasket(request)
    return _create_line(basket, Product(sku="6.0745"))
Пример #33
0
def _get_source_line(request):
    source = OrderSource(request.shop)
    return _create_line(source, Product(sku="6.0745"))
Пример #34
0
 def delete_variation(self, shop: Shop, supplier: Optional[Supplier],
                      parent_product: Product, variation: Product):
     variation.soft_delete()
     ProductVariationResult.objects.filter(
         product=parent_product, result=variation).update(
             status=ProductVariationLinkStatus.INVISIBLE)
Пример #35
0
def recover_deleted_product(parent_product: Product, shop: Shop,
                            deleted_product: Product, combination: Combination,
                            combination_hash: str) -> Product:
    deleted_product.name = get_variation_product_name(parent_product,
                                                      combination)
    deleted_product.tax_class = parent_product.tax_class
    deleted_product.sales_unit = parent_product.sales_unit
    deleted_product.shipping_mode = parent_product.shipping_mode
    deleted_product.type = parent_product.type
    deleted_product.manufacturer = parent_product.manufacturer
    deleted_product.height = parent_product.height
    deleted_product.depth = parent_product.depth
    deleted_product.net_weight = parent_product.net_weight
    deleted_product.gross_weight = parent_product.gross_weight
    deleted_product.deleted = False
    deleted_product.save()
    deleted_product.link_to_parent(parent_product,
                                   combination_hash=combination_hash)
    return deleted_product