Beispiel #1
0
    def is_orderable(self, supplier, customer, quantity, allow_cache=True):
        key, val = context_cache.get_cached_value(
            identifier="is_orderable",
            item=self,
            context={"customer": customer},
            supplier=supplier,
            stock_managed=bool(supplier and supplier.stock_managed),
            quantity=quantity,
            allow_cache=allow_cache)
        if customer and val is not None:
            return val

        if not supplier:
            supplier = self.get_supplier(customer, quantity)

        for message in self.get_orderability_errors(supplier=supplier,
                                                    quantity=quantity,
                                                    customer=customer):
            if customer:
                context_cache.set_cached_value(key, False)
            return False

        if customer:
            context_cache.set_cached_value(key, True)
        return True
Beispiel #2
0
def get_products_for_categories(context,
                                categories,
                                n_products=6,
                                orderable_only=True):
    request = context["request"]
    key, product_ids = context_cache.get_cached_value(
        identifier="products_for_category",
        item=cache_utils.get_products_for_category_cache_item(request.shop),
        context=request,
        n_products=n_products,
        categories=categories,
        orderable_only=orderable_only)
    if product_ids is not None and _can_use_cache(product_ids, request.shop,
                                                  request.customer):
        return Product.objects.filter(id__in=product_ids)

    products = get_listed_products(
        context,
        n_products,
        ordering="?",
        filter_dict={
            "variation_parent": None,
            "shop_products__categories__in": categories
        },
        orderable_only=orderable_only,
    )
    products = cache_product_things(request, products)
    product_ids = [product.id for product in products]
    context_cache.set_cached_value(
        key, product_ids, settings.SHUUP_TEMPLATE_HELPERS_CACHE_DURATION)
    return products
Beispiel #3
0
    def get_fields(self, request, category=None):
        if not Category.objects.filter(shops=request.shop).exists():
            return

        key, val = context_cache.get_cached_value(
            identifier="categoryproductfilter",
            item=self,
            context=request,
            category=category)
        if val:
            return val

        language = get_language()
        base_queryset = Category.objects.all_visible(request.customer,
                                                     request.shop,
                                                     language=language)
        if category:
            q = Q(
                Q(shop_products__categories=category),
                ~Q(shop_products__visibility=ShopProductVisibility.NOT_VISIBLE)
            )
            queryset = base_queryset.filter(q).exclude(
                pk=category.pk).distinct()
        else:
            # Show only first level when there is no category selected
            queryset = base_queryset.filter(parent=None)

        data = [("categories",
                 CommaSeparatedListField(
                     required=False,
                     label=get_form_field_label("categories", _('Categories')),
                     widget=FilterWidget(choices=[(cat.pk, cat.name)
                                                  for cat in queryset])))]
        context_cache.set_cached_value(key, data)
        return data
Beispiel #4
0
def cached_product_queryset(queryset, request, category, data):
    """
    Returns the cached queryset or cache it when needed
    Note: this method returns a list of Product instances
    rtype: list[Product]
    """
    key_data = OrderedDict()
    for k, v in data.items():
        if isinstance(v, list):
            v = "|".join(v)
        key_data[k] = v

    item = "product_queryset:"

    if request.customer.is_all_seeing:
        item = "%sU%s" % (item, request.user.pk)
    if category:
        item = "%sC%s" % (item, category.pk)

    key, products = context_cache.get_cached_value(
        identifier="product_queryset",
        item=item,
        allow_cache=True,
        context=request,
        data=key_data)

    if products is not None:
        return products

    products = list(queryset)
    context_cache.set_cached_value(key, products)
    return products
Beispiel #5
0
    def get_fields(self, request, category=None):
        if not category:
            return

        key, val = context_cache.get_cached_value(
            identifier="productvariationfilter",
            item=self,
            context=request,
            category=category)
        if val:
            return val

        variation_values = defaultdict(set)
        for variation in ProductVariationVariable.objects.filter(
                Q(product__shop_products__categories=category),
                ~Q(product__shop_products__visibility=ShopProductVisibility.
                   NOT_VISIBLE)):
            for value in variation.values.all():
                # TODO: Use ID here instead of this "trick"
                choices = (value.value.replace(" ", "*"), value.value)
                variation_values[slugify(variation.name)].add(choices)

        fields = []
        for variation_key, choices in six.iteritems(variation_values):
            fields.append(("variation_%s" % variation_key,
                           CommaSeparatedListField(
                               required=False,
                               label=capfirst(variation_key),
                               widget=FilterWidget(choices=choices))))
        context_cache.set_cached_value(key, fields)
        return fields
Beispiel #6
0
def cached_product_queryset(queryset, request, category, data):
    """
    Returns the cached queryset or cache it when needed
    Note: this method returns a list of Product instances
    rtype: list[Product]
    """
    key_data = OrderedDict()
    for k, v in data.items():
        if isinstance(v, list):
            v = "|".join(v)
        key_data[k] = v

    item = "product_queryset:"

    if request.customer.is_all_seeing:
        item = "%sU%s" % (item, request.user.pk)
    if category:
        item = "%sC%s" % (item, category.pk)

    key, products = context_cache.get_cached_value(
        identifier="product_queryset",
        item=item,
        allow_cache=True,
        context=request,
        data=key_data
    )

    if products is not None:
        return products

    products = list(queryset)
    context_cache.set_cached_value(key, products)
    return products
Beispiel #7
0
def get_search_product_ids(request,
                           query,
                           limit=settings.SHUUP_SIMPLE_SEARCH_LIMIT):
    query = query.strip().lower()
    cache_key_elements = {
        "query": query,
        "shop": request.shop.pk,
        "customer": request.customer.pk
    }

    key, val = context_cache.get_cached_value(
        identifier="simple_search",
        item=None,
        context=request,
        cache_key_elements=cache_key_elements)
    if val is not None:
        return val

    product_ids = get_product_ids_for_query_str(request, query, limit)
    for word in query.split(" ") or []:
        if word == query:
            break
        prod_count = len(product_ids)
        if prod_count >= limit:
            break
        product_ids += get_product_ids_for_query_str(request, word.strip(),
                                                     limit, product_ids)

    context_cache.set_cached_value(key, product_ids[:limit])
    return product_ids
