Files
bus-manager/busManager/coord/admin.py
T
2025-02-18 15:40:38 +11:00

320 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, \
email_companies_emergency_contacts, email_school_shuttle_roll
from .forms import roll_date_selector
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_bus_roll_on_date(self, request, queryset):
return roll_date_selector(self, request, queryset)
def show_emergency_contacts(self, request, queryset):
return render_to_pdf('reports/emergency_contacts.html', emergency_contacts_context(queryset))
def sms_traveller_contacts(self, request, queryset):
travellers = None
for bus in queryset:
query = Traveller.objects.filter(bus_stops__bus=bus).filter(is_active=True).distinct()
if travellers is None:
travellers = query
else:
travellers.union(query)
return send_sms(self, request, travellers)
def email_bus_roll(self, request, queryset):
return email_companies_bus_roll(request, queryset)
def email_emergency_contacts(self, request, queryset):
return email_companies_emergency_contacts(request, queryset)
email_bus_roll.short_description = "Email Bus Roll to Company"
email_emergency_contacts.short_description = "Email Emergency Contacts 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))
def email_shuttle_roll(self, request, queryset):
return email_school_shuttle_roll(request, queryset)
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 show_school_travellers_on_date(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 = ["show_bus_roll", "show_bus_roll_on_date", "show_emergency_contacts", "sms_traveller_contacts", "email_bus_roll", "email_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 FamilyInline(admin.StackedInline):
model = Family
classes = ['collapse']
extra = 0
clone_parent = "traveller"
class TravellerRouteInline(admin.TabularInline):
model = TravellerRoute
extra = 0
clone_parent = "traveller"
@admin.register(Traveller)
class TravellerAdmin(MyImportExportModelAdmin, CloneModelAdmin, TravellerRollMixin):
list_display = ["first_name", "last_name", "school", "year_level", "is_active", "address", "stop_route", "shuttle", "travel_start_date", "travel_end_date"]
list_filter = [
"is_active", "school", "year_level", "eligibility_status", "bus_stops__bus", "shuttle",
("travel_start_date", DateRangeFilterBuilder(
title="Start date"
)),
("travel_end_date", DateRangeFilterBuilder(
title="End date"
))
]
cloneable_fields = ["last_name"]
search_fields = ["first_name", "last_name", "address"]
inlines = [FamilyInline, TravellerRouteInline]
readonly_fields = ["travel_start_date", "travel_end_date", "fare_paying", "created_on", "last_edit", "is_active", "address"]
actions = ["export_to_csv", "send_sms", "confirmation_letter", "letter_creator"]
fieldsets = [
(None, {
'fields': [
"is_active",
"school",
"first_name",
"last_name",
"year_level",
"dob",
"address",
]
}),
('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",
]
}),
(None, {'fields': ["notes", "shuttle"]})
]
# list_display_links = None
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(Family)
class FamilyAdmin(MyImportExportModelAdmin, admin.ModelAdmin):
list_display = ["traveller", "__str__",
"parent_A_firstname", "parent_A_lastname", "parent_A_phone",
"parent_B_firstname", "parent_B_lastname", "parent_B_phone",
"emergency_contact_A_firstname", "emergency_contact_A_lastname", "emergency_contact_A_phone",
"emergency_contact_B_firstname", "emergency_contact_B_lastname", "emergency_contact_B_phone"]
# @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", "email_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)