more creditnote stuff
This commit is contained in:
parent
3e401f03bc
commit
062f7502d0
|
@ -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)
|
||||
|
|
36
shop/templates/creditnote_list.html
Normal file
36
shop/templates/creditnote_list.html
Normal 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 %}
|
|
@ -17,6 +17,9 @@
|
|||
<li class="pull-right"><a href="{% url 'shop:ticket_list' %}">Tickets</a></li>
|
||||
{% endif %}
|
||||
<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 %}
|
||||
</ol>
|
||||
</div>
|
||||
|
|
|
@ -23,4 +23,7 @@ urlpatterns = [
|
|||
|
||||
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'creditnotes/$', CreditNoteListView.as_view(), name='creditnote_list'),
|
||||
url(r'creditnotes/(?P<pk>[0-9]+)/pdf/$', DownloadCreditNoteView.as_view(), name='download_creditnote'),
|
||||
]
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in a new issue