Compare commits

...

5 Commits

Author SHA1 Message Date
Tom Price
a3cdef8570 Tidy up the querying and move into model
This should really be in the model not in the view
2017-05-08 23:49:33 +01:00
Tom Price
7ec1c726a6 Optimise down to just the one SQL query for waiting invoices.
Cuts down on all the unnecessary queries and selects everything in one go.
Down from ~6 queries per invoice
2017-03-01 02:43:53 +00:00
Tom Price
4773b43081 Refactor outstanding invoice query to use django annotations.
Considerably improves performance and also removes the explict PSQL code.

Can be further improved by reducing the number of hits to the db in the template.
2017-03-01 02:05:06 +00:00
Tom Price
9694d407ae Merge pull request #275 from nottinghamtec/hotfix/home-links
Make forum go to actual forum
2017-02-06 15:47:12 +00:00
Sam Osborne
82aa2785ea Make forum go to actual forum
Currently goes to old forum :(
2017-02-06 15:35:29 +00:00
3 changed files with 37 additions and 21 deletions

View File

@@ -1,16 +1,17 @@
import cStringIO as StringIO import cStringIO as StringIO
import datetime import datetime
import re import re
from decimal import Decimal
from django.contrib import messages from django.contrib import messages
from django.core.urlresolvers import reverse_lazy from django.core.urlresolvers import reverse_lazy
from django.db.models import Count, Sum, F, FloatField, Q, Value
from django.http import Http404, HttpResponseRedirect from django.http import Http404, HttpResponseRedirect
from django.http import HttpResponse from django.http import HttpResponse
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.template import RequestContext from django.template import RequestContext
from django.template.loader import get_template from django.template.loader import get_template
from django.views import generic from django.views import generic
from django.db.models import Q
from z3c.rml import rml2pdf from z3c.rml import rml2pdf
from RIGS import models from RIGS import models
@@ -30,19 +31,8 @@ class InvoiceIndex(generic.ListView):
return context return context
def get_queryset(self): def get_queryset(self):
# Manual query is the only way I have found to do this efficiently. Not ideal but needs must query = self.model.objects.outstanding().select_related('event', 'event__organisation', 'event__person',
sql = "SELECT * FROM " \ 'event__venue', 'event__mic')
"(SELECT " \
"(SELECT COUNT(p.amount) FROM \"RIGS_payment\" AS p WHERE p.invoice_id=\"RIGS_invoice\".id) AS \"payment_count\", " \
"(SELECT SUM(ei.cost * ei.quantity) FROM \"RIGS_eventitem\" AS ei WHERE ei.event_id=\"RIGS_invoice\".event_id) AS \"cost\", " \
"(SELECT SUM(p.amount) FROM \"RIGS_payment\" AS p WHERE p.invoice_id=\"RIGS_invoice\".id) AS \"payments\", " \
"\"RIGS_invoice\".\"id\", \"RIGS_invoice\".\"event_id\", \"RIGS_invoice\".\"invoice_date\", \"RIGS_invoice\".\"void\" FROM \"RIGS_invoice\") " \
"AS sub " \
"WHERE (((cost > 0.0) AND (payment_count=0)) OR (cost - payments) <> 0.0) AND void = '0'" \
"ORDER BY invoice_date"
query = self.model.objects.raw(sql)
return query return query
@@ -94,6 +84,7 @@ class InvoiceVoid(generic.View):
return HttpResponseRedirect(reverse_lazy('invoice_list')) return HttpResponseRedirect(reverse_lazy('invoice_list'))
return HttpResponseRedirect(reverse_lazy('invoice_detail', kwargs={'pk': object.pk})) return HttpResponseRedirect(reverse_lazy('invoice_detail', kwargs={'pk': object.pk}))
class InvoiceDelete(generic.DeleteView): class InvoiceDelete(generic.DeleteView):
model = models.Invoice model = models.Invoice
@@ -114,6 +105,7 @@ class InvoiceDelete(generic.DeleteView):
def get_success_url(self): def get_success_url(self):
return self.request.POST.get('next') return self.request.POST.get('next')
class InvoiceArchive(generic.ListView): class InvoiceArchive(generic.ListView):
model = models.Invoice model = models.Invoice
template_name = 'RIGS/invoice_list_archive.html' template_name = 'RIGS/invoice_list_archive.html'
@@ -142,11 +134,11 @@ class InvoiceWaiting(generic.ListView):
events = self.model.objects.filter( events = self.model.objects.filter(
( (
Q(start_date__lte=datetime.date.today(), end_date__isnull=True) | # Starts before with no end Q(start_date__lte=datetime.date.today(), end_date__isnull=True) | # Starts before with no end
Q(end_date__lte=datetime.date.today()) # Has end date, finishes before Q(end_date__lte=datetime.date.today()) # Has end date, finishes before
) & Q(invoice__isnull=True) # Has not already been invoiced ) & Q(invoice__isnull=True) # Has not already been invoiced
& Q(is_rig=True) # Is a rig (not non-rig) & Q(is_rig=True) # Is a rig (not non-rig)
).order_by('start_date') \ ).order_by('start_date') \
.select_related('person', .select_related('person',
'organisation', 'organisation',
'venue', 'mic') \ 'venue', 'mic') \

View File

@@ -1,11 +1,11 @@
import datetime import datetime
import hashlib import hashlib
import pytz
import random import random
import string import string
from collections import Counter from collections import Counter
from decimal import Decimal from decimal import Decimal
import pytz
import reversion import reversion
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
@@ -501,14 +501,34 @@ class EventCrew(models.Model):
notes = models.TextField(blank=True, null=True) notes = models.TextField(blank=True, null=True)
class InvoiceManager(models.Manager):
def outstanding(self):
return self.annotate(
_payment_total=models.Sum(models.F('payment__amount'))
).annotate(
_sum_total=models.Sum(models.F('event__items__cost') * models.F('event__items__quantity'),
output_field=models.DecimalField(decimal_places=2))
# ).annotate(
# _balance=models.ExpressionWrapper(models.F('_sum_total') - models.F('_payment_total'),
# models.DecimalField(decimal_places=2))
# ).filter(
# models.Q(_balance__isnull=True) |
# ~models.Q(_sum_total=models.F('_payment_total'))
)
@python_2_unicode_compatible @python_2_unicode_compatible
class Invoice(models.Model): class Invoice(models.Model):
event = models.OneToOneField('Event') event = models.OneToOneField('Event')
invoice_date = models.DateField(auto_now_add=True) invoice_date = models.DateField(auto_now_add=True)
void = models.BooleanField(default=False) void = models.BooleanField(default=False)
objects = InvoiceManager()
@property @property
def sum_total(self): def sum_total(self):
if getattr(self, '_sum_total', None):
return Decimal(getattr(self, '_sum_total'))
return self.event.sum_total return self.event.sum_total
@property @property
@@ -517,6 +537,10 @@ class Invoice(models.Model):
@property @property
def payment_total(self): def payment_total(self):
if hasattr(self, '_payment_total') and hasattr(self, '_payment_count'):
if getattr(self, '_payment_count') == 0:
return Decimal(0.00)
return Decimal(getattr(self, '_payment_total', 0.00))
total = self.payment_set.aggregate(total=models.Sum('amount'))['total'] total = self.payment_set.aggregate(total=models.Sum('amount'))['total']
if total: if total:
return total return total

View File

@@ -23,7 +23,7 @@
<div class="list-group-item default"></div> <div class="list-group-item default"></div>
<a class="list-group-item" href="//members.nottinghamtec.co.uk/forum" target="_blank"><span class="glyphicon glyphicon-link"></span> TEC Forum</a> <a class="list-group-item" href="https://forum.nottinghamtec.co.uk" target="_blank"><span class="glyphicon glyphicon-link"></span> TEC Forum</a>
<a class="list-group-item" href="//members.nottinghamtec.co.uk/wiki" target="_blank"><span class="glyphicon glyphicon-link"></span> TEC Wiki</a> <a class="list-group-item" href="//members.nottinghamtec.co.uk/wiki" target="_blank"><span class="glyphicon glyphicon-link"></span> TEC Wiki</a>
<a class="list-group-item" href="http://members.nottinghamtec.co.uk/wiki/images/2/22/Event_Risk_Assesment.pdf" target="_blank"><span class="glyphicon glyphicon-link"></span> Pre-Event Risk Assessment</a> <a class="list-group-item" href="http://members.nottinghamtec.co.uk/wiki/images/2/22/Event_Risk_Assesment.pdf" target="_blank"><span class="glyphicon glyphicon-link"></span> Pre-Event Risk Assessment</a>
<a class="list-group-item" href="//members.nottinghamtec.co.uk/price" target="_blank"><span class="glyphicon glyphicon-link"></span> Price List</a> <a class="list-group-item" href="//members.nottinghamtec.co.uk/price" target="_blank"><span class="glyphicon glyphicon-link"></span> Price List</a>