diff --git a/src/pretix/base/services/cross_selling.py b/src/pretix/base/services/cross_selling.py index 3166747158..132ce5d0cb 100644 --- a/src/pretix/base/services/cross_selling.py +++ b/src/pretix/base/services/cross_selling.py @@ -51,6 +51,7 @@ class CrossSellingService: self.sales_channel = sales_channel self.cartpositions = cartpositions self.customer = customer + self._discount_cache = {} def get_data(self): if self.event.has_subevents: @@ -177,6 +178,7 @@ class CrossSellingService: ) if self.customer else None ), + _discount_cache=self._discount_cache, ) new_items = list() for item in items: diff --git a/src/pretix/presale/productlist.py b/src/pretix/presale/productlist.py index a1cfaac149..0a0689819a 100644 --- a/src/pretix/presale/productlist.py +++ b/src/pretix/presale/productlist.py @@ -89,7 +89,7 @@ def _single_item_discounts(event: Event, sales_channel: Union[str, SalesChannel] def prepare_item_list_for_shop(event, *, channel: SalesChannel, subevent=None, voucher=None, require_seat=0, base_qs=None, allow_addons=False, allow_cross_sell=False, quota_cache=None, filter_items=None, filter_categories=None, memberships=None, - ignore_hide_sold_out_for_item_ids=None): + ignore_hide_sold_out_for_item_ids=None, _discount_cache=None): base_qs_set = base_qs is not None base_qs = base_qs if base_qs is not None else event.items @@ -226,13 +226,18 @@ def prepare_item_list_for_shop(event, *, channel: SalesChannel, subevent=None, v # This is not the same order of operations that is applied in the cart, so there could be some differences # when it comes to tax rate handling, but we don't have that information in the product list anyway, so # that is acceptable. - discounts = _single_item_discounts( - event=event, - sales_channel=channel, - voucher=voucher, - subevent=subevent, - is_addons=allow_addons, - ) + cache_key = (event, channel, voucher, subevent, allow_addons) + if _discount_cache is None: + _discount_cache = {} + if cache_key not in _discount_cache: + _discount_cache[cache_key] = list(_single_item_discounts( + event=event, + sales_channel=channel, + voucher=voucher, + subevent=subevent, + is_addons=allow_addons, + )) + discounts = _discount_cache[cache_key] display_add_to_cart = False quota_cache_key = f'item_quota_cache:{subevent.id if subevent else 0}:{channel.identifier}:{bool(require_seat)}' diff --git a/src/tests/base/test_cross_selling.py b/src/tests/base/test_cross_selling.py index ffbd0f49a9..6bd2c988c0 100644 --- a/src/tests/base/test_cross_selling.py +++ b/src/tests/base/test_cross_selling.py @@ -749,7 +749,7 @@ def test_query_count_many_items(event, itemcount): ''', recommendations=''' Price Discounted Price Max Count Prefix ''', - expect_num_queries=8, + expect_num_queries=9, ) check_cart_behaviour( event, @@ -763,7 +763,7 @@ def test_query_count_many_items(event, itemcount): recommendations=''' Price Discounted Price Max Count Prefix Tickets Ticket 2 42.00 0.00 1 - ''', - expect_num_queries=9, + expect_num_queries=10, ) check_cart_behaviour( event, @@ -779,7 +779,7 @@ def test_query_count_many_items(event, itemcount): recommendations=''' Price Discounted Price Max Count Prefix Tickets Ticket 2 42.00 0.00 1 - ''', - expect_num_queries=9, + expect_num_queries=10, ) @@ -803,7 +803,7 @@ def test_query_count_many_categories_and_discounts(event, catcount): ''', recommendations=''' Price Discounted Price Max Count Prefix ''', - expect_num_queries=8, + expect_num_queries=9, ) check_cart_behaviour( event, @@ -817,7 +817,7 @@ def test_query_count_many_categories_and_discounts(event, catcount): recommendations=''' Price Discounted Price Max Count Prefix Category 1 Ticket 1-B 42.00 0.00 1 - ''', - expect_num_queries=9, + expect_num_queries=10, ) check_cart_behaviour( event, @@ -833,7 +833,7 @@ def test_query_count_many_categories_and_discounts(event, catcount): recommendations=''' Price Discounted Price Max Count Prefix Category 1 Ticket 1-B 42.00 0.00 1 - ''', - expect_num_queries=9, + expect_num_queries=10, ) @@ -857,7 +857,7 @@ def test_query_count_many_cartpos(event, catcount): ''', recommendations=''' Price Discounted Price Max Count Prefix ''', - expect_num_queries=8, + expect_num_queries=9, ) check_cart_behaviour( event, @@ -871,7 +871,7 @@ def test_query_count_many_cartpos(event, catcount): recommendations=''' Price Discounted Price Max Count Prefix Category 1 Ticket 1-B 42.00 0.00 1 - ''', - expect_num_queries=9, + expect_num_queries=10, ) check_cart_behaviour( event, @@ -893,5 +893,5 @@ def test_query_count_many_cartpos(event, catcount): Category 1 Ticket 1-B 42.00 0.00 1 - Category 2 Ticket 2-B 42.00 0.00 1 - ''', - expect_num_queries=13, + expect_num_queries=14, ) diff --git a/src/tests/presale/test_productlist.py b/src/tests/presale/test_productlist.py index 5543d1711b..e536a9b888 100644 --- a/src/tests/presale/test_productlist.py +++ b/src/tests/presale/test_productlist.py @@ -237,6 +237,7 @@ def test_discounts_for_products(event, quota, item, variation, channel, discount assert items[1].available_variations[0].display_price.gross == Decimal("42.00") discount.condition_limit_products.add(item) + discount.condition_limit_products.add(variation.item) discount.save() items, _ = prepare_item_list_for_shop(event, channel=channel) assert len(items) == 2 @@ -271,6 +272,7 @@ def test_discounts_for_products_tax_additive_bundle_included(event, quota, item, variation.item.tax_rule = tr variation.item.save() item.bundles.create(bundled_item=b, count=2, designated_price=Decimal("5.00")) + variation.item.bundles.create(bundled_item=b, count=2, designated_price=Decimal("5.00")) items, _ = prepare_item_list_for_shop(event, channel=channel) assert len(items) == 2 assert items[0].display_price.gross == Decimal("45.98")