Beispiel #8
0
def get_products_for_categories(context,
                                categories,
                                n_products=6,
                                orderable_only=True):
    request = context["request"]
    key, products = context_cache.get_cached_value(
        identifier="products_for_category",
        item=cache_utils.get_products_for_category_cache_item(request.shop),
        context=request,
        n_products=n_products,
        categories=categories,
        orderable_only=orderable_only)
    if products is not None:
        return products

    products = _get_listed_products(context,
                                    n_products,
                                    ordering="?",
                                    filter_dict={
                                        "variation_parent": None,
                                        "shop_products__categories__in":
                                        categories
                                    },
                                    orderable_only=orderable_only)
    products = cache_product_things(request, products)
    context_cache.set_cached_value(
        key, products, settings.SHUUP_TEMPLATE_HELPERS_CACHE_DURATION)
    return products
    def get_fields(self, request, category=None):
        if not category:
            return

        key, val = context_cache.get_cached_value(
            identifier="productvariationfilter", item=self, context=request, category=category)
        if val:
            return val

        variation_values = defaultdict(set)
        for variation in ProductVariationVariable.objects.filter(
                Q(product__shop_products__categories=category),
                ~Q(product__shop_products__visibility=ShopProductVisibility.NOT_VISIBLE)):
            for value in variation.values.all():
                # TODO: Use ID here instead of this "trick"
                choices = (value.value.replace(" ", "*"), value.value)
                variation_values[slugify(variation.name)].add(choices)

        fields = []
        for variation_key, choices in six.iteritems(variation_values):
            fields.append((
                "variation_%s" % variation_key,
                forms.MultipleChoiceField(
                    choices=choices, required=False, label=capfirst(variation_key), widget=FilterWidget())
            ))
        context_cache.set_cached_value(key, fields)
        return fields
Beispiel #10
0
def get_orderable_variation_children(product, request, variation_variables):
    if not variation_variables:
        variation_variables = product.variation_variables.all().prefetch_related("values")

    key, val = context_cache.get_cached_value(
        identifier="orderable_variation_children", item=product, context=request,
        variation_variables=variation_variables)
    if val is not None:
        return val

    orderable_variation_children = OrderedDict()
    orderable = 0
    for combo_data in product.get_all_available_combinations():
        combo = combo_data["variable_to_value"]
        for k, v in six.iteritems(combo):
            if k not in orderable_variation_children:
                orderable_variation_children[k] = []

        res = ProductVariationResult.resolve(product, combo)
        if res and res.get_shop_instance(request.shop).is_orderable(
                supplier=None,
                customer=request.customer,
                quantity=1
        ):
            orderable += 1

            for k, v in six.iteritems(combo):
                if v not in orderable_variation_children[k]:
                    orderable_variation_children[k].append(v)

    values = (orderable_variation_children, orderable != 0)
    context_cache.set_cached_value(key, values)
    return values
Beispiel #11
0
    def __call__(self, context, product, quantity=1, allow_cache=True):
        """
        :type product: shuup.core.models.Product
        """

        key, val = context_cache.get_cached_value(
            identifier=self.cache_identifier, item=product, context=context.get('request', context),
            quantity=quantity, name=self.name, allow_cache=allow_cache)
        if val is not None:
            return val

        options = PriceDisplayOptions.from_context(context)
        if options.hide_prices:
            val = ("", "")
            context_cache.set_cached_value(key, val)
            return val

        request = context.get('request')
        priced_children = product.get_priced_children(request, quantity)
        priced_products = priced_children if priced_children else [
            (product, _get_priceful(request, product, quantity))]

        def get_formatted_price(priced_product):
            (prod, price_info) = priced_product
            if not price_info:
                return ""
            pf = convert_taxness(request, prod, price_info, options.include_taxes)
            price = money(pf.price)
            return price

        min_max = (priced_products[0], priced_products[-1])
        prices = tuple(get_formatted_price(x) for x in min_max)
        context_cache.set_cached_value(key, prices)
        return prices
Beispiel #12
0
def get_products_for_categories(context, categories, n_products=6, orderable_only=True):
    request = context["request"]
    key, products = context_cache.get_cached_value(
        identifier="products_for_category",
        item=cache_utils.get_products_for_category_cache_item(request.shop),
        context=request,
        n_products=n_products,
        categories=categories,
        orderable_only=orderable_only
    )
    if products is not None:
        return products

    products = _get_listed_products(
        context,
        n_products,
        ordering="?",
        filter_dict={
            "variation_parent": None,
            "shop_products__categories__in": categories
        },
        orderable_only=orderable_only
    )
    products = cache_product_things(request, products)
    context_cache.set_cached_value(key, products, settings.SHUUP_TEMPLATE_HELPERS_CACHE_DURATION)
    return products
Beispiel #13
0
def get_product_cross_sell_highlight(request, product_id, relation_type,
                                     use_parents, count, cache_timeout):
    key, html = context_cache.get_cached_value(
        identifier="xtheme_product_cross_sell_highlight",
        item=PRODUCT_HIGHLIGHT_CACHE_KEY_PREFIX % {"shop_id": request.shop.pk},
        context=request,
        product_id=product_id,
        type=relation_type,
        use_variation_parents=use_parents,
        count=count,
        cache_timeout=cache_timeout,
    )
    if html is not None:
        return HttpResponse(html)

    plugin = ProductCrossSellsPlugin(
        config={
            "product": int(product_id),
            "type": relation_type,
            "use_variation_parents": bool(use_parents),
            "count": int(count),
            "cache_timeout": int(cache_timeout),
        })
    html = plugin.render(dict(request=request))
    context_cache.set_cached_value(key, html, int(cache_timeout))
    return HttpResponse(html)
