diff --git a/RIGS/finance.py b/RIGS/finance.py index fb075684..20199f0a 100644 --- a/RIGS/finance.py +++ b/RIGS/finance.py @@ -13,13 +13,20 @@ class InvoiceIndex(generic.ListView): template_name = 'RIGS/invoice_list.html' def get_queryset(self): - active = self.model.objects.filter(void=False).select_related('payment_set', 'event').prefetch_related( - 'event__items').defer('event__person', 'event__organisation', 'event__venue', 'event__mic') - set = [] - for invoice in active: - if invoice.balance != 0: - set.append(invoice) - return set + # Manual query is the only way I have found to do this efficiently. Not ideal but needs must + query = self.model.objects.raw( + "SELECT *, " + "(SELECT SUM(ei.cost * ei.quantity) FROM RIGS_eventitem AS ei WHERE ei.event_id = i.event_id) AS cost, " + "(SELECT SUM(p.amount) FROM RIGS_payment AS p WHERE p.invoice_id = i.id) AS payments FROM RIGS_invoice as i " + "HAVING (cost - payments) > 0;" + ) + + items = [] + + for invoice in query: + items.append(invoice) + + return query class InvoiceDetail(generic.DetailView): diff --git a/RIGS/migrations/0019_auto_20150131_1919.py b/RIGS/migrations/0019_auto_20150131_1919.py new file mode 100644 index 00000000..c55541b6 --- /dev/null +++ b/RIGS/migrations/0019_auto_20150131_1919.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('RIGS', '0018_auto_20150130_0016'), + ] + + operations = [ + migrations.AlterField( + model_name='payment', + name='method', + field=models.CharField(blank=True, max_length=2, null=True, choices=[(b'C', b'Cash'), (b'I', b'Internal'), (b'E', b'External'), (b'SU', b'SU Core')]), + preserve_default=True, + ), + ] diff --git a/RIGS/migrations/0020_auto_20150303_0243.py b/RIGS/migrations/0020_auto_20150303_0243.py new file mode 100644 index 00000000..9d9ee33f --- /dev/null +++ b/RIGS/migrations/0020_auto_20150303_0243.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('RIGS', '0019_auto_20150131_1919'), + ] + + operations = [ + migrations.AlterField( + model_name='payment', + name='method', + field=models.CharField(blank=True, max_length=2, null=True, choices=[(b'C', b'Cash'), (b'I', b'Internal'), (b'E', b'External'), (b'SU', b'SU Core'), (b'T', b'TEC Adjustment')]), + preserve_default=True, + ), + ] diff --git a/RIGS/models.py b/RIGS/models.py index da58bbc6..de1156b7 100644 --- a/RIGS/models.py +++ b/RIGS/models.py @@ -247,10 +247,11 @@ class Event(models.Model, RevisionMixin): """ @property def sum_total(self): - total = 0 - for item in self.items.filter(cost__gt=0): - total += item.total_cost - return total + # Manual querying is required for efficiency whilst maintaining floating point arithmetic + total = self.items.raw("SELECT id, SUM(quantity * cost) AS sum_total FROM RIGS_eventitem WHERE event_id=%i" % self.id)[0] + if total.sum_total: + return total.sum_total + return 0.0 @cached_property def vat_rate(self): @@ -329,16 +330,15 @@ class Invoice(models.Model): @property def payment_total(self): - sum = self.payment_set.aggregate(models.Sum('amount'))['amount__sum'] - # for payment in self.payment_set.all(): - # total += payment.amount - if sum: - return sum - return 0 + # Manual querying is required for efficiency whilst maintaining floating point arithmetic + total = self.payment_set.raw("SELECT id, SUM(amount) AS total FROM RIGS_payment WHERE invoice_id=%i" % self.id)[0] + if total.total: + return total.total + return 0.0 @property def balance(self): - return self.sum_total - self.payment_total + return float(self.sum_total) - float(self.payment_total) def __str__(self): return "%i: %s (%.2f)" % (self.pk, self.event, self.balance)