Files
pretix_cgo/src/pretix/presale/views/waiting.py
Raphael Michel 40c8d014df Waiting list: Redirect to shop if no products can be awaited (Z#23168172) (#4517)
* Waiting list: Redirect to shop if no products can be awaited (Z#23168172)

* Update src/pretix/presale/views/waiting.py

Co-authored-by: Mira <weller@rami.io>

---------

Co-authored-by: Mira <weller@rami.io>
2024-10-14 09:26:06 +02:00

227 lines
9.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from datetime import timedelta
from django.conf import settings
from django.contrib import messages
from django.db import transaction
from django.http import Http404
from django.shortcuts import get_object_or_404, redirect, render
from django.utils.decorators import method_decorator
from django.utils.functional import cached_property
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _, pgettext_lazy
from django.views.generic import FormView, TemplateView
from pretix.base.models import Quota, SubEvent
from pretix.base.templatetags.urlreplace import url_replace
from pretix.multidomain.urlreverse import eventreverse
from pretix.presale.views import EventViewMixin, iframe_entry_view_wrapper
from ...base.i18n import get_language_without_region
from ...base.models import Voucher, WaitingListEntry
from ..forms.waitinglist import WaitingListForm
from . import allow_frame_if_namespaced
from .event import get_grouped_items
@method_decorator(allow_frame_if_namespaced, 'dispatch')
@method_decorator(iframe_entry_view_wrapper, 'dispatch')
class WaitingView(EventViewMixin, FormView):
template_name = 'pretixpresale/event/waitinglist.html'
form_class = WaitingListForm
@cached_property
def itemvars(self):
customer = getattr(self.request, 'customer', None)
items, display_add_to_cart = get_grouped_items(
self.request.event,
subevent=self.subevent,
require_seat=None,
channel=self.request.organizer.sales_channels.get(identifier="web"),
memberships=(
customer.usable_memberships(
for_event=self.subevent or self.request.event,
testmode=self.request.event.testmode
)
if customer else None
),
)
choices = []
for i in items:
if not i.allow_waitinglist:
continue
if i.has_variations:
for v in i.available_variations:
if v.cached_availability[0] == Quota.AVAILABILITY_OK:
continue
choices.append((f'{i.pk}-{v.pk}', f'{i.name} {v.value}'))
else:
if i.cached_availability[0] == Quota.AVAILABILITY_OK:
continue
choices.append((f'{i.pk}', f'{i.name}'))
return choices
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['request'] = self.request
kwargs['event'] = self.request.event
kwargs['instance'] = WaitingListEntry(
event=self.request.event, locale=get_language_without_region(),
subevent=self.subevent
)
kwargs['itemvars'] = self.itemvars
kwargs.setdefault('initial', {})
if 'var' in self.request.GET:
kwargs['initial']['itemvar'] = f'{self.request.GET.get("item")}-{self.request.GET.get("var")}'
else:
kwargs['initial']['itemvar'] = self.request.GET.get("item")
if getattr(self.request, 'customer', None):
kwargs['initial']['email'] = self.request.customer.email
return kwargs
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['event'] = self.request.event
ctx['subevent'] = self.subevent
return ctx
def get(self, request, *args, **kwargs):
if request.GET.get('iframe', '') == '1' and 'require_cookie' not in request.GET:
# Widget just opened. Let's to a stupid redirect to check if cookies are disabled
return redirect(request.get_full_path() + '&require_cookie=true')
elif 'require_cookie' in request.GET and settings.SESSION_COOKIE_NAME not in request.COOKIES and\
'__Host-' + settings.SESSION_COOKIE_NAME not in self.request.COOKIES:
# Cookies are in fact not supported. We can't even display the form, since we can't get CSRF right without
# cookies.
r = render(request, 'pretixpresale/event/cookies.html', {
'url': eventreverse(
request.event, "presale:event.waitinglist", kwargs={'cart_namespace': kwargs.get('cart_namespace')}
) + '?' + url_replace(request, 'require_cookie', '', 'iframe', '', 'locale', request.GET.get('locale', get_language_without_region()))
})
r._csp_ignore = True
return r
if not self.itemvars:
messages.info(request, _("No ticket types are available for the waiting list, have a look at the "
"ticket shop instead."))
return redirect(self.get_index_url())
return super().get(request, *args, **kwargs)
def dispatch(self, request, *args, **kwargs):
self.request = request
if not self.request.event.settings.waiting_list_enabled:
messages.error(request, _("Waiting lists are disabled for this event."))
return redirect(self.get_index_url())
if self.request.event.presale_has_ended:
messages.error(request, _("The booking period for this event is over."))
return redirect(self.get_index_url())
if not self.request.event.presale_is_running:
messages.error(request, _("The booking period for this event has not yet started."))
return redirect(self.get_index_url())
self.subevent = None
if request.event.has_subevents:
if 'subevent' in request.GET:
try:
self.subevent = get_object_or_404(SubEvent, event=request.event, pk=request.GET['subevent'],
active=True)
except ValueError:
raise Http404()
else:
messages.error(request, pgettext_lazy('subevent', "You need to select a date."))
return redirect(self.get_index_url())
if not (self.subevent or self.request.event).waiting_list_active:
messages.error(request, _("Waiting lists are disabled for this event."))
return redirect(self.get_index_url())
return super().dispatch(request, *args, **kwargs)
def form_valid(self, form):
availability = (
form.instance.variation.check_quotas(count_waitinglist=True, subevent=self.subevent)
if form.instance.variation
else form.instance.item.check_quotas(count_waitinglist=True, subevent=self.subevent)
)
if availability[0] == Quota.AVAILABILITY_OK:
messages.error(self.request, _("You cannot add yourself to the waiting list as this product is currently "
"available."))
return redirect(self.get_index_url())
form.save()
form.instance.log_action("pretix.event.orders.waitinglist.added")
messages.success(self.request, _(
"We've added you to the waiting list. We will send an email "
"to {email} as soon as this product gets available again."
).format(email=form.instance.email))
return super().form_valid(form)
def get_success_url(self):
return self.get_index_url()
@method_decorator(allow_frame_if_namespaced, 'dispatch')
class WaitingRemoveView(EventViewMixin, TemplateView):
template_name = 'pretixpresale/event/waitinglist_remove.html'
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['event'] = self.request.event
ctx['voucher'] = self.voucher
return ctx
def dispatch(self, request, *args, **kwargs):
self.request = request
try:
self.voucher = self.request.event.vouchers.get(
code=request.GET.get("voucher", ""),
waitinglistentries__isnull=False,
)
except Voucher.DoesNotExist:
messages.error(request, _("We could not find you on our waiting list."))
return redirect(self.get_index_url())
if not self.voucher.is_active():
messages.error(request, _("Your waiting list spot is no longer valid or already used. There's nothing more to do here."))
return redirect(self.get_index_url())
return super().dispatch(request, *args, **kwargs)
@transaction.atomic()
def post(self, request, *args, **kwargs):
self.voucher.valid_until = now() - timedelta(seconds=1)
self.voucher.save(update_fields=['valid_until'])
self.voucher.log_action('pretix.voucher.expired.waitinglist')
messages.success(request, _("Thank you very much! We will assign your spot on the waiting list to someone else."))
return redirect(self.get_index_url())
def get_success_url(self):
return self.get_index_url()