From 8ace7ecad60d8c0f8532c28ede7f1e6e7851d901 Mon Sep 17 00:00:00 2001
From: Jonathan Weth <git@jonathanweth.de>
Date: Tue, 18 Aug 2020 17:55:55 +0200
Subject: [PATCH] Fix and improve register absence form to work with excuse
 types and a to-period.

---
 aleksis/apps/alsijil/forms.py                 | 29 ++++++++++++++-----
 aleksis/apps/alsijil/model_extensions.py      |  4 +++
 .../templates/alsijil/absences/register.html  | 12 ++++++--
 aleksis/apps/alsijil/views.py                 | 22 +++++++++++---
 4 files changed, 54 insertions(+), 13 deletions(-)

diff --git a/aleksis/apps/alsijil/forms.py b/aleksis/apps/alsijil/forms.py
index 167a73dbc..7b74944b1 100644
--- a/aleksis/apps/alsijil/forms.py
+++ b/aleksis/apps/alsijil/forms.py
@@ -6,9 +6,10 @@ from django.db.models import Count
 from django.utils.translation import gettext_lazy as _
 
 from django_select2.forms import Select2Widget
-from material import Layout, Row
+from material import Fieldset, Layout, Row
 
 from aleksis.apps.chronos.managers import TimetableType
+from aleksis.apps.chronos.models import TimePeriod
 from aleksis.core.models import Group, Person
 
 from .models import ExcuseType, ExtraMark, LessonDocumentation, PersonalNote
