import cStringIO as StringIO import datetime import re from django.contrib import messages 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 HttpResponse from django.shortcuts import get_object_or_404 from django.template import RequestContext from django.template.loader import get_template from django.views import generic from z3c.rml import rml2pdf from RIGS import models class InvoiceIndex(generic.ListView): model = models.Invoice template_name = 'RIGS/invoice_list_active.html' def get_context_data(self, **kwargs): context = super(InvoiceIndex, self).get_context_data(**kwargs) total = 0 for i in context['object_list']: total += i.balance context['total'] = total context['count'] = len(list(context['object_list'])) return context def get_queryset(self): query = self.model.objects.annotate( cost=Sum(F('event__items__cost') * F('event__items__quantity'), output_field=FloatField()), payment_count=Count('payment'), payments=Sum('payment__amount'), ).filter( Q(cost__gt=0.0, payment_count=0) | Q(cost__lt=Value('payments'), cost__gt=Value('payments')) ).select_related('event', 'event__organisation', 'event__person', 'event__venue') return query class InvoiceDetail(generic.DetailView): model = models.Invoice class InvoicePrint(generic.View): def get(self, request, pk): invoice = get_object_or_404(models.Invoice, pk=pk) object = invoice.event template = get_template('RIGS/event_print.xml') copies = ('TEC', 'Client') context = RequestContext(request, { 'object': object, 'fonts': { 'opensans': { 'regular': 'RIGS/static/fonts/OPENSANS-REGULAR.TTF', 'bold': 'RIGS/static/fonts/OPENSANS-BOLD.TTF', } }, 'invoice': invoice, 'current_user': request.user, }) rml = template.render(context) buffer = StringIO.StringIO() buffer = rml2pdf.parseString(rml) pdfData = buffer.read() escapedEventName = re.sub('[^a-zA-Z0-9 \n\.]', '', object.name) response = HttpResponse(content_type='application/pdf') response['Content-Disposition'] = "filename=Invoice %05d | %s.pdf" % (invoice.pk, escapedEventName) response.write(pdfData) return response class InvoiceVoid(generic.View): def get(self, *args, **kwargs): pk = kwargs.get('pk') object = get_object_or_404(models.Invoice, pk=pk) object.void = not object.void object.save() if object.void: return HttpResponseRedirect(reverse_lazy('invoice_list')) return HttpResponseRedirect(reverse_lazy('invoice_detail', kwargs={'pk': object.pk})) class InvoiceDelete(generic.DeleteView): model = models.Invoice def get(self, request, pk): obj = self.get_object() if obj.payment_set.all().count() > 0: messages.info(self.request, 'To delete an invoice, delete the payments first.') return HttpResponseRedirect(reverse_lazy('invoice_detail', kwargs={'pk': obj.pk})) return super(InvoiceDelete, self).get(pk) def post(self, request, pk): obj = self.get_object() if obj.payment_set.all().count() > 0: messages.info(self.request, 'To delete an invoice, delete the payments first.') return HttpResponseRedirect(reverse_lazy('invoice_detail', kwargs={'pk': obj.pk})) return super(InvoiceDelete, self).post(pk) def get_success_url(self): return self.request.POST.get('next') class InvoiceArchive(generic.ListView): model = models.Invoice template_name = 'RIGS/invoice_list_archive.html' paginate_by = 25 class InvoiceWaiting(generic.ListView): model = models.Event paginate_by = 25 template_name = 'RIGS/event_invoice.html' def get_context_data(self, **kwargs): context = super(InvoiceWaiting, self).get_context_data(**kwargs) total = 0 for obj in self.get_objects(): total += obj.sum_total context['total'] = total context['count'] = len(self.get_objects()) return context def get_queryset(self): return self.get_objects() def get_objects(self): # @todo find a way to select items events = self.model.objects.filter( ( 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(invoice__isnull=True) # Has not already been invoiced & Q(is_rig=True) # Is a rig (not non-rig) ).order_by('start_date') \ .select_related('person', 'organisation', 'venue', 'mic') \ .prefetch_related('items') return events class InvoiceEvent(generic.View): def get(self, *args, **kwargs): epk = kwargs.get('pk') event = models.Event.objects.get(pk=epk) invoice, created = models.Invoice.objects.get_or_create(event=event) if created: invoice.invoice_date = datetime.date.today() messages.success(self.request, 'Invoice created successfully') return HttpResponseRedirect(reverse_lazy('invoice_detail', kwargs={'pk': invoice.pk})) class PaymentCreate(generic.CreateView): model = models.Payment fields = ['invoice', 'date', 'amount', 'method'] def get_initial(self): initial = super(generic.CreateView, self).get_initial() invoicepk = self.request.GET.get('invoice', self.request.POST.get('invoice', None)) if invoicepk == None: raise Http404() invoice = get_object_or_404(models.Invoice, pk=invoicepk) initial.update({'invoice': invoice}) return initial def get_success_url(self): messages.info(self.request, "location.reload()") return reverse_lazy('closemodal') class PaymentDelete(generic.DeleteView): model = models.Payment def get_success_url(self): return self.request.POST.get('next')