Compare commits

..

31 Commits

Author SHA1 Message Date
Matthew Smith
8ca55f2696 Added migration for name change 2020-01-22 03:06:29 +00:00
Matthew Smith
228592a0f3 Creating an invoice now appears in its history. Rudimentary tracking of payments is also implemented 2020-01-22 02:37:39 +00:00
Tom Price
1be1b1abd7 Add invoice versioning to templates. 2018-05-15 17:42:13 +01:00
Johnathan Graydon
42e1931e72 Add revision history to invoices & payments 2018-05-14 15:57:06 +01:00
David Taylor
e81af9e479 Merge pull request #335 from nottinghamtec/requires-io-master
[requires.io] dependency update on master branch
2018-05-08 17:57:11 +01:00
requires.io
efab8c8cef [requires.io] dependency update 2018-05-08 16:41:37 +01:00
requires.io
3f7531e157 [requires.io] dependency update 2018-05-02 03:12:55 +01:00
requires.io
988f3dced4 [requires.io] dependency update 2018-04-30 19:49:11 +01:00
requires.io
bd3240c2bc [requires.io] dependency update 2018-04-28 20:25:35 +01:00
requires.io
7fbbe2871f [requires.io] dependency update 2018-04-22 00:34:34 +01:00
requires.io
109ece508b [requires.io] dependency update 2018-04-19 07:36:06 +01:00
requires.io
971144c2e6 [requires.io] dependency update 2018-04-18 11:16:00 +01:00
David Taylor
a3c6edda0b Merge pull request #334 from nottinghamtec/requires-io-master
[requires.io] dependency update on master branch
2018-04-16 23:59:36 +01:00
requires.io
71bb4696b8 [requires.io] dependency update 2018-04-16 23:19:10 +01:00
requires.io
2a3ed0b763 [requires.io] dependency update 2018-04-12 01:29:58 +01:00
requires.io
632fa56353 [requires.io] dependency update 2018-04-11 06:08:19 +01:00
requires.io
f3020fc783 [requires.io] dependency update 2018-04-10 19:16:12 +01:00
requires.io
9fdf5e674e [requires.io] dependency update 2018-04-10 12:08:43 +01:00
requires.io
cfe03a8628 [requires.io] dependency update 2018-04-10 05:17:39 +01:00
requires.io
eccf224b63 [requires.io] dependency update 2018-04-03 04:33:32 +01:00
requires.io
0b2c86ebb5 [requires.io] dependency update 2018-04-03 00:19:18 +01:00
David Taylor
f616857131 Merge pull request #328 from nottinghamtec/django2
Upgrade to Django 2
2018-04-02 21:36:10 +01:00
David Taylor
60fb90a50c Merge pull request #333 from nottinghamtec/hotfix/fix-jonos-commit
Remove un-necessary use of reversion
2018-03-26 19:46:06 +01:00
David Taylor
66f024e961 Remove un-necessary use of reversion 2018-03-26 19:41:13 +01:00
Johnathan Graydon
06daacf611 Automatically set event to booked when the client authorises it (#332)
* Automatically set rig to booked when event is authorised
Will close #320
2018-03-26 14:51:42 +01:00
Johnathan Graydon
c74bc945b6 Not error if no person
Will close #330
2018-03-26 14:09:51 +01:00
Johnathan Graydon
3c605d2976 Fix pep8 2018-03-25 15:30:05 +01:00
Johnathan Graydon
9720066fd7 Remove checked in by on event duplication
Will close #327
2018-03-25 15:30:05 +01:00
Johnathan Graydon
b157e3b187 Add 127.0.0.1 to Allowed_Hosts for debug 2018-03-25 15:30:05 +01:00
David Taylor
9c2603557c Merge pull request #324 from nottinghamtec/hotfix/auth-request
Fix null person on authorisation request
2018-03-25 00:01:05 +00:00
Johnathan Graydon
7dff951f28 Fix null person on authorisation request
Will close #319
2018-03-24 23:54:03 +00:00
11 changed files with 122 additions and 62 deletions

View File

@@ -35,6 +35,7 @@ if STAGING:
if DEBUG:
ALLOWED_HOSTS.append('localhost')
ALLOWED_HOSTS.append('example.com')
ALLOWED_HOSTS.append('127.0.0.1')
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
if not DEBUG:

View File

@@ -1,25 +1,24 @@
from django.contrib import admin
from RIGS import models, forms
from django.contrib.auth.admin import UserAdmin
from django.utils.translation import ugettext_lazy as _
from reversion.admin import VersionAdmin
from django.contrib.admin import helpers
from django.template.response import TemplateResponse
from django.contrib import messages
from django.db import transaction
from django.contrib.admin import helpers
from django.contrib.auth.admin import UserAdmin
from django.core.exceptions import ObjectDoesNotExist
from django.db import transaction
from django.db.models import Count
from django.forms import ModelForm
from django.template.response import TemplateResponse
from django.utils.translation import ugettext_lazy as _
from reversion import revisions as reversion
from reversion.admin import VersionAdmin
from RIGS import models, forms
# Register your models here.
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)
@admin.register(models.Profile)

