Fix #1468 -- Fix sorting by fallback name parts in check-in lists

This commit is contained in:
Raphael Michel
2019-10-29 19:50:28 +01:00
parent f473439f77
commit b156efaae8
4 changed files with 118 additions and 7 deletions

View File

@@ -1,5 +1,7 @@
from django.apps import AppConfig
from .database import * # noqa
class PretixHelpersConfig(AppConfig):
name = 'pretix.helpers'

View File

@@ -1,7 +1,7 @@
import contextlib
from django.db import transaction
from django.db.models import Aggregate
from django.db.models import Aggregate, Field, Lookup
from django.db.models.expressions import OrderBy
@@ -94,3 +94,14 @@ class ReplicaRouter:
def allow_migrate(self, db, app_label, model_name=None, **hintrs):
return True
@Field.register_lookup
class NotEqual(Lookup):
lookup_name = 'ne'
def as_sql(self, compiler, connection):
lhs, lhs_params = self.process_lhs(compiler, connection)
rhs, rhs_params = self.process_rhs(compiler, connection)
params = lhs_params + rhs_params
return '%s <> %s' % (lhs, rhs), params

View File

@@ -3,8 +3,8 @@ from collections import OrderedDict
import dateutil.parser
from django import forms
from django.conf import settings
from django.db.models import Exists, Max, OuterRef, Subquery
from django.db.models.functions import Coalesce
from django.db.models import Case, Exists, Max, OuterRef, Subquery, Value, When
from django.db.models.functions import Coalesce, NullIf
from django.urls import reverse
from django.utils.formats import date_format
from django.utils.timezone import is_aware, make_aware
@@ -112,14 +112,24 @@ class CheckInListMixin(BaseExporter):
qs = qs.filter(subevent=cl.subevent)
if form_data['sort'] == 'name':
qs = qs.order_by(Coalesce('attendee_name_cached', 'addon_to__attendee_name_cached', 'order__invoice_address__name_cached'),
'order__code')
qs = qs.order_by(
Coalesce(
NullIf('attendee_name_cached', Value('')),
NullIf('addon_to__attendee_name_cached', Value('')),
NullIf('order__invoice_address__name_cached', Value('')),
'order__code'
)
)
elif form_data['sort'] == 'code':
qs = qs.order_by('order__code')
elif form_data['sort'].startswith('name:'):
part = form_data['sort'][5:]
qs = qs.annotate(
resolved_name=Coalesce('attendee_name_parts', 'addon_to__attendee_name_parts', 'order__invoice_address__name_parts')
resolved_name=Case(
When(attendee_name_cached__ne='', then='attendee_name_parts'),
When(addon_to__attendee_name_cached__isnull=False, addon_to__attendee_name_cached__ne='', then='addon_to__attendee_name_parts'),
default='order__invoice_address__name_parts',
)
).annotate(
resolved_name_part=JSONExtract('resolved_name', part)
).order_by(

View File

@@ -6,7 +6,9 @@ import pytz
from django.utils.timezone import now
from django_scopes import scope
from pretix.base.models import Event, Item, Order, OrderPosition, Organizer
from pretix.base.models import (
Event, InvoiceAddress, Item, Order, OrderPosition, Organizer,
)
from pretix.plugins.checkinlists.exporters import CSVCheckinList
@@ -114,3 +116,89 @@ def test_csv_order_by_name_parts(event): # noqa
"FOO","Mrs Andrea J Zulu","Mrs","Andrea","J","Zulu","Ticket","13.00","","No","ggsngqtnmhx74jswjngw3fk8pfwz2a7k",
"dummy@dummy.test","","","2019-02-22","No",""
""")
@pytest.mark.django_db
def test_csv_order_by_inherited_name_parts(event): # noqa
from django.conf import settings
if not settings.JSON_FIELD_AVAILABLE:
raise pytest.skip("Not supported on this database")
with scope(organizer=event.organizer):
OrderPosition.objects.filter(attendee_name_cached__icontains="Andrea").delete()
op = OrderPosition.objects.get()
op.attendee_name_parts = {}
op.save()
order2 = Order.objects.create(
code='BAR', event=event, email='dummy@dummy.test',
status=Order.STATUS_PAID,
datetime=datetime.datetime(2019, 2, 22, 14, 0, 0, tzinfo=pytz.UTC), expires=now() + datetime.timedelta(days=10),
total=33, locale='en'
)
OrderPosition.objects.create(
order=order2,
item=event.items.first(),
variation=None,
price=Decimal("23"),
secret='hutjztuxhkbtwnesv2suqv26k6ttytyy'
)
InvoiceAddress.objects.create(
order=event.orders.get(code='BAR'),
name_parts={"title": "Mr", "given_name": "Albert", "middle_name": "J", "family_name": "Zulu", "_scheme": "title_given_middle_family"}
)
InvoiceAddress.objects.create(
order=event.orders.get(code='FOO'),
name_parts={"title": "Mr", "given_name": "Paul", "middle_name": "A", "family_name": "Jones", "_scheme": "title_given_middle_family"}
)
c = CSVCheckinList(event)
_, _, content = c.render({
'list': event.checkin_lists.first().pk,
'secrets': True,
'sort': 'name',
'_format': 'default',
'questions': []
})
assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title",
"Attendee name: First name","Attendee name: Middle name","Attendee name: Family name","Product","Price",
"Checked in","Automatically checked in","Secret","E-mail","Company","Voucher code","Order date","Requires special
attention","Comment"
"BAR","Mr Albert J Zulu","Mr","Albert","J","Zulu","Ticket","23.00","","No","hutjztuxhkbtwnesv2suqv26k6ttytyy",
"dummy@dummy.test","","","2019-02-22","No",""
"FOO","Mr Paul A Jones","Mr","Paul","A","Jones","Ticket","23.00","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx",
"dummy@dummy.test","","","2019-02-22","No",""
""")
c = CSVCheckinList(event)
_, _, content = c.render({
'list': event.checkin_lists.first().pk,
'secrets': True,
'sort': 'name:given_name',
'_format': 'default',
'questions': []
})
assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title",
"Attendee name: First name","Attendee name: Middle name","Attendee name: Family name","Product","Price",
"Checked in","Automatically checked in","Secret","E-mail","Company","Voucher code","Order date","Requires special
attention","Comment"
"BAR","Mr Albert J Zulu","Mr","Albert","J","Zulu","Ticket","23.00","","No","hutjztuxhkbtwnesv2suqv26k6ttytyy",
"dummy@dummy.test","","","2019-02-22","No",""
"FOO","Mr Paul A Jones","Mr","Paul","A","Jones","Ticket","23.00","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx",
"dummy@dummy.test","","","2019-02-22","No",""
""")
c = CSVCheckinList(event)
_, _, content = c.render({
'list': event.checkin_lists.first().pk,
'secrets': True,
'sort': 'name:family_name',
'_format': 'default',
'questions': []
})
assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title",
"Attendee name: First name","Attendee name: Middle name","Attendee name: Family name","Product","Price",
"Checked in","Automatically checked in","Secret","E-mail","Company","Voucher code","Order date","Requires special
attention","Comment"
"FOO","Mr Paul A Jones","Mr","Paul","A","Jones","Ticket","23.00","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx",
"dummy@dummy.test","","","2019-02-22","No",""
"BAR","Mr Albert J Zulu","Mr","Albert","J","Zulu","Ticket","23.00","","No","hutjztuxhkbtwnesv2suqv26k6ttytyy",
"dummy@dummy.test","","","2019-02-22","No",""
""")