From c849276a3517255dfaa7489ade62a2f421d5c8b0 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Fri, 6 Mar 2020 17:00:26 +0100 Subject: [PATCH] Widget: Allow to filter by product --- doc/user/events/widget.rst | 11 +++++ src/pretix/presale/views/event.py | 5 ++- src/pretix/presale/views/widget.py | 10 ++++- .../static/pretixpresale/js/widget/widget.js | 10 +++++ src/tests/presale/test_widget.py | 44 +++++++++++++++++++ 5 files changed, 77 insertions(+), 3 deletions(-) diff --git a/doc/user/events/widget.rst b/doc/user/events/widget.rst index 5b2035d0c5..d5c0d1c4b8 100644 --- a/doc/user/events/widget.rst +++ b/doc/user/events/widget.rst @@ -114,6 +114,17 @@ If you want to disable voucher input in the widget, you can pass the ``disable-v +Filtering products +------------------ + +You can filter the products shown in the widget by passing in a list of product IDs:: + + + +Alternatively, you can select one or more categories to be shown:: + + + Multi-event selection --------------------- diff --git a/src/pretix/presale/views/event.py b/src/pretix/presale/views/event.py index 5f045aab9f..6d8bcdb41f 100644 --- a/src/pretix/presale/views/event.py +++ b/src/pretix/presale/views/event.py @@ -51,8 +51,9 @@ def item_group_by_category(items): ) -def get_grouped_items(event, subevent=None, voucher=None, channel='web', require_seat=0): - items = event.items.using(settings.DATABASE_REPLICA).filter_available(channel=channel, voucher=voucher).select_related( +def get_grouped_items(event, subevent=None, voucher=None, channel='web', require_seat=0, base_qs=None): + base_qs = base_qs if base_qs is not None else event.items + items = base_qs.using(settings.DATABASE_REPLICA).filter_available(channel=channel, voucher=voucher).select_related( 'category', 'tax_rule', # for re-grouping 'hidden_if_available', ).prefetch_related( diff --git a/src/pretix/presale/views/widget.py b/src/pretix/presale/views/widget.py index 5d88849db6..92a2d2d2ec 100644 --- a/src/pretix/presale/views/widget.py +++ b/src/pretix/presale/views/widget.py @@ -184,9 +184,17 @@ def get_picture(event, picture): class WidgetAPIProductList(EventListMixin, View): def _get_items(self): + qs = self.request.event.items + if 'items' in self.request.GET: + qs = qs.filter(pk__in=self.request.GET.get('items').split(",")) + if 'categories' in self.request.GET: + qs = qs.filter(category__pk__in=self.request.GET.get('categories').split(",")) + items, display_add_to_cart = get_grouped_items( - self.request.event, subevent=self.subevent, voucher=self.voucher, channel='web' + self.request.event, subevent=self.subevent, voucher=self.voucher, channel='web', + base_qs=qs ) + grps = [] for cat, g in item_group_by_category(items): grps.append({ diff --git a/src/pretix/static/pretixpresale/js/widget/widget.js b/src/pretix/static/pretixpresale/js/widget/widget.js index d61abf1aaa..0fcc2b00b8 100644 --- a/src/pretix/static/pretixpresale/js/widget/widget.js +++ b/src/pretix/static/pretixpresale/js/widget/widget.js @@ -1094,6 +1094,12 @@ var shared_root_methods = { if (this.$root.filter) { url += '&' + this.$root.filter; } + if (this.$root.item_filter) { + url += '&items=' + escape(this.$root.item_filter); + } + if (this.$root.category_filter) { + url += '&categories=' + escape(this.$root.category_filter); + } var cart_id = getCookie(this.cookieName); if (this.$root.voucher_code) { url += '&voucher=' + escape(this.$root.voucher_code); @@ -1308,6 +1314,8 @@ var create_widget = function (element) { var disable_vouchers = element.attributes["disable-vouchers"] ? true : false; var widget_data = JSON.parse(JSON.stringify(window.PretixWidget.widget_data)); var filter = element.attributes.filter ? element.attributes.filter.value : null; + var items = element.attributes.items ? element.attributes.items.value : null; + var categories = element.attributes.categories ? element.attributes.categories.value : null; for (var i = 0; i < element.attributes.length; i++) { var attrib = element.attributes[i]; if (attrib.name.match(/^data-.*$/)) { @@ -1331,6 +1339,8 @@ var create_widget = function (element) { currency: null, name: null, filter: filter, + item_filter: items, + category_filter: categories, voucher_code: voucher, display_net_prices: false, voucher_explanation_text: null, diff --git a/src/tests/presale/test_widget.py b/src/tests/presale/test_widget.py index e9c519c7ba..9b5d022653 100644 --- a/src/tests/presale/test_widget.py +++ b/src/tests/presale/test_widget.py @@ -205,6 +205,50 @@ class WidgetCartTest(CartTestMixin, TestCase): "voucher_explanation_text": "", } + def test_product_list_view_filter(self): + response = self.client.get('/%s/%s/widget/product_list?items=%s' % (self.orga.slug, self.event.slug, + self.ticket.pk)) + assert response['Access-Control-Allow-Origin'] == '*' + data = json.loads(response.content.decode()) + assert data['items_by_category'] == [ + { + "items": [ + { + "require_voucher": False, + "order_min": None, + "max_price": None, + "price": {"gross": "23.00", "net": "19.33", "tax": "3.67", "name": "", "rate": "19.00", + "includes_mixed_tax_rate": False}, + "picture": None, + "has_variations": 0, + "description": None, + "min_price": None, + "avail": [100, None], + "variations": [], + "id": self.ticket.pk, + "free_price": False, + "original_price": None, + "name": "Early-bird ticket", + "order_max": 4 + } + ], + "description": None, + "id": self.category.pk, + "name": "Everything" + } + ] + + response = self.client.get('/%s/%s/widget/product_list?categories=0,%s' % (self.orga.slug, self.event.slug, + self.category.pk)) + assert response['Access-Control-Allow-Origin'] == '*' + data = json.loads(response.content.decode()) + assert len(data['items_by_category']) == 1 + + response = self.client.get('/%s/%s/widget/product_list?categories=0' % (self.orga.slug, self.event.slug)) + assert response['Access-Control-Allow-Origin'] == '*' + data = json.loads(response.content.decode()) + assert len(data['items_by_category']) == 0 + def test_product_list_view_with_voucher(self): with scopes_disabled(): self.event.vouchers.create(item=self.ticket, code="ABCDE")