Files
bus-manager/busManager/coord/models.py
T
2023-09-08 16:17:13 +10:00

331 lines
12 KiB
Python

from datetime import datetime
import phonenumbers
from django.conf import settings
from django.db import models
from twilio.rest import Client
class Setting(models.Model):
name = models.CharField(max_length=20, unique=True)
value = models.CharField(max_length=20, blank=True)
def __str__(self):
return self.name
class Suburb(models.Model):
STATE = [
("VIC", "Victoria"),
("NSW", "New South Wales"),
("SA", "South Australia"),
("ACT", "Australia Capital Territory"),
("QLD", "Queensland"),
("NT", "Northern Territory"),
("WA", "Western Australia"),
("TAS", "Tasmania"),
]
name = models.CharField(max_length=30, unique=True)
state = models.CharField(max_length=3, choices=STATE)
postcode = models.PositiveSmallIntegerField()
distance = models.PositiveSmallIntegerField(blank=True, null=True)
class Meta:
ordering = ["name"]
def __str__(self):
return f"{self.name}, {self.state} {self.postcode}"
class School(models.Model):
name = models.CharField(max_length=30, unique=True)
shortName = models.CharField(max_length=10, unique=True)
address = models.CharField(max_length=50)
suburb = models.ForeignKey(Suburb, on_delete=models.CASCADE)
email = models.CharField(max_length=50, blank=True)
phone = models.CharField(max_length=15, blank=True)
principal_name = models.CharField(max_length=50, blank=True)
principal_phone = models.CharField(max_length=15, blank=True)
notes = models.TextField(blank=True)
def __str__(self):
return self.name
class Company(models.Model):
name = models.CharField(max_length=50, unique=True)
contact_name = models.CharField(max_length=50, blank=True)
contact_number = models.CharField(max_length=15, blank=True)
contact_mobile = models.CharField(max_length=15, blank=True)
contact_email = models.CharField(max_length=50, blank=True)
address = models.CharField(max_length=50, blank=True)
suburb = models.ForeignKey(Suburb, on_delete=models.CASCADE)
notes = models.TextField(blank=True)
class Meta:
verbose_name_plural = "Companies"
def __str__(self):
return f"{self.name}"
class Bus(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE)
route_name = models.CharField(max_length=50, unique=True)
contract_number = models.CharField(max_length=20, blank=True)
registration = models.CharField(max_length=10, blank=True)
seating_capacity = models.SmallIntegerField()
make = models.CharField(max_length=15, blank=True)
model = models.CharField(max_length=15, blank=True)
notes = models.TextField(blank=True)
class Meta:
verbose_name_plural = "Buses"
ordering = ["route_name"]
def __str__(self):
return f"{self.route_name}"
def traveller_count(self):
count = 0
for traveller in Traveller.objects.filter(bus_stops__bus=self):
if traveller.is_active():
count += 1
return count
class Shuttle(models.Model):
bus = models.ForeignKey(Bus, on_delete=models.CASCADE)
school = models.ForeignKey(School, on_delete=models.CASCADE)
class Meta:
ordering = ["school__name"]
def __str__(self):
return f"{self.school.shortName} <-> {self.bus.route_name}"
def traveller_count(self):
count = 0
for traveller in Traveller.objects.filter(shuttle=self):
if traveller.is_active():
count += 1
return count
class Driver(models.Model):
bus = models.ForeignKey(Bus, on_delete=models.CASCADE)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
phone_number = models.CharField(max_length=15, blank=True)
class Meta:
ordering = ["last_name"]
def __str__(self):
return f"{self.first_name} {self.last_name}"
class BusStop(models.Model):
bus = models.ForeignKey(Bus, on_delete=models.CASCADE)
am_time = models.TimeField()
pm_time = models.TimeField()
address = models.CharField(max_length=100)
notes = models.TextField(blank=True)
class Meta:
ordering = ["bus__route_name", "am_time"]
def get_stop_number(self):
return BusStop.objects.filter(bus=self.bus, am_time__lt=self.am_time).count() + 1
def __str__(self):
return f"{self.bus.route_name} #{self.get_stop_number()} - {self.address}"
class Traveller(models.Model):
YEAR = [
("PS", "PreSchool"),
("00", "Year 00"),
("01", "Year 01"),
("02", "Year 02"),
("03", "Year 03"),
("04", "Year 04"),
("05", "Year 05"),
("06", "Year 06"),
("07", "Year 07"),
("08", "Year 08"),
("09", "Year 09"),
("10", "Year 10"),
("11", "Year 11"),
("12", "Year 12"),
("AL", "Adult Learner"),
]
ELIGIBILITY_STATUS = [
("1", "Eligible"),
("2", "Fare Payer"),
("3", "<4.8 Exemption"),
("4", "Eligible waitlisted"),
("5", "Ineligible waitlisted"),
("6", "Kinder Exemption"),
("7", "Tafe/Post Secondary Exemption"),
("8", "Other Exemption"),
]
RELATIONS = [
("1", "Parent"),
("2", "Step-Parent"),
("3", "Foster Parent"),
("4", "Host Family"),
("5", "Sibling"),
("6", "Grandparent"),
("7", "Aunt/Uncle"),
("8", "Cousin"),
("9", "Carer"),
("10", "Case Worker"),
("11", "Friend/Other"),
]
school = models.ForeignKey(School, on_delete=models.PROTECT)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
dob = models.DateField(blank=True, null=True)
year_level = models.CharField(max_length=2, choices=YEAR)
bus_stops = models.ManyToManyField(BusStop, through='TravellerRoute', blank=True)
distance_to_school = models.PositiveSmallIntegerField(blank=True, null=True)
residential_address = models.CharField(max_length=50, blank=True)
residential_suburb = models.ForeignKey(Suburb, on_delete=models.PROTECT, blank=True, null=True, related_name='residential_suburb')
postal_address = models.CharField(max_length=50, blank=True)
postal_suburb = models.ForeignKey(Suburb, on_delete=models.PROTECT, blank=True, null=True, related_name='postal_suburb')
travel_start_date = models.DateField(blank=True, null=True)
travel_end_date = models.DateField(blank=True, null=True)
eligibility_status = models.CharField(max_length=1, choices=ELIGIBILITY_STATUS)
assessment_date = models.DateField(blank=True, null=True)
fee_per_term = models.DecimalField(decimal_places=2, max_digits=5, blank=True, null=True)
term_1_paid = models.BooleanField(default=False)
term_2_paid = models.BooleanField(default=False)
term_3_paid = models.BooleanField(default=False)
term_4_paid = models.BooleanField(default=False)
application_form_completed = models.BooleanField()
parent_notified = models.BooleanField()
seat_number = models.CharField(max_length=5, blank=True)
parent_A_firstname = models.CharField(max_length=50, blank=True)
parent_A_lastname = models.CharField(max_length=50, blank=True)
parent_A_phone = models.CharField(max_length=15, blank=True)
parent_A_email = models.CharField(max_length=50, blank=True)
parent_B_firstname = models.CharField(max_length=50, blank=True)
parent_B_lastname = models.CharField(max_length=50, blank=True)
parent_B_phone = models.CharField(max_length=15, blank=True)
parent_B_email = models.CharField(max_length=50, blank=True)
emergency_contact_A_firstname = models.CharField(max_length=50, blank=True)
emergency_contact_A_lastname = models.CharField(max_length=50, blank=True)
emergency_contact_A_phone = models.CharField(max_length=15, blank=True)
emergency_contact_A_relation = models.CharField(max_length=50, choices=RELATIONS, blank=True)
emergency_contact_B_firstname = models.CharField(max_length=50, blank=True)
emergency_contact_B_lastname = models.CharField(max_length=50, blank=True)
emergency_contact_B_phone = models.CharField(max_length=15, blank=True)
emergency_contact_B_relation = models.CharField(max_length=50, choices=RELATIONS, blank=True)
created_on = models.DateTimeField(auto_now_add=True, blank=True, null=True)
last_edit = models.DateTimeField(auto_now=True, blank=True, null=True)
is_archived = models.BooleanField(default=False, verbose_name="Archived")
notes = models.TextField(blank=True, verbose_name='Admin Notes')
shuttle = models.ForeignKey(Shuttle, on_delete=models.SET_NULL, blank=True, null=True)
class Meta:
ordering = ["last_name"]
def __str__(self):
return f"{self.first_name} {self.last_name}"
def is_active(self):
if self.is_archived:
return False
if not self.travel_end_date:
return True
return datetime(self.travel_end_date.year, self.travel_end_date.month,
self.travel_end_date.day) < datetime.today()
def fare_paying(self):
if self.eligibility_status != "2":
return
cost_setting = Setting.objects.filter(name="TERM_TRAVEL_COST")
if not cost_setting.exists():
return "TERM_TRAVEL_COST not configured"
cost = int(cost_setting.get().value)
stops = 0
for stop in TravellerRoute.objects.filter(traveller=self.id):
stops += stop.active_stops()
if stops > 1:
stops = 1
return f"${str(cost * stops)}"
def send_sms(self, message, parents=False, emergency=False):
numbers = []
if parents and self.parent_A_phone:
numbers.append(self.parent_A_phone)
if parents and self.parent_B_phone:
numbers.append(self.parent_B_phone)
if emergency and self.emergency_contact_A_phone:
numbers.append(self.emergency_contact_A_phone)
if emergency and self.emergency_contact_B_phone:
numbers.append(self.emergency_contact_B_phone)
count = 0
for number in numbers:
num = phonenumbers.parse(number, "AU")
if phonenumbers.is_valid_number(num):
count += 1
# num = f"+{num.country_code}{num.national_number}"
# client = Client(settings.TWILIO['ACCOUNT_SID'], settings.TWILIO['AUTH_TOKEN'])
# client.messages.create(num, from_=settings.TWILIO['SENDER'], body=message)
return count
class TravellerRoute(models.Model):
traveller = models.ForeignKey(Traveller, on_delete=models.CASCADE)
busStop = models.ForeignKey(BusStop, on_delete=models.CASCADE)
mon_am = models.BooleanField(default=True)
mon_pm = models.BooleanField(default=True)
tue_am = models.BooleanField(default=True)
tue_pm = models.BooleanField(default=True)
wen_am = models.BooleanField(default=True)
wen_pm = models.BooleanField(default=True)
thu_am = models.BooleanField(default=True)
thu_pm = models.BooleanField(default=True)
fri_am = models.BooleanField(default=True)
fri_pm = models.BooleanField(default=True)
notes = models.TextField(blank=True, verbose_name="Driver Notes")
def __str__(self):
return f"{self.busStop}"
def active_stops(self):
stops = 0
if self.mon_am:
stops += 1
if self.mon_pm:
stops += 1
if self.tue_am:
stops += 1
if self.tue_pm:
stops += 1
if self.wen_am:
stops += 1
if self.wen_pm:
stops += 1
if self.thu_am:
stops += 1
if self.thu_pm:
stops += 1
if self.fri_am:
stops += 1
if self.fri_pm:
stops += 1
return stops * 0.1