From e71d3e21cacaf1d177cb9042fe3b7f09aabf4042 Mon Sep 17 00:00:00 2001 From: Mira Weller Date: Mon, 10 Jun 2024 15:31:04 +0200 Subject: [PATCH] display discounted prices, limit number of products according to discount rule --- src/pretix/base/models/items.py | 12 ++++---- src/pretix/presale/checkoutflow.py | 45 +++++++++++++++--------------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/pretix/base/models/items.py b/src/pretix/base/models/items.py index 18d0997d8..64c7580b3 100644 --- a/src/pretix/base/models/items.py +++ b/src/pretix/base/models/items.py @@ -149,17 +149,17 @@ class ItemCategory(LoggedModel): If this category should be visible in the cross-selling step for a given cart and sales_channel, this method returns a dict describing the items that should be displayed. - :returns: dict {item: (max_count, discount_rule)} + :returns: (QuerySet, dict) max_count is None if the item should not be limited discount_rule is None if the item will not be discounted """ if self.cross_selling_mode is None: - return [] + return [], {} if self.cross_selling_condition == 'always': - return {item: (None, None) for item in self.items.all()} + return self.items.all(), {} if self.cross_selling_condition == 'products': match = set(match.pk for match in self.cross_selling_match_products.only('pk')) # TODO prefetch this - return {item: (None, None) for item in self.items.all()} if any(pos.item.pk in match for pos in cart) else [] + return (self.items.all(), {}) if any(pos.item.pk in match for pos in cart) else ([], {}) if self.cross_selling_condition == 'discounts': # aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarrrrgggghhhhhh @@ -203,12 +203,12 @@ class ItemCategory(LoggedModel): my_item_pks = self.items.values_list('pk', flat=True) print("grouped:",grouped_by_item) - potential_discount_items = {item: (sum_or_none(max_count for (item, discount_rule, max_count, i) in infos_for_item), next(discount_rule for (item, discount_rule, max_count, i) in infos_for_item)) + potential_discount_items = {item.pk: (sum_or_none(max_count for (item, discount_rule, max_count, i) in infos_for_item), next(discount_rule for (item, discount_rule, max_count, i) in infos_for_item)) for item, infos_for_item in grouped_by_item if item.pk in my_item_pks} #potential_discount_items = {item.pk for (discount_rule, max_count, i) in potential_discount_infos.keys() for item in discount_rule.benefit_limit_products.all()} - return potential_discount_items + return self.items.filter(pk__in=potential_discount_items), potential_discount_items def __str__(self): name = self.internal_name or self.name diff --git a/src/pretix/presale/checkoutflow.py b/src/pretix/presale/checkoutflow.py index d144697ef..0a2c3f1fa 100644 --- a/src/pretix/presale/checkoutflow.py +++ b/src/pretix/presale/checkoutflow.py @@ -499,12 +499,12 @@ class AddOnsStep(CartMixin, AsyncAction, TemplateFlowStep): def cross_selling_applicable_categories(self): cart = get_cart(self.request) return [ - (c, products) for (c, products) in + (c, products_qs, discount_info) for (c, products_qs, discount_info) in ( - (c, c.cross_sell_visible(cart, self.request.sales_channel.identifier)) + (c, *c.cross_sell_visible(cart, self.request.sales_channel.identifier)) for c in self.request.event.categories.filter(cross_selling_mode__isnull=False) ) - if len(products) > 0 + if len(products_qs) > 0 ] def is_completed(self, request, warn=False): @@ -630,23 +630,23 @@ class AddOnsStep(CartMixin, AsyncAction, TemplateFlowStep): if self.event.has_subevents: return [ - (DummyCategory(category, subevent), self._items_for_cross_selling(subevent, items), f'subevent_{subevent.pk}_') - for (category, items) in self.cross_selling_applicable_categories + (DummyCategory(category, subevent), self._items_for_cross_selling(subevent, items_qs, discount_info), f'subevent_{subevent.pk}_') + for (category, items_qs, discount_info) in self.cross_selling_applicable_categories for subevent in set(pos.subevent for pos in ctx['cart']['positions']) ] else: return [ - (category, self._items_for_cross_selling(None, items)) - for (category, items) in self.cross_selling_applicable_categories + (category, self._items_for_cross_selling(None, items_qs, discount_info)) + for (category, items_qs, discount_info) in self.cross_selling_applicable_categories ] - def _items_for_cross_selling(self, subevent, cross_sell_item_info): + def _items_for_cross_selling(self, subevent, items_qs, discount_info): items, _btn = get_grouped_items( self.request.event, subevent=subevent, voucher=None, channel=self.request.sales_channel.identifier, - base_qs=cross_sell_item_info.keys(), + base_qs=items_qs, allow_addons=True, allow_cross_sell=True, memberships=( @@ -659,21 +659,22 @@ class AddOnsStep(CartMixin, AsyncAction, TemplateFlowStep): ) for item in items: - (max_count, discount_rule) = cross_sell_item_info[item] + print("-> discount info: ",item, discount_info.get(item.pk)) + if item.pk in discount_info: + (max_count, discount_rule) = discount_info[item.pk] - # set item.order_max for benefit_only_apply_to_cheapest_n_matches discounted items - if max_count: - item.order_max = min(item.order_max, max_count) + # set item.order_max for benefit_only_apply_to_cheapest_n_matches discounted items + if max_count: + item.order_max = min(item.order_max, max_count) - # calculate discounted price - if discount_rule: - item.original_price = item.original_price or item.display_price - previous_price = item.display_price - new_price = round_decimal( - previous_price * (Decimal('100.00') - discount_rule.benefit_discount_matching_percent) / Decimal('100.00'), - self.event.currency, - ) - item.display_price = new_price + # calculate discounted price + if discount_rule: + item.original_price = item.original_price or item.display_price + previous_price = item.display_price + new_price = ( + previous_price * ((Decimal('100.00') - discount_rule.benefit_discount_matching_percent) / Decimal('100.00')) + ) + item.display_price = new_price return items