import csv from datetime import date from django.contrib.admin import DateFieldListFilter 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 .adminClone import CloneModelAdmin from .context_helpers import bus_roll_context, emergency_contacts_context, traveller_roll_context from .email_helpers import email_companies_bus_roll, render_to_pdf, email_school_roll_csv from .models import * 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 SchoolRollMixin: def email_school_roll(self, request, queryset): for school in queryset: if not school.email: return HttpResponse(f"No email is set for {school.name}") email_school_roll_csv(request, school) class TravellerRollMixin: 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 = ["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('{} 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 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", "residential_address", "residential_suburb", "stop_route", "travel_start_date", "travel_end_date"] list_filter = ["school", "eligibility_status", "bus_stops__bus", "residential_suburb", ("travel_end_date", DateFieldListFilter), "is_archived"] 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 = ["fare_paying", "created_on", "last_edit", "is_archived"] actions = ["export_to_csv", "yearly_rollover"] fieldsets = [ (None, { 'fields': [ "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", "is_archived", ] }), ('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): print("Saving") if obj.is_archived and obj.travel_end_date is None: obj.is_archived = False print("Pulling out of archive") 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_school_roll"] 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): list_display = ["__str__", "school", "bus", "shuttle_travellers"] 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)