From 062f7502d01d802c1ad64f6cb3d43ccb91925ba3 Mon Sep 17 00:00:00 2001 From: Thomas Steen Rasmussen Date: Sun, 19 Jun 2016 21:37:25 +0200 Subject: [PATCH] more creditnote stuff --- shop/models.py | 5 ++- shop/templates/creditnote_list.html | 36 ++++++++++++++++++++++ shop/templates/shop_base.html | 17 ++++++----- shop/urls.py | 3 ++ shop/views.py | 47 ++++++++++++++++++++++++++++- 5 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 shop/templates/creditnote_list.html diff --git a/shop/models.py b/shop/models.py index 7e8c792c..87a22985 100644 --- a/shop/models.py +++ b/shop/models.py @@ -285,6 +285,9 @@ class EpayPayment(CreatedUpdatedModel, UUIDModel): class CreditNote(CreatedUpdatedModel): + class Meta: + ordering = ['-created'] + amount = models.DecimalField(max_digits=10, decimal_places=2) text = models.TextField() pdf = models.FileField( @@ -300,7 +303,7 @@ class CreditNote(CreatedUpdatedModel): ) paid = models.BooleanField( verbose_name=_('Paid?'), - help_text=_('Whether this creditnote has been paid.'), + help_text=_('Whether the amount in this creditnote has been paid back to the customer.'), default=False, ) sent_to_customer = models.BooleanField(default=False) diff --git a/shop/templates/creditnote_list.html b/shop/templates/creditnote_list.html new file mode 100644 index 00000000..b93497a7 --- /dev/null +++ b/shop/templates/creditnote_list.html @@ -0,0 +1,36 @@ +{% extends 'shop_base.html' %} +{% load bootstrap3 %} +{% load shop_tags %} + +{% block shop_content %} +

Credit Notes

+ + + + + + + + + + + +{% for creditnote in creditnotes %} + + + + + + + +{% endfor %} + +
Credit Note IDTextAmountPaid?PDF
{{ creditnote.id }}{{ creditnote.text }}{{ creditnote.amount|currency }}{{ creditnote.paid|truefalseicon }} + {% if creditnote.pdf %} + {% url 'shop:download_creditnote' pk=creditnote.pk as creditnote_download_url %} + {% bootstrap_button "PDF" icon="save-file" href=creditnote_download_url button_class="btn-primary btn-xs" %} + {% else %} + N/A + {% endif %} +
+{% endblock %} diff --git a/shop/templates/shop_base.html b/shop/templates/shop_base.html index 77b63a87..e3550ec5 100644 --- a/shop/templates/shop_base.html +++ b/shop/templates/shop_base.html @@ -7,16 +7,19 @@ diff --git a/shop/urls.py b/shop/urls.py index 3e6892c0..5dc7d29b 100644 --- a/shop/urls.py +++ b/shop/urls.py @@ -23,4 +23,7 @@ urlpatterns = [ url(r'tickets/$', TicketListView.as_view(), name='ticket_list'), url(r'tickets/(?P\b[0-9A-Fa-f]{8}\b(-\b[0-9A-Fa-f]{4}\b){3}-\b[0-9A-Fa-f]{12}\b)$', TicketDetailView.as_view(), name='ticket_detail'), + + url(r'creditnotes/$', CreditNoteListView.as_view(), name='creditnote_list'), + url(r'creditnotes/(?P[0-9]+)/pdf/$', DownloadCreditNoteView.as_view(), name='download_creditnote'), ] diff --git a/shop/views.py b/shop/views.py index 2891cab6..178b971b 100644 --- a/shop/views.py +++ b/shop/views.py @@ -40,11 +40,38 @@ from vendor.coinify_callback import CoinifyCallback import json, time +class EnsureCreditNoteHasPDFMixin(SingleObjectMixin): + model = CreditNote + + def dispatch(self, request, *args, **kwargs): + if not self.get_object().pdf: + messages.error(request, "This creditnote has no PDF yet!") + return HttpResponseRedirect(reverse_lazy('shop:creditnote_list')) + + return super(EnsureCreditNoteHasPDFMixin, self).dispatch( + request, *args, **kwargs + ) + + +class EnsureUserOwnsCreditNoteMixin(SingleObjectMixin): + model = CreditNote + + def dispatch(self, request, *args, **kwargs): + # If the user does not own this creditnote OR is not staff + if not request.user.is_staff: + if self.get_object().user != request.user: + raise Http404("CreditNote not found") + + return super(EnsureUserOwnsCreditNoteMixin, self).dispatch( + request, *args, **kwargs + ) + + class EnsureUserOwnsOrderMixin(SingleObjectMixin): model = Order def dispatch(self, request, *args, **kwargs): - # If the user does not own this ticket OR is not staff + # If the user does not own this order OR is not staff if not request.user.is_staff: if self.get_object().user != request.user: raise Http404("Order not found") @@ -319,6 +346,24 @@ class DownloadInvoiceView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsurePa response.write(self.get_object().invoice.pdf.read()) return response + + +class CreditNoteListView(LoginRequiredMixin, ListView): + model = CreditNote + template_name = "creditnote_list.html" + context_object_name = 'creditnotes' + + +class DownloadCreditNoteView(LoginRequiredMixin, EnsureUserOwnsCreditNoteMixin, EnsureCreditNoteHasPDFMixin, SingleObjectMixin, View): + model = CreditNote + + def get(self, request, *args, **kwargs): + response = HttpResponse(content_type='application/pdf') + response['Content-Disposition'] = 'attachment; filename="%s"' % self.get_object().filename + response.write(self.get_object().invoice.pdf.read()) + return response + + ################################################################################# class EpayFormView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUnpaidOrderMixin, EnsureClosedOrderMixin, EnsureOrderHasProductsMixin, DetailView):