View File

@@ -10,8 +10,9 @@ from django.template import RequestContext
from django.template.loader import get_template
from django.views import generic
from django.db.models import Q
from django.db import transaction
from z3c.rml import rml2pdf
import reversion
from RIGS import models
from django import forms
@@ -101,14 +102,14 @@ class InvoiceDelete(generic.DeleteView):
def get(self, request, pk):
obj = self.get_object()
if obj.payment_set.all().count() > 0:
if obj.payments.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:
if obj.payments.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)
@@ -159,7 +160,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)
@@ -184,6 +188,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 removed")
return super().form_valid(form, *args, **kwargs)
def get_success_url(self):
messages.info(self.request, "location.reload()")
return reverse_lazy('closemodal')
@@ -192,5 +203,12 @@ class PaymentCreate(generic.CreateView):
class PaymentDelete(generic.DeleteView):
model = models.Payment
@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

@@ -0,0 +1,19 @@
# Generated by Django 2.0.13 on 2020-01-22 03:05
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('RIGS', '0033_auto_20180325_0016'),
]
operations = [
migrations.AlterField(
model_name='payment',
name='invoice',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='payments', to='RIGS.Invoice'),
),
]

View File

@@ -1,24 +1,21 @@
from collections import Counter
import datetime
import hashlib
import datetime
import pytz
from django.db import models
from django.contrib.auth.models import AbstractUser
import random
import string
from decimal import Decimal
from django.conf import settings
from django.contrib.auth.models import AbstractUser
from django.core.exceptions import ValidationError
from django.db import models
from django.urls import reverse_lazy
from django.utils import timezone
from django.utils.functional import cached_property
from django.utils.encoding import python_2_unicode_compatible
from django.utils.functional import cached_property
from reversion import revisions as reversion
from reversion.models import Version
import string
import random
from collections import Counter
from decimal import Decimal
from django.core.exceptions import ValidationError
from django.urls import reverse_lazy
# Create your models here.
@@ -530,8 +527,9 @@ class EventAuthorisation(models.Model, RevisionMixin):
return str("N%05d" % self.event.pk + ' (requested by ' + self.sent_by.initials + ')')
@reversion.register(follow=['payments'])
@python_2_unicode_compatible
class Invoice(models.Model):
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)
@@ -546,7 +544,7 @@ class Invoice(models.Model):
@property
def payment_total(self):
total = self.payment_set.aggregate(total=models.Sum('amount'))['total']
total = self.payments.aggregate(total=models.Sum('amount'))['total']
if total:
return total
return Decimal("0.00")
@@ -584,7 +582,7 @@ class Payment(models.Model):
(ADJUSTMENT, 'TEC Adjustment'),
)
invoice = models.ForeignKey('Invoice', on_delete=models.CASCADE)
invoice = models.ForeignKey('Invoice', on_delete=models.CASCADE, related_name="payments")
date = models.DateField()
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)

