forked from CGM_Public/pretix_original
Add support for reserved seating (#1228)
* Initial work on seating * Add seat guids * Add product_list_top * CartAdd: Ignore item when a seat is passed * Cart display * product_list_top → render_seating_plan * Render seating plan in voucher redemption * Fix failing tests * Add tests for extending cart positions with seats * Add subevent_forms to docs * Update schema, migrations * Dealing with expired orders * steps to order change * Change order positions * Allow to add seats * tests for ocm * Fix things after rebase * Seating plans API * Add more tests for cart behaviour * Widget support * Adjust widget tests * Re-enable CSP * Update schema * Api: position.seat * Add guid to word list * API: (sub)event.seating_plan * Vali fixes * Fix api * Fix reference in test * Fix test for real
This commit is contained in:
@@ -222,6 +222,18 @@ As with all plugin signals, the ``sender`` keyword argument will contain the eve
|
||||
receivers are expected to return HTML.
|
||||
"""
|
||||
|
||||
render_seating_plan = EventPluginSignal(
|
||||
providing_args=["request", "subevent", "voucher"]
|
||||
)
|
||||
"""
|
||||
This signal is sent out to render a seating plan, if one is configured for the specific event.
|
||||
You will be passed the ``request`` as a keyword argument. If applicable, a ``subevent`` or
|
||||
``voucher`` argument might be given.
|
||||
|
||||
As with all plugin signals, the ``sender`` keyword argument will contain the event. The
|
||||
receivers are expected to return HTML.
|
||||
"""
|
||||
|
||||
front_page_bottom = EventPluginSignal(
|
||||
providing_args=[]
|
||||
)
|
||||
|
||||
@@ -19,20 +19,7 @@
|
||||
{% endcompress %}
|
||||
{% endif %}
|
||||
|
||||
{% compress js %}
|
||||
<script type="text/javascript" src="{% static "jquery/js/jquery-2.1.1.min.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "moment/moment-with-locales.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "js/jquery.formset.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "bootstrap/js/bootstrap.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "datetimepicker/bootstrap-datetimepicker.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "pretixcontrol/js/jquery.qrcode.min.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "pretixpresale/js/ui/questions.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "pretixpresale/js/ui/main.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "pretixbase/js/asynctask.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "pretixbase/js/details.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "pretixpresale/js/ui/cart.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "lightbox/js/lightbox.min.js" %}"></script>
|
||||
{% endcompress %}
|
||||
{% include "pretixpresale/fragment_js.html" %}
|
||||
<meta name="referrer" content="origin">
|
||||
{{ html_head|safe }}
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
|
||||
@@ -79,20 +66,7 @@
|
||||
{% include "pretixpresale/base_footer.html" %}
|
||||
</footer>
|
||||
</div>
|
||||
<div id="ajaxerr">
|
||||
</div>
|
||||
<div id="loadingmodal">
|
||||
<div class="modal-card">
|
||||
<div class="modal-card-icon">
|
||||
<i class="fa fa-cog big-rotating-icon"></i>
|
||||
</div>
|
||||
<div class="modal-card-content">
|
||||
<h3></h3>
|
||||
<p class="text"></p>
|
||||
<p class="status">{% trans "If this takes longer than a few minutes, please contact us." %}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% include "pretixpresale/fragment_modals.html" %}
|
||||
{% if DEBUG %}
|
||||
<script type="text/javascript" src="{% url 'javascript-catalog' lang=request.LANGUAGE_CODE %}" async></script>
|
||||
{% else %}
|
||||
|
||||
@@ -13,11 +13,20 @@
|
||||
{% if line.variation %}
|
||||
– {{ line.variation }}
|
||||
{% endif %}
|
||||
{% if line.seat %}
|
||||
<br />
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="14" viewBox="0 0 4.7624999 3.7041668" class="svg-icon">
|
||||
<path
|
||||
style="fill:black"
|
||||
d="m 1.9592032,1.8522629e-4 c -0.21468,0 -0.38861,0.17394000371 -0.38861,0.38861000371 0,0.21466 0.17393,0.38861 0.38861,0.38861 0.21468,0 0.3886001,-0.17395 0.3886001,-0.38861 0,-0.21467 -0.1739201,-0.38861000371 -0.3886001,-0.38861000371 z m 0.1049,0.84543000371 c -0.20823,-0.0326 -0.44367,0.12499 -0.39998,0.40462997 l 0.20361,1.01854 c 0.0306,0.15316 0.15301,0.28732 0.3483,0.28732 h 0.8376701 v 0.92708 c 0,0.29313 0.41187,0.29447 0.41187,0.005 v -1.19115 c 0,-0.14168 -0.0995,-0.29507 -0.29094,-0.29507 l -0.65578,-10e-4 -0.1757,-0.87644 C 2.3042533,0.95300523 2.1890432,0.86500523 2.0641032,0.84547523 Z m -0.58549,0.44906997 c -0.0946,-0.0134 -0.20202,0.0625 -0.17829,0.19172 l 0.18759,0.91054 c 0.0763,0.33956 0.36802,0.55914 0.66042,0.55914 h 0.6015201 c 0.21356,0 0.21448,-0.32143 -0.003,-0.32143 H 2.1954632 c -0.19911,0 -0.36364,-0.11898 -0.41341,-0.34107 l -0.17777,-0.87126 c -0.0165,-0.0794 -0.0688,-0.11963 -0.12557,-0.12764 z"/>
|
||||
</svg>
|
||||
{{ line.seat }}
|
||||
{% endif %}
|
||||
{% if line.voucher %}
|
||||
<br /><span class="fa fa-tags"></span> {% trans "Voucher code used:" %} {{ line.voucher.code }}
|
||||
<br /><span class="fa fa-tags fa-fw"></span> {% trans "Voucher code used:" %} {{ line.voucher.code }}
|
||||
{% endif %}
|
||||
{% if line.subevent %}
|
||||
<br /><span class="fa fa-calendar"></span> {{ line.subevent.name }} · {{ line.subevent.get_date_range_display }}
|
||||
<br /><span class="fa fa-calendar fa-fw"></span> {{ line.subevent.name }} · {{ line.subevent.get_date_range_display }}
|
||||
{% if event.settings.show_times %}
|
||||
<span class="fa fa-clock-o"></span>
|
||||
{{ line.subevent.date_from|date:"TIME_FORMAT" }}
|
||||
@@ -116,7 +125,7 @@
|
||||
<input type="hidden" name="price_{{ line.item.id }}"
|
||||
value="{% if event.settings.display_net_prices %}{{ line.net_price }}{% else %}{{ line.price }}{% endif %}" />
|
||||
{% endif %}
|
||||
<button class="btn btn-mini btn-link" title="{% trans "Add one more" %}">
|
||||
<button class="btn btn-mini btn-link" title="{% trans "Add one more" %}" {% if line.seat %}disabled{% endif %}>
|
||||
<i class="fa fa-plus"></i>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
</div>
|
||||
{% elif var.cached_availability.0 == 100 %}
|
||||
<div class="col-md-2 col-xs-6 availability-box available">
|
||||
{% if item.max_per_order == 1 %}
|
||||
{% if item.max_per_order == 1 %}
|
||||
<label class="item-checkbox-label">
|
||||
<input type="checkbox" value="1"
|
||||
{% if not ev.presale_is_running %}disabled{% endif %}
|
||||
@@ -255,7 +255,7 @@
|
||||
</div>
|
||||
{% elif item.cached_availability.0 == 100 %}
|
||||
<div class="col-md-2 col-xs-6 availability-box available">
|
||||
{% if item.max_per_order == 1 %}
|
||||
{% if item.max_per_order == 1 %}
|
||||
<label class="item-checkbox-label">
|
||||
<input type="checkbox" value="1" {% if itemnum == 1 %}checked{% endif %}
|
||||
{% if not ev.presale_is_running %}disabled{% endif %}
|
||||
|
||||
@@ -219,6 +219,13 @@
|
||||
action="{% eventurl request.event "presale:event.cart.add" cart_namespace=cart_namespace %}?next={{ cart_redirect|urlencode }}">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="subevent" value="{{ subevent.id|default_if_none:"" }}" />
|
||||
{% if ev.seating_plan_id %}
|
||||
{% if event.has_subevents %}
|
||||
{% eventsignal event "pretix.presale.signals.render_seating_plan" request=request subevent=subevent %}
|
||||
{% else %}
|
||||
{% eventsignal event "pretix.presale.signals.render_seating_plan" request=request %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% include "pretixpresale/event/fragment_product_list.html" %}
|
||||
{% if ev.presale_is_running and display_add_to_cart %}
|
||||
<section class="front-page">
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% load eventurl %}
|
||||
{% load compress %}
|
||||
{% load eventsignal %}
|
||||
{% load statici18n %}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
{% if css_file %}
|
||||
<link rel="stylesheet" type="text/css" href="{{ css_file }}"/>
|
||||
{% else %}
|
||||
{% compress css %}
|
||||
<link rel="stylesheet" type="text/x-scss" href="{% static "pretixpresale/scss/main.scss" %}"/>
|
||||
{% endcompress %}
|
||||
{% endif %}
|
||||
{% include "pretixpresale/fragment_js.html" %}
|
||||
<meta name="referrer" content="origin">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
|
||||
</head>
|
||||
<body class="full-screen-seating" data-locale="{{ request.LANGUAGE_CODE }}">
|
||||
<form method="post" data-asynctask
|
||||
data-asynctask-headline="{% trans "We're now trying to reserve this for you!" %}"
|
||||
data-asynctask-text="{% blocktrans with time=event.settings.reservation_time %}Once the items are in your cart, you will have {{ time }} minutes to complete your purchase.{% endblocktrans %}"
|
||||
action="{% eventurl request.event "presale:event.cart.add" cart_namespace=cart_namespace %}?next={{ cart_redirect|urlencode }}">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="subevent" value="{{ subevent.id|default_if_none:"" }}"/>
|
||||
{% if event.has_subevents %}
|
||||
{% eventsignal event "pretix.presale.signals.render_seating_plan" request=request subevent=subevent %}
|
||||
{% else %}
|
||||
{% eventsignal event "pretix.presale.signals.render_seating_plan" request=request %}
|
||||
{% endif %}
|
||||
</form>
|
||||
{% include "pretixpresale/fragment_modals.html" %}
|
||||
{% if DEBUG %}
|
||||
<script type="text/javascript" src="{% url 'javascript-catalog' lang=request.LANGUAGE_CODE %}" async></script>
|
||||
{% else %}
|
||||
<script src="{% statici18n LANGUAGE_CODE %}" async></script>
|
||||
{% endif %}
|
||||
{% if request.session.iframe_session %}
|
||||
{% compress js %}
|
||||
<script type="text/javascript" src="{% static "iframeresizer/iframeResizer.contentWindow.js" %}"></script>
|
||||
{% endcompress %}
|
||||
{% endif %}
|
||||
{{ html_foot|safe }}
|
||||
</body>
|
||||
</html>
|
||||
@@ -29,6 +29,14 @@
|
||||
<input type="hidden" name="subevent" value="{{ subevent.id|default_if_none:"" }}" />
|
||||
<input type="hidden" name="_voucher_code" value="{{ voucher.code }}">
|
||||
|
||||
{% if voucher.seating_available %}
|
||||
{% if event.has_subevents %}
|
||||
{% eventsignal event "pretix.presale.signals.render_seating_plan" request=request subevent=subevent voucher=voucher %}
|
||||
{% else %}
|
||||
{% eventsignal event "pretix.presale.signals.render_seating_plan" request=request voucher=voucher %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% for tup in items_by_category %}
|
||||
<section>
|
||||
{% if tup.0 %}
|
||||
|
||||
16
src/pretix/presale/templates/pretixpresale/fragment_js.html
Normal file
16
src/pretix/presale/templates/pretixpresale/fragment_js.html
Normal file
@@ -0,0 +1,16 @@
|
||||
{% load static %}
|
||||
{% load compress %}
|
||||
{% compress js %}
|
||||
<script type="text/javascript" src="{% static "jquery/js/jquery-2.1.1.min.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "moment/moment-with-locales.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "js/jquery.formset.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "bootstrap/js/bootstrap.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "datetimepicker/bootstrap-datetimepicker.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "pretixcontrol/js/jquery.qrcode.min.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "pretixpresale/js/ui/questions.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "pretixpresale/js/ui/main.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "pretixbase/js/asynctask.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "pretixbase/js/details.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "pretixpresale/js/ui/cart.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "lightbox/js/lightbox.min.js" %}"></script>
|
||||
{% endcompress %}
|
||||
@@ -0,0 +1,15 @@
|
||||
{% load i18n %}
|
||||
<div id="ajaxerr">
|
||||
</div>
|
||||
<div id="loadingmodal">
|
||||
<div class="modal-card">
|
||||
<div class="modal-card-icon">
|
||||
<i class="fa fa-cog big-rotating-icon"></i>
|
||||
</div>
|
||||
<div class="modal-card-content">
|
||||
<h3></h3>
|
||||
<p class="text"></p>
|
||||
<p class="status">{% trans "If this takes longer than a few minutes, please contact us." %}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -27,6 +27,10 @@ frame_wrapped_urls = [
|
||||
name='event.checkout'),
|
||||
url(r'^redeem/?$', pretix.presale.views.cart.RedeemView.as_view(),
|
||||
name='event.redeem'),
|
||||
url(r'^seatingframe/$', pretix.presale.views.event.SeatingPlanView.as_view(),
|
||||
name='event.seatingplan'),
|
||||
url(r'^(?P<subevent>[0-9]+)/seatingframe/$', pretix.presale.views.event.SeatingPlanView.as_view(),
|
||||
name='event.seatingplan'),
|
||||
url(r'^(?P<subevent>[0-9]+)/$', pretix.presale.views.event.EventIndex.as_view(), name='event.index'),
|
||||
url(r'^waitinglist', pretix.presale.views.waiting.WaitingView.as_view(), name='event.waitinglist'),
|
||||
url(r'^$', pretix.presale.views.event.EventIndex.as_view(), name='event.index'),
|
||||
|
||||
@@ -59,7 +59,7 @@ class CartMixin:
|
||||
cartpos = queryset.order_by(
|
||||
'item__category__position', 'item__category_id', 'item__position', 'item__name', 'variation__value'
|
||||
).select_related(
|
||||
'item', 'variation', 'addon_to', 'subevent', 'subevent__event', 'subevent__event__organizer'
|
||||
'item', 'variation', 'addon_to', 'subevent', 'subevent__event', 'subevent__event__organizer', 'seat'
|
||||
).prefetch_related(
|
||||
*prefetch
|
||||
)
|
||||
@@ -103,13 +103,13 @@ class CartMixin:
|
||||
)
|
||||
addon_penalty = 1 if pos.addon_to else 0
|
||||
if downloads or pos.pk in has_addons or pos.addon_to:
|
||||
return i, addon_penalty, pos.pk, 0, 0, 0, 0, (pos.subevent_id or 0)
|
||||
return i, addon_penalty, pos.pk, 0, 0, 0, 0, (pos.subevent_id or 0), pos.seat_id
|
||||
if answers and (has_attendee_data or pos.item.questions.all()):
|
||||
return i, addon_penalty, pos.pk, 0, 0, 0, 0, (pos.subevent_id or 0)
|
||||
return i, addon_penalty, pos.pk, 0, 0, 0, 0, (pos.subevent_id or 0), pos.seat_id
|
||||
|
||||
return (
|
||||
0, addon_penalty, 0, pos.item_id, pos.variation_id, pos.price, (pos.voucher_id or 0),
|
||||
(pos.subevent_id or 0)
|
||||
(pos.subevent_id or 0), pos.seat_id
|
||||
)
|
||||
|
||||
positions = []
|
||||
|
||||
@@ -90,10 +90,26 @@ class CartActionMixin:
|
||||
if value.strip() == '' or '_' not in key:
|
||||
return
|
||||
|
||||
if not key.startswith('item_') and not key.startswith('variation_'):
|
||||
if not key.startswith('item_') and not key.startswith('variation_') and not key.startswith('seat_'):
|
||||
return
|
||||
|
||||
parts = key.split("_")
|
||||
price = self.request.POST.get('price_' + "_".join(parts[1:]), "")
|
||||
|
||||
if key.startswith('seat_'):
|
||||
try:
|
||||
return {
|
||||
'item': int(parts[1]),
|
||||
'variation': int(parts[2]) if len(parts) > 2 else None,
|
||||
'count': 1,
|
||||
'seat': value,
|
||||
'price': price,
|
||||
'voucher': voucher,
|
||||
'subevent': self.request.POST.get("subevent")
|
||||
}
|
||||
except ValueError:
|
||||
raise CartError(_('Please enter numbers only.'))
|
||||
|
||||
try:
|
||||
amount = int(value)
|
||||
except ValueError:
|
||||
@@ -103,7 +119,6 @@ class CartActionMixin:
|
||||
elif amount == 0:
|
||||
return
|
||||
|
||||
price = self.request.POST.get('price_' + "_".join(parts[1:]), "")
|
||||
if key.startswith('item_'):
|
||||
try:
|
||||
return {
|
||||
@@ -131,8 +146,7 @@ class CartActionMixin:
|
||||
|
||||
def _items_from_post_data(self):
|
||||
"""
|
||||
Parses the POST data and returns a list of tuples in the
|
||||
form (item id, variation id or None, number)
|
||||
Parses the POST data and returns a list of dictionaries
|
||||
"""
|
||||
|
||||
# Compatibility patch that makes the frontend code a lot easier
|
||||
|
||||
@@ -7,7 +7,7 @@ from importlib import import_module
|
||||
import pytz
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db.models import Count, Prefetch
|
||||
from django.db.models import Count, Exists, OuterRef, Prefetch
|
||||
from django.http import Http404, HttpResponse
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.utils.decorators import method_decorator
|
||||
@@ -17,7 +17,7 @@ from django.views import View
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
from pretix.base.models import ItemVariation, Quota
|
||||
from pretix.base.models import ItemVariation, Quota, SeatCategoryMapping
|
||||
from pretix.base.models.event import SubEvent
|
||||
from pretix.base.models.items import ItemBundle
|
||||
from pretix.multidomain.urlreverse import eventreverse
|
||||
@@ -49,7 +49,7 @@ def item_group_by_category(items):
|
||||
)
|
||||
|
||||
|
||||
def get_grouped_items(event, subevent=None, voucher=None, channel='web'):
|
||||
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(
|
||||
'category', 'tax_rule', # for re-grouping
|
||||
).prefetch_related(
|
||||
@@ -81,10 +81,20 @@ def get_grouped_items(event, subevent=None, voucher=None, channel='web'):
|
||||
).distinct()),
|
||||
).annotate(
|
||||
quotac=Count('quotas'),
|
||||
has_variations=Count('variations')
|
||||
has_variations=Count('variations'),
|
||||
requires_seat=Exists(
|
||||
SeatCategoryMapping.objects.filter(
|
||||
product_id=OuterRef('pk'),
|
||||
subevent=subevent
|
||||
)
|
||||
)
|
||||
).filter(
|
||||
quotac__gt=0
|
||||
quotac__gt=0,
|
||||
).order_by('category__position', 'category_id', 'position', 'name')
|
||||
if require_seat:
|
||||
items = items.filter(requires_seat__gt=0)
|
||||
else:
|
||||
items = items.filter(requires_seat=0)
|
||||
display_add_to_cart = False
|
||||
external_quota_cache = event.cache.get('item_quota_cache')
|
||||
quota_cache = external_quota_cache or {}
|
||||
@@ -342,6 +352,52 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
||||
return context
|
||||
|
||||
|
||||
@method_decorator(allow_frame_if_namespaced, 'dispatch')
|
||||
@method_decorator(iframe_entry_view_wrapper, 'dispatch')
|
||||
class SeatingPlanView(EventViewMixin, TemplateView):
|
||||
template_name = "pretixpresale/event/seatingplan.html"
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
from pretix.presale.views.cart import get_or_create_cart_id
|
||||
|
||||
self.subevent = None
|
||||
if request.GET.get('src', '') == 'widget' and 'take_cart_id' in request.GET:
|
||||
# User has clicked "Open in a new tab" link in widget
|
||||
get_or_create_cart_id(request)
|
||||
return redirect(eventreverse(request.event, 'presale:event.seatingplan', kwargs=kwargs))
|
||||
elif request.GET.get('iframe', '') == '1' and 'take_cart_id' in request.GET:
|
||||
# Widget just opened, a cart already exists. Let's to a stupid redirect to check if cookies are disabled
|
||||
get_or_create_cart_id(request)
|
||||
return redirect(eventreverse(request.event, 'presale:event.seatingplan', kwargs=kwargs) + '?require_cookie=true&cart_id={}'.format(
|
||||
request.GET.get('take_cart_id')
|
||||
))
|
||||
elif request.GET.get('iframe', '') == '1' and len(self.request.GET.get('widget_data', '{}')) > 3:
|
||||
# We've been passed data from a widget, we need to create a cart session to store it.
|
||||
get_or_create_cart_id(request)
|
||||
|
||||
if request.event.has_subevents:
|
||||
if 'subevent' in kwargs:
|
||||
self.subevent = request.event.subevents.using(settings.DATABASE_REPLICA).filter(pk=kwargs['subevent'], active=True).first()
|
||||
if not self.subevent or not self.subevent.seating_plan:
|
||||
raise Http404()
|
||||
return super().get(request, *args, **kwargs)
|
||||
else:
|
||||
raise Http404()
|
||||
else:
|
||||
if 'subevent' in kwargs or not request.event.seating_plan:
|
||||
raise Http404()
|
||||
else:
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['cart_redirect'] = eventreverse(self.request.event, 'presale:event.checkout.start',
|
||||
kwargs={'cart_namespace': kwargs.get('cart_namespace') or ''})
|
||||
if context['cart_redirect'].startswith('https:'):
|
||||
context['cart_redirect'] = '/' + context['cart_redirect'].split('/', 3)[3]
|
||||
return context
|
||||
|
||||
|
||||
class EventIcalDownload(EventViewMixin, View):
|
||||
def get(self, request, *args, **kwargs):
|
||||
if not self.request.event:
|
||||
|
||||
@@ -515,6 +515,8 @@ class WidgetAPIProductList(EventListMixin, View):
|
||||
data['display_add_to_cart'] = False
|
||||
data['itemnum'] = 0
|
||||
|
||||
data['has_seating_plan'] = ev.seating_plan is not None
|
||||
|
||||
vouchers_exist = self.request.event.get_cache().get('vouchers_exist')
|
||||
if vouchers_exist is None:
|
||||
vouchers_exist = self.request.event.vouchers.exists()
|
||||
|
||||
Reference in New Issue
Block a user