Files
PyRIGS/RIGS/models.py
Tom Price ff9bca1e61 Moved the table element from the main rigboard out to something reusuable.
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
2015-01-22 20:48:37 +00:00

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)