mirror of
https://github.com/pretix/pretix.git
synced 2025-12-05 21:32:28 +00:00
Fix #1468 -- Fix sorting by fallback name parts in check-in lists
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
from .database import * # noqa
|
||||
|
||||
|
||||
class PretixHelpersConfig(AppConfig):
|
||||
name = 'pretix.helpers'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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",""
|
||||
""")
|
||||
|
||||
Reference in New Issue
Block a user