Added locations app
Moved contacts to new model
This commit is contained in:
@@ -45,6 +45,7 @@ INSTALLED_APPS = [
|
|||||||
'import_export',
|
'import_export',
|
||||||
'rangefilter',
|
'rangefilter',
|
||||||
'common',
|
'common',
|
||||||
|
'locations',
|
||||||
'transport',
|
'transport',
|
||||||
'traveller',
|
'traveller',
|
||||||
'messaging'
|
'messaging'
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
from common.admin import MyImportExportModelAdmin
|
||||||
|
from locations.models import Suburb, Location
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Suburb)
|
||||||
|
class SuburbsAdmin(MyImportExportModelAdmin, admin.ModelAdmin):
|
||||||
|
list_filter = ["state"]
|
||||||
|
|
||||||
|
@admin.register(Location)
|
||||||
|
class LocationAdmin(admin.ModelAdmin):
|
||||||
|
search_fields = ["address", "suburb__name", "suburb__postcode"]
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class LocationsConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'locations'
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
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 Location(models.Model):
|
||||||
|
address = models.CharField(max_length=255, blank=True)
|
||||||
|
suburb = models.ForeignKey(Suburb, on_delete=models.PROTECT)
|
||||||
|
|
||||||
|
latitude = models.FloatField(null=True, blank=True)
|
||||||
|
longitude = models.FloatField(null=True, blank=True)
|
||||||
|
|
||||||
|
class Meta: unique_together = ("suburb", "address")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.address}, {self.suburb}"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
import requests
|
import requests
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.db.models import Prefetch
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
from traveller.models import Family
|
||||||
|
|
||||||
|
|
||||||
def _get_token():
|
def _get_token():
|
||||||
url = 'https://products.api.telstra.com/v2/oauth/token'
|
url = 'https://products.api.telstra.com/v2/oauth/token'
|
||||||
@@ -81,45 +84,120 @@ class SMSForm(forms.Form):
|
|||||||
|
|
||||||
|
|
||||||
def _get_numbers(request, queryset):
|
def _get_numbers(request, queryset):
|
||||||
|
|
||||||
send_to_parents = bool(request.POST.get("send_to_parents"))
|
send_to_parents = bool(request.POST.get("send_to_parents"))
|
||||||
send_to_emergency_contacts = bool(request.POST.get("send_to_emergency_contacts"))
|
send_to_emergency_contacts = bool(request.POST.get("send_to_emergency_contacts"))
|
||||||
only_include_active_travellers = bool(request.POST.get("only_include_active_travellers"))
|
only_include_active_travellers = bool(request.POST.get("only_include_active_travellers"))
|
||||||
|
|
||||||
numbers = []
|
numbers = set()
|
||||||
for traveller in queryset:
|
|
||||||
if only_include_active_travellers and not traveller._is_active():
|
families_prefetch = Prefetch(
|
||||||
|
"family_set",
|
||||||
|
queryset=Family.objects.select_related(
|
||||||
|
"contact_A",
|
||||||
|
"contact_B",
|
||||||
|
"emergency_contact_A",
|
||||||
|
"emergency_contact_B",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
travellers = queryset.prefetch_related(families_prefetch)
|
||||||
|
|
||||||
|
for traveller in travellers:
|
||||||
|
|
||||||
|
if only_include_active_travellers and not traveller.is_active:
|
||||||
continue
|
continue
|
||||||
for family in traveller.get_families():
|
|
||||||
family_numbers, _ = family.get_parsed_numbers(parents=send_to_parents, emergency=send_to_emergency_contacts)
|
for family in traveller.family_set.all():
|
||||||
if family_numbers:
|
|
||||||
numbers = numbers + family_numbers
|
family_numbers, _ = family.get_parsed_numbers(
|
||||||
return list(set(numbers)) # Remove duplicates
|
parents=send_to_parents,
|
||||||
|
emergency=send_to_emergency_contacts
|
||||||
|
)
|
||||||
|
|
||||||
|
numbers.update(family_numbers)
|
||||||
|
|
||||||
|
return list(numbers)
|
||||||
|
|
||||||
|
|
||||||
def _family_context(queryset):
|
def _family_context(queryset):
|
||||||
|
|
||||||
|
families_prefetch = Prefetch(
|
||||||
|
"family_set",
|
||||||
|
queryset=Family.objects.select_related(
|
||||||
|
"contact_A",
|
||||||
|
"contact_B",
|
||||||
|
"emergency_contact_A",
|
||||||
|
"emergency_contact_B",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
travellers = queryset.prefetch_related(families_prefetch)
|
||||||
|
|
||||||
family_set = []
|
family_set = []
|
||||||
for traveller in queryset:
|
|
||||||
families = traveller.get_families()
|
for traveller in travellers:
|
||||||
if len(families) == 0:
|
|
||||||
|
families = traveller.family_set.all()
|
||||||
|
|
||||||
|
if not families:
|
||||||
family_set.append({
|
family_set.append({
|
||||||
'traveller': traveller.__str__(),
|
"traveller": str(traveller),
|
||||||
'has_failed_number': True
|
"has_failed_number": True
|
||||||
})
|
})
|
||||||
|
continue
|
||||||
|
|
||||||
for family in families:
|
for family in families:
|
||||||
|
|
||||||
_, failed_numbers = family.get_parsed_numbers(True, True)
|
_, failed_numbers = family.get_parsed_numbers(True, True)
|
||||||
|
|
||||||
family_context = {
|
family_context = {
|
||||||
'traveller': traveller.__str__(),
|
"traveller": str(traveller),
|
||||||
'has_failed_number': len(failed_numbers) > 0
|
"has_failed_number": len(failed_numbers) > 0,
|
||||||
}
|
}
|
||||||
if family.parent_A_phone:
|
|
||||||
family_context['parent_A'] = f"{family.parent_A_firstname} {family.parent_A_lastname} ({family.parent_A_phone})"
|
# -----------------------
|
||||||
if family.parent_B_phone:
|
# Parent A
|
||||||
family_context['parent_B'] = f"{family.parent_B_firstname} {family.parent_B_lastname} ({family.parent_B_phone})"
|
# -----------------------
|
||||||
if family.emergency_contact_A_phone:
|
if family.contact_A:
|
||||||
family_context['contact_A'] = f"{family.emergency_contact_A_firstname} {family.emergency_contact_A_lastname} ({family.emergency_contact_A_phone})"
|
family_context["parent_A"] = (
|
||||||
if family.emergency_contact_B_phone:
|
f"{family.contact_A.first_name} "
|
||||||
family_context['contact_B'] = f"{family.emergency_contact_B_firstname} {family.emergency_contact_B_lastname} ({family.emergency_contact_B_phone})"
|
f"{family.contact_A.last_name} "
|
||||||
|
f"({family.contact_A.phone})"
|
||||||
|
)
|
||||||
|
|
||||||
|
# -----------------------
|
||||||
|
# Parent B
|
||||||
|
# -----------------------
|
||||||
|
if family.contact_B:
|
||||||
|
family_context["parent_B"] = (
|
||||||
|
f"{family.contact_B.first_name} "
|
||||||
|
f"{family.contact_B.last_name} "
|
||||||
|
f"({family.contact_B.phone})"
|
||||||
|
)
|
||||||
|
|
||||||
|
# -----------------------
|
||||||
|
# Emergency A
|
||||||
|
# -----------------------
|
||||||
|
if family.emergency_contact_A:
|
||||||
|
family_context["contact_A"] = (
|
||||||
|
f"{family.emergency_contact_A.first_name} "
|
||||||
|
f"{family.emergency_contact_A.last_name} "
|
||||||
|
f"({family.emergency_contact_A.phone})"
|
||||||
|
)
|
||||||
|
|
||||||
|
# -----------------------
|
||||||
|
# Emergency B
|
||||||
|
# -----------------------
|
||||||
|
if family.emergency_contact_B:
|
||||||
|
family_context["contact_B"] = (
|
||||||
|
f"{family.emergency_contact_B.first_name} "
|
||||||
|
f"{family.emergency_contact_B.last_name} "
|
||||||
|
f"({family.emergency_contact_B.phone})"
|
||||||
|
)
|
||||||
|
|
||||||
family_set.append(family_context)
|
family_set.append(family_context)
|
||||||
|
|
||||||
return family_set
|
return family_set
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
from setup_django import *
|
||||||
|
|
||||||
|
from coord.models import Suburb as OldSuburb
|
||||||
|
from common.models import Suburb as NewSuburb
|
||||||
|
|
||||||
|
created = 0
|
||||||
|
skipped = 0
|
||||||
|
|
||||||
|
for old in OldSuburb.objects.all():
|
||||||
|
|
||||||
|
obj, was_created = NewSuburb.objects.get_or_create(
|
||||||
|
id=old.id,
|
||||||
|
defaults={
|
||||||
|
"name": old.name,
|
||||||
|
"state": old.state,
|
||||||
|
"postcode": old.postcode,
|
||||||
|
"distance": old.distance,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if was_created:
|
||||||
|
created += 1
|
||||||
|
else:
|
||||||
|
skipped += 1
|
||||||
|
|
||||||
|
print(f"Created: {created}, Skipped: {skipped}")
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
from setup_django import *
|
from setup_django import *
|
||||||
|
|
||||||
from coord.models import Suburb as OldSuburb
|
from common.models import Suburb as OldSuburb
|
||||||
from common.models import Suburb as NewSuburb
|
from locations.models import Suburb as NewSuburb
|
||||||
|
|
||||||
created = 0
|
created = 0
|
||||||
skipped = 0
|
skipped = 0
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
from setup_django import *
|
||||||
|
|
||||||
|
from traveller.models import Family, ContactPerson
|
||||||
|
|
||||||
|
created_contacts = 0
|
||||||
|
updated_families = 0
|
||||||
|
|
||||||
|
for family in Family.objects.all():
|
||||||
|
if family.parent_A_firstname or family.parent_A_lastname:
|
||||||
|
|
||||||
|
contact_A, created = ContactPerson.objects.get_or_create(
|
||||||
|
first_name=family.parent_A_firstname.strip() if family.parent_A_firstname else "",
|
||||||
|
last_name=family.parent_A_lastname.strip() if family.parent_A_lastname else "",
|
||||||
|
phone=family.parent_A_phone.strip() if family.parent_A_phone else "",
|
||||||
|
email=family.parent_A_email.strip() if family.parent_A_email else "",
|
||||||
|
)
|
||||||
|
|
||||||
|
family.contact_A = contact_A
|
||||||
|
|
||||||
|
if created:
|
||||||
|
created_contacts += 1
|
||||||
|
|
||||||
|
if family.parent_B_firstname or family.parent_B_lastname:
|
||||||
|
|
||||||
|
contact_B, created = ContactPerson.objects.get_or_create(
|
||||||
|
first_name=family.parent_B_firstname.strip() if family.parent_B_firstname else "",
|
||||||
|
last_name=family.parent_B_lastname.strip() if family.parent_B_lastname else "",
|
||||||
|
phone=family.parent_B_phone.strip() if family.parent_B_phone else "",
|
||||||
|
email=family.parent_B_email.strip() if family.parent_B_email else "",
|
||||||
|
)
|
||||||
|
|
||||||
|
family.contact_B = contact_B
|
||||||
|
|
||||||
|
if created:
|
||||||
|
created_contacts += 1
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# Emergency A
|
||||||
|
# -------------------------
|
||||||
|
if family.emergency_contact_A_firstname or family.emergency_contact_A_lastname:
|
||||||
|
|
||||||
|
contact_EA, created = ContactPerson.objects.get_or_create(
|
||||||
|
first_name=family.emergency_contact_A_firstname.strip() if family.emergency_contact_A_firstname else "",
|
||||||
|
last_name=family.emergency_contact_A_lastname.strip() if family.emergency_contact_A_lastname else "",
|
||||||
|
phone=family.emergency_contact_A_phone.strip() if family.emergency_contact_A_phone else "",
|
||||||
|
)
|
||||||
|
|
||||||
|
family.emergency_contact_A = contact_EA
|
||||||
|
|
||||||
|
if created:
|
||||||
|
created_contacts += 1
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# Emergency B
|
||||||
|
# -------------------------
|
||||||
|
if family.emergency_contact_B_firstname or family.emergency_contact_B_lastname:
|
||||||
|
|
||||||
|
contact_EB, created = ContactPerson.objects.get_or_create(
|
||||||
|
first_name=family.emergency_contact_B_firstname.strip() if family.emergency_contact_B_firstname else "",
|
||||||
|
last_name=family.emergency_contact_B_lastname.strip() if family.emergency_contact_B_lastname else "",
|
||||||
|
phone=family.emergency_contact_B_phone.strip() if family.emergency_contact_B_phone else "",
|
||||||
|
)
|
||||||
|
|
||||||
|
family.emergency_contact_B = contact_EB
|
||||||
|
|
||||||
|
if created:
|
||||||
|
created_contacts += 1
|
||||||
|
|
||||||
|
family.save()
|
||||||
|
updated_families += 1
|
||||||
|
|
||||||
|
print(f"Families updated: {updated_families}")
|
||||||
|
print(f"Contacts created: {created_contacts}")
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
from setup_django import *
|
||||||
|
|
||||||
|
from traveller.models import Family
|
||||||
|
from locations.models import Suburb, Location
|
||||||
|
|
||||||
|
for family in Family.objects.all():
|
||||||
|
residential_address = family.residential_address
|
||||||
|
residential_suburb = family.residential_suburb
|
||||||
|
postal_address = family.postal_address
|
||||||
|
postal_suburb = family.postal_suburb
|
||||||
|
|
||||||
|
if residential_address and residential_suburb:
|
||||||
|
suburb = Suburb.objects.get(pk=residential_suburb.id)
|
||||||
|
location, created = Location.objects.get_or_create(
|
||||||
|
address=residential_address,
|
||||||
|
suburb=suburb,
|
||||||
|
)
|
||||||
|
family.location = location
|
||||||
|
|
||||||
|
if postal_address and postal_suburb:
|
||||||
|
suburb = Suburb.objects.get(pk=postal_suburb.id)
|
||||||
|
location, created = Location.objects.get_or_create(
|
||||||
|
address=postal_address,
|
||||||
|
suburb=suburb,
|
||||||
|
)
|
||||||
|
family.postal_location = location
|
||||||
|
|
||||||
|
family.save()
|
||||||
|
|
||||||
|
residential_count = Family.objects.filter(
|
||||||
|
location__isnull=False
|
||||||
|
).count()
|
||||||
|
postal_count = Family.objects.filter(
|
||||||
|
postal_location__isnull=False
|
||||||
|
).count()
|
||||||
|
|
||||||
|
print(f"Residential count: {residential_count}")
|
||||||
|
print(f"Postal count: {postal_count}")
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
|
from django.db.models import Prefetch
|
||||||
|
|
||||||
from transport.models import Bus, Driver, BusStop, Shuttle
|
from transport.models import Bus, Driver, BusStop, Shuttle
|
||||||
from traveller.models import TravellerRoute, Traveller
|
from traveller.models import TravellerRoute, Traveller, Family
|
||||||
|
|
||||||
|
|
||||||
def bus_summary_context():
|
def bus_summary_context():
|
||||||
@@ -52,37 +54,83 @@ def emergency_contacts_context(queryset=None):
|
|||||||
else:
|
else:
|
||||||
buses = queryset
|
buses = queryset
|
||||||
|
|
||||||
bus_routes = []
|
buses = buses.prefetch_related(
|
||||||
for bus in buses:
|
Prefetch(
|
||||||
drivers = []
|
"driver_set",
|
||||||
for driver in Driver.objects.filter(bus=bus):
|
queryset=Driver.objects.all()
|
||||||
drivers.append(driver)
|
),
|
||||||
traveller_list = []
|
Prefetch(
|
||||||
for travellerRoute in TravellerRoute.objects.filter(busStop__bus=bus):
|
"busstop_set__traverseroute_set",
|
||||||
traveller = travellerRoute.traveller
|
queryset=TravellerRoute.objects.select_related(
|
||||||
if not traveller._is_active():
|
"traveller",
|
||||||
continue
|
"busStop"
|
||||||
for family in traveller.get_families():
|
).prefetch_related(
|
||||||
parent_a = ""
|
Prefetch(
|
||||||
if family.parent_A_firstname:
|
"traveller__family_set",
|
||||||
parent_a = f"{family.parent_A_firstname} {family.parent_A_lastname} ({family.parent_A_phone})"
|
queryset=Family.objects.select_related(
|
||||||
parent_b = ""
|
"contact_A",
|
||||||
if family.parent_B_firstname:
|
"contact_B",
|
||||||
parent_b = f"{family.parent_B_firstname} {family.parent_B_lastname} ({family.parent_B_phone})"
|
"emergency_contact_A",
|
||||||
contact_a = ""
|
"emergency_contact_B",
|
||||||
if family.emergency_contact_A_firstname:
|
)
|
||||||
contact_a = f"{family.emergency_contact_A_firstname} {family.emergency_contact_A_lastname} ({family.emergency_contact_A_phone})"
|
)
|
||||||
contact_b = ""
|
)
|
||||||
if family.emergency_contact_B_firstname:
|
)
|
||||||
contact_b = f"{family.emergency_contact_B_firstname} {family.emergency_contact_B_lastname} ({family.emergency_contact_B_phone})"
|
)
|
||||||
traveller_list.append({
|
|
||||||
'traveller': traveller,
|
|
||||||
'parent_a': parent_a,
|
|
||||||
'parent_b': parent_b,
|
|
||||||
'contact_a': contact_a,
|
|
||||||
'contact_b': contact_b,
|
|
||||||
'note': travellerRoute.notes
|
|
||||||
})
|
|
||||||
bus_routes.append({'bus': bus, 'drivers': drivers, 'travellers': traveller_list})
|
|
||||||
|
|
||||||
return {'routes': bus_routes}
|
bus_routes = []
|
||||||
|
|
||||||
|
for bus in buses:
|
||||||
|
|
||||||
|
drivers = list(bus.driver_set.all())
|
||||||
|
|
||||||
|
traveller_list = []
|
||||||
|
|
||||||
|
traveller_routes = TravellerRoute.objects.filter(
|
||||||
|
busStop__bus=bus
|
||||||
|
).select_related(
|
||||||
|
"traveller"
|
||||||
|
)
|
||||||
|
|
||||||
|
for travellerRoute in traveller_routes:
|
||||||
|
|
||||||
|
traveller = travellerRoute.traveller
|
||||||
|
|
||||||
|
if not traveller.is_active:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for family in traveller.family_set.all():
|
||||||
|
|
||||||
|
parent_a = ""
|
||||||
|
parent_b = ""
|
||||||
|
contact_a = ""
|
||||||
|
contact_b = ""
|
||||||
|
|
||||||
|
if family.contact_A:
|
||||||
|
parent_a = f"{family.contact_A.first_name} {family.contact_A.last_name} ({family.contact_A.phone})"
|
||||||
|
|
||||||
|
if family.contact_B:
|
||||||
|
parent_b = f"{family.contact_B.first_name} {family.contact_B.last_name} ({family.contact_B.phone})"
|
||||||
|
|
||||||
|
if family.emergency_contact_A:
|
||||||
|
contact_a = f"{family.emergency_contact_A.first_name} {family.emergency_contact_A.last_name} ({family.emergency_contact_A.phone})"
|
||||||
|
|
||||||
|
if family.emergency_contact_B:
|
||||||
|
contact_b = f"{family.emergency_contact_B.first_name} {family.emergency_contact_B.last_name} ({family.emergency_contact_B.phone})"
|
||||||
|
|
||||||
|
traveller_list.append({
|
||||||
|
"traveller": traveller,
|
||||||
|
"parent_a": parent_a,
|
||||||
|
"parent_b": parent_b,
|
||||||
|
"contact_a": contact_a,
|
||||||
|
"contact_b": contact_b,
|
||||||
|
"note": travellerRoute.notes
|
||||||
|
})
|
||||||
|
|
||||||
|
bus_routes.append({
|
||||||
|
"bus": bus,
|
||||||
|
"drivers": drivers,
|
||||||
|
"travellers": traveller_list
|
||||||
|
})
|
||||||
|
|
||||||
|
return {"routes": bus_routes}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
from django.db import models
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
from rangefilter.filters import DateRangeFilterBuilder
|
from rangefilter.filters import DateRangeFilterBuilder
|
||||||
|
|
||||||
from common.admin import MyImportExportModelAdmin
|
from common.admin import MyImportExportModelAdmin
|
||||||
from traveller.adminClone import CloneModelAdmin
|
from traveller.adminClone import CloneModelAdmin
|
||||||
from traveller.admin_mixins import SchoolRollMixin, TravellerRollMixin
|
from traveller.admin_mixins import SchoolRollMixin, TravellerRollMixin
|
||||||
from traveller.models import Family, TravellerRoute, Traveller, School
|
from traveller.models import Family, TravellerRoute, Traveller, School, ContactPerson
|
||||||
|
|
||||||
|
|
||||||
class FamilyInline(admin.StackedInline):
|
class FamilyInline(admin.StackedInline):
|
||||||
@@ -13,6 +15,70 @@ class FamilyInline(admin.StackedInline):
|
|||||||
classes = ['collapse']
|
classes = ['collapse']
|
||||||
extra = 0
|
extra = 0
|
||||||
clone_parent = "traveller"
|
clone_parent = "traveller"
|
||||||
|
autocomplete_fields = [
|
||||||
|
"location",
|
||||||
|
"postal_location",
|
||||||
|
"contact_A",
|
||||||
|
"contact_B",
|
||||||
|
"emergency_contact_A",
|
||||||
|
"emergency_contact_B",
|
||||||
|
]
|
||||||
|
|
||||||
|
readonly_fields = [
|
||||||
|
"contact_A_phone_display",
|
||||||
|
"contact_B_phone_display",
|
||||||
|
"emergency_contact_A_phone_display",
|
||||||
|
"emergency_contact_B_phone_display",
|
||||||
|
]
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
("Residential Address", {
|
||||||
|
"fields": ("location",)
|
||||||
|
}),
|
||||||
|
|
||||||
|
("Postal Address", {
|
||||||
|
"fields": ("postal_location",)
|
||||||
|
}),
|
||||||
|
|
||||||
|
("Parents / Guardians", {
|
||||||
|
"fields": (
|
||||||
|
"contact_A_relation",
|
||||||
|
"contact_A",
|
||||||
|
"contact_A_phone_display",
|
||||||
|
"contact_B_relation",
|
||||||
|
"contact_B",
|
||||||
|
"contact_B_phone_display",
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
|
||||||
|
("Emergency Contacts", {
|
||||||
|
"fields": (
|
||||||
|
"emergency_contact_A_relation",
|
||||||
|
"emergency_contact_A",
|
||||||
|
"emergency_contact_A_phone_display",
|
||||||
|
"emergency_contact_B_relation",
|
||||||
|
"emergency_contact_B",
|
||||||
|
"emergency_contact_B_phone_display",
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
def contact_A_phone_display(self, obj):
|
||||||
|
return obj.contact_A.phone if obj.contact_A else "-"
|
||||||
|
|
||||||
|
def contact_B_phone_display(self, obj):
|
||||||
|
return obj.contact_B.phone if obj.contact_B else "-"
|
||||||
|
|
||||||
|
def emergency_contact_A_phone_display(self, obj):
|
||||||
|
return obj.emergency_contact_A.phone if obj.emergency_contact_A else "-"
|
||||||
|
|
||||||
|
def emergency_contact_B_phone_display(self, obj):
|
||||||
|
return obj.emergency_contact_B.phone if obj.emergency_contact_B else "-"
|
||||||
|
|
||||||
|
contact_A_phone_display.short_description = "Phone"
|
||||||
|
contact_B_phone_display.short_description = "Phone"
|
||||||
|
emergency_contact_A_phone_display.short_description = "Phone"
|
||||||
|
emergency_contact_B_phone_display.short_description = "Phone"
|
||||||
|
|
||||||
|
|
||||||
class TravellerRouteInline(admin.TabularInline):
|
class TravellerRouteInline(admin.TabularInline):
|
||||||
@@ -87,6 +153,85 @@ class TravellerAdmin(MyImportExportModelAdmin, CloneModelAdmin, TravellerRollMix
|
|||||||
# obj.is_archived = False
|
# obj.is_archived = False
|
||||||
# super().save_model(request, obj, form, change)
|
# super().save_model(request, obj, form, change)
|
||||||
|
|
||||||
|
@admin.register(ContactPerson)
|
||||||
|
class ContactPersonAdmin(MyImportExportModelAdmin):
|
||||||
|
list_display = [
|
||||||
|
"first_name",
|
||||||
|
"last_name",
|
||||||
|
"phone",
|
||||||
|
"email"
|
||||||
|
]
|
||||||
|
|
||||||
|
search_fields = [
|
||||||
|
"first_name",
|
||||||
|
"last_name",
|
||||||
|
"phone",
|
||||||
|
"email",
|
||||||
|
]
|
||||||
|
|
||||||
|
readonly_fields = [
|
||||||
|
"traveller_relationship_summary"
|
||||||
|
]
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
(None, {
|
||||||
|
"fields": ("first_name", "last_name", "phone", "email")
|
||||||
|
}),
|
||||||
|
|
||||||
|
("Relationships", {
|
||||||
|
"fields": ("traveller_relationship_summary",)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
def traveller_relationship_summary(self, obj):
|
||||||
|
from django.utils.html import format_html
|
||||||
|
|
||||||
|
families = Family.objects.filter(
|
||||||
|
models.Q(contact_A=obj) |
|
||||||
|
models.Q(contact_B=obj) |
|
||||||
|
models.Q(emergency_contact_A=obj) |
|
||||||
|
models.Q(emergency_contact_B=obj)
|
||||||
|
).select_related("traveller", "location")
|
||||||
|
|
||||||
|
if not families.exists():
|
||||||
|
return "No traveller relationships"
|
||||||
|
|
||||||
|
output = []
|
||||||
|
|
||||||
|
for family in families:
|
||||||
|
traveller = family.traveller
|
||||||
|
|
||||||
|
relation = ""
|
||||||
|
if family.contact_A == obj:
|
||||||
|
relation = family.contact_A_relation
|
||||||
|
elif family.contact_B == obj:
|
||||||
|
relation = family.contact_B_relation
|
||||||
|
elif family.emergency_contact_A == obj:
|
||||||
|
relation = family.emergency_contact_A_relation
|
||||||
|
elif family.emergency_contact_B == obj:
|
||||||
|
relation = family.emergency_contact_B_relation
|
||||||
|
|
||||||
|
address = family.location if family.location else "No address"
|
||||||
|
|
||||||
|
url = reverse(
|
||||||
|
"admin:traveller_traveller_change",
|
||||||
|
args=[traveller.id]
|
||||||
|
)
|
||||||
|
|
||||||
|
output.append(
|
||||||
|
format_html(
|
||||||
|
'<a href="{}">{}</a> ({})<br>'
|
||||||
|
'<small style="color:#888">{}</small>',
|
||||||
|
url,
|
||||||
|
f"{traveller.first_name} {traveller.last_name}",
|
||||||
|
relation,
|
||||||
|
address
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return format_html("".join(output))
|
||||||
|
|
||||||
|
traveller_relationship_summary.short_description = "Traveller Relationships"
|
||||||
|
|
||||||
# @admin.register(Family)
|
# @admin.register(Family)
|
||||||
class FamilyAdmin(MyImportExportModelAdmin, admin.ModelAdmin):
|
class FamilyAdmin(MyImportExportModelAdmin, admin.ModelAdmin):
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import phonenumbers
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from common.models import Suburb
|
from common.models import Suburb
|
||||||
|
from locations.models import Location
|
||||||
|
|
||||||
|
|
||||||
class School(models.Model):
|
class School(models.Model):
|
||||||
@@ -152,6 +152,20 @@ class Traveller(models.Model):
|
|||||||
def get_families(self):
|
def get_families(self):
|
||||||
return Family.objects.filter(traveller__id__exact=self.id)
|
return Family.objects.filter(traveller__id__exact=self.id)
|
||||||
|
|
||||||
|
class ContactPerson(models.Model):
|
||||||
|
first_name = models.CharField(max_length=100, blank=True)
|
||||||
|
last_name = models.CharField(max_length=100, blank=True)
|
||||||
|
phone = models.CharField(max_length=15, blank=True)
|
||||||
|
email = models.EmailField(blank=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["phone"]),
|
||||||
|
models.Index(fields=["last_name"]),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.first_name} {self.last_name}"
|
||||||
|
|
||||||
class Family(models.Model):
|
class Family(models.Model):
|
||||||
RELATIONS = [
|
RELATIONS = [
|
||||||
@@ -169,6 +183,9 @@ class Family(models.Model):
|
|||||||
]
|
]
|
||||||
|
|
||||||
traveller = models.ForeignKey(Traveller, on_delete=models.CASCADE)
|
traveller = models.ForeignKey(Traveller, on_delete=models.CASCADE)
|
||||||
|
location = models.ForeignKey(Location, on_delete=models.PROTECT, blank=True, null=True)
|
||||||
|
postal_location = models.ForeignKey(Location, on_delete=models.PROTECT, null=True, blank=True,
|
||||||
|
related_name="family_postal_locations")
|
||||||
residential_address = models.CharField(max_length=50, blank=True)
|
residential_address = models.CharField(max_length=50, blank=True)
|
||||||
residential_suburb = models.ForeignKey(Suburb, on_delete=models.PROTECT, blank=True, null=True,
|
residential_suburb = models.ForeignKey(Suburb, on_delete=models.PROTECT, blank=True, null=True,
|
||||||
related_name='family_residential_suburb')
|
related_name='family_residential_suburb')
|
||||||
@@ -191,14 +208,29 @@ class Family(models.Model):
|
|||||||
emergency_contact_B_lastname = 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_phone = models.CharField(max_length=15, blank=True)
|
||||||
emergency_contact_B_relation = models.CharField(max_length=50, choices=RELATIONS, blank=True)
|
emergency_contact_B_relation = models.CharField(max_length=50, choices=RELATIONS, blank=True)
|
||||||
|
contact_A_relation = models.CharField(max_length=50, choices=RELATIONS, blank=True)
|
||||||
|
contact_A = models.ForeignKey(ContactPerson, on_delete=models.SET_NULL, blank=True, null=True, related_name='family_contact_A')
|
||||||
|
contact_B_relation = models.CharField(max_length=50, choices=RELATIONS, blank=True)
|
||||||
|
contact_B = models.ForeignKey(ContactPerson, on_delete=models.SET_NULL, blank=True, null=True, related_name='family_contact_B')
|
||||||
|
emergency_contact_A = models.ForeignKey(ContactPerson, on_delete=models.SET_NULL, blank=True, null=True, related_name='family_emergency_contact_A')
|
||||||
|
emergency_contact_B = models.ForeignKey(ContactPerson, on_delete=models.SET_NULL, blank=True, null=True, related_name='family_emergency_contact_B')
|
||||||
created_on = models.DateTimeField(auto_now_add=True, blank=True, null=True)
|
created_on = models.DateTimeField(auto_now_add=True, blank=True, null=True)
|
||||||
last_edit = models.DateTimeField(auto_now=True, blank=True, null=True)
|
last_edit = models.DateTimeField(auto_now=True, blank=True, null=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name_plural = "Families"
|
verbose_name_plural = "Families"
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["contact_A"]),
|
||||||
|
models.Index(fields=["contact_B"]),
|
||||||
|
models.Index(fields=["emergency_contact_A"]),
|
||||||
|
models.Index(fields=["emergency_contact_B"]),
|
||||||
|
]
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.parent_names()
|
name = self.parent_names()
|
||||||
|
if name:
|
||||||
|
return f"{self.traveller}: {name}"
|
||||||
|
return str(self.traveller)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
valid_numbers, failed_numbers = self.get_parsed_numbers(True, True)
|
valid_numbers, failed_numbers = self.get_parsed_numbers(True, True)
|
||||||
@@ -206,8 +238,8 @@ class Family(models.Model):
|
|||||||
raise ValidationError(f"Phone number {failed_numbers[0]} not valid")
|
raise ValidationError(f"Phone number {failed_numbers[0]} not valid")
|
||||||
|
|
||||||
def parent_names(self):
|
def parent_names(self):
|
||||||
a_name = self.parent_A_firstname
|
a_name = self.contact_A.first_name
|
||||||
b_name = self.parent_B_firstname
|
b_name = self.contact_B.first_name
|
||||||
if a_name:
|
if a_name:
|
||||||
if b_name:
|
if b_name:
|
||||||
return f"{a_name} and {b_name}"
|
return f"{a_name} and {b_name}"
|
||||||
@@ -217,24 +249,24 @@ class Family(models.Model):
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
def get_parsed_numbers(self, parents=False, emergency=False):
|
def get_parsed_numbers(self, parents=False, emergency=False):
|
||||||
|
import phonenumbers
|
||||||
numbers = []
|
numbers = []
|
||||||
if parents:
|
if parents:
|
||||||
if self.parent_A_phone:
|
for contact in [self.contact_A, self.contact_B]:
|
||||||
numbers.append(self.parent_A_phone)
|
if contact and contact.phone:
|
||||||
if self.parent_B_phone:
|
numbers.append(contact.phone)
|
||||||
numbers.append(self.parent_B_phone)
|
|
||||||
if emergency:
|
if emergency:
|
||||||
if self.emergency_contact_A_phone:
|
for contact in [self.emergency_contact_A, self.emergency_contact_B]:
|
||||||
numbers.append(self.emergency_contact_A_phone)
|
if contact and contact.phone:
|
||||||
if self.emergency_contact_B_phone:
|
numbers.append(contact.phone)
|
||||||
numbers.append(self.emergency_contact_B_phone)
|
|
||||||
valid_numbers = []
|
valid_numbers = []
|
||||||
failed_numbers = []
|
failed_numbers = []
|
||||||
for number in numbers:
|
for number in numbers:
|
||||||
try:
|
try:
|
||||||
num = phonenumbers.parse(number, "AU")
|
parsed = phonenumbers.parse(number, "AU")
|
||||||
if phonenumbers.is_valid_number(num):
|
if phonenumbers.is_valid_number(parsed):
|
||||||
valid_numbers.append(f"+{num.country_code}{num.national_number}")
|
valid_numbers.append(f"+{parsed.country_code}{parsed.national_number}")
|
||||||
else:
|
else:
|
||||||
failed_numbers.append(number)
|
failed_numbers.append(number)
|
||||||
except:
|
except:
|
||||||
|
|||||||
Reference in New Issue
Block a user