mirror of
https://github.com/pretix/pretix.git
synced 2026-08-11 10:57:00 +00:00
filter using a dateFrameField
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
# License for the specific language governing permissions and limitations under the License.
|
||||
import copy
|
||||
import os
|
||||
from datetime import timezone
|
||||
from decimal import Decimal
|
||||
from urllib.parse import urlencode
|
||||
|
||||
@@ -47,6 +48,7 @@ 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.timezone import now
|
||||
from django.utils.translation import (
|
||||
gettext as __, gettext_lazy as _, pgettext_lazy,
|
||||
)
|
||||
@@ -58,11 +60,14 @@ 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, SubEvent,
|
||||
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
|
||||
from pretix.base.timeframes import (
|
||||
DateFrameField, resolve_timeframe_to_dates_inclusive,
|
||||
)
|
||||
from pretix.control.forms import (
|
||||
ButtonGroupRadioSelect, ExtFileField, ItemMultipleChoiceField,
|
||||
SalesChannelCheckboxSelectMultiple, SplitDateTimeField,
|
||||
@@ -308,6 +313,10 @@ class QuestionFilterForm(forms.Form):
|
||||
required=False,
|
||||
empty_label=pgettext_lazy('subevent', 'All dates')
|
||||
)
|
||||
date_range = DateFrameField(
|
||||
required=False,
|
||||
include_future_frames=True
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.event = kwargs.pop('event')
|
||||
@@ -333,6 +342,62 @@ class QuestionFilterForm(forms.Form):
|
||||
else:
|
||||
del self.fields['subevent']
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
subevent = cleaned_data.get('subevent')
|
||||
date_range = cleaned_data.get('date_range')
|
||||
|
||||
if subevent is not None and cleaned_data is not None:
|
||||
start_d, end_d = resolve_timeframe_to_dates_inclusive(now(), date_range, timezone.utc)
|
||||
if not (start_d <= subevent.date_from.date() <= end_d):
|
||||
raise forms.ValidationError(_("Selected subevent isn't part of the date range."))
|
||||
return cleaned_data
|
||||
|
||||
def filter_qs(self):
|
||||
fdata = self.cleaned_data
|
||||
|
||||
opqs = OrderPosition.objects.filter(
|
||||
order__event=self.event,
|
||||
)
|
||||
|
||||
subevent = fdata.get('subevent', None)
|
||||
date_range = fdata.get('date_range', None)
|
||||
|
||||
if subevent is not None:
|
||||
opqs = opqs.filter(order__event__subevents=subevent)
|
||||
|
||||
if date_range is not None:
|
||||
d_start, d_end = resolve_timeframe_to_dates_inclusive(now(), date_range, timezone.utc)
|
||||
opqs = opqs.filter(
|
||||
order__event__subevents__date_from__gte=d_start,
|
||||
order__event__subevents__date_from__lte=d_end
|
||||
)
|
||||
|
||||
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(
|
||||
|
||||
@@ -14,6 +14,12 @@
|
||||
</a>
|
||||
</h1>
|
||||
|
||||
{% for e in form.errors.values %}
|
||||
<div class="alert alert-danger has-error">
|
||||
{{ e }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{% trans "Filter" %}</h3>
|
||||
@@ -21,16 +27,19 @@
|
||||
<form class="panel-body filter-form" action="" method="get">
|
||||
<div class="row">
|
||||
<div class="col-lg-2 col-sm-6 col-xs-6">
|
||||
{{ form.status }}
|
||||
{% bootstrap_field form.status layout='inline' %}
|
||||
</div>
|
||||
<div class="col-lg-5 col-sm-6 col-xs-6">
|
||||
{{ form.item }}
|
||||
{% bootstrap_field form.item layout='inline' %}
|
||||
</div>
|
||||
{% if has_subevents %}
|
||||
<div class="col-lg-5 col-sm-6 col-xs-6">
|
||||
<p>
|
||||
{{ form.subevent }}
|
||||
</p>
|
||||
{% bootstrap_field form.subevent layout='inline' %}
|
||||
</div>
|
||||
<div class="col-lg-5 col-sm-6 col-xs-6">
|
||||
{% bootstrap_field form.date_range layout='inline' %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<button class="btn btn-primary btn-lg" type="submit">
|
||||
|
||||
@@ -45,9 +45,7 @@ from django.db import transaction
|
||||
from django.db.models import (
|
||||
Count, Exists, F, OuterRef, Prefetch, ProtectedError, Q,
|
||||
)
|
||||
|
||||
from django.forms.models import inlineformset_factory
|
||||
|
||||
from django.http import (
|
||||
Http404, HttpResponse, HttpResponseBadRequest, HttpResponseRedirect,
|
||||
)
|
||||
@@ -67,9 +65,8 @@ from pretix.api.serializers.item import (
|
||||
)
|
||||
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
|
||||
@@ -669,40 +666,19 @@ class QuestionView(EventPermissionRequiredMixin, ChartContainingView, DetailView
|
||||
permission = 'can_change_items'
|
||||
template_name_field = 'question'
|
||||
|
||||
@cached_property
|
||||
def filter_form(self):
|
||||
return QuestionFilterForm(event=self.request.event, data=self.request.GET)
|
||||
|
||||
def get_answer_statistics(self):
|
||||
opqs = OrderPosition.objects.filter(
|
||||
order__event=self.request.event,
|
||||
)
|
||||
if not self.filter_form.is_valid():
|
||||
return
|
||||
|
||||
opqs = self.filter_form.filter_qs()
|
||||
|
||||
qs = QuestionAnswer.objects.filter(
|
||||
question=self.object, orderposition__isnull=False,
|
||||
)
|
||||
|
||||
if self.request.GET.get("subevent", "") != "":
|
||||
opqs = opqs.filter(subevent=self.request.GET["subevent"])
|
||||
|
||||
s = self.request.GET.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 self.request.GET.get("item", "") != "":
|
||||
i = self.request.GET.get("item", "")
|
||||
opqs = opqs.filter(item_id__in=(i,))
|
||||
|
||||
qs = qs.filter(orderposition__in=opqs)
|
||||
op_cnt = opqs.filter(item__in=self.object.items.all()).count()
|
||||
|
||||
@@ -749,10 +725,12 @@ class QuestionView(EventPermissionRequiredMixin, ChartContainingView, DetailView
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data()
|
||||
ctx['items'] = self.object.items.all()
|
||||
ctx['items'] = self.object.items.exists()
|
||||
ctx['has_subevents'] = self.request.event.has_subevents
|
||||
stats = self.get_answer_statistics()
|
||||
ctx['stats'], ctx['total'] = stats
|
||||
ctx['form'] = QuestionFilterForm(data=self.request.GET, event=self.request.event)
|
||||
if stats:
|
||||
ctx['stats'], ctx['total'] = stats
|
||||
ctx['form'] = self.filter_form
|
||||
return ctx
|
||||
|
||||
def get_object(self, queryset=None) -> Question:
|
||||
|
||||
Reference in New Issue
Block a user