Improve global order filters

This commit is contained in:
Martin Gross
2020-05-06 13:12:17 +02:00
parent c0972ef39d
commit 4b01c42f31
3 changed files with 94 additions and 5 deletions

View File

@@ -363,6 +363,28 @@ class OrderSearchFilterForm(OrderFilterForm):
) )
) )
status = forms.ChoiceField(
label=_('Order status'),
choices=(
('', _('All orders')),
(Order.STATUS_PAID, _('Paid (or canceled with paid fee)')),
(Order.STATUS_PENDING, _('Pending')),
('o', _('Pending (overdue)')),
(Order.STATUS_PENDING + Order.STATUS_PAID, _('Pending or paid')),
(Order.STATUS_EXPIRED, _('Expired')),
(Order.STATUS_PENDING + Order.STATUS_EXPIRED, _('Pending or expired')),
(Order.STATUS_CANCELED, _('Canceled')),
('cp', _('Canceled (or with paid fee)')),
('pa', _('Approval pending')),
('overpaid', _('Overpaid')),
('underpaid', _('Underpaid')),
('pendingpaid', _('Pending (but fully paid)')),
('testmode', _('Test mode')),
('rc', _('Cancellation requested')),
),
required=False,
)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
request = kwargs.pop('request') request = kwargs.pop('request')
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@@ -381,6 +403,47 @@ class OrderSearchFilterForm(OrderFilterForm):
if fdata.get('organizer'): if fdata.get('organizer'):
qs = qs.filter(event__organizer=fdata.get('organizer')) qs = qs.filter(event__organizer=fdata.get('organizer'))
if fdata.get('status') == 'overpaid':
qs = Order.annotate_overpayments(qs, refunds=False, results=False, sums=True)
qs = qs.filter(
Q(~Q(status=Order.STATUS_CANCELED) & Q(pending_sum_t__lt=0))
| Q(Q(status=Order.STATUS_CANCELED) & Q(pending_sum_rc__lt=0))
)
elif fdata.get('status') == 'rc':
qs = qs.filter(
cancellation_requests__isnull=False
)
elif fdata.get('status') == 'pendingpaid':
qs = Order.annotate_overpayments(qs, refunds=False, results=False, sums=True)
qs = qs.filter(
Q(status__in=(Order.STATUS_EXPIRED, Order.STATUS_PENDING)) & Q(pending_sum_t__lte=0)
& Q(require_approval=False)
)
elif fdata.get('status') == 'underpaid':
qs = Order.annotate_overpayments(qs, refunds=False, results=False, sums=True)
qs = qs.filter(
status=Order.STATUS_PAID,
pending_sum_t__gt=0
)
elif fdata.get('status') == 'pa':
qs = qs.filter(
status=Order.STATUS_PENDING,
require_approval=True
)
elif fdata.get('status') == 'testmode':
qs = qs.filter(
testmode=True
)
elif fdata.get('status') == 'cp':
s = OrderPosition.objects.filter(
order=OuterRef('pk')
)
qs = qs.annotate(
has_pc=Exists(s)
).filter(
Q(status=Order.STATUS_PAID, has_pc=False) | Q(status=Order.STATUS_CANCELED)
)
return qs return qs

View File

@@ -73,7 +73,24 @@
{% endif %} {% endif %}
</td> </td>
<td>{{ o.datetime|date:"SHORT_DATETIME_FORMAT" }}</td> <td>{{ o.datetime|date:"SHORT_DATETIME_FORMAT" }}</td>
<td class="text-right flip">{{ o.total|money:o.event.currency }}</td> <td class="text-right flip">
{% if o.has_cancellation_request %}
<span class="label label-warning">{% trans "CANCELLATION REQUESTED" %}</span>
{% endif %}
{% if o.has_external_refund or o.has_pending_refund %}
<span class="label label-danger">{% trans "REFUND PENDING" %}</span>
{% elif o.has_pending_refund %}
<span class="label label-warning">{% trans "REFUND PENDING" %}</span>
{% endif %}
{% if o.is_overpaid %}
<span class="label label-warning">{% trans "OVERPAID" %}</span>
{% elif o.is_underpaid %}
<span class="label label-danger">{% trans "UNDERPAID" %}</span>
{% elif o.is_pending_with_full_payment %}
<span class="label label-danger">{% trans "FULLY PAID" %}</span>
{% endif %}
{{ o.total|money:o.event.currency }}
</td>
<td class="text-right flip">{% include "pretixcontrol/orders/fragment_order_status.html" with order=o %}</td> <td class="text-right flip">{% include "pretixcontrol/orders/fragment_order_status.html" with order=o %}</td>
</tr> </tr>
{% empty %} {% empty %}

View File

@@ -1,9 +1,10 @@
from django.conf import settings from django.conf import settings
from django.db.models import Count, IntegerField, OuterRef, Q, Subquery from django.db.models import Count, Exists, IntegerField, OuterRef, Q, Subquery
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.views.generic import ListView from django.views.generic import ListView
from pretix.base.models import Order, OrderPosition from pretix.base.models import Order, OrderPosition
from pretix.base.models.orders import CancellationRequest
from pretix.control.forms.filter import OrderSearchFilterForm from pretix.control.forms.filter import OrderSearchFilterForm
from pretix.control.views import LargeResultSetPaginator, PaginationMixin from pretix.control.views import LargeResultSetPaginator, PaginationMixin
@@ -29,12 +30,14 @@ class OrderSearch(PaginationMixin, ListView):
annotated = { annotated = {
o['pk']: o o['pk']: o
for o in for o in
Order.objects.using(settings.DATABASE_REPLICA).filter( Order.annotate_overpayments(Order.objects).using(settings.DATABASE_REPLICA).filter(
pk__in=[o.pk for o in ctx['orders']] pk__in=[o.pk for o in ctx['orders']]
).annotate( ).annotate(
pcnt=Subquery(s, output_field=IntegerField()) pcnt=Subquery(s, output_field=IntegerField()),
has_cancellation_request=Exists(CancellationRequest.objects.filter(order=OuterRef('pk')))
).values( ).values(
'pk', 'pcnt', 'pk', 'pcnt', 'is_overpaid', 'is_underpaid', 'is_pending_with_full_payment', 'has_external_refund',
'has_pending_refund', 'has_cancellation_request'
) )
} }
@@ -42,6 +45,12 @@ class OrderSearch(PaginationMixin, ListView):
if o.pk not in annotated: if o.pk not in annotated:
continue continue
o.pcnt = annotated.get(o.pk)['pcnt'] o.pcnt = annotated.get(o.pk)['pcnt']
o.is_overpaid = annotated.get(o.pk)['is_overpaid']
o.is_underpaid = annotated.get(o.pk)['is_underpaid']
o.is_pending_with_full_payment = annotated.get(o.pk)['is_pending_with_full_payment']
o.has_external_refund = annotated.get(o.pk)['has_external_refund']
o.has_pending_refund = annotated.get(o.pk)['has_pending_refund']
o.has_cancellation_request = annotated.get(o.pk)['has_cancellation_request']
return ctx return ctx