Add revision history to invoices/payments.

Also patches previously introduced reversion permissions hole.

Supersedes and closes #337.
This commit is contained in:
2020-09-16 11:37:56 +01:00
parent fd926aef85
commit ce5a92dfa8
8 changed files with 89 additions and 50 deletions

View File

@@ -19,8 +19,8 @@ from reversion import revisions as reversion
admin.site.register(models.VatRate, VersionAdmin)
admin.site.register(models.Event, VersionAdmin)
admin.site.register(models.EventItem, VersionAdmin)
admin.site.register(models.Invoice)
admin.site.register(models.Payment)
admin.site.register(models.Invoice, VersionAdmin)
admin.site.register(models.Payment, VersionAdmin)
def approve_user(modeladmin, request, queryset):

View File

@@ -13,6 +13,9 @@ from django.db.models import Q
from z3c.rml import rml2pdf
from django.db.models import Q
from django.db import transaction
import reversion
from RIGS import models
from django import forms
@@ -192,7 +195,10 @@ class InvoiceWaiting(generic.ListView):
class InvoiceEvent(generic.View):
@transaction.atomic()
@reversion.create_revision()
def get(self, *args, **kwargs):
reversion.set_user(self.request.user)
epk = kwargs.get('pk')
event = models.Event.objects.get(pk=epk)
invoice, created = models.Invoice.objects.get_or_create(event=event)
@@ -223,6 +229,13 @@ class PaymentCreate(generic.CreateView):
initial.update({'invoice': invoice})
return initial
@transaction.atomic()
@reversion.create_revision()
def form_valid(self, form, *args, **kwargs):
reversion.add_to_revision(form.cleaned_data['invoice'])
reversion.set_comment("Payment added")
return super().form_valid(form, *args, **kwargs)
def get_success_url(self):
messages.info(self.request, "location.reload()")
return reverse_lazy('closemodal')
@@ -232,5 +245,12 @@ class PaymentDelete(generic.DeleteView):
model = models.Payment
template_name = 'payment_confirm_delete.html'
@transaction.atomic()
@reversion.create_revision()
def delete(self, *args, **kwargs):
reversion.add_to_revision(self.get_object().invoice)
reversion.set_comment("Payment removed")
return super().delete(*args, **kwargs)
def get_success_url(self):
return self.request.POST.get('next')

View File

@@ -489,7 +489,8 @@ class Event(models.Model, RevisionMixin):
super(Event, self).save(*args, **kwargs)
class EventItem(models.Model):
@reversion.register
class EventItem(models.Model, RevisionMixin):
event = models.ForeignKey('Event', related_name='items', blank=True, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
description = models.TextField(blank=True, null=True)
@@ -528,11 +529,14 @@ class EventAuthorisation(models.Model, RevisionMixin):
return str("N%05d" % self.event.pk + ' (requested by ' + self.sent_by.initials + ')')
class Invoice(models.Model):
@reversion.register(follow=['payment_set'])
class Invoice(models.Model, RevisionMixin):
event = models.OneToOneField('Event', on_delete=models.CASCADE)
invoice_date = models.DateField(auto_now_add=True)
void = models.BooleanField(default=False)
reversion_perm = 'RIGS.view_invoice'
@property
def sum_total(self):
return self.event.sum_total
@@ -556,6 +560,13 @@ class Invoice(models.Model):
def is_closed(self):
return self.balance == 0 or self.void
def get_absolute_url(self):
return reverse_lazy('invoice_detail', kwargs={'pk': self.pk})
@property
def activity_feed_string(self):
return "#{} for Event {}".format(self.pk, "N%05d" % self.event.pk)
def __str__(self):
return "%i: %s (%.2f)" % (self.pk, self.event, self.balance)
@@ -563,7 +574,8 @@ class Invoice(models.Model):
ordering = ['-invoice_date']
class Payment(models.Model):
@reversion.register
class Payment(models.Model, RevisionMixin):
CASH = 'C'
INTERNAL = 'I'
EXTERNAL = 'E'
@@ -582,6 +594,8 @@ class Payment(models.Model):
amount = models.DecimalField(max_digits=10, decimal_places=2, help_text='Please use ex. VAT')
method = models.CharField(max_length=2, choices=METHODS, null=True, blank=True)
reversion_hide = True
def __str__(self):
return "%s: %d" % (self.get_method_display(), self.amount)

View File

@@ -103,5 +103,8 @@
</div>
</div>
</div>
<div class="col-12 text-right">
{% include 'partials/last_edited.html' with target="invoice_history" %}
</div>
</div>
{% endblock %}

View File

@@ -3,35 +3,19 @@
{% block title %}Delete payment on invoice {{ object.invoice.pk }}{% endblock %}
{% block content %}
<div class="col-sm-offset-2 col-sm-8">
<div class="alert alert-danger" role="alert">
<h2>Delete payment on invoice {{ object.invoice.pk }}</h2>
<div class="alert alert-danger" role="alert">
<h2>Delete payment on invoice {{ object.invoice.pk }}</h2>
<p>Are you sure you wish to delete a payment for £{{ object.amount|floatformat:2 }}
({{ object.get_method_display }})
from {{ object.date }} on invoice {{ object.invoice.pk }}.</p>
<p class="text-center"><strong>This action cannot be undone!</strong></p>
<div class="row">
<div class="col-sm-12">
<form action="{{ action_link }}" method="post">{% csrf_token %}
<input type="hidden" name="next" value="{% url 'invoice_detail' object.invoice.pk %}"/>
<a href="{% url 'invoice_detail' object.invoice.pk %}" class="btn btn-default col-sm-1">No</a>
<a href="{% url 'invoice_detail' object.invoice.pk %}" class="btn btn-default col-sm-1">No</a>
<a href="{% url 'invoice_detail' object.invoice.pk %}" class="btn btn-default col-sm-1">No</a>
<a href="{% url 'invoice_detail' object.invoice.pk %}" class="btn btn-default col-sm-1">No</a>
<a href="{% url 'invoice_detail' object.invoice.pk %}" class="btn btn-default col-sm-1">No</a>
<a href="{% url 'invoice_detail' object.invoice.pk %}" class="btn btn-default col-sm-1">No</a>
<a href="{% url 'invoice_detail' object.invoice.pk %}" class="btn btn-default col-sm-1">No</a>
<a href="{% url 'invoice_detail' object.invoice.pk %}" class="btn btn-default col-sm-1">No</a>
<input type="submit" value="Yes" class="btn btn-danger col-sm-1"/>
<a href="{% url 'invoice_detail' object.invoice.pk %}" class="btn btn-default col-sm-1">No</a>
<a href="{% url 'invoice_detail' object.invoice.pk %}" class="btn btn-default col-sm-1">No</a>
<a href="{% url 'invoice_detail' object.invoice.pk %}" class="btn btn-default col-sm-1">No</a>
</form>
</div>
</div>
</div>
<p>Are you sure you wish to delete a payment for £{{ object.amount|floatformat:2 }}
({{ object.get_method_display }})
from {{ object.date }} on invoice {{ object.invoice.pk }}?</p>
<hr>
<div class="text-right">
<form action="{{ action_link }}" method="post">{% csrf_token %}
<input type="hidden" name="next" value="{% url 'invoice_detail' object.invoice.pk %}"/>
<input type="submit" value="Yes" class="btn btn-danger col-sm-1"/>
<a href="{% url 'invoice_detail' object.invoice.pk %}" class="btn btn-success col-sm-1">No</a>
</form>
</div>
{% endblock %}
</div>
{% endblock %}