From b4dd2145ff33fb8cf81da6937bf087ed50064dba Mon Sep 17 00:00:00 2001 From: Lukas Bockstaller Date: Thu, 4 Dec 2025 09:33:51 +0100 Subject: [PATCH] move form out of views.py --- src/pretix/control/forms/item.py | 106 ++++++++++++++++++++++++++++- src/pretix/control/views/item.py | 110 ++----------------------------- 2 files changed, 109 insertions(+), 107 deletions(-) diff --git a/src/pretix/control/forms/item.py b/src/pretix/control/forms/item.py index 6d5b8f179..b6d1aa2d5 100644 --- a/src/pretix/control/forms/item.py +++ b/src/pretix/control/forms/item.py @@ -47,7 +47,10 @@ from django.urls import reverse from django.utils.functional import cached_property from django.utils.html import escape, format_html from django.utils.safestring import mark_safe -from django.utils.translation import gettext as __, gettext_lazy as _ +from django.utils.timezone import now +from django.utils.translation import ( + gettext as __, gettext_lazy as _, pgettext_lazy, +) from django_scopes.forms import ( SafeModelChoiceField, SafeModelMultipleChoiceField, ) @@ -56,8 +59,8 @@ from i18nfield.forms import I18nFormField, I18nTextarea from pretix.base.forms import I18nFormSet, I18nMarkdownTextarea, I18nModelForm from pretix.base.forms.widgets import DatePickerWidget from pretix.base.models import ( - Item, ItemCategory, ItemProgramTime, ItemVariation, Question, - QuestionOption, Quota, + Item, ItemCategory, ItemProgramTime, ItemVariation, Order, OrderPosition, + Question, QuestionOption, Quota, SubEvent, ) from pretix.base.models.items import ItemAddOn, ItemBundle, ItemMetaValue from pretix.base.signals import item_copy_data @@ -272,6 +275,103 @@ class QuestionOptionForm(I18nModelForm): ] +class QuestionFilterForm(forms.Form): + STATUS_VARIANTS = [ + ("", _("All orders")), + ("p", _("Paid")), + ("pv", _("Paid or confirmed")), + ("n", _("Pending")), + ("np", _("Pending or paid")), + ("o", _("Pending (overdue)")), + ("e", _("Expired")), + ("ne", _("Pending or expired")), + ("c", _("Canceled")) + ] + + status = forms.ChoiceField( + choices=STATUS_VARIANTS, + widget=forms.Select( + attrs={ + 'class': 'form-control', + } + ), + required=False, + ) + item = forms.ChoiceField( + choices=[], + widget=forms.Select( + attrs={'class': 'form-control'} + ), + required=False + ) + subevent = forms.ModelChoiceField( + queryset=SubEvent.objects.none(), + required=False, + empty_label=pgettext_lazy('subevent', 'All dates') + ) + + def __init__(self, *args, **kwargs): + self.event = kwargs.pop('event') + super().__init__(*args, **kwargs) + self.initial['status'] = "np" + self.fields['item'].choices = [('', _('All products'))] + [(item.id, item.name) for item in Item.objects.filter(event=self.event)] + + if self.event.has_subevents: + self.fields["subevent"].queryset = self.event.subevents.all() + self.fields['subevent'].widget = Select2( + attrs={ + 'class': 'form-control simple-subevent-choice', + 'data-model-select2': 'event', + 'data-select2-url': reverse('control:event.subevents.select2', kwargs={ + 'event': self.event.slug, + 'organizer': self.event.organizer.slug, + }), + 'data-placeholder': pgettext_lazy('subevent', 'All dates') + } + ) + self.fields['subevent'].widget.choices = self.fields['subevent'].choices + else: + del self.fields['subevent'] + + def is_valid(self) -> bool: + return True + + def order_position_queryset(self): + fdata = self.data + + opqs = OrderPosition.objects.filter( + order__event=self.event, + ) + + if (fdata.get('subevent', "") != "") & (fdata.get('subevent', "") is not None): + opqs = opqs.filter(subevent=fdata["subevent"]) + + s = fdata.get("status", "np") + if s != "": + if s == 'o': + opqs = opqs.filter(order__status=Order.STATUS_PENDING, + order__expires__lt=now().replace(hour=0, minute=0, second=0)) + elif s == 'np': + opqs = opqs.filter(order__status__in=[Order.STATUS_PENDING, Order.STATUS_PAID]) + elif s == 'pv': + opqs = opqs.filter( + Q(order__status=Order.STATUS_PAID) | + Q(order__status=Order.STATUS_PENDING, order__valid_if_pending=True) + ) + elif s == 'ne': + opqs = opqs.filter(order__status__in=[Order.STATUS_PENDING, Order.STATUS_EXPIRED]) + else: + opqs = opqs.filter(order__status=s) + + if s not in (Order.STATUS_CANCELED, ""): + opqs = opqs.filter(canceled=False) + if fdata.get("item", "") != "": + i = fdata.get("item", "") + opqs = opqs.filter(item_id__in=(i,)) + + return opqs + + class QuotaForm(I18nModelForm): itemvars = forms.MultipleChoiceField( label=_("Products"), diff --git a/src/pretix/control/views/item.py b/src/pretix/control/views/item.py index 0ad8d06d0..065aed33d 100644 --- a/src/pretix/control/views/item.py +++ b/src/pretix/control/views/item.py @@ -55,7 +55,7 @@ from django.shortcuts import redirect from django.urls import resolve, reverse from django.utils.functional import cached_property from django.utils.timezone import now -from django.utils.translation import gettext, gettext_lazy as _, pgettext_lazy +from django.utils.translation import gettext, gettext_lazy as _ from django.views.decorators.http import require_http_methods from django.views.generic import ListView from django.views.generic.detail import DetailView, SingleObjectMixin @@ -68,9 +68,8 @@ from pretix.api.serializers.item import ( from pretix.base.exporter import ListExporter from pretix.base.forms import I18nFormSet from pretix.base.models import ( - CartPosition, Item, ItemCategory, ItemProgramTime, ItemVariation, Order, - OrderPosition, Question, QuestionAnswer, QuestionOption, Quota, - SeatCategoryMapping, Voucher, + CartPosition, Item, ItemCategory, ItemProgramTime, ItemVariation, Question, + QuestionAnswer, QuestionOption, Quota, SeatCategoryMapping, Voucher, ) from pretix.base.models.event import SubEvent from pretix.base.models.items import ItemAddOn, ItemBundle, ItemMetaValue @@ -81,7 +80,8 @@ from pretix.control.forms.item import ( CategoryForm, ItemAddOnForm, ItemAddOnsFormSet, ItemBundleForm, ItemBundleFormSet, ItemCreateForm, ItemMetaValueForm, ItemProgramTimeForm, ItemProgramTimeFormSet, ItemUpdateForm, ItemVariationForm, - ItemVariationsFormSet, QuestionForm, QuestionOptionForm, QuotaForm, + ItemVariationsFormSet, QuestionFilterForm, QuestionForm, + QuestionOptionForm, QuotaForm, ) from pretix.control.permissions import ( EventPermissionRequiredMixin, event_permission_required, @@ -90,7 +90,6 @@ from pretix.control.signals import item_forms, item_formsets from pretix.helpers.models import modelcopy from ...helpers.compat import CompatDeleteView -from ..forms.widgets import Select2 from . import ChartContainingView, CreateView, PaginationMixin, UpdateView @@ -664,103 +663,6 @@ class QuestionMixin: return ctx -class QuestionFilterForm(forms.Form): - STATUS_VARIANTS = [ - ("", _("All orders")), - ("p", _("Paid")), - ("pv", _("Paid or confirmed")), - ("n", _("Pending")), - ("np", _("Pending or paid")), - ("o", _("Pending (overdue)")), - ("e", _("Expired")), - ("ne", _("Pending or expired")), - ("c", _("Canceled")) - ] - - status = forms.ChoiceField( - choices=STATUS_VARIANTS, - widget=forms.Select( - attrs={ - 'class': 'form-control', - } - ), - required=False, - ) - item = forms.ChoiceField( - choices=[], - widget=forms.Select( - attrs={'class': 'form-control'} - ), - required=False - ) - subevent = forms.ModelChoiceField( - queryset=SubEvent.objects.none(), - required=False, - empty_label=pgettext_lazy('subevent', 'All dates') - ) - - def __init__(self, *args, **kwargs): - self.event = kwargs.pop('event') - super().__init__(*args, **kwargs) - self.initial['status'] = "np" - self.fields['item'].choices = [('', _('All products'))] + [(item.id, item.name) for item in Item.objects.filter(event=self.event)] - - if self.event.has_subevents: - self.fields["subevent"].queryset = self.event.subevents.all() - self.fields['subevent'].widget = Select2( - attrs={ - 'class': 'form-control simple-subevent-choice', - 'data-model-select2': 'event', - 'data-select2-url': reverse('control:event.subevents.select2', kwargs={ - 'event': self.event.slug, - 'organizer': self.event.organizer.slug, - }), - 'data-placeholder': pgettext_lazy('subevent', 'All dates') - } - ) - self.fields['subevent'].widget.choices = self.fields['subevent'].choices - else: - del self.fields['subevent'] - - def is_valid(self) -> bool: - return True - - def orderPositionQuerySet(self): - fdata = self.data - - opqs = OrderPosition.objects.filter( - order__event=self.event, - ) - - if (fdata.get('subevent', "") != "") & (fdata.get('subevent', "") is not None): - opqs = opqs.filter(subevent=fdata["subevent"]) - - s = fdata.get("status", "np") - if s != "": - if s == 'o': - opqs = opqs.filter(order__status=Order.STATUS_PENDING, - order__expires__lt=now().replace(hour=0, minute=0, second=0)) - elif s == 'np': - opqs = opqs.filter(order__status__in=[Order.STATUS_PENDING, Order.STATUS_PAID]) - elif s == 'pv': - opqs = opqs.filter( - Q(order__status=Order.STATUS_PAID) | - Q(order__status=Order.STATUS_PENDING, order__valid_if_pending=True) - ) - elif s == 'ne': - opqs = opqs.filter(order__status__in=[Order.STATUS_PENDING, Order.STATUS_EXPIRED]) - else: - opqs = opqs.filter(order__status=s) - - if s not in (Order.STATUS_CANCELED, ""): - opqs = opqs.filter(canceled=False) - if fdata.get("item", "") != "": - i = fdata.get("item", "") - opqs = opqs.filter(item_id__in=(i,)) - - return opqs - - class QuestionAnswerExporter(ListExporter): identifier = 'question_answer_exporter' verbose_name = _('Question answers exporter') @@ -783,7 +685,7 @@ class QuestionAnswerExporter(ListExporter): def iterate_list(self, form_data): question = Question.objects.filter(event=self.event).get(pk=form_data['question']) - opqs = QuestionFilterForm(event=self.event, data=form_data).orderPositionQuerySet() + opqs = QuestionFilterForm(event=self.event, data=form_data).order_position_queryset() qs = QuestionAnswer.objects.filter( question=question, orderposition__isnull=False,