diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/person.html b/aleksis/apps/alsijil/templates/alsijil/class_register/person.html index bc715d6794e65d000cc016d0ff3430e6e04054c9..a71e0c115a3586b16d9d02b3172fa8a7e382d19c 100644 --- a/aleksis/apps/alsijil/templates/alsijil/class_register/person.html +++ b/aleksis/apps/alsijil/templates/alsijil/class_register/person.html @@ -42,6 +42,47 @@ </li> {% endfor %} </ul> + <h5>{% trans "Statistics on absences, tardinesses and remarks" %}</h5> + <ul class="collapsible"> + {% for school_term, stat in stats %} + <li {% if forloop.first %}class="active"{% endif %}> + <div class="collapsible-header"> + <i class="material-icons">date_range</i>{{ school_term }}</div> + <div class="collapsible-body"> + <table> + <tr> + <th colspan="2">{% trans 'Absences' %}</th> + <td>{{ stat.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>{{ stat.excused }}</td> + </tr> + {% for excuse_type in excuse_types %} + <th>{{ excuse_type.name }}</th> + <td>{{ stat|get_dict:excuse_type.count_label }}</td> + {% endfor %} + <tr> + <th>{% trans 'Unexcused' %}</th> + <td>{{ stat.unexcused }}</td> + </tr> + <tr> + <th colspan="2">{% trans 'Tardiness' %}</th> + <td>{{ stat.tardiness }}'</td> + </tr> + {% for extra_mark in extra_marks %} + <tr> + <th colspan="2">{{ extra_mark.name }}</th> + <td>{{ stat|get_dict:extra_mark.count_label }}</td> + </tr> + {% endfor %} + </table> + </div> + </li> + {% endfor %} + </ul> </div> <div class="col s12 m12 l6"> <h5>{% trans "Relevant personal notes" %}</h5> diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py index 41c8d29612e9cec49914700c1b6463a7d4cfcf62..87b74da2592a779edf15fafb20cc0d3e6af0edd8 100644 --- a/aleksis/apps/alsijil/views.py +++ b/aleksis/apps/alsijil/views.py @@ -529,6 +529,55 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp ) context["personal_notes"] = personal_notes context["excuse_types"] = ExcuseType.objects.all() + + school_terms = SchoolTerm.objects.all().order_by("-date_start") + stats = [] + for school_term in school_terms: + stat = {} + personal_notes = PersonalNote.objects.filter( + person=person, lesson_period__lesson__validity__school_term=school_term + ) + + if not personal_notes.exists(): + continue + + stat.update( + personal_notes.filter(absent=True).aggregate(absences_count=Count("absent")) + ) + stat.update( + personal_notes.filter( + absent=True, excused=True, excuse_type__isnull=True + ).aggregate(excused=Count("absent")) + ) + stat.update( + personal_notes.filter(absent=True, excused=False).aggregate( + unexcused=Count("absent") + ) + ) + stat.update( + personal_notes.filter(absent=True, excused=False).aggregate( + tardiness=Count("late") + ) + ) + + for extra_mark in ExtraMark.objects.all(): + stat.update( + personal_notes.filter(extra_marks=extra_mark).aggregate( + **{extra_mark.count_label: Count("pk")} + ) + ) + + for excuse_type in ExcuseType.objects.all(): + stat.update( + personal_notes.filter(absent=True, excuse_type=excuse_type).aggregate( + **{excuse_type.count_label: Count("absent")} + ) + ) + + stats.append((school_term, stat)) + context["stats"] = stats + context["excuse_types"] = ExcuseType.objects.all() + context["extra_marks"] = ExtraMark.objects.all() return render(request, "alsijil/class_register/person.html", context)