View File

@@ -138,7 +138,11 @@ class EventDuplicate(EventUpdate):
old = super(EventDuplicate, self).get_object(queryset) # Get the object (the event you're duplicating)
new = copy.copy(old) # Make a copy of the object in memory
new.based_on = old # Make the new event based on the old event
new.purchase_order = None
new.purchase_order = None # Remove old PO
# Clear checked in by if it's a dry hire
if new.dry_hire is True:
new.checked_in_by = None
# Remove all the authorisation information from the new event
new.auth_request_to = None
@@ -340,8 +344,10 @@ class EventAuthorisationRequest(generic.FormView, generic.detail.SingleObjectMix
'sent_by': self.request.user.pk,
}),
}
if email == event.person.email:
if event.person is not None and email == event.person.email:
context['to_name'] = event.person.name
elif event.organisation is not None and email == event.organisation.email:
context['to_name'] = event.organisation.name
msg = EmailMultiAlternatives(
"N%05d | %s - Event Authorisation Request" % (self.object.pk, self.object.name),

View File

@@ -50,8 +50,10 @@ def send_eventauthorisation_success_email(instance):
'object': instance,
}
if instance.email == instance.event.person.email:
if instance.event.person is not None and instance.email == instance.event.person.email:
context['to_name'] = instance.event.person.name
elif instance.event.organisation is not None and instance.email == instance.event.organisation.email:
context['to_name'] = instance.event.organisation.name
subject = "N%05d | %s - Event Authorised" % (instance.event.pk, instance.event.name)
@@ -89,6 +91,10 @@ def send_eventauthorisation_success_email(instance):
client_email.send(fail_silently=True)
mic_email.send(fail_silently=True)
# Set event to booked now that it's authorised
instance.event.status = models.Event.BOOKED
instance.event.save()
def on_revision_commit(sender, instance, created, **kwargs):
if created:

View File

@@ -264,7 +264,7 @@
</para>
</td>
</tr>
{% for payment in object.invoice.payment_set.all %}
{% for payment in object.invoice.payments.all %}
<tr>
<td>{{ payment.get_method_display }}</td>
<td>{{ payment.date }}</td>

View File

@@ -6,20 +6,21 @@
<div class="col-sm-12">
<div class="row">
<div class="col-sm-8">
<h2>Invoice {{ object.pk }} ({{ object.invoice_date|date:"d/m/Y"}})</h2>
<h2>Invoice {{ object.pk }} ({{ object.invoice_date|date:"d/m/Y" }})</h2>
</div>
<div class="col-sm-4 text-right">
<div class="btn-group btn-page">
<a href="{% url 'invoice_delete' object.pk %}" class="btn btn-default" title="Delete Invoice">
<span class="glyphicon glyphicon-remove"></span> <span
<a href="{% url 'invoice_delete' object.pk %}" class="btn btn-default" title="Delete Invoice">
<span class="glyphicon glyphicon-remove"></span> <span
class="hidden-xs">Delete</span>
</a>
<a href="{% url 'invoice_void' object.pk %}" class="btn btn-default" title="Void Invoice">
<span class="glyphicon glyphicon-ban-circle"></span> <span
</a>
<a href="{% url 'invoice_void' object.pk %}" class="btn btn-default" title="Void Invoice">
<span class="glyphicon glyphicon-ban-circle"></span> <span
class="hidden-xs">Void</span>
</a>
<a href="{% url 'invoice_print' object.pk %}" target="_blank" title="Print Invoice" class="btn btn-default"><span
</a>
<a href="{% url 'invoice_print' object.pk %}" target="_blank" title="Print Invoice"
class="btn btn-default"><span
class="glyphicon glyphicon-print"></span> <span
class="hidden-xs">Print</span></a>
</div>
@@ -83,9 +84,11 @@
<dt>Authorised by</dt>
<dd>
{% if object.event.authorised %}
{% if object.event.authorised %}
{{ object.event.authorisation.name }}
(<a href="mailto:{{ object.event.authorisation.email }}">{{ object.event.authorisation.email }}</a>)
(
<a href="mailto:{{ object.event.authorisation.email }}">{{ object.event.authorisation.email }}</a>
)
{% endif %}
</dd>
@@ -140,7 +143,7 @@
</tr>
</thead>
<tbody>
{% for payment in object.payment_set.all %}
{% for payment in object.payments.all %}
<tr>
<td>{{ payment.date }}</td>
<td>{{ payment.amount|floatformat:2 }}</td>
@@ -172,6 +175,13 @@
</div>
</div>
</div>
</div>
<div class="col-sm-12 text-right">
<div>
<a href="{% url 'invoice_history' object.pk %}" title="View Revision History">
Last edited at {{ object.last_edited_at }} by {{ object.last_edited_by.name }}
</a>
</div>
</div>
{% endblock %}

