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
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
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
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
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
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
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
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
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
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
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_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
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
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
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
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
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
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
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)
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
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
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
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
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
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
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
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)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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)
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
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
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
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
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
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
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
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
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
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
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)
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