@@ -92,22 +93,36 @@ PersonalNoteFormSet = forms.modelformset_factory(
 
 class RegisterAbsenceForm(forms.Form):
     layout = Layout(
-        Row("date_start", "date_end"),
-        Row("from_period"),
-        Row("absent", "excused"),
-        Row("person"),
-        Row("remarks"),
+        Fieldset("", "person"),
+        Fieldset("", Row("date_start", "date_end"), Row("from_period", "to_period")),
+        Fieldset("", Row("absent", "excused"), Row("excuse_type"), Row("remarks")),
     )
     date_start = forms.DateField(label=_("Start date"), initial=datetime.today)
     date_end = forms.DateField(label=_("End date"), initial=datetime.today)
-    from_period = forms.IntegerField(label=_("From period"), initial=0, min_value=0)
+    from_period = forms.ChoiceField(label=_("Start period"))
+    to_period = forms.ChoiceField(label=_("End period"))
     person = forms.ModelChoiceField(
         label=_("Person"), queryset=Person.objects.all(), widget=Select2Widget
     )
     absent = forms.BooleanField(label=_("Absent"), initial=True, required=False)
     excused = forms.BooleanField(label=_("Excused"), initial=True, required=False)
+    excuse_type = forms.ModelChoiceField(
+        label=_("Excuse type"),
+        queryset=ExcuseType.objects.all(),
+        widget=Select2Widget,
+        required=False,
+    )
     remarks = forms.CharField(label=_("Remarks"), max_length=30, required=False)
 
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        period_choices = TimePeriod.period_choices
+
+        self.fields["from_period"].choices = period_choices
+        self.fields["to_period"].choices = period_choices
+        self.fields["from_period"].initial = TimePeriod.period_min
+        self.fields["to_period"].initial = TimePeriod.period_max
+
 
 class ExtraMarkForm(forms.ModelForm):
     layout = Layout("short_name", "name")
diff --git a/aleksis/apps/alsijil/model_extensions.py b/aleksis/apps/alsijil/model_extensions.py
index 1a10bec3b..e381407c4 100644
--- a/aleksis/apps/alsijil/model_extensions.py
+++ b/aleksis/apps/alsijil/model_extensions.py
@@ -20,6 +20,7 @@ def mark_absent(
     excused: bool = False,
     excuse_type: Optional[ExcuseType] = None,
     remarks: str = "",
+    to_period: Optional[int] = None,
 ):
     """Mark a person absent for all lessons in a day, optionally starting with a selected period number.
 
@@ -39,6 +40,9 @@ def mark_absent(
         period__period__gte=from_period
     )
 
+    if to_period:
+        lesson_periods = lesson_periods.filter(period__period__lte=to_period)
+
     # Create and update all personal notes for the discovered lesson periods
     for lesson_period in lesson_periods:
         personal_note, created = PersonalNote.objects.update_or_create(
diff --git a/aleksis/apps/alsijil/templates/alsijil/absences/register.html b/aleksis/apps/alsijil/templates/alsijil/absences/register.html
index 908f3b321..b14890e21 100644
--- a/aleksis/apps/alsijil/templates/alsijil/absences/register.html
+++ b/aleksis/apps/alsijil/templates/alsijil/absences/register.html
@@ -2,8 +2,8 @@
 {% extends "core/base.html" %}
 {% load material_form i18n static %}
 
-{% block browser_title %}{% blocktrans %}Manage absence{% endblocktrans %}{% endblock %}
-{% block page_title %}{% blocktrans %}Manage absence{% endblocktrans %}{% endblock %}
+{% block browser_title %}{% blocktrans %}Register absence{% endblocktrans %}{% endblock %}
+{% block page_title %}{% blocktrans %}Register absence{% endblocktrans %}{% endblock %}
 
 {% block content %}
 
@@ -13,4 +13,12 @@
     {% include "core/partials/save_button.html" %}
   </form>
 
+  <script>
+    $(document).ready(function () {
+      $("#id_date_start").change(function () {
+        $("#id_date_end").val($("#id_date_start").val());
+        $("#id_date_end").change();
+      });
+    });
+  </script>
 {% endblock %}
diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py
index f0c2ad33d..efa967377 100644
--- a/aleksis/apps/alsijil/views.py
+++ b/aleksis/apps/alsijil/views.py
@@ -14,7 +14,7 @@ from reversion.views import RevisionMixin
 from rules.contrib.views import PermissionRequiredMixin
 
 from aleksis.apps.chronos.managers import TimetableType
-from aleksis.apps.chronos.models import LessonPeriod
+from aleksis.apps.chronos.models import LessonPeriod, TimePeriod
 from aleksis.apps.chronos.util.chronos_helpers import get_el_by_pk
 from aleksis.apps.chronos.util.date import get_weeks_for_year, week_weekday_to_date
 from aleksis.core.mixins import AdvancedCreateView, AdvancedDeleteView, AdvancedEditView
@@ -470,19 +470,33 @@ def register_absence(request: HttpRequest) -> HttpResponse:
             start_date = register_absence_form.cleaned_data["date_start"]
             end_date = register_absence_form.cleaned_data["date_end"]
             from_period = register_absence_form.cleaned_data["from_period"]
+            to_period = register_absence_form.cleaned_data["to_period"]
             absent = register_absence_form.cleaned_data["absent"]
             excused = register_absence_form.cleaned_data["excused"]
+            excuse_type = register_absence_form.cleaned_data["excuse_type"]
             remarks = register_absence_form.cleaned_data["remarks"]
 
             # Mark person as absent
             delta = end_date - start_date
             for i in range(delta.days + 1):
-                from_period = from_period if i == 0 else 0
+                from_period_on_day = from_period if i == 0 else TimePeriod.period_min
+                to_period_on_day = (
+                    to_period if i == delta.days else TimePeriod.period_max
+                )
                 day = start_date + timedelta(days=i)
-                person.mark_absent(day, from_period, absent, excused, remarks)
+
+                person.mark_absent(
+                    day,
+                    from_period_on_day,
+                    absent,
+                    excused,
+                    excuse_type,
+                    remarks,
+                    to_period_on_day,
+                )
 
             messages.success(request, _("The absence has been saved."))
-            return redirect("index")
+            return redirect("register_absence")
 
     context["register_absence_form"] = register_absence_form
 
-- 
GitLab