def get_product_queryset(queryset, request, category, data):
    key_data = OrderedDict()
    for k, v in data.items():
        if isinstance(v, list):
            v = "|".join(v)
        key_data[k] = v

    item = "product_queryset:"

    if request.customer.is_all_seeing:
        item = "%sU%s" % (item, request.user.pk)
    if category:
        item = "%sC%s" % (item, category.pk)

    key, product_ids = context_cache.get_cached_value(
        identifier="product_queryset",
        item=item,
        allow_cache=True,
        context=request,
        data=key_data)

    if product_ids is not None:
        return Product.objects.filter(id__in=product_ids)

    # pass the request and category down to the `get_queryset` method
    queryset_data = data.copy()
    queryset_data.update({"request": request, "category": category})
    for extend_obj in _get_active_modifiers(request.shop, category):
        new_queryset = extend_obj.get_queryset(queryset, queryset_data)
        if new_queryset is not None:
            queryset = new_queryset

    product_ids = list(queryset.values_list("id", flat=True))
    context_cache.set_cached_value(key, product_ids)
    return queryset
Beispiel #15
0
def get_listed_products(context, n_products, ordering=None, filter_dict=None, orderable_only=True, extra_filters=None):
    """
    A cached version of _get_listed_products
    """
    request = context["request"]

    key, products = context_cache.get_cached_value(
        identifier="listed_products",
        item=cache_utils.get_listed_products_cache_item(request.shop),
        context=request,
        n_products=n_products,
        ordering=ordering,
        filter_dict=filter_dict,
        orderable_only=orderable_only,
        extra_filters=hash(str(extra_filters))
    )
    if products is not None:
        return products

    products = _get_listed_products(
        context,
        n_products,
        ordering=ordering,
        filter_dict=filter_dict,
        orderable_only=orderable_only,
        extra_filters=extra_filters
    )
    products = cache_product_things(request, products)
    context_cache.set_cached_value(key, products, settings.SHUUP_TEMPLATE_HELPERS_CACHE_DURATION)
    return products
Beispiel #16
0
def get_random_products(context,
                        n_products=6,
                        orderable_only=True,
                        sale_items_only=False):
    request = context["request"]
    key, product_ids = context_cache.get_cached_value(
        identifier="random_products",
        item=None,
        context=request,
        n_products=n_products,
        orderable_only=orderable_only,
        sale_items_only=sale_items_only)
    if product_ids is not None and _can_use_cache(product_ids, request.shop,
                                                  request.customer):
        return Product.objects.filter(id__in=product_ids)

    products = get_listed_products(context,
                                   n_products,
                                   ordering="?",
                                   filter_dict={"variation_parent": None},
                                   orderable_only=orderable_only,
                                   sale_items_only=sale_items_only)
    products = cache_product_things(request, products)
    product_ids = [product.id for product in products]
    context_cache.set_cached_value(
        key, product_ids, settings.SHUUP_TEMPLATE_HELPERS_CACHE_DURATION)
    return products
Beispiel #17
0
def get_best_selling_products(context,
                              n_products=12,
                              cutoff_days=30,
                              orderable_only=True,
                              sale_items_only=False):
    request = context["request"]

    key, product_ids = context_cache.get_cached_value(
        identifier="best_selling_products",
        item=None,
        context=request,
        n_products=n_products,
        cutoff_days=cutoff_days,
        orderable_only=orderable_only,
        sale_items_only=sale_items_only)

    if product_ids is not None and _can_use_cache(product_ids, request.shop,
                                                  request.customer):
        return Product.objects.filter(id__in=product_ids)

    products = _get_best_selling_products(cutoff_days, n_products,
                                          orderable_only, request,
                                          sale_items_only)
    product_ids = [product.id for product in products]
    context_cache.set_cached_value(
        key, product_ids, settings.SHUUP_TEMPLATE_HELPERS_CACHE_DURATION)
    return products
Beispiel #18
0
def _get_active_modifiers(shop=None, category=None):
    key = None
    if category:
        key, val = context_cache.get_cached_value(
            identifier="active_modifiers",
            item=category,
            allow_cache=True,
            context={"shop": shop})
        if val is not None:
            return val

    configurations = get_configuration(shop=shop, category=category)

    def sorter(extend_obj):
        return extend_obj.get_ordering(configurations)

    objs = []
    for cls in get_provide_objects(FORM_MODIFIER_PROVIDER_KEY):
        obj = cls()
        if obj.should_use(configurations):
            objs.append(obj)

    sorted_objects = sorted(objs, key=sorter)
    if category and key:
        context_cache.set_cached_value(key, sorted_objects)
    return sorted_objects
Beispiel #19
0
def get_product_queryset(queryset, request, category, data):
    key_data = OrderedDict()
    for k, v in data.items():
        if isinstance(v, list):
            v = "|".join(v)
        key_data[k] = v

    if request.customer.is_all_seeing:
        identifier = "product_queryset_all_seeing_%d" % request.user.id
    else:
        identifier = "product_queryset"

    key, product_ids = context_cache.get_cached_value(
        identifier=identifier, item=category, allow_cache=True, context=request, data=key_data
    )
    if product_ids is not None:
        return Product.objects.filter(id__in=product_ids)

    for extend_obj in _get_active_modifiers(request.shop, category):
        new_queryset = extend_obj.get_queryset(queryset, data)
        if new_queryset is not None:
            queryset = new_queryset

    product_ids = list(queryset.values_list("id", flat=True))
    context_cache.set_cached_value(key, product_ids)
    return queryset
Beispiel #20
0
def get_products_for_category(context,
                              category,
                              n_products=6,
                              orderable_only=True):
    request = context["request"]
    key, products = context_cache.get_cached_value(
        identifier="products_for_category",
        item=None,
        context=request,
        n_products=n_products,
        category=category,
        orderable_only=orderable_only)
    if products is not None and _can_use_cache(products, request.shop,
                                               request.customer):
        return products

    products = get_listed_products(
        context,
        n_products,
        ordering="?",
        filter_dict={
            "variation_parent": None,
            "shop_products__categories__in": category
        },
        orderable_only=orderable_only,
    )
    products = cache_product_things(request, products)
    context_cache.set_cached_value(
        key, products, settings.SHUUP_TEMPLATE_HELPERS_CACHE_DURATION)
    return products
