d74290036e
Cleaned up logout redirects Added suburbs admin page back. Wasn't able to create new suburbs Made active status check to any traveller save function
315 lines
11 KiB
Python
315 lines
11 KiB
Python
import csv
|
|
from datetime import date
|
|
|
|
from django.forms import widgets
|
|
from django.contrib import admin
|
|
from django.http import HttpResponse
|
|
from django.urls import reverse
|
|
from django.utils.html import format_html
|
|
from django.utils.http import urlencode
|
|
from import_export.admin import ImportExportModelAdmin
|
|
from rangefilter.filters import DateRangeFilterBuilder
|
|
|
|
from .adminClone import CloneModelAdmin
|
|
from .context_helpers import *
|
|
from .email_helpers import email_companies_bus_roll, render_to_pdf, email_school_roll
|
|
from .models import *
|
|
from .utils.send_sms import send_sms
|
|
|
|
|
|
class BusRollMixin:
|
|
|
|
def show_bus_roll(self, request, queryset):
|
|
return render_to_pdf('reports/bus_roll.html', bus_roll_context(queryset))
|
|
|
|
def show_emergency_contacts(self, request, queryset):
|
|
return render_to_pdf('reports/emergency_contacts.html', emergency_contacts_context(queryset))
|
|
|
|
def email_company(self, request, queryset):
|
|
return email_companies_bus_roll(request, queryset)
|
|
|
|
email_company.short_description = "Email Bus Roll to Company"
|
|
|
|
|
|
class ShuttleRollMixin:
|
|
|
|
def show_shuttle_roll(self, request, queryset):
|
|
if queryset is None:
|
|
buses = None
|
|
else:
|
|
buses = []
|
|
for shuttle in queryset:
|
|
if shuttle.bus not in buses:
|
|
buses.append(shuttle.bus)
|
|
return render_to_pdf('reports/bus_roll.html', bus_roll_context(buses, include_bus_stops=False))
|
|
|
|
|
|
class SchoolRollMixin:
|
|
|
|
def email_travellers_to_school(self, request, queryset):
|
|
return email_school_roll(request, queryset)
|
|
|
|
def show_school_travellers(self, request, queryset):
|
|
return render_to_pdf('reports/school_roll.html', school_roll_context(queryset))
|
|
|
|
def export_travellers_to_csv(self, request, queryset):
|
|
traveller_list = []
|
|
for school in queryset:
|
|
for travellerRoute in TravellerRoute.objects.filter(traveller__school=school):
|
|
if not travellerRoute.traveller._is_active():
|
|
continue
|
|
traveller_list.append(traveller_route_context(travellerRoute))
|
|
|
|
response = HttpResponse(content_type="text/csv")
|
|
response["Content-Disposition"] = f"attachment; filename=traveller_list_{date.today()}.csv"
|
|
|
|
writer = csv.DictWriter(response, fieldnames=traveller_list[0].keys())
|
|
writer.writeheader()
|
|
writer.writerows(traveller_list)
|
|
|
|
return response
|
|
|
|
|
|
class TravellerRollMixin:
|
|
|
|
def confirmation_letter(self, request, queryset):
|
|
return render_to_pdf('mail/confirmation_letter.html', confirmation_letter_context(queryset))
|
|
|
|
def send_sms(self, request, queryset):
|
|
return send_sms(self, request, queryset)
|
|
|
|
def export_to_csv(self, request, queryset):
|
|
traveller_list = traveller_roll_context(queryset)
|
|
response = HttpResponse(content_type="text/csv")
|
|
response["Content-Disposition"] = f"attachment; filename=traveller_list_{date.today()}.csv"
|
|
|
|
writer = csv.DictWriter(response, fieldnames=traveller_list[0].keys())
|
|
writer.writeheader()
|
|
writer.writerows(traveller_list)
|
|
|
|
return response
|
|
|
|
|
|
class HiddenNowTime(widgets.TimeInput):
|
|
pass
|
|
|
|
|
|
class MyImportExportModelAdmin(ImportExportModelAdmin):
|
|
def has_import_permission(self, request):
|
|
return request.user.is_superuser
|
|
|
|
|
|
@admin.register(Company)
|
|
class CompanyAdmin(MyImportExportModelAdmin, admin.ModelAdmin):
|
|
list_display = ["name", "contact_name", "email", "buses"]
|
|
|
|
def buses(self, obj):
|
|
count = obj.bus_set.count()
|
|
url = (
|
|
reverse("admin:coord_bus_changelist")
|
|
+ "?"
|
|
+ urlencode({"company__id__exact": f"{obj.id}"})
|
|
)
|
|
return format_html('<a href="{}">{} Buses</a>', url, count)
|
|
|
|
def email(self, obj):
|
|
return format_html('<a href="mailto:{}">{}</a>', obj.contact_email, obj.contact_email)
|
|
|
|
|
|
class DriverInline(admin.StackedInline):
|
|
model = Driver
|
|
extra = 0
|
|
|
|
|
|
class BusStopInline(admin.TabularInline):
|
|
model = BusStop
|
|
extra = 0
|
|
ordering = ("am_time",)
|
|
|
|
|
|
@admin.register(Bus)
|
|
class BusesAdmin(MyImportExportModelAdmin, admin.ModelAdmin, BusRollMixin):
|
|
list_filter = ["company"]
|
|
list_display = ["route_name", "company", "contract_number", "seating_capacity", "route_travellers"]
|
|
readonly_fields = ["traveller_count"]
|
|
actions = ["email_company", "show_bus_roll", "show_emergency_contacts"]
|
|
inlines = [DriverInline, BusStopInline]
|
|
fieldsets = [
|
|
(None, {'fields': [
|
|
"company", "route_name", "contract_number", "registration",
|
|
"traveller_count", "seating_capacity", "make", "model", "notes"
|
|
]})
|
|
]
|
|
|
|
def route_travellers(self, obj):
|
|
url = (
|
|
reverse("admin:coord_traveller_changelist")
|
|
+ "?"
|
|
+ urlencode({"bus_stops__bus__id__exact": f"{obj.id}"})
|
|
)
|
|
return format_html('<a href="{}">{} Travellers</a>', url, obj.traveller_count())
|
|
|
|
|
|
# @admin.register(BusStop)
|
|
class BusStopAdmin(MyImportExportModelAdmin, admin.ModelAdmin):
|
|
list_filter = ["bus__company", "bus__route_name"]
|
|
list_display = ["__str__", "am_time", "pm_time", "address"]
|
|
search_fields = ["bus__route_name", "address"]
|
|
|
|
|
|
@admin.register(Suburb)
|
|
class SuburbsAdmin(MyImportExportModelAdmin, admin.ModelAdmin):
|
|
list_filter = ["state"]
|
|
|
|
|
|
class TravellerRouteInline(admin.TabularInline):
|
|
model = TravellerRoute
|
|
extra = 0
|
|
|
|
|
|
@admin.register(Traveller)
|
|
class TravellerAdmin(MyImportExportModelAdmin, CloneModelAdmin, admin.ModelAdmin, TravellerRollMixin):
|
|
list_display = ["first_name", "last_name", "school", "year_level", "is_active", "residential_address", "residential_suburb", "stop_route", "shuttle", "travel_start_date", "travel_end_date"]
|
|
list_filter = [
|
|
"is_active", "school", "year_level", "eligibility_status", "bus_stops__bus", "shuttle", "residential_suburb",
|
|
("travel_start_date", DateRangeFilterBuilder(
|
|
title="Start date"
|
|
)),
|
|
("travel_end_date", DateRangeFilterBuilder(
|
|
title="End date"
|
|
))
|
|
]
|
|
search_fields = ["first_name", "last_name", "residential_address"]
|
|
cloneable_fields = ["last_name", "residential_address", "residential_suburb",
|
|
"postal_address", "postal_suburb", "eligibility_status", "shuttle",
|
|
"parent_A_firstname", "parent_A_lastname", "parent_A_phone", "parent_A_email",
|
|
"parent_B_firstname", "parent_B_lastname", "parent_B_phone", "parent_B_email",
|
|
"emergency_contact_A_firstname", "emergency_contact_A_lastname", "emergency_contact_A_phone",
|
|
"emergency_contact_A_relation", "emergency_contact_B_firstname", "emergency_contact_B_lastname",
|
|
"emergency_contact_B_phone", "emergency_contact_B_relation"]
|
|
inlines = [TravellerRouteInline]
|
|
readonly_fields = ["travel_start_date", "travel_end_date", "fare_paying", "created_on", "last_edit", "is_active"]
|
|
actions = ["export_to_csv", "send_sms", "confirmation_letter", "letter_creator"]
|
|
fieldsets = [
|
|
(None, {
|
|
'fields': [
|
|
"is_active",
|
|
"school",
|
|
"first_name",
|
|
"last_name",
|
|
"dob",
|
|
"year_level",
|
|
]
|
|
}),
|
|
('Address', {
|
|
'classes': ('collapse',),
|
|
'fields': [
|
|
"residential_address",
|
|
"residential_suburb",
|
|
"postal_address",
|
|
"postal_suburb",
|
|
]
|
|
}),
|
|
('Office Use', {
|
|
'classes': ('collapse',),
|
|
'fields': [
|
|
"distance_to_school",
|
|
"travel_start_date",
|
|
"travel_end_date",
|
|
"eligibility_status",
|
|
"fare_paying",
|
|
"term_1_paid",
|
|
"term_2_paid",
|
|
"term_3_paid",
|
|
"term_4_paid",
|
|
"assessment_date",
|
|
"application_form_completed",
|
|
"parent_notified",
|
|
"seat_number",
|
|
"created_on",
|
|
"last_edit",
|
|
]
|
|
}),
|
|
('Adult Contacts', {
|
|
'classes': ('collapse',),
|
|
'fields': [
|
|
"parent_A_firstname",
|
|
"parent_A_lastname",
|
|
"parent_A_phone",
|
|
"parent_A_email",
|
|
"parent_B_firstname",
|
|
"parent_B_lastname",
|
|
"parent_B_phone",
|
|
"parent_B_email",
|
|
"emergency_contact_A_firstname",
|
|
"emergency_contact_A_lastname",
|
|
"emergency_contact_A_phone",
|
|
"emergency_contact_A_relation",
|
|
"emergency_contact_B_firstname",
|
|
"emergency_contact_B_lastname",
|
|
"emergency_contact_B_phone",
|
|
"emergency_contact_B_relation"
|
|
]
|
|
}),
|
|
(None, {'fields': ["notes", "shuttle"]})
|
|
]
|
|
# list_display_links = None
|
|
|
|
def yearly_rollover(self, request, queryset):
|
|
pass
|
|
|
|
def stop_route(self, obj):
|
|
stops = BusStop.objects.filter(traveller__id__exact=obj.id)
|
|
if stops.count() == 0:
|
|
return ""
|
|
if stops.count() == 1:
|
|
return stops.first()
|
|
return "Multiple"
|
|
|
|
def save_model(self, request, obj, form, change):
|
|
if obj.is_archived and obj.travel_end_date is None:
|
|
obj.is_archived = False
|
|
super().save_model(request, obj, form, change)
|
|
|
|
|
|
# @admin.register(TravellerRoute)
|
|
class TravellerRouteAdmin(MyImportExportModelAdmin, admin.ModelAdmin):
|
|
list_display = ["traveller", "busStop"]
|
|
|
|
|
|
@admin.register(School)
|
|
class SchoolAdmin(MyImportExportModelAdmin, admin.ModelAdmin, SchoolRollMixin):
|
|
list_display = ["__str__", "address", "suburb", "school_email", "phone"]
|
|
actions = ["email_travellers_to_school", "show_school_travellers", "export_travellers_to_csv"]
|
|
|
|
def school_email(self, obj):
|
|
return format_html('<a href="mailto:{}">{}</a>', obj.email, obj.email)
|
|
|
|
|
|
@admin.register(Setting)
|
|
class SettingAdmin(MyImportExportModelAdmin, admin.ModelAdmin):
|
|
list_display = ["name", "value"]
|
|
|
|
|
|
@admin.register(Shuttle)
|
|
class ShuttleAdmin(MyImportExportModelAdmin, admin.ModelAdmin, ShuttleRollMixin):
|
|
list_display = ["__str__", "school", "bus", "shuttle_travellers"]
|
|
actions = ["show_shuttle_roll"]
|
|
|
|
def shuttle_travellers(self, obj):
|
|
url = (
|
|
reverse("admin:coord_traveller_changelist")
|
|
+ "?"
|
|
+ urlencode({"shuttle__id__exact": f"{obj.id}"})
|
|
)
|
|
return format_html('<a href="{}">{} Travellers</a>', url, obj.traveller_count())
|
|
|
|
|
|
# @admin.register(Driver)
|
|
class DriverAdmin(MyImportExportModelAdmin, admin.ModelAdmin):
|
|
list_display = ["__str__", "route", "phone_number"]
|
|
|
|
def route(self, obj):
|
|
url = reverse("admin:coord_bus_change", args=(obj.bus.id,))
|
|
return format_html('<a href="{}">{}</a>', url, obj.bus)
|