mirror of
https://github.com/pretix/pretix.git
synced 2026-05-05 15:14:04 +00:00
Fix #767 -- Allow to obtain the list of orders for a question answer
This commit is contained in:
@@ -7,7 +7,8 @@ from django.utils.timezone import now
|
||||
from django.utils.translation import pgettext_lazy, ugettext_lazy as _
|
||||
|
||||
from pretix.base.models import (
|
||||
Checkin, Event, Invoice, Item, Order, OrderPosition, Organizer, SubEvent,
|
||||
Checkin, Event, Invoice, Item, Order, OrderPosition, Organizer, Question,
|
||||
QuestionAnswer, SubEvent,
|
||||
)
|
||||
from pretix.base.signals import register_payment_providers
|
||||
from pretix.control.forms.widgets import Select2
|
||||
@@ -99,6 +100,7 @@ class OrderFilterForm(FilterForm):
|
||||
('p', _('Paid')),
|
||||
('n', _('Pending')),
|
||||
('o', _('Pending (overdue)')),
|
||||
('np', _('Pending or paid')),
|
||||
('e', _('Expired')),
|
||||
('ne', _('Pending or expired')),
|
||||
('c', _('Canceled')),
|
||||
@@ -145,6 +147,8 @@ class OrderFilterForm(FilterForm):
|
||||
s = fdata.get('status')
|
||||
if s == 'o':
|
||||
qs = qs.filter(status=Order.STATUS_PENDING, expires__lt=now().replace(hour=0, minute=0, second=0))
|
||||
elif s == 'np':
|
||||
qs = qs.filter(status__in=[Order.STATUS_PENDING, Order.STATUS_PAID])
|
||||
elif s == 'ne':
|
||||
qs = qs.filter(status__in=[Order.STATUS_PENDING, Order.STATUS_EXPIRED])
|
||||
else:
|
||||
@@ -175,11 +179,19 @@ class EventOrderFilterForm(OrderFilterForm):
|
||||
required=False,
|
||||
empty_label=pgettext_lazy('subevent', 'All dates')
|
||||
)
|
||||
question = forms.ModelChoiceField(
|
||||
queryset=Question.objects.none(),
|
||||
required=False,
|
||||
)
|
||||
answer = forms.CharField(
|
||||
required=False
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.event = kwargs.pop('event')
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['item'].queryset = self.event.items.all()
|
||||
self.fields['question'].queryset = self.event.questions.all()
|
||||
self.fields['provider'].choices += [(k, v.verbose_name) for k, v
|
||||
in self.event.get_payment_providers().items()]
|
||||
|
||||
@@ -209,6 +221,31 @@ class EventOrderFilterForm(OrderFilterForm):
|
||||
if fdata.get('subevent'):
|
||||
qs = qs.filter(positions__subevent=fdata.get('subevent'))
|
||||
|
||||
if fdata.get('question') and fdata.get('answer') is not None:
|
||||
q = fdata.get('question')
|
||||
|
||||
if q.type == Question.TYPE_FILE:
|
||||
answers = QuestionAnswer.objects.filter(
|
||||
orderposition__order_id=OuterRef('pk'),
|
||||
question_id=q.pk,
|
||||
file__isnull=False
|
||||
)
|
||||
qs = qs.annotate(has_answer=Exists(answers)).filter(has_answer=True)
|
||||
elif q.type in (Question.TYPE_CHOICE, Question.TYPE_CHOICE_MULTIPLE):
|
||||
answers = QuestionAnswer.objects.filter(
|
||||
question_id=q.pk,
|
||||
orderposition__order_id=OuterRef('pk'),
|
||||
options__pk=fdata.get('answer')
|
||||
)
|
||||
qs = qs.annotate(has_answer=Exists(answers)).filter(has_answer=True)
|
||||
else:
|
||||
answers = QuestionAnswer.objects.filter(
|
||||
question_id=q.pk,
|
||||
orderposition__order_id=OuterRef('pk'),
|
||||
answer__iexact=fdata.get('answer')
|
||||
)
|
||||
qs = qs.annotate(has_answer=Exists(answers)).filter(has_answer=True)
|
||||
|
||||
return qs
|
||||
|
||||
|
||||
|
||||
@@ -74,7 +74,9 @@
|
||||
{% for stat in stats %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ stat.answer }}
|
||||
<a href="{% url "control:event.orders" event=request.event.slug organizer=request.event.organizer.slug %}?status={{ request.GET.status|default:"np" }}&item={{ request.GET.item }}&question={{ question.pk }}&answer={{ stat.alink|default:stat.answer|urlencode }}">
|
||||
{{ stat.answer }}
|
||||
</a>
|
||||
</td>
|
||||
<td>{{ stat.count }}</td>
|
||||
</tr>
|
||||
|
||||
@@ -72,6 +72,18 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% if filter_form.is_valid and filter_form.cleaned_data.question %}
|
||||
<p class="text-muted">
|
||||
<span class="fa fa-filter"></span>
|
||||
{% blocktrans trimmed with question=filter_form.cleaned_data.question.question %}
|
||||
List filtered by answers to question "{{ question }}".
|
||||
{% endblocktrans %}
|
||||
<a href="?{% url_replace request 'question' '' 'answer' ''%}" class="text-muted">
|
||||
<span class="fa fa-times"></span>
|
||||
{% trans "Remove filter" %}
|
||||
</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
|
||||
@@ -416,13 +416,14 @@ class QuestionView(EventPermissionRequiredMixin, QuestionMixin, ChartContainingV
|
||||
qs = [
|
||||
{
|
||||
'answer': ugettext('File uploaded'),
|
||||
'count': qs.filter(file__isnull=False).count()
|
||||
'count': qs.filter(file__isnull=False).count(),
|
||||
}
|
||||
]
|
||||
elif self.object.type in (Question.TYPE_CHOICE, Question.TYPE_CHOICE_MULTIPLE):
|
||||
qs = qs.order_by('options').values('options', 'options__answer') \
|
||||
.annotate(count=Count('id')).order_by('-count')
|
||||
for a in qs:
|
||||
a['alink'] = a['options']
|
||||
a['answer'] = str(a['options__answer'])
|
||||
del a['options__answer']
|
||||
elif self.object.type in (Question.TYPE_TIME, Question.TYPE_DATE, Question.TYPE_DATETIME):
|
||||
@@ -430,12 +431,14 @@ class QuestionView(EventPermissionRequiredMixin, QuestionMixin, ChartContainingV
|
||||
qs_model = qs
|
||||
qs = qs.values('answer').annotate(count=Count('id')).order_by('-count')
|
||||
for a, a_model in zip(qs, qs_model):
|
||||
a['alink'] = a['answer']
|
||||
a['answer'] = str(a_model)
|
||||
else:
|
||||
qs = qs.order_by('answer').values('answer').annotate(count=Count('id')).order_by('-count')
|
||||
|
||||
if self.object.type == Question.TYPE_BOOLEAN:
|
||||
for a in qs:
|
||||
a['alink'] = a['answer']
|
||||
a['answer'] = ugettext('Yes') if a['answer'] == 'True' else ugettext('No')
|
||||
a['answer_bool'] = a['answer'] == 'True'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user