From 25ddf1edfaadbb6073b74db076816f54da8b4c90 Mon Sep 17 00:00:00 2001 From: John Mullins Date: Thu, 21 Dec 2023 16:14:56 +1100 Subject: [PATCH] Moved active status to a database entry apposed to a function Added settings page Cleaned up rollover page --- .../busManager/templates/admin/base.html | 1 + busManager/busManager/urls.py | 4 +- busManager/coord/admin.py | 27 ++---------- busManager/coord/context_helpers.py | 15 ++++--- busManager/coord/models.py | 43 +++++++++++++++---- busManager/coord/scheduled_tasks.py | 8 ++++ .../coord/templates/admin/rollover_form.html | 16 +++++++ .../coord/templates/admin/settings_index.html | 16 +++++++ busManager/coord/urls_settings.py | 10 +++++ busManager/coord/utils/rollover.py | 15 +------ busManager/coord/utils/send_sms.py | 4 +- busManager/coord/views_settings.py | 27 ++++++++++++ 12 files changed, 128 insertions(+), 58 deletions(-) create mode 100644 busManager/coord/scheduled_tasks.py create mode 100644 busManager/coord/templates/admin/rollover_form.html create mode 100644 busManager/coord/templates/admin/settings_index.html create mode 100644 busManager/coord/urls_settings.py create mode 100644 busManager/coord/views_settings.py diff --git a/busManager/busManager/templates/admin/base.html b/busManager/busManager/templates/admin/base.html index 7fd1c3f..8ec486c 100644 --- a/busManager/busManager/templates/admin/base.html +++ b/busManager/busManager/templates/admin/base.html @@ -14,6 +14,7 @@ Bus Roll / Bus Routes / Resources / + Settings /
{% csrf_token %} diff --git a/busManager/busManager/urls.py b/busManager/busManager/urls.py index 9574012..4f92ea2 100644 --- a/busManager/busManager/urls.py +++ b/busManager/busManager/urls.py @@ -18,14 +18,12 @@ from azure_auth.views import azure_auth_logout from django.contrib import admin from django.urls import path, include -from coord.utils.rollover import rollover - admin.site.site_header = "Bus Portal Admin" urlpatterns = [ path('report/', include("coord.urls")), path('logout/', azure_auth_logout), path('auth/', include("azure_auth.urls"),), - path('rollover', rollover, name="rollover"), + path('settings/', include('coord.urls_settings')), path('', admin.site.urls), ] diff --git a/busManager/coord/admin.py b/busManager/coord/admin.py index a42be11..316f908 100644 --- a/busManager/coord/admin.py +++ b/busManager/coord/admin.py @@ -58,7 +58,7 @@ class SchoolRollMixin: traveller_list = [] for school in queryset: for travellerRoute in TravellerRoute.objects.filter(traveller__school=school): - if not travellerRoute.traveller.is_active(): + if not travellerRoute.traveller._is_active(): continue traveller_list.append(traveller_route_context(travellerRoute)) @@ -92,25 +92,6 @@ class TravellerRollMixin: return response -class ArchiveFilter(BooleanFieldListFilter): - parameter_name = 'is_archived' - - def choices(self, changelist): - field_choices = dict(self.field.flatchoices) - for lookup, title in ( - (None, gettext_lazy("All")), - ("0", field_choices.get(True, gettext_lazy("Current Year"))), - ("1", field_choices.get(False, gettext_lazy("Archived"))), - ): - yield { - "selected": self.lookup_val == lookup and not self.lookup_val2, - "query_string": changelist.get_query_string( - {self.lookup_kwarg: lookup}, [self.lookup_kwarg2] - ), - "display": title, - } - - class HiddenNowTime(widgets.TimeInput): pass @@ -192,7 +173,7 @@ class TravellerRouteInline(admin.TabularInline): class TravellerAdmin(MyImportExportModelAdmin, CloneModelAdmin, admin.ModelAdmin, TravellerRollMixin): list_display = ["first_name", "last_name", "school", "year_level", "residential_address", "residential_suburb", "stop_route", "shuttle", "travel_start_date", "travel_end_date"] list_filter = [ - ("is_archived", ArchiveFilter), "school", "year_level", "eligibility_status", "bus_stops__bus", "shuttle", "residential_suburb", + "is_active", "school", "year_level", "eligibility_status", "bus_stops__bus", "shuttle", "residential_suburb", ("travel_start_date", DateRangeFilterBuilder( title="Start date" )), @@ -209,7 +190,7 @@ class TravellerAdmin(MyImportExportModelAdmin, CloneModelAdmin, admin.ModelAdmin "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"] + 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, { @@ -248,7 +229,7 @@ class TravellerAdmin(MyImportExportModelAdmin, CloneModelAdmin, admin.ModelAdmin "seat_number", "created_on", "last_edit", - "is_archived", + "is_active", ] }), ('Adult Contacts', { diff --git a/busManager/coord/context_helpers.py b/busManager/coord/context_helpers.py index 0b65a56..bc3cc7c 100644 --- a/busManager/coord/context_helpers.py +++ b/busManager/coord/context_helpers.py @@ -33,7 +33,7 @@ def school_roll_context(queryset): travellers = [] for trav_route in TravellerRoute.objects.filter(query).filter(busStop__bus=bus).order_by('busStop__am_time'): traveller = trav_route.traveller - if not traveller.is_active(): + if not traveller._is_active(): continue bus_stop = trav_route.busStop @@ -82,7 +82,7 @@ def route_paged_context(bus): traveller_list = [] for trav_route in traveller_routes: traveller = trav_route.traveller - if not traveller.is_active(): + if not traveller._is_active(): continue is_fared = "---" if traveller.eligibility_status == "2": @@ -114,17 +114,18 @@ def route_paged_context(bus): def shuttle_route_context(shuttle): shuttle_travellers = [] for traveller in Traveller.objects.filter(shuttle=shuttle): - if traveller.is_active(): + if traveller._is_active(): shuttle_travellers.append({ 'display': f"{traveller} ({traveller.get_year_level_display()}, {traveller.school})", }) return {'shuttle': shuttle, 'shuttle_travellers': shuttle_travellers} + def school_travellerRoute_context(school): travellers = [] for travellerRoute in TravellerRoute.objects.filter(traveller__school=school): traveller = travellerRoute.traveller - if not traveller.is_active(): + if not traveller._is_active(): continue travellers.append(traveller_route_context(travellerRoute)) return travellers @@ -165,7 +166,7 @@ def emergency_contacts_context(queryset=None): traveller_list = [] for travellerRoute in TravellerRoute.objects.filter(busStop__bus=bus): traveller = travellerRoute.traveller - if not traveller.is_active(): + if not traveller._is_active(): continue parent_a = "" if travellerRoute.traveller.parent_A_firstname: @@ -206,7 +207,7 @@ def bus_summary_context(): traveller_count = 0 for travellerRoute in TravellerRoute.objects.filter(busStop__bus=bus): - if travellerRoute.traveller.is_active(): + if travellerRoute.traveller._is_active(): traveller_count += 1 shuttle_name = "" @@ -218,7 +219,7 @@ def bus_summary_context(): shuttle_name += f", {shuttle.school.shortName}" for traveller in Traveller.objects.filter(shuttle=shuttle): - if traveller.is_active(): + if traveller._is_active(): shuttle_count += 1 over_capacity = traveller_count > bus.seating_capacity or shuttle_count > bus.seating_capacity diff --git a/busManager/coord/models.py b/busManager/coord/models.py index a9cf36b..5b8f17d 100644 --- a/busManager/coord/models.py +++ b/busManager/coord/models.py @@ -87,7 +87,7 @@ class Bus(models.Model): def traveller_count(self): count = 0 for traveller in Traveller.objects.filter(bus_stops__bus=self): - if traveller.is_active(): + if traveller._is_active(): count += 1 return count @@ -96,6 +96,9 @@ class Shuttle(models.Model): bus = models.ForeignKey(Bus, on_delete=models.CASCADE) school = models.ForeignKey(School, on_delete=models.CASCADE) custom_name = models.CharField(max_length=10, blank=True) + transfer_school = models.ForeignKey(School, related_name='transfer_school', on_delete=models.CASCADE) + am_service = models.BooleanField(default=True) + pm_service = models.BooleanField(default=True) class Meta: ordering = ["school__name"] @@ -111,7 +114,7 @@ class Shuttle(models.Model): def traveller_count(self): count = 0 for traveller in Traveller.objects.filter(shuttle=self, is_archived=False): - if traveller.is_active(): + if traveller._is_active(): count += 1 return count @@ -235,6 +238,7 @@ class Traveller(models.Model): created_on = models.DateTimeField(auto_now_add=True, blank=True, null=True) last_edit = models.DateTimeField(auto_now=True, blank=True, null=True) is_archived = models.BooleanField(default=False, verbose_name="Archived") + is_active = models.BooleanField(default=True, verbose_name='Active') notes = models.TextField(blank=True, verbose_name='Admin Notes') shuttle = models.ForeignKey(Shuttle, on_delete=models.SET_NULL, blank=True, null=True) @@ -244,18 +248,33 @@ class Traveller(models.Model): def __str__(self): return f"{self.first_name} {self.last_name}" - def is_active(self): - if self.is_archived: - return False - if not self.travel_start_date: - return False - if datetime(self.travel_start_date.year, self.travel_start_date.month, self.travel_start_date.day) > datetime.today(): + def _is_active(self): + today = datetime.today() + today = datetime(today.year, today.month, today.day) + if not self.travel_start_date or datetime(self.travel_start_date.year, self.travel_start_date.month, self.travel_start_date.day) > today: return False if not self.travel_end_date: return True end_date = datetime(self.travel_end_date.year, self.travel_end_date.month, self.travel_end_date.day) - return end_date > datetime.today() + return end_date >= today + + def update_active_status(self): + self.travel_start_date = None + self.travel_end_date = None + for travellerRoute in TravellerRoute.objects.filter(traveller=self): + route_start = travellerRoute.travel_start_date + print(route_start) + route_end = travellerRoute.travel_end_date + if route_start is not None: + if self.travel_start_date is None or self.travel_start_date > route_start: + self.travel_start_date = route_start + if route_end is not None: + if self.travel_end_date is None or self.travel_end_date < route_end: + self.travel_end_date = route_end + + self.is_active = self._is_active() + self.save() def fare_paying(self): if self.eligibility_status != "2": @@ -299,6 +318,8 @@ class Traveller(models.Model): class TravellerRoute(models.Model): traveller = models.ForeignKey(Traveller, on_delete=models.CASCADE) busStop = models.ForeignKey(BusStop, on_delete=models.CASCADE) + travel_start_date = models.DateField(blank=True, null=True) + travel_end_date = models.DateField(blank=True, null=True) mon_am = models.BooleanField(default=True) mon_pm = models.BooleanField(default=True) tue_am = models.BooleanField(default=True) @@ -314,6 +335,10 @@ class TravellerRoute(models.Model): def __str__(self): return f"{self.busStop}" + def save(self, *args, **kwargs): + super(TravellerRoute, self).save(*args, **kwargs) + # self.traveller.update_active_status() + def active_stops(self): stops = 0 if self.mon_am: diff --git a/busManager/coord/scheduled_tasks.py b/busManager/coord/scheduled_tasks.py new file mode 100644 index 0000000..eadcb90 --- /dev/null +++ b/busManager/coord/scheduled_tasks.py @@ -0,0 +1,8 @@ +from coord.models import TravellerRoute + + +def copy_travel_dates(): + for Route in TravellerRoute.objects.all(): + Route.travel_start_date = Route.traveller.travel_start_date + Route.travel_end_date = Route.traveller.travel_end_date + Route.save() diff --git a/busManager/coord/templates/admin/rollover_form.html b/busManager/coord/templates/admin/rollover_form.html new file mode 100644 index 0000000..f352f5d --- /dev/null +++ b/busManager/coord/templates/admin/rollover_form.html @@ -0,0 +1,16 @@ +{% extends "admin/base_site.html" %} + +{% block content %} +

Yearly rollover

+

Initiating a rollover will perform the following actions.

+ + + {% csrf_token %} + {{ form.as_p }} +
+ +{% endblock %} \ No newline at end of file diff --git a/busManager/coord/templates/admin/settings_index.html b/busManager/coord/templates/admin/settings_index.html new file mode 100644 index 0000000..74395f6 --- /dev/null +++ b/busManager/coord/templates/admin/settings_index.html @@ -0,0 +1,16 @@ +{% extends "admin/base_site.html" %} + +{% block content %} +
Run nightly task
+
+
+ + +
+
+ Rollover + + +{% endblock %} \ No newline at end of file diff --git a/busManager/coord/urls_settings.py b/busManager/coord/urls_settings.py new file mode 100644 index 0000000..447af69 --- /dev/null +++ b/busManager/coord/urls_settings.py @@ -0,0 +1,10 @@ +from django.urls import path + +from . import views_settings + +app_name = "settings" +urlpatterns = [ + path('rollover', views_settings.rollover, name='rollover'), + path('nightly_task', views_settings.nightly_task, name='nightly-task'), + path('', views_settings.settings, name='index'), +] diff --git a/busManager/coord/utils/rollover.py b/busManager/coord/utils/rollover.py index ea5395b..6e65e1e 100644 --- a/busManager/coord/utils/rollover.py +++ b/busManager/coord/utils/rollover.py @@ -23,7 +23,7 @@ class RolloverForm(forms.Form): agreement = forms.BooleanField(label='I have run an export/backup for travellers') -def _rollover(exit_date): +def execute_rollover(exit_date): print(f"Setting exit date {exit_date}") result = Traveller.objects.filter(year_level='12', travel_end_date=None).update(travel_end_date=exit_date) print(f"{result} Year 12s exited") @@ -45,16 +45,3 @@ def _rollover(exit_date): result += Traveller.objects.filter(is_archived=False, year_level='PS').update(year_level='00') print(f"{result} travellers modified") - -@staff_member_required -def rollover(request): - # if 'confirm' in request.POST: - if request.method == 'POST': - form = RolloverForm(request.POST) - if form.is_valid(): - _rollover(form.cleaned_data['exit_date']) - # rollover_mixin.message_user(request, "Users have been rolled over") - return HttpResponseRedirect('/') - - form = RolloverForm() - return render(request, 'admin/rollover_form.html', context={'form': form}) diff --git a/busManager/coord/utils/send_sms.py b/busManager/coord/utils/send_sms.py index 1952cc4..e275924 100644 --- a/busManager/coord/utils/send_sms.py +++ b/busManager/coord/utils/send_sms.py @@ -12,7 +12,7 @@ class SMSForm(forms.Form): def send_sms(send_sms_mixin, request, queryset): - if 'send' in request.POST: + if 'confirm' in request.POST: message = request.POST["message"] send_to_parents = False if request.POST.get("send_to_parents"): @@ -26,7 +26,7 @@ def send_sms(send_sms_mixin, request, queryset): total = 0 numbers = [] for traveller in queryset: - if only_include_active_travellers and not traveller.is_active(): + if only_include_active_travellers and not traveller._is_active(): continue numbers.append(traveller.get_parsed_numbers(parents=send_to_parents, emergency=send_to_emergency_contacts)) diff --git a/busManager/coord/views_settings.py b/busManager/coord/views_settings.py new file mode 100644 index 0000000..eb7aef7 --- /dev/null +++ b/busManager/coord/views_settings.py @@ -0,0 +1,27 @@ +from django.contrib.admin.views.decorators import staff_member_required +from django.shortcuts import render, redirect + +from coord.scheduled_tasks import copy_travel_dates +from coord.utils.rollover import RolloverForm, execute_rollover + + +@staff_member_required +def settings(request): + return render(request, 'admin/settings_index.html') + + +@staff_member_required +def rollover(request): + if request.method == 'POST': + form = RolloverForm(request.POST) + if form.is_valid(): + execute_rollover(form.cleaned_data['exit_date']) + return redirect('settings:index') + + form = RolloverForm() + return render(request, 'admin/rollover_form.html', context={'form': form}) + +@staff_member_required +def nightly_task(request): + copy_travel_dates() + return redirect('settings:index')