View File

@@ -1,13 +1,12 @@
from django.conf.urls import url
from django.contrib.auth.views import password_reset
from django.contrib.auth.decorators import login_required
from RIGS import models, views, rigboard, finance, ical, versioning, forms
from django.views.generic import RedirectView
from django.contrib.auth.views import password_reset
from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.generic import RedirectView
from PyRIGS.decorators import permission_required_with_403
from PyRIGS.decorators import api_key_required
from PyRIGS.decorators import permission_required_with_403
from RIGS import models, views, rigboard, finance, ical, versioning, forms
urlpatterns = [
# Examples:
@@ -144,6 +143,10 @@ urlpatterns = [
url(r'^invoice/(?P<pk>\d+)/delete/$',
permission_required_with_403('RIGS.change_invoice')(finance.InvoiceDelete.as_view()),
name='invoice_delete'),
url(r'^invoice/(?P<pk>\d+)/history/$',
permission_required_with_403('RIGS.view_invoice')(versioning.VersionHistory.as_view()),
name='invoice_history', kwargs={'model': models.Invoice}),
url(r'^payment/create/$',
permission_required_with_403('RIGS.add_payment')(finance.PaymentCreate.as_view()),
name='payment_create'),

View File

@@ -3,36 +3,36 @@ contextlib2==0.5.5
diff-match-patch==20121119
dj-database-url==0.5.0
dj-static==0.0.6
Django==2.0.3
Django==2.0.5
django-debug-toolbar==1.9.1
django-ical==1.4
django-recaptcha==1.4.0
django-registration-redux==2.2
django-registration-redux==2.4
django-reversion==2.0.13
django-toolbelt==0.0.1
premailer==3.1.1
premailer==3.2.0
#django-widget-tweaks==1.4.1
git+git://github.com/jazzband/django-widget-tweaks.git@1.4.2
gunicorn==19.7.1
gunicorn==19.8.1
icalendar==4.0.1
lxml==4.2.1
Markdown==2.6.11
Pillow==5.0.0
Pillow==5.1.0
psycopg2==2.7.4
Pygments==2.2.0
PyPDF2==1.26.0
python-dateutil==2.7.1
pytz==2018.3
raven==6.6.0
python-dateutil==2.7.2
pytz==2018.4
raven==6.7.0
reportlab==3.4.0
selenium==3.11.0
simplejson==3.13.2
selenium==3.12.0
simplejson==3.14.0
six==1.11.0
sqlparse==0.2.4
static3==0.7.0
svg2rlg==0.3
yolk==0.4.3
z3c.rml==3.3.0
z3c.rml==3.5.0
zope.event==4.3.0
zope.interface==4.4.3
zope.interface==4.5.0
zope.schema==4.5.0