Changed bus roll to be a pdf view. Small changes needed to be able to email to companies.
Dropdown selection in admin > buses > Email Bus Roll To Company Will email bus roll only to the company the route is a member of. Will show all to the admin in a pdf file. Recipients are currently hardcoded for testing purposes.
This commit is contained in:
@@ -9,6 +9,8 @@ from django.utils.http import urlencode
|
||||
from import_export.admin import ImportExportModelAdmin
|
||||
|
||||
from .adminClone import CloneModelAdmin
|
||||
from .context_helpers import bus_roll_context
|
||||
from .email_helpers import email_companies_bus_roll, render_to_pdf
|
||||
from .models import *
|
||||
from .views import bus_roll
|
||||
|
||||
@@ -33,11 +35,11 @@ class ExportCsvMixin:
|
||||
|
||||
class BusRollMixin:
|
||||
|
||||
def bus_roll(self, request, queryset):
|
||||
return bus_roll(request, queryset)
|
||||
def show_bus_roll(self, request, queryset):
|
||||
return render_to_pdf('reports/bus_roll.html', bus_roll_context(queryset))
|
||||
|
||||
def email_company(self, request, queryset):
|
||||
pass
|
||||
return email_companies_bus_roll(request, queryset)
|
||||
|
||||
email_company.short_description = "Email Bus Roll to Company"
|
||||
|
||||
@@ -81,7 +83,7 @@ class BusesAdmin(MyImportExportModelAdmin, admin.ModelAdmin, BusRollMixin):
|
||||
list_filter = ["company"]
|
||||
list_display = ["route_name", "company", "contract_number", "route_travellers"]
|
||||
readonly_fields = ["traveller_count"]
|
||||
actions = ["email_company", "bus_roll"]
|
||||
actions = ["email_company", "show_bus_roll"]
|
||||
inlines = [DriverInline, BusStopInline]
|
||||
fieldsets = [
|
||||
(None, {'fields': [
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
from coord.models import Bus, BusStop, TravellerRoute
|
||||
|
||||
|
||||
def bus_roll_context(queryset=None):
|
||||
bus_routes = []
|
||||
if queryset is None:
|
||||
buses = Bus.objects.all()
|
||||
else:
|
||||
buses = queryset
|
||||
|
||||
for bus in buses:
|
||||
bus_route = []
|
||||
|
||||
for bus_stop in BusStop.objects.filter(bus=bus):
|
||||
traveller_list = []
|
||||
for trav_route in TravellerRoute.objects.filter(busStop=bus_stop):
|
||||
traveller = trav_route.traveller
|
||||
if not traveller.is_active():
|
||||
continue
|
||||
is_fared = "---"
|
||||
if traveller.eligibility_status == "2":
|
||||
is_fared = "Y"
|
||||
traveller_list.append({
|
||||
'display': f"{traveller} ({traveller.get_year_level_display()}, {traveller.school.shortName})",
|
||||
'isFared': is_fared
|
||||
})
|
||||
stop_result = {
|
||||
'stop_num': bus_stop.get_stop_number(),
|
||||
'name': bus_stop.address,
|
||||
'am': bus_stop.am_time,
|
||||
'pm': bus_stop.pm_time,
|
||||
'travellers': traveller_list
|
||||
}
|
||||
# print(traveller_list)
|
||||
bus_route.append(stop_result)
|
||||
|
||||
# Todo Add shuttles
|
||||
|
||||
bus_routes.append({'bus': bus, 'stops': bus_route})
|
||||
return {'routes': bus_routes}
|
||||
@@ -0,0 +1,47 @@
|
||||
from datetime import date
|
||||
from io import BytesIO
|
||||
|
||||
from django.contrib.admin.views.decorators import staff_member_required
|
||||
from django.core.mail import send_mail, EmailMessage
|
||||
from django.http import HttpResponse
|
||||
from django.template.loader import get_template
|
||||
from xhtml2pdf import pisa
|
||||
|
||||
from coord.context_helpers import bus_roll_context
|
||||
from coord.models import Company
|
||||
|
||||
|
||||
def render_to_pdf(template, context):
|
||||
html = get_template(template).render(context)
|
||||
result = BytesIO()
|
||||
pdf = pisa.pisaDocument(BytesIO(html.encode("ISO-8859-1")), result)
|
||||
if pdf.err:
|
||||
return HttpResponse("Invalid PDF", status_code=400, content_type='text/plan')
|
||||
return HttpResponse(result.getvalue(), content_type='application/pdf')
|
||||
|
||||
|
||||
@staff_member_required
|
||||
def email_companies_bus_roll(request, query_set=None):
|
||||
html_template = 'reports/bus_roll.html'
|
||||
context = bus_roll_context(query_set)
|
||||
|
||||
for company in Company.objects.all():
|
||||
company_route = []
|
||||
for route in context.get("routes"):
|
||||
bus = route.get("bus")
|
||||
if route.get("bus").company == company:
|
||||
company_route.append(route)
|
||||
if not company_route:
|
||||
continue
|
||||
company_context = {'routes': company_route}
|
||||
pdf = render_to_pdf(html_template, company_context)
|
||||
|
||||
subject = "Echuca Schools Bus Roll"
|
||||
message = f"A new bus roll for {company.name} has been generated"
|
||||
email_from = "bus.manager@education.vic.gov.au"
|
||||
recipient = ["john.mullins@education.vic.gov.au", "nicole.edwards@education.vic.gov.au"]
|
||||
email = EmailMessage(subject, message, email_from, recipient)
|
||||
email.attach(f"school_bus_roll_{date.today()}.pdf", pdf.content)
|
||||
email.send()
|
||||
|
||||
return render_to_pdf(html_template, context)
|
||||
@@ -6,35 +6,24 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table.traveller th {
|
||||
text-align: left;
|
||||
border-bottom: 2px solid #000;
|
||||
}
|
||||
|
||||
|
||||
table.traveller td {
|
||||
table-layout: fixed;
|
||||
border-bottom: 2px solid #000;
|
||||
border-right-style: dashed;
|
||||
width: 100%;
|
||||
min-width: 30px;
|
||||
border: 2px solid #000;
|
||||
}
|
||||
|
||||
|
||||
hr {
|
||||
border: 2px solid;
|
||||
border: 3px solid;
|
||||
}
|
||||
</style>
|
||||
|
||||
{% for route in routes %}
|
||||
<h1>{{ route.route_name }}</h1>
|
||||
<h1 style="font-size: 2.5em">{{ route.bus.route_name }}</h1>
|
||||
{% for stop in route.stops %}
|
||||
<hr>
|
||||
<hr style="border: 5px">
|
||||
<table class="stopHeader">
|
||||
<tr>
|
||||
<th>Stop Number #{{ stop.stop_num }}</th>
|
||||
<th>Pickup Time</th>
|
||||
<th>Drop-off Time</th>
|
||||
<th style="width: 100%">Stop Number #{{ stop.stop_num }}</th>
|
||||
<th style="width: 20%">Pickup Time</th>
|
||||
<th style="width: 25%">Drop-off Time</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ stop.name }}</td>
|
||||
@@ -44,23 +33,23 @@
|
||||
</table>
|
||||
<table class="traveller">
|
||||
<tr>
|
||||
<th>Student</th>
|
||||
<th>Fare</th>
|
||||
<th>Mon AM</th>
|
||||
<th>Mon PM</th>
|
||||
<th>Tue AM</th>
|
||||
<th>Tue PM</th>
|
||||
<th>Wed AM</th>
|
||||
<th>Wed PM</th>
|
||||
<th>Thu AM</th>
|
||||
<th>Thu PM</th>
|
||||
<th>Fri AM</th>
|
||||
<th>Fri PM</th>
|
||||
<th style="width: 100%; text-align: left">Student</th>
|
||||
<th style="width: 10%">Fare</th>
|
||||
<th style="width: 8%">Mon AM</th>
|
||||
<th style="width: 8%">Mon PM</th>
|
||||
<th style="width: 8%">Tue AM</th>
|
||||
<th style="width: 8%">Tue PM</th>
|
||||
<th style="width: 8%">Wed AM</th>
|
||||
<th style="width: 8%">Wed PM</th>
|
||||
<th style="width: 8%">Thu AM</th>
|
||||
<th style="width: 8%">Thu PM</th>
|
||||
<th style="width: 8%">Fri AM</th>
|
||||
<th style="width: 8%">Fri PM</th>
|
||||
</tr>
|
||||
{% for traveller in stop.travellers %}
|
||||
<tr>
|
||||
<td>{{ traveller.display }}</td>
|
||||
<td><b>{{ traveller.isFared }}</b></td>
|
||||
<td style="padding-top: 3px; padding-left: 2px; text-align: left">{{ traveller.display }}</td>
|
||||
<td style="padding-top: 3px; text-align: center"><b>{{ traveller.isFared }}</b></td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
|
||||
@@ -6,5 +6,6 @@ urlpatterns = [
|
||||
path("roll", views.bus_roll, name="Student Roll"),
|
||||
path("contacts", views.emergency_contacts, name="Emergency Contacts"),
|
||||
path("stops", views.bus_summary, name="Stop Summary"),
|
||||
path("summary", views.bus_numbers, name="Bus Summary")
|
||||
path("summary", views.bus_numbers, name="Bus Summary"),
|
||||
path("testemail", views.TestEmail, name="Test Email")
|
||||
]
|
||||
|
||||
@@ -2,6 +2,8 @@ from django.contrib.admin.views.decorators import staff_member_required
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import render
|
||||
from django.views.generic import ListView
|
||||
|
||||
from .context_helpers import bus_roll_context
|
||||
from .models import Company, Bus, Traveller, BusStop, TravellerRoute, Shuttle, Driver
|
||||
|
||||
|
||||
@@ -46,43 +48,7 @@ def bus_numbers(request):
|
||||
|
||||
@staff_member_required
|
||||
def bus_roll(request, queryset=None):
|
||||
bus_routes = []
|
||||
if queryset is None:
|
||||
buses = Bus.objects.all()
|
||||
else:
|
||||
buses = queryset
|
||||
|
||||
for bus in buses:
|
||||
bus_route = []
|
||||
|
||||
for bus_stop in BusStop.objects.filter(bus=bus):
|
||||
traveller_list = []
|
||||
for trav_route in TravellerRoute.objects.filter(busStop=bus_stop):
|
||||
traveller = trav_route.traveller
|
||||
if not traveller.is_active():
|
||||
continue
|
||||
is_fared = "---"
|
||||
if traveller.eligibility_status == "2":
|
||||
is_fared = "Y"
|
||||
traveller_list.append({
|
||||
'display': f"{traveller} ({traveller.get_year_level_display()}, {traveller.school.shortName})",
|
||||
'isFared': is_fared
|
||||
})
|
||||
stop_result = {
|
||||
'stop_num': bus_stop.get_stop_number(),
|
||||
'name': bus_stop.address,
|
||||
'am': bus_stop.am_time,
|
||||
'pm': bus_stop.pm_time,
|
||||
'travellers': traveller_list
|
||||
}
|
||||
# print(traveller_list)
|
||||
bus_route.append(stop_result)
|
||||
|
||||
# Todo Add shuttles
|
||||
|
||||
bus_routes.append({'route_name': bus.route_name, 'stops': bus_route})
|
||||
|
||||
return render(request, 'reports/bus_roll.html', {'routes': bus_routes})
|
||||
return render(request, 'reports/bus_roll.html', bus_roll_context(queryset))
|
||||
|
||||
|
||||
@staff_member_required
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user