more creditnote stuff

This commit is contained in:
Thomas Steen Rasmussen 2016-06-19 21:37:25 +02:00
parent 3e401f03bc
commit 062f7502d0
5 changed files with 99 additions and 9 deletions

View file

@ -285,6 +285,9 @@ class EpayPayment(CreatedUpdatedModel, UUIDModel):
class CreditNote(CreatedUpdatedModel): class CreditNote(CreatedUpdatedModel):
class Meta:
ordering = ['-created']
amount = models.DecimalField(max_digits=10, decimal_places=2) amount = models.DecimalField(max_digits=10, decimal_places=2)
text = models.TextField() text = models.TextField()
pdf = models.FileField( pdf = models.FileField(
@ -300,7 +303,7 @@ class CreditNote(CreatedUpdatedModel):
) )
paid = models.BooleanField( paid = models.BooleanField(
verbose_name=_('Paid?'), 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, default=False,
) )
sent_to_customer = models.BooleanField(default=False) sent_to_customer = models.BooleanField(default=False)

View file

@ -0,0 +1,36 @@
{% extends 'shop_base.html' %}
{% load bootstrap3 %}
{% load shop_tags %}
{% block shop_content %}
<h3>Credit Notes</h3>
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>Credit Note ID</th>
<th>Text</th>
<th class="text-right">Amount</th>
<th>Paid?</th>
<th>PDF</th>
</tr>
</thead>
<tbody>
{% for creditnote in creditnotes %}
<tr>
<td>{{ creditnote.id }}</td>
<td>{{ creditnote.text }}</td>
<td class="text-right">{{ creditnote.amount|currency }}</td>
<td class="text-center">{{ creditnote.paid|truefalseicon }}</td>
<td>
{% 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 %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View file

@ -17,6 +17,9 @@
<li class="pull-right"><a href="{% url 'shop:ticket_list' %}">Tickets</a></li> <li class="pull-right"><a href="{% url 'shop:ticket_list' %}">Tickets</a></li>
{% endif %} {% endif %}
<li class="pull-right no-before"><a href="{% url 'shop:order_list' %}">Orders</a></li> <li class="pull-right no-before"><a href="{% url 'shop:order_list' %}">Orders</a></li>
{% if user.creditnotes.exists %}
<li class="pull-right"><a href="{% url 'shop:creditnote_list' %}">Credit Notes</a></li>
{% endif %}
{% endif %} {% endif %}
</ol> </ol>
</div> </div>

View file

@ -23,4 +23,7 @@ urlpatterns = [
url(r'tickets/$', TicketListView.as_view(), name='ticket_list'), url(r'tickets/$', TicketListView.as_view(), name='ticket_list'),
url(r'tickets/(?P<pk>\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'tickets/(?P<pk>\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<pk>[0-9]+)/pdf/$', DownloadCreditNoteView.as_view(), name='download_creditnote'),
] ]

View file

@ -40,11 +40,38 @@ from vendor.coinify_callback import CoinifyCallback
import json, time 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): class EnsureUserOwnsOrderMixin(SingleObjectMixin):
model = Order model = Order
def dispatch(self, request, *args, **kwargs): 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 not request.user.is_staff:
if self.get_object().user != request.user: if self.get_object().user != request.user:
raise Http404("Order not found") raise Http404("Order not found")
@ -319,6 +346,24 @@ class DownloadInvoiceView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsurePa
response.write(self.get_object().invoice.pdf.read()) response.write(self.get_object().invoice.pdf.read())
return response 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): class EpayFormView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUnpaidOrderMixin, EnsureClosedOrderMixin, EnsureOrderHasProductsMixin, DetailView):