diff --git a/src/pretix/base/models/invoices.py b/src/pretix/base/models/invoices.py index c310b7fc70..d9cebc7ff1 100644 --- a/src/pretix/base/models/invoices.py +++ b/src/pretix/base/models/invoices.py @@ -2,6 +2,8 @@ import string from decimal import Decimal from django.db import DatabaseError, models, transaction +from django.db.models import Max +from django.db.models.functions import Cast from django.utils import timezone from django.utils.crypto import get_random_string from django.utils.functional import cached_property @@ -124,8 +126,12 @@ class Invoice(models.Model): numeric_invoices = Invoice.objects.filter( event__organizer=self.event.organizer, prefix=self.prefix, - ).exclude(invoice_no__contains='-') - return self._to_numeric_invoice_number(numeric_invoices.count() + 1) + ).exclude(invoice_no__contains='-').annotate( + numeric_number=Cast('invoice_no', models.IntegerField()) + ).aggregate( + max=Max('numeric_number') + )['max'] or 0 + return self._to_numeric_invoice_number(numeric_invoices + 1) def _get_invoice_number_from_order(self): return '{order}-{count}'.format( @@ -183,7 +189,7 @@ class Invoice(models.Model): class Meta: unique_together = ('organizer', 'prefix', 'invoice_no') - ordering = ('invoice_no',) + ordering = ('date', 'invoice_no',) class InvoiceLine(models.Model): diff --git a/src/tests/base/test_invoices.py b/src/tests/base/test_invoices.py index 70ecfef5e8..22aef5f5a6 100644 --- a/src/tests/base/test_invoices.py +++ b/src/tests/base/test_invoices.py @@ -294,20 +294,27 @@ def test_invoice_numbers(env): event.settings.set('invoice_numbers_consecutive', True) inv5 = generate_invoice(order) + inv6 = generate_invoice(order) + inv7 = generate_invoice(order) + Invoice.objects.filter(pk=inv6.pk).delete() # This should never ever happen, but what if it happens anyway? + inv8 = generate_invoice(order) inv23 = generate_invoice(order2) - # expected behaviour for switching between numbering formats + # expected behaviour for switching between numbering formats or dealing with gaps assert inv1.invoice_no == '00001' assert inv2.invoice_no == '00002' assert inv3.invoice_no == '{}-3'.format(order.code) assert inv4.invoice_no == '{}-4'.format(order.code) assert inv5.invoice_no == '00003' + assert inv6.invoice_no == '00004' + assert inv7.invoice_no == '00005' + assert inv8.invoice_no == '00006' # test that separate orders are counted separately in this mode assert inv21.invoice_no == '{}-1'.format(order2.code) assert inv22.invoice_no == '{}-2'.format(order2.code) # but consecutively in this mode - assert inv23.invoice_no == '00004' + assert inv23.invoice_no == '00007' # test Invoice.number, too assert inv1.number == '{}-00001'.format(event.slug.upper())