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('{} Buses', url, count)
def email(self, obj):
return format_html('{}', 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('{} Travellers', 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", "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",
"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('{}', 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('{} Travellers', 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('{}', url, obj.bus)