Beispiel #21
0
def cache_many_price_info(context, item, quantity, prices_infos,
                          **context_args):
    """
    Cache a list of PriceInfo

    :param object|WSGIRequest context: the context should contain at least a shop and a customer property
    :param object item
    :param float|Decimal quantity
    :param iterable[PriceInfo] prices_infos
    """
    # check whether the prices are iterable
    try:
        iter(prices_infos)
    except TypeError:
        return

    # all items must be PriceInfo
    if not all(isinstance(item, PriceInfo) for item in prices_infos):
        return

    key = context_cache.get_cache_key_for_context(
        many=True,
        **_get_price_info_cache_key_params(context, item, quantity,
                                           **context_args))
    context_cache.set_cached_value(key, prices_infos)
Beispiel #22
0
    def get_package_content(self, shop_product):
        key, val = context_cache.get_cached_value(
            identifier="package_contents",
            item=shop_product,
            context={"customer": self.context["customer"]},
            allow_cache=True)
        if val is not None:
            return val

        package_contents = []
        pkge_links = ProductPackageLink.objects.filter(
            parent=shop_product.product)
        for pkge_link in pkge_links:
            try:
                pkge_shop_product = pkge_link.parent.get_shop_instance(
                    shop_product.shop)

                package_contents.append({
                    "quantity":
                    pkge_link.quantity,
                    "product":
                    self.children_serializer(pkge_shop_product,
                                             context=self.context).data
                })
            except ShopProduct.DoesNotExist:
                continue

        context_cache.set_cached_value(key, package_contents)
        return package_contents
Beispiel #23
0
def get_orderable_variation_children(product, request, variation_variables):
    if not variation_variables:
        variation_variables = product.variation_variables.all(
        ).prefetch_related("values")

    key, val = context_cache.get_cached_value(
        identifier="orderable_variation_children",
        item=product,
        context=request,
        variation_variables=variation_variables)
    if val is not None:
        return val

    orderable_variation_children = OrderedDict()
    orderable = 0
    for combo_data in product.get_all_available_combinations():
        combo = combo_data["variable_to_value"]
        for k, v in six.iteritems(combo):
            if k not in orderable_variation_children:
                orderable_variation_children[k] = set()

        res = ProductVariationResult.resolve(product, combo)
        if res and res.get_shop_instance(request.shop).is_orderable(
                supplier=None, customer=request.customer, quantity=1):
            orderable += 1

            for k, v in six.iteritems(combo):
                orderable_variation_children[k].add(v)

    values = (orderable_variation_children, orderable != 0)
    context_cache.set_cached_value(key, values)
    return values
Beispiel #24
0
def get_random_products(context, n_products=6, orderable_only=True, sale_items_only=False):
    request = context["request"]
    key, products = context_cache.get_cached_value(
        identifier="random_products",
        item=cache_utils.get_random_products_cache_item(request.shop),
        context=request,
        n_products=n_products, orderable_only=orderable_only,
        sale_items_only=sale_items_only
    )
    if products is not None:
        return products

    products = get_listed_products(
        context,
        n_products,
        ordering="?",
        filter_dict={
            "variation_parent": None
        },
        orderable_only=orderable_only,
        sale_items_only=sale_items_only
    )
    products = cache_product_things(request, products)
    context_cache.set_cached_value(key, products, settings.SHUUP_TEMPLATE_HELPERS_CACHE_DURATION)
    return products
Beispiel #25
0
def get_product_queryset(queryset, request, category, data):
    key_data = OrderedDict()
    for k, v in data.items():
        if isinstance(v, list):
            v = "|".join(v)
        key_data[k] = v

    if request.customer.is_all_seeing:
        identifier = "product_queryset_all_seeing_%d" % request.user.id
    else:
        identifier = "product_queryset"

    key, val = context_cache.get_cached_value(identifier=identifier,
                                              item=category,
                                              allow_cache=True,
                                              context=request,
                                              data=key_data)
    if val is not None:
        return val

    for extend_obj in _get_active_modifiers(request.shop, category):
        new_queryset = extend_obj.get_queryset(queryset, data)
        if new_queryset is not None:
            queryset = new_queryset
    context_cache.set_cached_value(key, queryset)
    return queryset
Beispiel #26
0
def get_listed_products(context,
                        n_products,
                        ordering=None,
                        filter_dict=None,
                        orderable_only=True,
                        extra_filters=None):
    """
    A cached version of _get_listed_products
    """
    request = context["request"]

    key, products = context_cache.get_cached_value(
        identifier="listed_products",
        item=cache_utils.get_listed_products_cache_item(request.shop),
        context=request,
        n_products=n_products,
        ordering=ordering,
        filter_dict=filter_dict,
        orderable_only=orderable_only,
        extra_filters=hash(str(extra_filters)))
    if products is not None:
        return products

    products = _get_listed_products(context,
                                    n_products,
                                    ordering=ordering,
                                    filter_dict=filter_dict,
                                    orderable_only=orderable_only,
                                    extra_filters=extra_filters)
    products = cache_product_things(request, products)
    context_cache.set_cached_value(
        key, products, settings.SHUUP_TEMPLATE_HELPERS_CACHE_DURATION)
    return products
Beispiel #27
0
    def __call__(self, context, product, quantity=1, allow_cache=True):
        """
        :type product: shuup.core.models.Product
        """

        key, val = context_cache.get_cached_value(
            identifier=self.cache_identifier, item=product, context=context,
            quantity=quantity, name=self.name, allow_cache=allow_cache)
        if val is not None:
            return val

        options = PriceDisplayOptions.from_context(context)
        if options.hide_prices:
            val = ("", "")
            context_cache.set_cached_value(key, val)
            return val

        request = context.get('request')
        priced_children = product.get_priced_children(request, quantity)
        priced_products = priced_children if priced_children else [
            (product, _get_priceful(request, product, quantity))]

        def get_formatted_price(priced_product):
            (prod, price_info) = priced_product
            if not price_info:
                return ""
            pf = convert_taxness(request, prod, price_info, options.include_taxes)
            price = money(pf.price)
            return price

        min_max = (priced_products[0], priced_products[-1])
        prices = tuple(get_formatted_price(x) for x in min_max)
        context_cache.set_cached_value(key, prices)
        return prices
