diff --git a/RIGS/migrations/0025_eventauthorisation.py b/RIGS/migrations/0025_eventauthorisation.py new file mode 100644 index 00000000..88f38ff4 --- /dev/null +++ b/RIGS/migrations/0025_eventauthorisation.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('RIGS', '0024_auto_20160229_2042'), + ] + + operations = [ + migrations.CreateModel( + name='EventAuthorisation', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('email', models.EmailField(max_length=254)), + ('name', models.CharField(max_length=255)), + ('uni_id', models.CharField(max_length=10, null=True, verbose_name=b'University ID', blank=True)), + ('account_code', models.CharField(max_length=50, null=True, blank=True)), + ('po', models.CharField(max_length=255, null=True, verbose_name=b'purchase order', blank=True)), + ('amount', models.DecimalField(verbose_name=b'authorisation amount', max_digits=10, decimal_places=2)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('event', models.ForeignKey(related_name='authroisations', to='RIGS.Event')), + ], + ), + ] diff --git a/RIGS/models.py b/RIGS/models.py index 0650d81c..350f406a 100644 --- a/RIGS/models.py +++ b/RIGS/models.py @@ -385,6 +385,10 @@ class Event(models.Model, RevisionMixin): def confirmed(self): return (self.status == self.BOOKED or self.status == self.CONFIRMED) + @property + def authorised(self): + return self.authroisations.latest('created_at').amount >= self.total + @property def has_start_time(self): return self.start_time is not None @@ -501,6 +505,30 @@ class EventCrew(models.Model): notes = models.TextField(blank=True, null=True) +class EventAuthorisation(models.Model): + event = models.ForeignKey('Event', related_name='authroisations') + email = models.EmailField() + name = models.CharField(max_length=255) + uni_id = models.CharField(max_length=10, blank=True, null=True, verbose_name="University ID") + account_code = models.CharField(max_length=50, blank=True, null=True) + po = models.CharField(max_length=255, blank=True, null=True, verbose_name="purchase order") + amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="authorisation amount") + created_at = models.DateTimeField(auto_now_add=True) + + def clean(self): + if self.amount != self.event.total: + raise ValidationError("The amount authorised must equal the total for the event") + if self.event.organisation and self.event.organisation.union_account: + # Is a union account, requires username and account number + if self.uni_id is None or self.uni_id == "" or self.account_code is None or self.account_code == "": + raise ValidationError("Internal clients require a University ID number and an account code") + else: + # Is an external client, only requires PO + if self.po is None or self.po == "": + raise ValidationError("External clients require a Purchase Order number") + return super(EventAuthorisation, self).clean() + + @python_2_unicode_compatible class Invoice(models.Model): event = models.OneToOneField('Event') diff --git a/RIGS/test_models.py b/RIGS/test_models.py index a7896cbe..0cbe58f1 100644 --- a/RIGS/test_models.py +++ b/RIGS/test_models.py @@ -1,5 +1,6 @@ import pytz from django.conf import settings +from django.core.exceptions import ValidationError from django.test import TestCase from RIGS import models from datetime import date, timedelta, datetime, time @@ -327,3 +328,53 @@ class EventPricingTestCase(TestCase): def test_grand_total(self): self.assertEqual(self.e1.total, Decimal('84.48')) self.assertEqual(self.e2.total, Decimal('419.32')) + + +class EventAuthorisationTestCase(TestCase): + @classmethod + def setUpTestData(cls): + cls.person = models.Person.objects.create(name='Authorisation Test Person') + cls.organisation = models.Organisation.objects.create(name='Authorisation Test Organisation') + cls.event = models.Event.objects.create(name="AuthorisationTestCase", person=cls.person, + start_date=date.today()) + # Add some items + models.EventItem.objects.create(event=cls.event, name="Authorisation test item", quantity=2, cost=123.45, + order=1) + + def test_validation(self): + auth = models.EventAuthorisation(event=self.event, email="authroisation@model.test.case", name="Test Auth") + + auth.amount = self.event.total - 1 + self.assertRaises(ValidationError, auth.clean) + auth.amount = self.event.total + + # Test for externals first + self.assertRaises(ValidationError, auth.clean) + self.event.organisation = self.organisation + self.assertRaises(ValidationError, auth.clean) + auth.po = "TEST123" + self.assertIsNone(auth.clean()) + + auth.po = None + self.organisation.union_account = True + self.assertRaises(ValidationError, auth.clean) + auth.uni_id = "1234567" + self.assertRaises(ValidationError, auth.clean) + auth.account_code = "TST AUTH 12345" + self.assertIsNone(auth.clean()) + + def test_event_property(self): + auth1 = models.EventAuthorisation.objects.create(event=self.event, email="authroisation@model.test.case", + name="Test Auth 1", amount=self.event.total - 1) + self.assertFalse(self.event.authorised) + auth1.amount = self.event.total + auth1.save() + self.assertTrue(self.event.authorised) + + auth2 = models.EventAuthorisation.objects.create(event=self.event, email="authroisation@model.test.case", + name="Test Auth 2", amount=self.event.total - 1) + self.assertEqual(auth2.pk, self.event.authroisations.latest('created_at').pk) + self.assertFalse(self.event.authorised) + auth2.amount = self.event.total + 1 + auth2.save() + self.assertTrue(self.event.authorised)