mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-01-17 05:22:16 +00:00
Added the ability to view organisations by people and vice versa, as well as the option to see all the rigs associated with orgs/people/venues. Added helper properties for the above
333 lines
10 KiB
Python
333 lines
10 KiB
Python
import hashlib
|
|
import datetime
|
|
|
|
from django.db import models
|
|
from django.contrib.auth.models import AbstractUser
|
|
from django.conf import settings
|
|
import reversion
|
|
|
|
|
|
# Create your models here.
|
|
class Profile(AbstractUser):
|
|
initials = models.CharField(max_length=5, unique=True, null=True, blank=True)
|
|
phone = models.CharField(max_length=13, null=True, blank=True)
|
|
|
|
@property
|
|
def profile_picture(self):
|
|
url = ""
|
|
if settings.USE_GRAVATAR or settings.USE_GRAVATAR is None:
|
|
url = "https://www.gravatar.com/avatar/" + hashlib.md5(self.email).hexdigest() + "?d=identicon&s=500"
|
|
return url
|
|
|
|
@property
|
|
def name(self):
|
|
return self.get_full_name() + ' "' + self.initials + '"'
|
|
|
|
|
|
class RevisionMixin(object):
|
|
@property
|
|
def last_edited_at(self):
|
|
version = reversion.get_for_object(self)[0]
|
|
return version.revision.date_created
|
|
|
|
@property
|
|
def last_edited_by(self):
|
|
version = reversion.get_for_object(self)[0]
|
|
return version.revision.user
|
|
|
|
|
|
@reversion.register
|
|
class Person(models.Model, RevisionMixin):
|
|
name = models.CharField(max_length=50)
|
|
phone = models.CharField(max_length=15, blank=True, null=True)
|
|
email = models.EmailField(blank=True, null=True)
|
|
|
|
address = models.TextField(blank=True, null=True)
|
|
|
|
notes = models.TextField(blank=True, null=True)
|
|
|
|
def __str__(self):
|
|
string = self.name
|
|
if len(self.notes) > 0:
|
|
string += "*"
|
|
return string
|
|
|
|
@property
|
|
def organisations(self):
|
|
o = []
|
|
for e in self.event_set.all():
|
|
if e.organisation and e.organisation not in o:
|
|
o.append(e.organisation)
|
|
return o
|
|
|
|
@property
|
|
def latest_events(self):
|
|
return self.event_set.order_by('-start_date')
|
|
|
|
class Meta:
|
|
permissions = (
|
|
('view_person', 'Can view Persons'),
|
|
)
|
|
|
|
|
|
@reversion.register
|
|
class Organisation(models.Model, RevisionMixin):
|
|
name = models.CharField(max_length=50)
|
|
phone = models.CharField(max_length=15, blank=True, null=True)
|
|
email = models.EmailField(blank=True, null=True)
|
|
|
|
address = models.TextField(blank=True, null=True)
|
|
|
|
notes = models.TextField(blank=True, null=True)
|
|
union_account = models.BooleanField(default=False)
|
|
|
|
def __str__(self):
|
|
string = self.name
|
|
if len(self.notes) > 0:
|
|
string += "*"
|
|
return string
|
|
|
|
@property
|
|
def persons(self):
|
|
p = []
|
|
for e in self.event_set.all():
|
|
if e.person and e.person not in p:
|
|
p.append(e.person)
|
|
return p
|
|
|
|
@property
|
|
def latest_events(self):
|
|
return self.event_set.order_by('-start_date')
|
|
|
|
class Meta:
|
|
permissions = (
|
|
('view_organisation', 'Can view Organisations'),
|
|
)
|
|
|
|
|
|
class VatManager(models.Manager):
|
|
def current_rate(self):
|
|
return self.find_rate(datetime.datetime.now())
|
|
|
|
def find_rate(self, date):
|
|
# return self.filter(startAt__lte=date).latest()
|
|
try:
|
|
return self.filter(start_at__lte=date).latest()
|
|
except VatRate.DoesNotExist:
|
|
r = VatRate
|
|
r.rate = 0
|
|
return r
|
|
|
|
|
|
@reversion.register
|
|
class VatRate(models.Model, RevisionMixin):
|
|
start_at = models.DateTimeField()
|
|
rate = models.DecimalField(max_digits=6, decimal_places=6)
|
|
comment = models.CharField(max_length=255)
|
|
|
|
objects = VatManager()
|
|
|
|
@property
|
|
def as_percent(self):
|
|
return self.rate * 100
|
|
|
|
class Meta:
|
|
ordering = ['-start_at']
|
|
get_latest_by = 'start_at'
|
|
|
|
def __str__(self):
|
|
return self.comment + " " + str(self.start_at) + " @ " + str(self.as_percent) + "%"
|
|
|
|
|
|
@reversion.register
|
|
class Venue(models.Model, RevisionMixin):
|
|
name = models.CharField(max_length=255)
|
|
phone = models.CharField(max_length=15, blank=True, null=True)
|
|
email = models.EmailField(blank=True, null=True)
|
|
three_phase_available = models.BooleanField(default=False)
|
|
notes = models.TextField(blank=True, null=True)
|
|
|
|
address = models.TextField(blank=True, null=True)
|
|
|
|
def __str__(self):
|
|
string = self.name
|
|
if self.notes and len(self.notes) > 0:
|
|
string += "*"
|
|
return string
|
|
|
|
@property
|
|
def latest_events(self):
|
|
return self.event_set.order_by('-start_date')
|
|
|
|
class Meta:
|
|
permissions = (
|
|
('view_venue', 'Can view Venues'),
|
|
)
|
|
|
|
|
|
class EventManager(models.Manager):
|
|
def current_events(self):
|
|
# startAfter = self.filter(startDate__gte=datetime.date.today(), endDate__isnull=True)
|
|
# endAfter = self.filter(endDate__gte=datetime.date.today())
|
|
# activeDryHire = filter(dryHire=True, checkedInBy__isnull=False, canceled=False)
|
|
# canceledDryHire = filter(dry_hire=True, canceled=True)
|
|
# events = chain(startAfter, endAfter, activeDryHire, canceledDryHire)
|
|
# return sorted(events, key=operator.attrgetter('start_date'))
|
|
events = self.filter(
|
|
models.Q(start_date__gte=datetime.date.today(), end_date__isnull=True) | # Starts after with no end
|
|
models.Q(end_date__gte=datetime.date.today()) | # Ends after
|
|
models.Q(dry_hire=True, checked_in_by__isnull=False, status__lt=Event.CANCELLED) | # Active dry hire LT
|
|
models.Q(dry_hire=True, checked_in_by__isnull=False, status__gt=Event.CANCELLED) | # Active dry hire GT
|
|
models.Q(dry_hire=True, status=Event.CANCELLED, start_date__gte=datetime.date.today())
|
|
# Canceled but not started
|
|
).order_by('meet_at', 'start_date')
|
|
return events
|
|
|
|
def rig_count(self):
|
|
events = self.filter(
|
|
models.Q(start_date__gte=datetime.date.today(), end_date__isnull=True,
|
|
is_rig=True) | # Starts after with no end
|
|
models.Q(end_date__gte=datetime.date.today(), is_rig=True) | # Ends after
|
|
models.Q(dry_hire=True, checked_in_by__isnull=False, status__lt=Event.CANCELLED,
|
|
is_rig=True) | # Active dry hire LT
|
|
models.Q(dry_hire=True, checked_in_by__isnull=False, status__gt=Event.CANCELLED, is_rig=True)
|
|
# Active dry hire GT
|
|
).order_by('meet_at', 'start_date')
|
|
return len(events)
|
|
|
|
|
|
@reversion.register(follow=['items'])
|
|
class Event(models.Model, RevisionMixin):
|
|
# Done to make it much nicer on the database
|
|
PROVISIONAL = 0
|
|
CONFIRMED = 1
|
|
BOOKED = 2
|
|
CANCELLED = 3
|
|
EVENT_STATUS_CHOICES = (
|
|
(PROVISIONAL, 'Provisional'),
|
|
(CONFIRMED, 'Confirmed'),
|
|
(BOOKED, 'Booked'),
|
|
(CANCELLED, 'Cancelled'),
|
|
)
|
|
|
|
name = models.CharField(max_length=255)
|
|
person = models.ForeignKey('Person', null=True, blank=True)
|
|
organisation = models.ForeignKey('Organisation', blank=True, null=True)
|
|
venue = models.ForeignKey('Venue', blank=True, null=True)
|
|
description = models.TextField(blank=True, null=True)
|
|
notes = models.TextField(blank=True, null=True)
|
|
status = models.IntegerField(choices=EVENT_STATUS_CHOICES, default=PROVISIONAL)
|
|
dry_hire = models.BooleanField(default=False)
|
|
is_rig = models.BooleanField(default=True)
|
|
based_on = models.ForeignKey('Event', related_name='future_events', blank=True, null=True)
|
|
|
|
# Timing
|
|
start_date = models.DateField()
|
|
start_time = models.TimeField(blank=True, null=True)
|
|
end_date = models.DateField(blank=True, null=True)
|
|
end_time = models.TimeField(blank=True, null=True)
|
|
access_at = models.DateTimeField(blank=True, null=True)
|
|
meet_at = models.DateTimeField(blank=True, null=True)
|
|
meet_info = models.CharField(max_length=255, blank=True, null=True)
|
|
|
|
# Crew management
|
|
checked_in_by = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='event_checked_in', blank=True, null=True)
|
|
mic = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='event_mic', blank=True, null=True, verbose_name="MIC")
|
|
|
|
# Monies
|
|
payment_method = models.CharField(max_length=255, blank=True, null=True)
|
|
payment_received = models.CharField(max_length=255, blank=True, null=True)
|
|
purchase_order = models.CharField(max_length=255, blank=True, null=True)
|
|
collector = models.CharField(max_length=255, blank=True, null=True)
|
|
|
|
# Calculated values
|
|
@property
|
|
def sum_total(self):
|
|
total = 0
|
|
for item in self.items.all():
|
|
total += item.total_cost
|
|
return total
|
|
|
|
@property
|
|
def vat_rate(self):
|
|
return VatRate.objects.find_rate(self.start_date)
|
|
|
|
@property
|
|
def vat(self):
|
|
return self.sum_total * self.vat_rate.rate
|
|
|
|
@property
|
|
def total(self):
|
|
return self.sum_total + self.vat
|
|
|
|
@property
|
|
def cancelled(self):
|
|
return (self.status == self.CANCELLED)
|
|
|
|
@property
|
|
def confirmed(self):
|
|
return (self.status == self.BOOKED or self.status == self.CONFIRMED)
|
|
|
|
objects = EventManager()
|
|
|
|
def __str__(self):
|
|
return str(self.pk) + ": " + self.name
|
|
|
|
class Meta:
|
|
permissions = (
|
|
('view_event', 'Can view Events'),
|
|
)
|
|
|
|
|
|
class EventItem(models.Model):
|
|
event = models.ForeignKey('Event', related_name='items', blank=True)
|
|
name = models.CharField(max_length=255)
|
|
description = models.TextField(blank=True, null=True)
|
|
quantity = models.IntegerField()
|
|
cost = models.DecimalField(max_digits=10, decimal_places=2)
|
|
order = models.IntegerField()
|
|
|
|
@property
|
|
def total_cost(self):
|
|
return self.cost * self.quantity
|
|
|
|
class Meta:
|
|
ordering = ['order']
|
|
|
|
def __str__(self):
|
|
return str(self.event.pk) + "." + str(self.order) + ": " + self.event.name + " | " + self.name
|
|
|
|
|
|
class EventCrew(models.Model):
|
|
event = models.ForeignKey('Event', related_name='crew')
|
|
user = models.ForeignKey(settings.AUTH_USER_MODEL)
|
|
rig = models.BooleanField(default=False)
|
|
run = models.BooleanField(default=False)
|
|
derig = models.BooleanField(default=False)
|
|
notes = models.TextField(blank=True, null=True)
|
|
|
|
|
|
class Invoice(models.Model):
|
|
event = models.OneToOneField('Event')
|
|
invoice_date = models.DateField(auto_now_add=True)
|
|
void = models.BooleanField()
|
|
|
|
|
|
class Payment(models.Model):
|
|
CASH = 'C'
|
|
INTERNAL = 'I'
|
|
EXTERNAL = 'E'
|
|
SUCORE = 'SU'
|
|
MEMBERS = 'M'
|
|
METHODS = (
|
|
(CASH, 'Cash'),
|
|
(INTERNAL, 'Internal'),
|
|
(EXTERNAL, 'External'),
|
|
(SUCORE, 'SU Core'),
|
|
(MEMBERS, 'Members'),
|
|
)
|
|
|
|
invoice = models.ForeignKey('Invoice')
|
|
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) |