Beispiel #28
0
    def get_variations(self, shop_product):
        key, val = context_cache.get_cached_value(identifier="variations",
                                                  item=shop_product,
                                                  context={"customer": self.context["customer"]},
                                                  allow_cache=True)
        if val is not None:
            return val
        data = []
        combinations = list(shop_product.product.get_all_available_combinations() or [])
        if not combinations and shop_product.product.mode == ProductMode.SIMPLE_VARIATION_PARENT:
            for product_pk, sku in Product.objects.filter(
                    variation_parent_id=shop_product.product_id).values_list("pk", "sku"):
                combinations.append({
                    "result_product_pk": product_pk,
                    "sku_part": sku,
                    "hash": None,
                    "variable_to_value": {}
                })

        qs = get_shop_product_queryset(False).filter(
            shop_id=shop_product.shop_id, product__pk__in=[combo["result_product_pk"] for combo in combinations])
        products = self.children_serializer(qs, many=True, context=self.context).data
        product_map = {product["product_id"]: product for product in products}
        for combination in combinations:
            child = product_map.get(combination["result_product_pk"])
            data.append({
                "product": child or {},
                "sku_part": combination["sku_part"],
                "hash": combination["hash"],
                "combination": {
                    force_text(k): force_text(v) for k, v in six.iteritems(combination["variable_to_value"])
                }
            })
        context_cache.set_cached_value(key, data)
        return data
Beispiel #29
0
def get_product_highlight(request, plugin_type, cutoff_days, count, cache_timeout):
    orderable_only = "orderable_only" in request.GET
    key, html = context_cache.get_cached_value(
        identifier="xtheme_category_proudcts_highlights",
        item=PRODUCT_HIGHLIGHT_CACHE_KEY_PREFIX % {"shop_id": request.shop.pk},
        context=request,
        plugin_type=plugin_type,
        cutoff_days=cutoff_days,
        count=count,
        cache_timeout=cache_timeout,
        orderable_only=orderable_only,
    )
    if html is not None:
        return HttpResponse(html)

    plugin = ProductHighlightPlugin(
        config={
            "type": plugin_type,
            "cutoff_days": int(cutoff_days),
            "count": int(count),
            "cache_timeout": int(cache_timeout),
            "orderable_only": orderable_only,
        }
    )
    html = plugin.render(dict(request=request))
    context_cache.set_cached_value(key, html, int(cache_timeout))
    return HttpResponse(html)
Beispiel #30
0
    def get_fields(self, request, category=None):
        if not Category.objects.filter(shops=request.shop).exists():
            return

        key, val = context_cache.get_cached_value(
            identifier="categoryproductfilter", item=self, context=request, category=category)
        if val:
            return val

        language = get_language()
        base_queryset = Category.objects.all_visible(request.customer, request.shop, language=language)
        if category:
            q = Q(
                Q(shop_products__categories=category),
                ~Q(shop_products__visibility=ShopProductVisibility.NOT_VISIBLE)
            )
            queryset = base_queryset.filter(q).exclude(pk=category.pk).distinct()
        else:
            # Show only first level when there is no category selected
            queryset = base_queryset.filter(parent=None)

        data = [
            (
                "categories",
                CommaSeparatedListField(
                    required=False,
                    label=get_form_field_label("categories", _('Categories')),
                    widget=FilterWidget(choices=[(cat.pk, cat.name) for cat in queryset])
                )
            )
        ]
        context_cache.set_cached_value(key, data)
        return data
Beispiel #31
0
def get_best_selling_products(context,
                              n_products=12,
                              cutoff_days=30,
                              orderable_only=True,
                              supplier=None):
    request = context["request"]

    key, products = context_cache.get_cached_value(
        identifier="best_selling_products_%s" %
        (supplier.pk if supplier else ""),
        item=cache_utils.get_best_selling_products_cache_item(request.shop),
        context=request,
        n_products=n_products,
        cutoff_days=cutoff_days,
        orderable_only=orderable_only)

    if products is not None:
        return products

    products = _get_best_selling_products(cutoff_days,
                                          n_products,
                                          orderable_only,
                                          request,
                                          supplier=supplier)
    context_cache.set_cached_value(
        key, products, settings.SHUUP_TEMPLATE_HELPERS_CACHE_DURATION)
    return products
Beispiel #32
0
    def get_cross_sell(self, shop_product):
        key, val = context_cache.get_cached_value(identifier="cross_sell",
                                                  item=shop_product,
                                                  context={"customer": self.context["customer"]},
                                                  allow_cache=True)
        if val is not None:
            return val

        cross_sell_data = self._get_cross_sell(shop_product)
        context_cache.set_cached_value(key, cross_sell_data)
        return cross_sell_data
Beispiel #33
0
    def get_cross_sell(self, shop_product):
        key, val = context_cache.get_cached_value(identifier="cross_sell",
                                                  item=shop_product,
                                                  context={"customer": self.context["customer"]},
                                                  allow_cache=True)
        if val is not None:
            return val

        cross_sell_data = self._get_cross_sell(shop_product)
        context_cache.set_cached_value(key, cross_sell_data)
        return cross_sell_data
Beispiel #34
0
    def get_package_content(self, shop_product):
        key, val = context_cache.get_cached_value(identifier="package_contents",
                                                  item=shop_product,
                                                  context={"customer": self.context["customer"]},
                                                  allow_cache=True)
        if val is not None:
            return val

        package_contents = self._get_package_content(shop_product)
        context_cache.set_cached_value(key, package_contents)
        return package_contents
Beispiel #35
0
    def get_package_content(self, shop_product):
        key, val = context_cache.get_cached_value(identifier="package_contents",
                                                  item=shop_product,
                                                  context={"customer": self.context["customer"]},
                                                  allow_cache=True)
        if val is not None:
            return val

        package_contents = self._get_package_content(shop_product)
        context_cache.set_cached_value(key, package_contents)
        return package_contents
