Source code for shuup.front.template_helpers.product

from typing import Iterable

from django.db.models.functions import Coalesce

from shuup.compat import contextfunction
from shuup.core.catalog import ProductCatalog, ProductCatalogContext
from shuup.core.models import (
    AttributeVisibility,
    Product,
    ProductAttribute,
    ProductCrossSell,
    ProductCrossSellType,
    ShopProductVisibility,
    get_person_contact,
)
from shuup.core.utils.product_subscription import ProductSubscriptionContext, get_product_subscription_options
from shuup.utils.text import force_ascii


[docs] def get_visible_attributes(product): return ProductAttribute.objects.filter( product=product, attribute__visibility_mode=AttributeVisibility.SHOW_ON_PRODUCT_PAGE, )
[docs] def get_subscription_options_for_product(shop, product, supplier=None, user=None, **kwargs): context = ProductSubscriptionContext(shop, product, supplier, user) return list(get_product_subscription_options(context, **kwargs))
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))
[docs] @contextfunction def get_products_bought_with(context, product: Product, count=5, orderable_only=True, use_variation_parents=True): types = [ProductCrossSellType.BOUGHT_WITH, ProductCrossSellType.COMPUTED] return _get_cross_sell_products(context, product, types, count, orderable_only, use_variation_parents)
[docs] @contextfunction def is_visible(context, product): request = context["request"] shop_product = product.get_shop_instance(shop=request.shop, allow_cache=True) return shop_product.is_visible(request.customer)
[docs] @contextfunction def get_product_cross_sells( context, product, relation_type=ProductCrossSellType.RELATED, count=4, orderable_only=True, use_variation_parents=False, ): rtype = map_relation_type(relation_type) return _get_cross_sell_products( context, product, types=[rtype], count=count, orderable_only=orderable_only, use_variation_parents=use_variation_parents, )
[docs] def map_relation_type(relation_type): """ Map relation type to enum value. :type relation_type: ProductCrossSellType|str :rtype: ProductCrossSellType :raises: `LookupError` if unknown string is given """ if isinstance(relation_type, ProductCrossSellType): return relation_type attr_name = force_ascii(relation_type).upper() try: return getattr(ProductCrossSellType, attr_name) except AttributeError as err: raise LookupError(f"Unknown ProductCrossSellType {relation_type!r}") from err