mirror of
https://github.com/pretix/pretix.git
synced 2026-05-07 15:34:02 +00:00
Allow to enter a voucher before choosing a subevent
This commit is contained in:
@@ -32,7 +32,7 @@
|
|||||||
<label class="col-md-3 control-label" for="id_url">{% trans "Voucher link" %}</label>
|
<label class="col-md-3 control-label" for="id_url">{% trans "Voucher link" %}</label>
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
<input type="text" name="url"
|
<input type="text" name="url"
|
||||||
value="{% abseventurl request.event "presale:event.redeem" %}?voucher={{ voucher.code }}{% if voucher.subevent_id %}&subevent={{ voucher.subevent_id }}{% endif %}"
|
value="{% abseventurl request.event "presale:event.redeem" %}?voucher={{ voucher.code|urlencode }}{% if voucher.subevent_id %}&subevent={{ voucher.subevent_id }}{% endif %}"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
id="id_url" readonly>
|
id="id_url" readonly>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load eventurl %}
|
{% load eventurl %}
|
||||||
{% for subev in subevent_list %}
|
{% for subev in subevent_list %}
|
||||||
<a href="{% eventurl event "presale:event.index" subevent=subev.id cart_namespace=cart_namespace %}"
|
<a href="{% if request.GET.voucher %}{% eventurl event "presale:event.redeem" cart_namespace=cart_namespace %}?voucher={{ request.GET.voucher|urlencode }}&subevent={{ subev.pk }}{% else %}{% eventurl event "presale:event.index" subevent=subev.id cart_namespace=cart_namespace %}{% endif %}"
|
||||||
class="subevent-row">
|
class="subevent-row">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
|
|||||||
@@ -101,6 +101,12 @@
|
|||||||
{{ frontpage_text|rich_text }}
|
{{ frontpage_text|rich_text }}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if request.GET.voucher %}
|
||||||
|
<div class="alert alert-info">
|
||||||
|
{% trans "Please select a date to redeem your voucher." %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if subevent and "year" not in request.GET %}
|
{% if subevent and "year" not in request.GET %}
|
||||||
|
|||||||
@@ -10,7 +10,13 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>{% trans "Voucher redemption" %}</h2>
|
<h2>{% trans "Voucher redemption" %}</h2>
|
||||||
|
|
||||||
{% if subevent %}
|
{% if subevent %}
|
||||||
|
{% if request.GET.subevent and subevent.pk|stringformat:"i" != request.GET.subevent %}
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
{% trans "This voucher is valid only for the following specific date and time." %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<h3>{{ subevent.name }}</h3>
|
<h3>{{ subevent.name }}</h3>
|
||||||
{% with ev=subevent %}
|
{% with ev=subevent %}
|
||||||
<div class="info-row">
|
<div class="info-row">
|
||||||
|
|||||||
@@ -518,7 +518,6 @@ class RedeemView(NoSearchIndexViewMixin, EventViewMixin, TemplateView):
|
|||||||
kwargs={'cart_namespace': kwargs.get('cart_namespace') or ''})
|
kwargs={'cart_namespace': kwargs.get('cart_namespace') or ''})
|
||||||
if context['cart_redirect'].startswith('https:'):
|
if context['cart_redirect'].startswith('https:'):
|
||||||
context['cart_redirect'] = '/' + context['cart_redirect'].split('/', 3)[3]
|
context['cart_redirect'] = '/' + context['cart_redirect'].split('/', 3)[3]
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
@@ -566,6 +565,10 @@ class RedeemView(NoSearchIndexViewMixin, EventViewMixin, TemplateView):
|
|||||||
|
|
||||||
if hasattr(self, 'voucher') and self.voucher.subevent:
|
if hasattr(self, 'voucher') and self.voucher.subevent:
|
||||||
self.subevent = self.voucher.subevent
|
self.subevent = self.voucher.subevent
|
||||||
|
|
||||||
|
if not err and not self.subevent:
|
||||||
|
return redirect(eventreverse(self.request.event, 'presale:event.index',
|
||||||
|
kwargs={'cart_namespace': kwargs.get('cart_namespace') or ''}) + '?voucher=' + quote(self.voucher.code))
|
||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ from django.views.decorators.csrf import csrf_exempt
|
|||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
from pretix.base.channels import get_all_sales_channels
|
from pretix.base.channels import get_all_sales_channels
|
||||||
from pretix.base.models import ItemVariation, Quota, SeatCategoryMapping
|
from pretix.base.models import ItemVariation, Quota, SeatCategoryMapping, Voucher
|
||||||
from pretix.base.models.event import SubEvent
|
from pretix.base.models.event import SubEvent
|
||||||
from pretix.base.models.items import (
|
from pretix.base.models.items import (
|
||||||
ItemBundle, SubEventItem, SubEventItemVariation,
|
ItemBundle, SubEventItem, SubEventItemVariation,
|
||||||
@@ -375,6 +375,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
|||||||
if vouchers_exist is None:
|
if vouchers_exist is None:
|
||||||
vouchers_exist = self.request.event.vouchers.exists()
|
vouchers_exist = self.request.event.vouchers.exists()
|
||||||
self.request.event.cache.set('vouchers_exist', vouchers_exist)
|
self.request.event.cache.set('vouchers_exist', vouchers_exist)
|
||||||
|
context['show_vouchers'] = context['vouchers_exist'] = vouchers_exist
|
||||||
|
|
||||||
if not self.request.event.has_subevents or self.subevent:
|
if not self.request.event.has_subevents or self.subevent:
|
||||||
# Fetch all items
|
# Fetch all items
|
||||||
@@ -399,12 +400,6 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
|||||||
context['items_by_category'] = item_group_by_category(items)
|
context['items_by_category'] = item_group_by_category(items)
|
||||||
context['display_add_to_cart'] = display_add_to_cart
|
context['display_add_to_cart'] = display_add_to_cart
|
||||||
|
|
||||||
context['show_vouchers'] = vouchers_exist
|
|
||||||
context['vouchers_exist'] = vouchers_exist
|
|
||||||
else:
|
|
||||||
context['show_vouchers'] = False
|
|
||||||
context['vouchers_exist'] = vouchers_exist
|
|
||||||
|
|
||||||
context['ev'] = self.subevent or self.request.event
|
context['ev'] = self.subevent or self.request.event
|
||||||
context['subevent'] = self.subevent
|
context['subevent'] = self.subevent
|
||||||
context['cart'] = self.get_cart()
|
context['cart'] = self.get_cart()
|
||||||
@@ -434,6 +429,13 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
def _subevent_list_context(self):
|
def _subevent_list_context(self):
|
||||||
|
voucher = None
|
||||||
|
if self.request.GET.get('voucher'):
|
||||||
|
try:
|
||||||
|
voucher = Voucher.objects.get(code__iexact=self.request.GET.get('voucher'), event=self.request.event)
|
||||||
|
except Voucher.DoesNotExist:
|
||||||
|
pass
|
||||||
|
|
||||||
context = {}
|
context = {}
|
||||||
context['list_type'] = self.request.GET.get("style", self.request.event.settings.event_list_type)
|
context['list_type'] = self.request.GET.get("style", self.request.event.settings.event_list_type)
|
||||||
if context['list_type'] not in ("calendar", "week") and self.request.event.subevents.filter(date_from__gt=now()).count() > 50:
|
if context['list_type'] not in ("calendar", "week") and self.request.event.subevents.filter(date_from__gt=now()).count() > 50:
|
||||||
@@ -456,7 +458,8 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
|||||||
add_subevents_for_days(
|
add_subevents_for_days(
|
||||||
filter_qs_by_attr(self.request.event.subevents_annotated(self.request.sales_channel.identifier).using(settings.DATABASE_REPLICA), self.request),
|
filter_qs_by_attr(self.request.event.subevents_annotated(self.request.sales_channel.identifier).using(settings.DATABASE_REPLICA), self.request),
|
||||||
before, after, ebd, set(), self.request.event,
|
before, after, ebd, set(), self.request.event,
|
||||||
self.kwargs.get('cart_namespace')
|
self.kwargs.get('cart_namespace'),
|
||||||
|
voucher,
|
||||||
)
|
)
|
||||||
|
|
||||||
context['show_names'] = ebd.get('_subevents_different_names', False) or sum(
|
context['show_names'] = ebd.get('_subevents_different_names', False) or sum(
|
||||||
@@ -484,7 +487,9 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
|||||||
add_subevents_for_days(
|
add_subevents_for_days(
|
||||||
filter_qs_by_attr(self.request.event.subevents_annotated(self.request.sales_channel.identifier).using(settings.DATABASE_REPLICA), self.request),
|
filter_qs_by_attr(self.request.event.subevents_annotated(self.request.sales_channel.identifier).using(settings.DATABASE_REPLICA), self.request),
|
||||||
before, after, ebd, set(), self.request.event,
|
before, after, ebd, set(), self.request.event,
|
||||||
self.kwargs.get('cart_namespace')
|
self.kwargs.get('cart_namespace'),
|
||||||
|
self.request.GET.get('voucher'),
|
||||||
|
voucher,
|
||||||
)
|
)
|
||||||
|
|
||||||
context['show_names'] = ebd.get('_subevents_different_names', False) or sum(
|
context['show_names'] = ebd.get('_subevents_different_names', False) or sum(
|
||||||
@@ -503,7 +508,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
|||||||
context['subevent_list'] = self.request.event.subevents_sorted(
|
context['subevent_list'] = self.request.event.subevents_sorted(
|
||||||
filter_qs_by_attr(self.request.event.subevents_annotated(self.request.sales_channel.identifier).using(settings.DATABASE_REPLICA), self.request)
|
filter_qs_by_attr(self.request.event.subevents_annotated(self.request.sales_channel.identifier).using(settings.DATABASE_REPLICA), self.request)
|
||||||
)
|
)
|
||||||
if self.request.event.settings.event_list_available_only:
|
if self.request.event.settings.event_list_available_only and not voucher:
|
||||||
context['subevent_list'] = [
|
context['subevent_list'] = [
|
||||||
se for se in context['subevent_list']
|
se for se in context['subevent_list']
|
||||||
if not se.presale_has_ended and se.best_availability_state >= Quota.AVAILABILITY_RESERVED
|
if not se.presale_has_ended and se.best_availability_state >= Quota.AVAILABILITY_RESERVED
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import calendar
|
import calendar
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from datetime import date, datetime, time, timedelta
|
from datetime import date, datetime, time, timedelta
|
||||||
|
from urllib.parse import quote
|
||||||
|
|
||||||
import isoweek
|
import isoweek
|
||||||
import pytz
|
import pytz
|
||||||
@@ -357,7 +358,7 @@ def add_events_for_days(request, baseqs, before, after, ebd, timezones):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def add_subevents_for_days(qs, before, after, ebd, timezones, event=None, cart_namespace=None):
|
def add_subevents_for_days(qs, before, after, ebd, timezones, event=None, cart_namespace=None, voucher=None):
|
||||||
qs = qs.filter(active=True, is_public=True).filter(
|
qs = qs.filter(active=True, is_public=True).filter(
|
||||||
Q(Q(date_to__gte=before) & Q(date_from__lte=after)) |
|
Q(Q(date_to__gte=before) & Q(date_from__lte=after)) |
|
||||||
Q(Q(date_from__lte=after) & Q(date_to__gte=before)) |
|
Q(Q(date_from__lte=after) & Q(date_to__gte=before)) |
|
||||||
@@ -365,6 +366,7 @@ def add_subevents_for_days(qs, before, after, ebd, timezones, event=None, cart_n
|
|||||||
).order_by(
|
).order_by(
|
||||||
'date_from'
|
'date_from'
|
||||||
)
|
)
|
||||||
|
|
||||||
quotas_to_compute = []
|
quotas_to_compute = []
|
||||||
for se in qs:
|
for se in qs:
|
||||||
if se.presale_is_running:
|
if se.presale_is_running:
|
||||||
@@ -388,7 +390,7 @@ def add_subevents_for_days(qs, before, after, ebd, timezones, event=None, cart_n
|
|||||||
s = event.settings if event else se.event.settings
|
s = event.settings if event else se.event.settings
|
||||||
|
|
||||||
if s.event_list_available_only:
|
if s.event_list_available_only:
|
||||||
if se.presale_has_ended or se.best_availability_state < Quota.AVAILABILITY_RESERVED:
|
if se.presale_has_ended or ((not voucher or not voucher.allow_ignore_quota) and se.best_availability_state < Quota.AVAILABILITY_RESERVED):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
timezones.add(s.timezones)
|
timezones.add(s.timezones)
|
||||||
@@ -417,7 +419,12 @@ def add_subevents_for_days(qs, before, after, ebd, timezones, event=None, cart_n
|
|||||||
else None
|
else None
|
||||||
),
|
),
|
||||||
'event': se,
|
'event': se,
|
||||||
'url': eventreverse(se.event, 'presale:event.index', kwargs=kwargs)
|
'url': (
|
||||||
|
eventreverse(se.event, 'presale:event.redeem',
|
||||||
|
kwargs={k: v for k, v in kwargs.items() if k != 'subevent'}) + f'?subevent={se.pk}&voucher={quote(voucher.code)}'
|
||||||
|
if voucher
|
||||||
|
else eventreverse(se.event, 'presale:event.index', kwargs=kwargs)
|
||||||
|
)
|
||||||
})
|
})
|
||||||
d += timedelta(days=1)
|
d += timedelta(days=1)
|
||||||
|
|
||||||
@@ -426,7 +433,12 @@ def add_subevents_for_days(qs, before, after, ebd, timezones, event=None, cart_n
|
|||||||
'event': se,
|
'event': se,
|
||||||
'continued': False,
|
'continued': False,
|
||||||
'time': datetime_from.time().replace(tzinfo=None) if s.show_times else None,
|
'time': datetime_from.time().replace(tzinfo=None) if s.show_times else None,
|
||||||
'url': eventreverse(se.event, 'presale:event.index', kwargs=kwargs),
|
'url': (
|
||||||
|
eventreverse(se.event, 'presale:event.redeem',
|
||||||
|
kwargs={k: v for k, v in kwargs.items() if k != 'subevent'}) + f'?subevent={se.pk}&voucher={quote(voucher.code)}'
|
||||||
|
if voucher
|
||||||
|
else eventreverse(se.event, 'presale:event.index', kwargs=kwargs)
|
||||||
|
),
|
||||||
'timezone': s.timezone,
|
'timezone': s.timezone,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user