mirror of
https://github.com/pretix/pretix.git
synced 2026-05-05 15:14:04 +00:00
Add sub-events and relative date settings (#503)
* Data model * little crud * SubEventItemForm etc * Drop SubEventItem.active, quota editor * Fix failing tests * First frontend stuff * Addons form stuff * Quota calculation * net price display on EventIndex * Add tests, solve some bugs * Correct quota selection in more places, consolidate pricing logic * Fix failing quota tests * Fix TypeError * Add tests for checkout * Fixed a bug in QuotaForm * Prevent immutable cart if a quota was removed from an item * Add tests for pricing * Handle waiting list * Filter in check-in list * Fixed import lost in rebase * Fix waiting list widget * Voucher management * Voucher redemption * Fix broken tests * Add subevents to OrderChangeManager * Create a subevent during event creation * Fix bulk voucher creation * Introduce subevent.active * Copy from for subevents * Show active in list * ICal download for subevents * Check start and end of presale * Failing tests / show cart logic * Test * Rebase migrations * REST API integration of sub-events * Integrate quota calculation into the traditional quota form * Make subevent argument to add_position optional * Log-display foo * pretixdroid and subevents * Filter by subevent * Add more tests * Some mor tests * Rebase fixes * More tests * Relative dates * Restrict selection in relative datetime widgets * Filter subevent list * Re-label has_subevents * Rebase fixes, subevents in calendar view * Performance and caching issues * Refactor calendar templates * Permission tests * Calendar fixes and month selection * subevent selection * Rename subevents to dates * Add tests for calendar views
This commit is contained in:
@@ -37,7 +37,11 @@ class CheckInView(EventPermissionRequiredMixin, ListView):
|
||||
|
||||
if self.request.GET.get("item", "") != "":
|
||||
u = self.request.GET.get("item", "")
|
||||
qs = qs.filter(item_id__in=(u,))
|
||||
qs = qs.filter(item_id=u)
|
||||
|
||||
if self.request.GET.get("subevent", "") != "":
|
||||
s = self.request.GET.get("subevent", "")
|
||||
qs = qs.filter(subevent_id=s)
|
||||
|
||||
qs = qs.prefetch_related(
|
||||
Prefetch('checkins', queryset=Checkin.objects.filter(position__order__event=self.request.event))
|
||||
@@ -48,8 +52,11 @@ class CheckInView(EventPermissionRequiredMixin, ListView):
|
||||
keys_allowed = self.get_ordering_keys_mappings()
|
||||
if p in keys_allowed:
|
||||
mapped_field = keys_allowed[p]
|
||||
if type(mapped_field) is tuple:
|
||||
qs = qs.annotate(**mapped_field[1]).order_by(mapped_field[0])
|
||||
if isinstance(mapped_field, dict):
|
||||
order = mapped_field.pop('_order')
|
||||
qs = qs.annotate(**mapped_field).order_by(order)
|
||||
elif isinstance(mapped_field, (list, tuple)):
|
||||
qs = qs.order_by(*mapped_field)
|
||||
else:
|
||||
qs = qs.order_by(mapped_field)
|
||||
|
||||
@@ -58,7 +65,8 @@ class CheckInView(EventPermissionRequiredMixin, ListView):
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['items'] = Item.objects.filter(event=self.request.event)
|
||||
ctx['filtered'] = ("status" in self.request.GET or "user" in self.request.GET or "item" in self.request.GET)
|
||||
ctx['filtered'] = ("status" in self.request.GET or "user" in self.request.GET or "item" in self.request.GET
|
||||
or "subevent" in self.request.GET)
|
||||
return ctx
|
||||
|
||||
@staticmethod
|
||||
@@ -73,10 +81,12 @@ class CheckInView(EventPermissionRequiredMixin, ListView):
|
||||
'-status': F('checkins__id').desc(nulls_last=True),
|
||||
'timestamp': F('checkins__datetime').asc(nulls_first=True),
|
||||
'-timestamp': F('checkins__datetime').desc(nulls_last=True),
|
||||
'item': 'item__name',
|
||||
'-item': '-item__name',
|
||||
'name': (F('display_name').asc(nulls_first=True),
|
||||
{'display_name': Coalesce('attendee_name', 'addon_to__attendee_name')}),
|
||||
'-name': (F('display_name').desc(nulls_last=True),
|
||||
{'display_name': Coalesce('attendee_name', 'addon_to__attendee_name')}),
|
||||
'item': ('item__name', 'variation__value'),
|
||||
'-item': ('-item__name', 'variation__value'),
|
||||
'subevent': ('subevent__date_from', 'subevent__name'),
|
||||
'-subevent': ('-subevent__date_from', '-subevent__name'),
|
||||
'name': {'_order': F('display_name').asc(nulls_first=True),
|
||||
'display_name': Coalesce('attendee_name', 'addon_to__attendee_name')},
|
||||
'-name': {'_order': F('display_name').desc(nulls_last=True),
|
||||
'display_name': Coalesce('attendee_name', 'addon_to__attendee_name')},
|
||||
}
|
||||
|
||||
@@ -98,9 +98,9 @@ def waitinglist_widgets(sender, **kwargs):
|
||||
for wle in wles:
|
||||
if (wle.item, wle.variation) not in itemvar_cache:
|
||||
itemvar_cache[(wle.item, wle.variation)] = (
|
||||
wle.variation.check_quotas(count_waitinglist=False, _cache=quota_cache)
|
||||
wle.variation.check_quotas(subevent=wle.subevent, count_waitinglist=False, _cache=quota_cache)
|
||||
if wle.variation
|
||||
else wle.item.check_quotas(count_waitinglist=False, _cache=quota_cache)
|
||||
else wle.item.check_quotas(subevent=wle.subevent, count_waitinglist=False, _cache=quota_cache)
|
||||
)
|
||||
row = itemvar_cache.get((wle.item, wle.variation))
|
||||
if row[1] > 0:
|
||||
|
||||
@@ -5,7 +5,7 @@ from django.core.files import File
|
||||
from django.core.urlresolvers import resolve, reverse
|
||||
from django.db import transaction
|
||||
from django.db.models import Count, F, Q
|
||||
from django.forms.models import ModelMultipleChoiceField, inlineformset_factory
|
||||
from django.forms.models import inlineformset_factory
|
||||
from django.http import Http404, HttpResponseRedirect
|
||||
from django.shortcuts import redirect
|
||||
from django.utils.functional import cached_property
|
||||
@@ -21,6 +21,7 @@ from pretix.base.models import (
|
||||
CachedTicket, Item, ItemCategory, ItemVariation, Order, Question,
|
||||
QuestionAnswer, QuestionOption, Quota, Voucher,
|
||||
)
|
||||
from pretix.base.models.event import SubEvent
|
||||
from pretix.base.models.items import ItemAddOn
|
||||
from pretix.control.forms.item import (
|
||||
CategoryForm, ItemAddOnForm, ItemAddOnsFormSet, ItemCreateForm,
|
||||
@@ -549,54 +550,16 @@ class QuotaList(ListView):
|
||||
template_name = 'pretixcontrol/items/quotas.html'
|
||||
|
||||
def get_queryset(self):
|
||||
return Quota.objects.filter(
|
||||
qs = Quota.objects.filter(
|
||||
event=self.request.event
|
||||
).prefetch_related("items")
|
||||
if self.request.GET.get("subevent", "") != "":
|
||||
s = self.request.GET.get("subevent", "")
|
||||
qs = qs.filter(subevent_id=s)
|
||||
return qs
|
||||
|
||||
|
||||
class QuotaEditorMixin:
|
||||
@cached_property
|
||||
def items(self) -> "List[Item]":
|
||||
return list(self.request.event.items.all().prefetch_related("variations"))
|
||||
|
||||
def get_form(self, form_class=QuotaForm):
|
||||
if not hasattr(self, '_form'):
|
||||
kwargs = self.get_form_kwargs()
|
||||
kwargs['items'] = self.items
|
||||
self._form = form_class(**kwargs)
|
||||
return self._form
|
||||
|
||||
def get_context_data(self, *args, **kwargs) -> dict:
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['items'] = self.items
|
||||
for item in context['items']:
|
||||
item.field = self.get_form(QuotaForm)['item_%s' % item.id]
|
||||
return context
|
||||
|
||||
@transaction.atomic
|
||||
def form_valid(self, form):
|
||||
res = super().form_valid(form)
|
||||
items = self.object.items.all()
|
||||
variations = self.object.variations.all()
|
||||
selected_variations = []
|
||||
self.object = form.instance
|
||||
for item in self.items:
|
||||
field = form.fields['item_%s' % item.id]
|
||||
data = form.cleaned_data['item_%s' % item.id]
|
||||
if isinstance(field, ModelMultipleChoiceField):
|
||||
for v in data:
|
||||
selected_variations.append(v)
|
||||
if data and item not in items:
|
||||
self.object.items.add(item)
|
||||
elif not data and item in items:
|
||||
self.object.items.remove(item)
|
||||
|
||||
self.object.variations.add(*[v for v in selected_variations if v not in variations])
|
||||
self.object.variations.remove(*[v for v in variations if v not in selected_variations])
|
||||
return res
|
||||
|
||||
|
||||
class QuotaCreate(EventPermissionRequiredMixin, QuotaEditorMixin, CreateView):
|
||||
class QuotaCreate(EventPermissionRequiredMixin, CreateView):
|
||||
model = Quota
|
||||
form_class = QuotaForm
|
||||
template_name = 'pretixcontrol/items/quota_edit.html'
|
||||
@@ -691,7 +654,7 @@ class QuotaView(ChartContainingView, DetailView):
|
||||
raise Http404(_("The requested quota does not exist."))
|
||||
|
||||
|
||||
class QuotaUpdate(EventPermissionRequiredMixin, QuotaEditorMixin, UpdateView):
|
||||
class QuotaUpdate(EventPermissionRequiredMixin, UpdateView):
|
||||
model = Quota
|
||||
form_class = QuotaForm
|
||||
template_name = 'pretixcontrol/items/quota_edit.html'
|
||||
@@ -719,6 +682,22 @@ class QuotaUpdate(EventPermissionRequiredMixin, QuotaEditorMixin, UpdateView):
|
||||
k: form.cleaned_data.get(k) for k in form.changed_data
|
||||
}
|
||||
)
|
||||
if ((form.initial.get('subevent') and not form.instance.subevent)
|
||||
or (form.instance.subevent and form.initial.get('subevent') != form.instance.subevent.pk)):
|
||||
|
||||
if form.initial.get('subevent'):
|
||||
se = SubEvent.objects.get(event=self.request.event, pk=form.initial.get('subevent'))
|
||||
se.log_action(
|
||||
'pretix.subevent.quota.deleted', user=self.request.user, data={
|
||||
'id': form.instance.pk
|
||||
}
|
||||
)
|
||||
if form.instance.subevent:
|
||||
form.instance.subevent.log_action(
|
||||
'pretix.subevent.quota.added', user=self.request.user, data={
|
||||
'id': form.instance.pk
|
||||
}
|
||||
)
|
||||
return super().form_valid(form)
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
|
||||
@@ -90,6 +90,7 @@ class EventWizard(SessionWizardView):
|
||||
event = form_dict['basics'].instance
|
||||
event.organizer = foundation_data['organizer']
|
||||
event.plugins = settings.PRETIX_PLUGINS_DEFAULT
|
||||
event.has_subevents = foundation_data['has_subevents']
|
||||
form_dict['basics'].save()
|
||||
|
||||
has_control_rights = self.request.user.teams.filter(
|
||||
@@ -106,6 +107,17 @@ class EventWizard(SessionWizardView):
|
||||
t.members.add(self.request.user)
|
||||
t.limit_events.add(event)
|
||||
|
||||
if event.has_subevents:
|
||||
event.subevents.create(
|
||||
name=event.name,
|
||||
date_from=event.date_from,
|
||||
date_to=event.date_to,
|
||||
presale_start=event.presale_start,
|
||||
presale_end=event.presale_end,
|
||||
location=event.location,
|
||||
active=True
|
||||
)
|
||||
|
||||
logdata = {}
|
||||
for f in form_list:
|
||||
logdata.update({
|
||||
|
||||
@@ -16,6 +16,7 @@ from pretix.base.models import (
|
||||
CachedFile, CachedTicket, Invoice, InvoiceAddress, Item, ItemVariation,
|
||||
Order, Quota, generate_position_secret, generate_secret,
|
||||
)
|
||||
from pretix.base.models.event import SubEvent
|
||||
from pretix.base.services.export import export
|
||||
from pretix.base.services.invoices import (
|
||||
generate_cancellation, generate_invoice, invoice_pdf, invoice_qualified,
|
||||
@@ -53,13 +54,6 @@ class OrderList(EventPermissionRequiredMixin, ListView):
|
||||
if self.filter_form.is_valid():
|
||||
qs = self.filter_form.filter_qs(qs)
|
||||
|
||||
if self.request.GET.get("ordering", "") != "":
|
||||
p = self.request.GET.get("ordering", "")
|
||||
p_admissable = ('-code', 'code', '-email', 'email', '-total', 'total', '-datetime', 'datetime',
|
||||
'-status', 'status', 'pcnt', '-pcnt')
|
||||
if p in p_admissable:
|
||||
qs = qs.order_by(p)
|
||||
|
||||
return qs.distinct()
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
@@ -480,7 +474,8 @@ class OrderChange(OrderView):
|
||||
try:
|
||||
ocm.add_position(item, variation,
|
||||
self.add_form.cleaned_data['price'],
|
||||
self.add_form.cleaned_data.get('addon_to'))
|
||||
self.add_form.cleaned_data.get('addon_to'),
|
||||
self.add_form.cleaned_data.get('subevent'))
|
||||
except OrderError as e:
|
||||
self.add_form.custom_error = str(e)
|
||||
return False
|
||||
@@ -506,6 +501,8 @@ class OrderChange(OrderView):
|
||||
ocm.change_item(p, item, variation)
|
||||
elif p.form.cleaned_data['operation'] == 'price':
|
||||
ocm.change_price(p, p.form.cleaned_data['price'])
|
||||
elif p.form.cleaned_data['operation'] == 'subevent':
|
||||
ocm.change_subevent(p, p.form.cleaned_data['subevent'])
|
||||
elif p.form.cleaned_data['operation'] == 'cancel':
|
||||
ocm.cancel(p)
|
||||
|
||||
@@ -613,7 +610,19 @@ class OverView(EventPermissionRequiredMixin, TemplateView):
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data()
|
||||
ctx['items_by_category'], ctx['total'] = order_overview(self.request.event)
|
||||
|
||||
subevent = None
|
||||
if self.request.GET.get("subevent", "") != "" and self.request.event.has_subevents:
|
||||
i = self.request.GET.get("subevent", "")
|
||||
try:
|
||||
subevent = self.request.event.subevents.get(pk=i)
|
||||
except SubEvent.DoesNotExist:
|
||||
pass
|
||||
|
||||
ctx['items_by_category'], ctx['total'] = order_overview(self.request.event, subevent=subevent)
|
||||
ctx['subevent_warning'] = self.request.event.has_subevents and subevent and (
|
||||
self.request.event.orders.filter(payment_fee__gt=0).exists()
|
||||
)
|
||||
return ctx
|
||||
|
||||
|
||||
|
||||
312
src/pretix/control/views/subevents.py
Normal file
312
src/pretix/control/views/subevents.py
Normal file
@@ -0,0 +1,312 @@
|
||||
import copy
|
||||
|
||||
from django.contrib import messages
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import transaction
|
||||
from django.forms import inlineformset_factory
|
||||
from django.http import Http404, HttpResponseRedirect
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.translation import pgettext_lazy, ugettext_lazy as _
|
||||
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
|
||||
|
||||
from pretix.base.models.event import SubEvent
|
||||
from pretix.base.models.items import Quota, SubEventItem, SubEventItemVariation
|
||||
from pretix.control.forms.filter import SubEventFilterForm
|
||||
from pretix.control.forms.item import QuotaForm
|
||||
from pretix.control.forms.subevents import (
|
||||
QuotaFormSet, SubEventForm, SubEventItemForm, SubEventItemVariationForm,
|
||||
)
|
||||
from pretix.control.permissions import EventPermissionRequiredMixin
|
||||
|
||||
|
||||
class SubEventList(EventPermissionRequiredMixin, ListView):
|
||||
model = SubEvent
|
||||
context_object_name = 'subevents'
|
||||
paginate_by = 30
|
||||
template_name = 'pretixcontrol/subevents/index.html'
|
||||
permission = 'can_change_settings'
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.request.event.subevents.all()
|
||||
if self.filter_form.is_valid():
|
||||
qs = self.filter_form.filter_qs(qs)
|
||||
return qs
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['filter_form'] = self.filter_form
|
||||
return ctx
|
||||
|
||||
@cached_property
|
||||
def filter_form(self):
|
||||
return SubEventFilterForm(data=self.request.GET)
|
||||
|
||||
|
||||
class SubEventDelete(EventPermissionRequiredMixin, DeleteView):
|
||||
model = SubEvent
|
||||
template_name = 'pretixcontrol/subevents/delete.html'
|
||||
permission = 'can_change_settings'
|
||||
context_object_name = 'subevents'
|
||||
|
||||
def get_object(self, queryset=None) -> SubEvent:
|
||||
try:
|
||||
return self.request.event.subevents.get(
|
||||
id=self.kwargs['subevent']
|
||||
)
|
||||
except SubEvent.DoesNotExist:
|
||||
raise Http404(pgettext_lazy("subevent", "The requested date does not exist."))
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if self.get_object().orderposition_set.count() > 0:
|
||||
messages.error(request, pgettext_lazy('subevent', 'A date can not be deleted if orders already have been '
|
||||
'placed.'))
|
||||
return HttpResponseRedirect(self.get_success_url())
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
@transaction.atomic
|
||||
def delete(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
success_url = self.get_success_url()
|
||||
|
||||
if self.get_object().orderposition_set.count() > 0:
|
||||
messages.error(request, pgettext_lazy('subevent', 'A date can not be deleted if orders already have been '
|
||||
'placed.'))
|
||||
return HttpResponseRedirect(self.get_success_url())
|
||||
else:
|
||||
self.object.log_action('pretix.subevent.deleted', user=self.request.user)
|
||||
self.object.delete()
|
||||
messages.success(request, pgettext_lazy('subevent', 'The selected date has been deleted.'))
|
||||
return HttpResponseRedirect(success_url)
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
return reverse('control:event.subevents', kwargs={
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
'event': self.request.event.slug,
|
||||
})
|
||||
|
||||
|
||||
class SubEventEditorMixin:
|
||||
@cached_property
|
||||
def formset(self):
|
||||
extra = 0
|
||||
kwargs = {}
|
||||
|
||||
if self.copy_from:
|
||||
kwargs['initial'] = [
|
||||
{
|
||||
'size': q.size,
|
||||
'name': q.name,
|
||||
'itemvars': [str(i.pk) for i in q.items.all()] + [
|
||||
'{}-{}'.format(v.item_id, v.pk) for v in q.variations.all()
|
||||
]
|
||||
} for q in self.copy_from.quotas.prefetch_related('items', 'variations')
|
||||
]
|
||||
extra = len(kwargs['initial'])
|
||||
|
||||
formsetclass = inlineformset_factory(
|
||||
SubEvent, Quota,
|
||||
form=QuotaForm, formset=QuotaFormSet,
|
||||
can_order=False, can_delete=True, extra=extra,
|
||||
)
|
||||
if self.object:
|
||||
kwargs['queryset'] = self.object.quotas.prefetch_related('items', 'variations')
|
||||
|
||||
return formsetclass(self.request.POST if self.request.method == "POST" else None,
|
||||
instance=self.object,
|
||||
event=self.request.event, **kwargs)
|
||||
|
||||
def save_formset(self, obj):
|
||||
for form in self.formset.initial_forms:
|
||||
if form in self.formset.deleted_forms:
|
||||
if not form.instance.pk:
|
||||
continue
|
||||
form.instance.log_action(action='pretix.event.quota.deleted', user=self.request.user)
|
||||
obj.log_action('pretix.subevent.quota.deleted', user=self.request.user, data={
|
||||
'id': form.instance.pk
|
||||
})
|
||||
form.instance.delete()
|
||||
form.instance.pk = None
|
||||
elif form.has_changed():
|
||||
form.instance.question = obj
|
||||
form.save()
|
||||
change_data = {k: form.cleaned_data.get(k) for k in form.changed_data}
|
||||
change_data['id'] = form.instance.pk
|
||||
obj.log_action(
|
||||
'pretix.subevent.quota.changed', user=self.request.user, data={
|
||||
k: form.cleaned_data.get(k) for k in form.changed_data
|
||||
}
|
||||
)
|
||||
form.instance.log_action(
|
||||
'pretix.event.quota.changed', user=self.request.user, data={
|
||||
k: form.cleaned_data.get(k) for k in form.changed_data
|
||||
}
|
||||
)
|
||||
|
||||
for form in self.formset.extra_forms:
|
||||
if not form.has_changed():
|
||||
continue
|
||||
if self.formset._should_delete_form(form):
|
||||
continue
|
||||
form.instance.subevent = obj
|
||||
form.instance.event = obj.event
|
||||
form.save()
|
||||
change_data = {k: form.cleaned_data.get(k) for k in form.changed_data}
|
||||
change_data['id'] = form.instance.pk
|
||||
form.instance.log_action(action='pretix.event.quota.added', user=self.request.user, data=change_data)
|
||||
obj.log_action('pretix.subevent.quota.added', user=self.request.user, data=change_data)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['formset'] = self.formset
|
||||
ctx['itemvar_forms'] = self.itemvar_forms
|
||||
return ctx
|
||||
|
||||
@cached_property
|
||||
def copy_from(self):
|
||||
if self.request.GET.get("copy_from") and not getattr(self, 'object'):
|
||||
try:
|
||||
return self.request.event.subevents.get(pk=self.request.GET.get("copy_from"))
|
||||
except SubEvent.DoesNotExist:
|
||||
pass
|
||||
|
||||
@cached_property
|
||||
def itemvar_forms(self):
|
||||
se_item_instances = {
|
||||
sei.item_id: sei for sei in SubEventItem.objects.filter(subevent=self.object)
|
||||
}
|
||||
se_var_instances = {
|
||||
sei.variation_id: sei for sei in SubEventItemVariation.objects.filter(subevent=self.object)
|
||||
}
|
||||
|
||||
if self.copy_from:
|
||||
se_item_instances = {
|
||||
sei.item_id: SubEventItem(item=sei.item, price=sei.price)
|
||||
for sei in SubEventItem.objects.filter(subevent=self.copy_from).select_related('item')
|
||||
}
|
||||
se_var_instances = {
|
||||
sei.variation_id: SubEventItemVariation(variation=sei.variation, price=sei.price)
|
||||
for sei in SubEventItemVariation.objects.filter(subevent=self.copy_from).select_related('variation')
|
||||
}
|
||||
|
||||
formlist = []
|
||||
for i in self.request.event.items.filter(active=True).prefetch_related('variations'):
|
||||
if i.has_variations:
|
||||
for v in i.variations.all():
|
||||
inst = se_var_instances.get(v.pk) or SubEventItemVariation(subevent=self.object, variation=v)
|
||||
formlist.append(SubEventItemVariationForm(
|
||||
prefix='itemvar-{}'.format(v.pk),
|
||||
item=i, variation=v,
|
||||
instance=inst,
|
||||
data=(self.request.POST if self.request.method == "POST" else None)
|
||||
))
|
||||
else:
|
||||
inst = se_item_instances.get(i.pk) or SubEventItem(subevent=self.object, item=i)
|
||||
formlist.append(SubEventItemForm(
|
||||
prefix='item-{}'.format(i.pk),
|
||||
item=i,
|
||||
instance=inst,
|
||||
data=(self.request.POST if self.request.method == "POST" else None)
|
||||
))
|
||||
return formlist
|
||||
|
||||
def is_valid(self, form):
|
||||
return form.is_valid() and all([f.is_valid() for f in self.itemvar_forms]) and self.formset.is_valid()
|
||||
|
||||
|
||||
class SubEventUpdate(EventPermissionRequiredMixin, SubEventEditorMixin, UpdateView):
|
||||
model = SubEvent
|
||||
template_name = 'pretixcontrol/subevents/detail.html'
|
||||
permission = 'can_change_settings'
|
||||
context_object_name = 'subevent'
|
||||
form_class = SubEventForm
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
form = self.get_form()
|
||||
if self.is_valid(form):
|
||||
return self.form_valid(form)
|
||||
else:
|
||||
return self.form_invalid(form)
|
||||
|
||||
def get_object(self, queryset=None) -> SubEvent:
|
||||
try:
|
||||
return self.request.event.subevents.get(
|
||||
id=self.kwargs['subevent']
|
||||
)
|
||||
except SubEvent.DoesNotExist:
|
||||
raise Http404(pgettext_lazy("subevent", "The requested date does not exist."))
|
||||
|
||||
@transaction.atomic
|
||||
def form_valid(self, form):
|
||||
self.save_formset(self.object)
|
||||
|
||||
for f in self.itemvar_forms:
|
||||
f.save()
|
||||
# TODO: LogEntry?
|
||||
|
||||
messages.success(self.request, _('Your changes have been saved.'))
|
||||
if form.has_changed():
|
||||
self.object.log_action(
|
||||
'pretix.subevent.changed', user=self.request.user, data={
|
||||
k: form.cleaned_data.get(k) for k in form.changed_data
|
||||
}
|
||||
)
|
||||
return super().form_valid(form)
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
return reverse('control:event.subevents', kwargs={
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
'event': self.request.event.slug,
|
||||
})
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs['event'] = self.request.event
|
||||
return kwargs
|
||||
|
||||
|
||||
class SubEventCreate(SubEventEditorMixin, EventPermissionRequiredMixin, CreateView):
|
||||
model = SubEvent
|
||||
template_name = 'pretixcontrol/subevents/detail.html'
|
||||
permission = 'can_change_settings'
|
||||
context_object_name = 'subevent'
|
||||
form_class = SubEventForm
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = SubEvent(event=self.request.event)
|
||||
form = self.get_form()
|
||||
if self.is_valid(form):
|
||||
return self.form_valid(form)
|
||||
else:
|
||||
return self.form_invalid(form)
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
return reverse('control:event.subevents', kwargs={
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
'event': self.request.event.slug,
|
||||
})
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs['event'] = self.request.event
|
||||
if self.copy_from:
|
||||
i = copy.copy(self.copy_from)
|
||||
i.pk = None
|
||||
kwargs['instance'] = i
|
||||
else:
|
||||
kwargs['instance'] = SubEvent(event=self.request.event)
|
||||
return kwargs
|
||||
|
||||
@transaction.atomic
|
||||
def form_valid(self, form):
|
||||
form.instance.event = self.request.event
|
||||
messages.success(self.request, pgettext_lazy('subevent', 'The new date has been created.'))
|
||||
ret = super().form_valid(form)
|
||||
form.instance.log_action('pretix.subevent.added', data=dict(form.cleaned_data), user=self.request.user)
|
||||
|
||||
self.save_formset(form.instance)
|
||||
for f in self.itemvar_forms:
|
||||
f.instance.subevent = form.instance
|
||||
f.save()
|
||||
|
||||
return ret
|
||||
@@ -46,6 +46,9 @@ class VoucherList(EventPermissionRequiredMixin, ListView):
|
||||
qs = qs.filter(redeemed__gt=0)
|
||||
elif s == 'e':
|
||||
qs = qs.filter(Q(valid_until__isnull=False) & Q(valid_until__lt=now())).filter(redeemed=0)
|
||||
if self.request.GET.get("subevent", "") != "":
|
||||
s = self.request.GET.get("subevent", "")
|
||||
qs = qs.filter(subevent_id=s)
|
||||
return qs
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
|
||||
@@ -35,7 +35,8 @@ class AutoAssign(EventPermissionRequiredMixin, AsyncAction, View):
|
||||
})
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
return self.do(self.request.event.id, self.request.user.id)
|
||||
return self.do(self.request.event.id, self.request.user.id,
|
||||
self.request.POST.get('subevent'))
|
||||
|
||||
|
||||
class WaitingListView(EventPermissionRequiredMixin, ListView):
|
||||
@@ -78,7 +79,9 @@ class WaitingListView(EventPermissionRequiredMixin, ListView):
|
||||
def get_queryset(self):
|
||||
qs = WaitingListEntry.objects.filter(
|
||||
event=self.request.event
|
||||
).select_related('item', 'variation', 'voucher').prefetch_related('item__quotas', 'variation__quotas')
|
||||
).select_related('item', 'variation', 'voucher').prefetch_related(
|
||||
'item__quotas', 'variation__quotas'
|
||||
)
|
||||
|
||||
s = self.request.GET.get("status", "")
|
||||
if s == 's':
|
||||
@@ -90,7 +93,11 @@ class WaitingListView(EventPermissionRequiredMixin, ListView):
|
||||
|
||||
if self.request.GET.get("item", "") != "":
|
||||
i = self.request.GET.get("item", "")
|
||||
qs = qs.filter(item_id__in=(i,))
|
||||
qs = qs.filter(item_id=i)
|
||||
|
||||
if self.request.GET.get("subevent", "") != "":
|
||||
s = self.request.GET.get("subevent", "")
|
||||
qs = qs.filter(subevent_id=s)
|
||||
|
||||
return qs
|
||||
|
||||
@@ -107,9 +114,9 @@ class WaitingListView(EventPermissionRequiredMixin, ListView):
|
||||
wle.availability = itemvar_cache.get((wle.item, wle.variation))
|
||||
else:
|
||||
wle.availability = (
|
||||
wle.variation.check_quotas(count_waitinglist=False, _cache=quota_cache)
|
||||
wle.variation.check_quotas(count_waitinglist=False, subevent=wle.subevent, _cache=quota_cache)
|
||||
if wle.variation
|
||||
else wle.item.check_quotas(count_waitinglist=False, _cache=quota_cache)
|
||||
else wle.item.check_quotas(count_waitinglist=False, subevent=wle.subevent, _cache=quota_cache)
|
||||
)
|
||||
itemvar_cache[(wle.item, wle.variation)] = wle.availability
|
||||
if wle.availability[0] == 100:
|
||||
|
||||
Reference in New Issue
Block a user