Beispiel #36
0
    def get_variations(self, shop_product):
        key, val = context_cache.get_cached_value(identifier="variations",
                                                  item=shop_product,
                                                  context={"customer": self.context["customer"]},
                                                  allow_cache=True)
        if val is not None:
            return val

        variations = self._get_variations(shop_product)
        context_cache.set_cached_value(key, variations)
        return variations
Beispiel #37
0
    def get_variations(self, shop_product):
        key, val = context_cache.get_cached_value(identifier="variations",
                                                  item=shop_product,
                                                  context={"customer": self.context["customer"]},
                                                  allow_cache=True)
        if val is not None:
            return val

        variations = self._get_variations(shop_product)
        context_cache.set_cached_value(key, variations)
        return variations
Beispiel #38
0
    def _get_cached_product_price_info(self, shop_product):
        key, val = context_cache.get_cached_value(identifier="shop_product_price_info",
                                                  item=shop_product,
                                                  context={"customer": self.context["customer"]},
                                                  allow_cache=True)
        if val is not None:
            return val

        price_info = self._get_product_price_info(shop_product)
        context_cache.set_cached_value(key, price_info)
        return price_info
Beispiel #39
0
    def _get_cached_product_price_info(self, shop_product):
        key, val = context_cache.get_cached_value(identifier="shop_product_price_info",
                                                  item=shop_product,
                                                  context={"customer": self.context["customer"]},
                                                  allow_cache=True)
        if val is not None:
            return val

        price_info = self._get_product_price_info(shop_product)
        context_cache.set_cached_value(key, price_info)
        return price_info
Beispiel #40
0
def is_visible(context, product):
    key, val = context_cache.get_cached_value(identifier="is_visible", item=product, context=context)
    if val is not None:
        return val

    request = context["request"]
    shop_product = product.get_shop_instance(shop=request.shop, allow_cache=True)
    for error in shop_product.get_visibility_errors(customer=request.customer):  # pragma: no branch
        context_cache.set_cached_value(key, False)
        return False
    context_cache.set_cached_value(key, True)
    return True
Beispiel #41
0
def get_best_selling_products(context, n_products=12, cutoff_days=30, orderable_only=True):
    request = context["request"]

    key, products = context_cache.get_cached_value(
        identifier="best_selling_products", item=None, context=request,
        n_products=n_products, cutoff_days=cutoff_days, orderable_only=orderable_only)
    if products is not None and _can_use_cache(products, request.shop, request.customer):
        return products

    products = _get_best_selling_products(cutoff_days, n_products, orderable_only, request)
    context_cache.set_cached_value(key, products, settings.SHUUP_TEMPLATE_HELPERS_CACHE_DURATION)
    return products
Beispiel #42
0
def get_all_manufacturers(context):
    request = context["request"]
    key, manufacturers = context_cache.get_cached_value(
        identifier="all_manufacturers", item=None, context=request)
    if manufacturers is not None:
        return manufacturers

    products = Product.objects.listed(shop=request.shop, customer=request.customer)
    manufacturers_ids = products.values_list("manufacturer__id").distinct()
    manufacturers = Manufacturer.objects.filter(pk__in=manufacturers_ids)
    context_cache.set_cached_value(key, manufacturers, settings.SHUUP_TEMPLATE_HELPERS_CACHE_DURATION)
    return manufacturers
Beispiel #43
0
def get_orderable_variation_children(product,
                                     request,
                                     variation_variables,
                                     supplier=None):  # noqa (C901)
    if not variation_variables:
        variation_variables = product.variation_variables.all(
        ).prefetch_related("values")

    key, val = context_cache.get_cached_value(
        identifier="orderable_variation_children",
        item=product,
        context=request,
        variation_variables=variation_variables,
        supplier=supplier)
    if val is not None:
        return _unpack_orderable_variation_children_from_cache(val)

    orderable_variation_children = OrderedDict()
    orderable = 0

    shop = request.shop
    product_queryset = product.variation_children.visible(
        shop=shop, customer=request.customer).values_list("pk", flat=True)
    all_combinations = list(product.get_all_available_combinations())
    for shop_product in (ShopProduct.objects.filter(
            shop=shop, product__id__in=product_queryset).select_related(
                "product").prefetch_related("suppliers")):
        shop_product.shop = shop  # To avoid query on orderability checks
        combo_data = first(
            combo for combo in all_combinations
            if combo["result_product_pk"] == shop_product.product.id)
        if not combo_data:
            continue

        combo = combo_data["variable_to_value"]
        for variable, values in six.iteritems(combo):
            if variable not in orderable_variation_children:
                orderable_variation_children[variable] = []

        if shop_product.is_orderable(
                supplier=supplier,
                customer=request.customer,
                quantity=shop_product.minimum_purchase_quantity):
            orderable += 1
            for variable, value in six.iteritems(combo):
                if value not in orderable_variation_children[variable]:
                    orderable_variation_children[variable].append(value)

    orderable = (orderable > 0)
    values = (orderable_variation_children, orderable)
    context_cache.set_cached_value(
        key, _pack_orderable_variation_children_to_cache(*values))
    return values
Beispiel #44
0
 def get_shop_instance(self, shop, allow_cache=False):
     """
     :type shop: shuup.core.models.Shop
     :rtype: shuup.core.models.ShopProduct
     """
     key, val = context_cache.get_cached_value(
         identifier="shop_product", item=self, context={"shop": shop}, allow_cache=allow_cache)
     if val is not None:
         return val
     shop_inst = self.shop_products.get(shop_id=shop.id)
     context_cache.set_cached_value(key, shop_inst)
     return shop_inst
Beispiel #45
0
    def get_shop_instance(self, shop, allow_cache=False):
        """
        :type shop: shuup.core.models.Shop
        :rtype: shuup.core.models.ShopProduct
        """
        key, val = context_cache.get_cached_value(
            identifier="shop_product", item=self, context={"shop": shop}, allow_cache=allow_cache)
        if val is not None:
            return val

        shop_inst = self.shop_products.get(shop=shop)
        context_cache.set_cached_value(key, shop_inst)
        return shop_inst
