From 29eae0ce31281e2c3f3d1e333fc1ca35d59ab91d Mon Sep 17 00:00:00 2001
From: Julian Leucker <leuckerj@gmail.com>
Date: Wed, 13 Apr 2022 19:41:49 +0200
Subject: [PATCH] Correctly count absences in the class register printout

---
 aleksis/apps/alsijil/model_extensions.py      |  15 ++-
 .../alsijil/print/full_register.html          | 112 ++++++++++++------
 aleksis/apps/alsijil/views.py                 |   3 +-
 3 files changed, 92 insertions(+), 38 deletions(-)

diff --git a/aleksis/apps/alsijil/model_extensions.py b/aleksis/apps/alsijil/model_extensions.py
index c5502d54e..0bc0bacce 100644
--- a/aleksis/apps/alsijil/model_extensions.py
+++ b/aleksis/apps/alsijil/model_extensions.py
@@ -423,9 +423,22 @@ def generate_person_list_with_class_register_statistics(
     ).annotate(
         absences_count=Count(
             "filtered_personal_notes",
-            filter=Q(filtered_personal_notes__absent=True),
+            filter=Q(
+                filtered_personal_notes__absent=True
+            ) & ~Q(
+                filtered_personal_notes__excuse_type__count_as_absent=False
+            ),
         ),
         excused=Count(
+            "filtered_personal_notes",
+            filter=Q(
+                filtered_personal_notes__absent=True,
+                filtered_personal_notes__excused=True,
+            ) & ~Q(
+                filtered_personal_notes__excuse_type__count_as_absent=False
+            ),
+        ),
+        excused_without_excuse_type=Count(
             "filtered_personal_notes",
             filter=Q(
                 filtered_personal_notes__absent=True,
diff --git a/aleksis/apps/alsijil/templates/alsijil/print/full_register.html b/aleksis/apps/alsijil/templates/alsijil/print/full_register.html
index 1f8b6132f..ab63dc7a7 100644
--- a/aleksis/apps/alsijil/templates/alsijil/print/full_register.html
+++ b/aleksis/apps/alsijil/templates/alsijil/print/full_register.html
@@ -97,6 +97,18 @@
     </ul>
   {% endif %}
 
+  {% if excuse_types_not_absent %}
+    <h5>{% trans "Custom excuse types (not counted as absent)" %}</h5>
+
+    <ul class="collection">
+      {% for excuse_type in excuse_types_not_absent %}
+        <li class="collection-item">
+          <strong>({{ excuse_type.short_name }})</strong> {{ excuse_type.name }}
+        </li>
+      {% endfor %}
+    </ul>
+  {% endif %}
+
   {% if extra_marks %}
     <h5>{% trans "Available extra marks" %}</h5>
 
@@ -123,11 +135,15 @@
       <th>{% trans 'Sex' %}</th>
       <th>{% trans 'Date of birth' %}</th>
       <th>{% trans '(a)' %}</th>
+      <th>{% trans "Sum (e)" %}</th>
       <th>{% trans "(e)" %}</th>
       {% for excuse_type in excuse_types %}
         <th>({{ excuse_type.short_name }})</th>
       {% endfor %}
       <th>{% trans '(u)' %}</th>
+      {% for excuse_type in excuse_types_not_absent %}
+        <th>({{ excuse_type.short_name }})</th>
+      {% endfor %}
       <th>{% trans '(b)' %}</th>
       {% for extra_mark in extra_marks %}
         <th>{{ extra_mark.short_name }}</th>
@@ -145,11 +161,15 @@
         <td>{{ person.date_of_birth }}</td>
         <td>{{ person.absences_count }}</td>
         <td>{{ person.excused }}</td>
+        <td>{{ person.excused_without_excuse_type }}</td>
         {% for excuse_type in excuse_types %}
           <td>{{ person|get_dict:excuse_type.count_label }}</td>
         {% endfor %}
         <td>{{ person.unexcused }}</td>
-        <td>{{ person.tardiness }}'/{{ person.tardiness_count }} &times;</td>
+        {% for excuse_type in excuse_types_not_absent %}
+          <td>{{ person|get_dict:excuse_type.count_label }}</td>
+        {% endfor %}
+        <td>{{ person.tardiness }}'/{{ person.tardiness_count }}&times;</td>
         {% for extra_mark in extra_marks %}
           <td>{{ person|get_dict:extra_mark.count_label }}</td>
         {% endfor %}
@@ -263,43 +283,63 @@
       </tr>
     </table>
 
-    <h5>{% trans 'Absences and tardiness' %}</h5>
-    <table>
-      <tr>
-        <th colspan="2">{% trans 'Absences' %}</th>
-        <td>{{ person.absences_count }}</td>
-      </tr>
-      <tr>
-        <td rowspan="{{ excuse_types.count|add:2 }}" style="width: 16mm;"
-            class="rotate small-print">{% trans "thereof" %}</td>
-        <th>{% trans 'Excused' %}</th>
-        <td>{{ person.excused }}</td>
-      </tr>
-      {% for excuse_type in excuse_types %}
-        <th>{{ excuse_type.name }}</th>
-        <td>{{ person|get_dict:excuse_type.count_label }}</td>
-      {% endfor %}
-      <tr>
-        <th>{% trans 'Unexcused' %}</th>
-        <td>{{ person.unexcused }}</td>
-      </tr>
-      <tr>
-        <th colspan="2">{% trans 'Tardiness' %}</th>
-        <td>{{ person.tardiness }}'/{{ person.tardiness_count }} &times;</td>
-      </tr>
-    </table>
-
-    {% if extra_marks %}
-      <h5>{% trans 'Extra marks' %}</h5>
-      <table>
-        {% for extra_mark in extra_marks %}
+    <div class="row">
+      <div class="col s6">
+        <h5>{% trans 'Absences and tardiness' %}</h5>
+        <table>
           <tr>
-            <th>{{ extra_mark.name }}</th>
-            <td>{{ person|get_dict:extra_mark.count_label }}</td>
+            <th colspan="3">{% trans 'Absences' %}</th>
+            <td>{{ person.absences_count }}</td>
           </tr>
-        {% endfor %}
-      </table>
-    {% endif %}
+          <tr>
+            <td rowspan="{{ excuse_types.count|add:3 }}" style="width: 16mm;"
+                class="rotate small-print">{% trans "thereof" %}</td>
+            <th colspan="2">{% trans 'Excused' %}</th>
+            <td>{{ person.excused }}</td>
+          </tr>
+          <tr>
+            <td rowspan="{{ excuse_types.count|add:1 }}" style="width: 16mm;"
+                class="rotate small-print">{% trans "thereof" %}</td>
+            <th>{% trans "Without excuse type" %}</th>
+            <td>{{ person.excused_without_excuse_type }}</td>
+          </tr>
+          {% for excuse_type in excuse_types %}
+            <tr>
+              <th>{{ excuse_type.name }}</th>
+              <td>{{ person|get_dict:excuse_type.count_label }}</td>
+            </tr>
+          {% endfor %}
+          <tr>
+            <th colspan="2">{% trans 'Unexcused' %}</th>
+            <td>{{ person.unexcused }}</td>
+          </tr>
+          {% for excuse_type in excuse_types_not_absent %}
+            <tr>
+              <th colspan="3">{{ excuse_type.name }}</th>
+              <td>{{ person|get_dict:excuse_type.count_label }}</td>
+            </tr>
+          {% endfor %}
+          <tr>
+            <th colspan="3">{% trans 'Tardiness' %}</th>
+            <td>{{ person.tardiness }}'/{{ person.tardiness_count }}&times;</td>
+          </tr>
+        </table>
+      </div>
+
+      <div class="col s6">
+        {% if extra_marks %}
+        <h5>{% trans 'Extra marks' %}</h5>
+        <table>
+          {% for extra_mark in extra_marks %}
+            <tr>
+              <th>{{ extra_mark.name }}</th>
+              <td>{{ person|get_dict:extra_mark.count_label }}</td>
+            </tr>
+          {% endfor %}
+        </table>
+      {% endif %}
+      </div>
+    </div>
 
     <h5>{% trans 'Relevant personal notes' %}</h5>
     <table class="small-print">
diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py
index 5226e591b..c8297882d 100644
--- a/aleksis/apps/alsijil/views.py
+++ b/aleksis/apps/alsijil/views.py
@@ -694,7 +694,8 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
 
     context["school_term"] = group.school_term
     context["persons"] = prefetched_persons
-    context["excuse_types"] = ExcuseType.objects.all()
+    context["excuse_types"] = ExcuseType.objects.filter(count_as_absent=True)
+    context["excuse_types_not_absent"] = ExcuseType.objects.filter(count_as_absent=False)
     context["extra_marks"] = ExtraMark.objects.all()
     context["group"] = group
     context["weeks"] = weeks
-- 
GitLab