Beispiel #46
0
    def __call__(self, context, item, quantity=1, allow_cache=True):
        key, val = context_cache.get_cached_value(
            identifier=self.cache_identifier, item=item, context=context.get('request', context),
            quantity=quantity, name=self.name, allow_cache=allow_cache)
        if val is not None:
            return val

        priceful = _get_priceful(context.get('request'), item, quantity)
        if not priceful:
            context_cache.set_cached_value(key, "")
            return ""

        val = percent(getattr(priceful, self.property_name))
        context_cache.set_cached_value(key, val)
        return val
Beispiel #47
0
def cache_price_info(context, item, quantity, price_info, **context_args):
    """
    Cache a PriceInfo

    :param context object|WSGIRequest: the context should contain at least a shop and a customer property
    :param item any
    :param quantity float|Decimal
    :param price_info PriceInfo
    """
    # we can just cache PriceInfo instances
    if isinstance(price_info, PriceInfo):
        key = context_cache.get_cache_key_for_context(
            **_get_price_info_cache_key_params(context, item, quantity, **context_args)
        )
        context_cache.set_cached_value(key, price_info)
Beispiel #48
0
    def is_orderable(self, supplier, customer, quantity, allow_cache=True):
        key, val = context_cache.get_cached_value(
            identifier="is_orderable", item=self, context={"customer": customer},
            supplier=supplier, quantity=quantity, allow_cache=allow_cache)
        if customer and val is not None:
            return val

        if not supplier:
            supplier = self.suppliers.first()  # TODO: Allow multiple suppliers
        for message in self.get_orderability_errors(supplier=supplier, quantity=quantity, customer=customer):
            if customer:
                context_cache.set_cached_value(key, False)
            return False

        if customer:
            context_cache.set_cached_value(key, True)
        return True
Beispiel #49
0
def get_product_cross_sells(
        context, product, relation_type=ProductCrossSellType.RELATED,
        count=4, orderable_only=True):
    request = context["request"]

    key, products = context_cache.get_cached_value(
        identifier="product_cross_sells",
        item=cache_utils.get_cross_sells_cache_item(request.shop),
        context=request,
        product=product,
        relation_type=relation_type,
        count=count,
        orderable_only=orderable_only
    )

    if products is not None:
        return products

    rtype = map_relation_type(relation_type)
    related_product_ids = list((
        ProductCrossSell.objects
        .filter(product1=product, type=rtype)
        .order_by("weight")[:(count * 4)]).values_list("product2_id", flat=True)
    )

    related_products = []
    for product in Product.objects.filter(id__in=related_product_ids):
        try:
            shop_product = product.get_shop_instance(request.shop, allow_cache=True)
        except ShopProduct.DoesNotExist:
            continue
        if orderable_only:
            for supplier in Supplier.objects.enabled():
                if shop_product.is_orderable(
                        supplier, request.customer, shop_product.minimum_purchase_quantity, allow_cache=True):
                    related_products.append(product)
                    break
        elif shop_product.is_visible(request.customer):
            related_products.append(product)

    # Order related products by weight. Related product ids is in weight order.
    # If same related product is linked twice to product then lowest weight stands.
    related_products.sort(key=lambda prod: list(related_product_ids).index(prod.id))
    products = related_products[:count]
    context_cache.set_cached_value(key, products, settings.SHUUP_TEMPLATE_HELPERS_CACHE_DURATION)
    return products
Beispiel #50
0
def get_product_queryset(queryset, request, category, data):
    key_data = OrderedDict()
    for k, v in data.items():
        if isinstance(v, list):
            v = "|".join(v)
        key_data[k] = v

    key, val = context_cache.get_cached_value(
        identifier="product_queryset", item=category, allow_cache=True, context=request, data=key_data)
    if val is not None:
        return val

    for extend_obj in _get_active_modifiers(request.shop, category):
        new_queryset = extend_obj.get_queryset(queryset, data)
        if new_queryset is not None:
            queryset = new_queryset
    context_cache.set_cached_value(key, queryset)
    return queryset
Beispiel #51
0
def get_orderable_variation_children(product, request, variation_variables, supplier=None):    # noqa (C901)
    if not variation_variables:
        variation_variables = product.variation_variables.all().prefetch_related("values")

    key, val = context_cache.get_cached_value(
        identifier="orderable_variation_children",
        item=product, context=request,
        variation_variables=variation_variables,
        supplier=supplier
    )
    if val is not None:
        return _unpack_orderable_variation_children_from_cache(val)

    orderable_variation_children = OrderedDict()
    orderable = 0

    for combo_data in product.get_all_available_combinations():
        combo = combo_data["variable_to_value"]
        for variable, values in six.iteritems(combo):
            if variable not in orderable_variation_children:
                orderable_variation_children[variable] = []

        res = ProductVariationResult.resolve(product, combo)
        if not res:
            continue

        try:
            shop_product = res.get_shop_instance(request.shop)
        except ShopProduct.DoesNotExist:
            continue

        if res and shop_product.is_orderable(
                supplier=supplier, customer=request.customer, quantity=shop_product.minimum_purchase_quantity):
            orderable += 1
            for variable, value in six.iteritems(combo):
                if value not in orderable_variation_children[variable]:
                    orderable_variation_children[variable].append(value)

    orderable = (orderable > 0)
    values = (orderable_variation_children, orderable)
    context_cache.set_cached_value(key, _pack_orderable_variation_children_to_cache(*values))
    return values
Beispiel #52
0
def get_random_products(context, n_products=6, orderable_only=True):
    request = context["request"]
    key, products = context_cache.get_cached_value(
        identifier="random_products", item=None, context=request,
        n_products=n_products, orderable_only=orderable_only)
    if products is not None and _can_use_cache(products, request.shop, request.customer):
        return products

    products = get_listed_products(
        context,
        n_products,
        ordering="?",
        filter_dict={
            "variation_parent": None
        },
        orderable_only=orderable_only,
    )
    products = cache_product_things(request, products)
    context_cache.set_cached_value(key, products, settings.SHUUP_TEMPLATE_HELPERS_CACHE_DURATION)
    return products
Beispiel #53
0
    def __call__(self, context, item, quantity=1, include_taxes=None, allow_cache=True):
        key, val = context_cache.get_cached_value(
            identifier=self.cache_identifier, item=item, context=context.get('request', context),
            quantity=quantity, include_taxes=include_taxes, name=self.name, allow_cache=allow_cache)
        if val is not None:
            return val

        options = PriceDisplayOptions.from_context(context)
        if options.hide_prices:
            context_cache.set_cached_value(key, "")
            return ""

        if include_taxes is None:
            include_taxes = options.include_taxes

        request = context.get('request')
        orig_priceful = _get_priceful(request, item, quantity)
        if not orig_priceful:
            context_cache.set_cached_value(key, "")
            return ""
        priceful = convert_taxness(request, item, orig_priceful, include_taxes)
        price_value = getattr(priceful, self.property_name)
        val = money(price_value)
        context_cache.set_cached_value(key, val)
        return val
Beispiel #54
0
    def get_cross_sell(self, shop_product):
        key, val = context_cache.get_cached_value(identifier="cross_sell",
                                                  item=shop_product,
                                                  context={"customer": self.context["customer"]},
                                                  allow_cache=True)
        if val is not None:
            return val

        cross_sell_data = {
            "recommended": [],
            "related": [],
            "computed": [],
            "bought_with": []
        }

        keys = {
            ProductCrossSellType.RECOMMENDED: "recommended",
            ProductCrossSellType.RELATED: "related",
            ProductCrossSellType.COMPUTED: "computed",
            ProductCrossSellType.BOUGHT_WITH: "bought_with",
        }
        customer = self.context["customer"]
        for cross_sell in shop_product.product.cross_sell_1.all():
            try:
                cross_shop_product = cross_sell.product2.get_shop_instance(shop_product.shop)
            except ShopProduct.DoesNotExist:
                continue

            supplier = cross_shop_product.suppliers.first()
            quantity = cross_shop_product.minimum_purchase_quantity

            if not cross_shop_product.is_orderable(supplier=supplier, customer=customer, quantity=quantity):
                continue

            key = keys[cross_sell.type]
            cross_sell_data[key].append(self.children_serializer(cross_shop_product, context=self.context).data)

        context_cache.set_cached_value(key, cross_sell_data)
        return cross_sell_data
Beispiel #55
0
    def is_orderable(self, supplier, customer, quantity, allow_cache=True):
        """
        Product to be orderable it needs to be visible and purchasable
        """
        key, val = context_cache.get_cached_value(
            identifier="is_orderable", item=self, context={"customer": customer},
            supplier=supplier, stock_managed=bool(supplier and supplier.stock_managed),
            quantity=quantity, allow_cache=allow_cache)
        if customer and val is not None:
            return val

        if not supplier:
            supplier = self.get_supplier(customer, quantity)

        for message in self.get_orderability_errors(supplier=supplier, quantity=quantity, customer=customer):
            if customer:
                context_cache.set_cached_value(key, False)
            return False

        if customer:
            context_cache.set_cached_value(key, True)
        return True
Beispiel #56
0
    def get_package_content(self, shop_product):
        key, val = context_cache.get_cached_value(identifier="package_contents",
                                                  item=shop_product,
                                                  context={"customer": self.context["customer"]},
                                                  allow_cache=True)
        if val is not None:
            return val

        package_contents = []
        pkge_links = ProductPackageLink.objects.filter(parent=shop_product.product)
        for pkge_link in pkge_links:
            try:
                pkge_shop_product = pkge_link.parent.get_shop_instance(shop_product.shop)

                package_contents.append({
                    "quantity": pkge_link.quantity,
                    "product": self.children_serializer(pkge_shop_product, context=self.context).data
                })
            except ShopProduct.DoesNotExist:
                continue

        context_cache.set_cached_value(key, package_contents)
        return package_contents
Beispiel #57
0
def _get_active_modifiers(shop=None, category=None):
    key = None
    if category:
        key, val = context_cache.get_cached_value(
            identifier="active_modifiers", item=category, allow_cache=True, context={"shop": shop})
        if val is not None:
            return val

    configurations = get_configuration(shop=shop, category=category)

    def sorter(extend_obj):
        return extend_obj.get_ordering(configurations)

    objs = []
    for cls in get_provide_objects(FORM_MODIFIER_PROVIDER_KEY):
        obj = cls()
        if obj.should_use(configurations):
            objs.append(obj)

    sorted_objects = sorted(objs, key=sorter)
    if category and key:
        context_cache.set_cached_value(key, sorted_objects)
    return sorted_objects
Beispiel #58
0
def cache_many_price_info(context, item, quantity, prices_infos, **context_args):
    """
    Cache a list of PriceInfo

    :param object|WSGIRequest context: the context should contain at least a shop and a customer property
    :param object item
    :param float|Decimal quantity
    :param iterable[PriceInfo] prices_infos
    """
    # check whether the prices are iterable
    try:
        iter(prices_infos)
    except TypeError:
        return

    # all items must be PriceInfo
    if not all(isinstance(item, PriceInfo) for item in prices_infos):
        return

    key = context_cache.get_cache_key_for_context(
        many=True,
        **_get_price_info_cache_key_params(context, item, quantity, **context_args)
    )
    context_cache.set_cached_value(key, prices_infos)
Beispiel #59
0
def get_search_product_ids(request, query, limit=settings.SHUUP_SIMPLE_SEARCH_LIMIT):
    query = query.strip().lower()
    cache_key_elements = {
        "query": query,
        "shop": request.shop.pk,
        "customer": request.customer.pk
    }

    key, val = context_cache.get_cached_value(
        identifier="simple_search", item=None, context=request, cache_key_elements=cache_key_elements)
    if val is not None:
        return val

    product_ids = get_product_ids_for_query_str(request, query, limit)
    for word in query.split(" ") or []:
        if word == query:
            break
        prod_count = len(product_ids)
        if prod_count >= limit:
            break
        product_ids += get_product_ids_for_query_str(request, word.strip(), limit, product_ids)

    context_cache.set_cached_value(key, product_ids[:limit])
    return product_ids