From eae1c27b764a0d85a24b0f6c65fabc77605733fa Mon Sep 17 00:00:00 2001
From: Jonathan Weth <git@jonathanweth.de>
Date: Fri, 24 Jan 2025 18:24:16 +0100
Subject: [PATCH 1/4] Calculate statistics about participations with lesson
 events

---
 aleksis/apps/alsijil/model_extensions.py | 12 +++---------
 aleksis/apps/alsijil/tasks.py            |  8 ++++++++
 2 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/aleksis/apps/alsijil/model_extensions.py b/aleksis/apps/alsijil/model_extensions.py
index a3d9c14fa..e1a2bd0ef 100644
--- a/aleksis/apps/alsijil/model_extensions.py
+++ b/aleksis/apps/alsijil/model_extensions.py
@@ -2,6 +2,7 @@ from django.db.models import FilteredRelation, Q, QuerySet, Value
 from django.db.models.aggregates import Count, Sum
 from django.utils.translation import gettext as _
 
+from aleksis.apps.chronos.models import LessonEvent
 from aleksis.apps.kolego.models import AbsenceReason
 from aleksis.core.models import Group, Person, SchoolTerm
 
@@ -137,13 +138,6 @@ def annotate_person_statistics_for_school_term(
         datetime_end__date__lte=school_term.date_end,
     )
     if group:
-        documentations = documentations.filter(
-            pk__in=Documentation.objects.filter(course__groups=group)
-            .values_list("pk", flat=True)
-            .union(
-                Documentation.objects.filter(course__groups__parent_groups=group).values_list(
-                    "pk", flat=True
-                )
-            )
-        )
+        lesson_events = LessonEvent.objects.filter(LessonEvent.objects.for_group_q(group))
+        documentations = documentations.filter(amends__in=lesson_events)
     return annotate_person_statistics_from_documentations(persons, documentations)
diff --git a/aleksis/apps/alsijil/tasks.py b/aleksis/apps/alsijil/tasks.py
index 5c0377d74..71de0d315 100644
--- a/aleksis/apps/alsijil/tasks.py
+++ b/aleksis/apps/alsijil/tasks.py
@@ -7,6 +7,7 @@ from django.utils.translation import gettext as _
 from celery.result import allow_join_result
 from celery.states import SUCCESS
 
+from aleksis.apps.chronos.models import LessonEvent
 from aleksis.apps.cursus.models import Course
 from aleksis.apps.kolego.models.absence import AbsenceReason
 from aleksis.core.models import Group, PDFFile
@@ -118,6 +119,13 @@ def generate_full_register_printout(
                             course__groups__parent_groups=group
                         ).values_list("pk", flat=True)
                     )
+                    .union(
+                        Documentation.objects.filter(
+                            amends__in=LessonEvent.objects.filter(
+                                LessonEvent.objects.for_group_q(group)
+                            )
+                        ).values_list("pk", flat=True)
+                    )
                 )
             )
 
-- 
GitLab


From 40967ac94f86967b7c86afc7e911313b026b41e2 Mon Sep 17 00:00:00 2001
From: Jonathan Weth <git@jonathanweth.de>
Date: Fri, 24 Jan 2025 18:25:23 +0100
Subject: [PATCH 2/4] Add indicator for not counted absences

---
 .../coursebook/statistics/StatisticsForPersonPage.vue     | 8 ++++++++
 .../components/coursebook/statistics/statistics.graphql   | 1 +
 aleksis/apps/alsijil/frontend/messages/de.json            | 3 ++-
 aleksis/apps/alsijil/frontend/messages/en.json            | 3 ++-
 aleksis/apps/alsijil/schema/documentation.py              | 6 ++++++
 5 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/statistics/StatisticsForPersonPage.vue b/aleksis/apps/alsijil/frontend/components/coursebook/statistics/StatisticsForPersonPage.vue
index dc8ae7867..c9c8bcd3c 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/statistics/StatisticsForPersonPage.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/statistics/StatisticsForPersonPage.vue
@@ -179,6 +179,14 @@
                         <v-list-item-action
                           class="flex-row full-width justify-md-end ma-0 align-center fill-height"
                         >
+                          <v-chip
+                            color="warning"
+                            class="mx-1"
+                            v-if="!item.relatedDocumentation.amended"
+                            >{{
+                              $t("alsijil.coursebook.statistics.not_counted")
+                            }}</v-chip
+                          >
                           <!-- chips: absences & extraMarks -->
                           <absence-reason-chip
                             v-if="item.absenceReason"
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/statistics/statistics.graphql b/aleksis/apps/alsijil/frontend/components/coursebook/statistics/statistics.graphql
index 1cffdc717..a83e3fa59 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/statistics/statistics.graphql
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/statistics/statistics.graphql
@@ -64,6 +64,7 @@ query participationsOfPerson($person: ID!) {
         colourFg
         colourBg
       }
+      amended
     }
     canEdit
     canDelete
diff --git a/aleksis/apps/alsijil/frontend/messages/de.json b/aleksis/apps/alsijil/frontend/messages/de.json
index 4d134acfe..b1650ed2b 100644
--- a/aleksis/apps/alsijil/frontend/messages/de.json
+++ b/aleksis/apps/alsijil/frontend/messages/de.json
@@ -82,7 +82,8 @@
           "title": "Kursbuch · Statistiken · {fullName}"
         },
         "person_view_details": "Details",
-        "title_plural": "Statistiken"
+        "title_plural": "Statistiken",
+        "not_counted": "nicht gezählt"
       },
       "status": {
         "available": "Kursbucheintrag vorhanden",
diff --git a/aleksis/apps/alsijil/frontend/messages/en.json b/aleksis/apps/alsijil/frontend/messages/en.json
index a40f8d547..99ce86919 100644
--- a/aleksis/apps/alsijil/frontend/messages/en.json
+++ b/aleksis/apps/alsijil/frontend/messages/en.json
@@ -85,7 +85,8 @@
           "summary": "Summary"
         },
         "person_view_details": "Details",
-        "title_plural": "Statistics"
+        "title_plural": "Statistics",
+        "not_counted": "not counted"
       },
       "notes": {
         "show_list": "List of participants",
diff --git a/aleksis/apps/alsijil/schema/documentation.py b/aleksis/apps/alsijil/schema/documentation.py
index ad88b2de3..9548581a6 100644
--- a/aleksis/apps/alsijil/schema/documentation.py
+++ b/aleksis/apps/alsijil/schema/documentation.py
@@ -48,6 +48,7 @@ class DocumentationType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectTyp
 
     course = graphene.Field(CourseType, required=False)
     amends = graphene.Field(lambda: LessonEventType, required=False)
+    amended = graphene.Boolean(required=False)
     subject = graphene.Field(SubjectType, required=False)
     participations = graphene.List(ParticipationStatusType, required=False)
 
@@ -66,6 +67,11 @@ class DocumentationType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectTyp
             return root._amends_prefetched
         return root.amends
 
+    @staticmethod
+    @bypass_get_queryset
+    def resolve_amended(root: Documentation, info, **kwargs):
+        return root.amends_id is not None
+
     @staticmethod
     @bypass_get_queryset
     def resolve_teachers(root: Documentation, info, **kwargs):
-- 
GitLab


From d43b44bd75d97a293bbc4b876fc92c0804475744 Mon Sep 17 00:00:00 2001
From: Jonathan Weth <git@jonathanweth.de>
Date: Fri, 24 Jan 2025 18:25:45 +0100
Subject: [PATCH 3/4] Fix query

---
 .../frontend/components/extra_marks/ExtraMarkButtons.vue      | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/aleksis/apps/alsijil/frontend/components/extra_marks/ExtraMarkButtons.vue b/aleksis/apps/alsijil/frontend/components/extra_marks/ExtraMarkButtons.vue
index 01deef401..8a8485bcc 100644
--- a/aleksis/apps/alsijil/frontend/components/extra_marks/ExtraMarkButtons.vue
+++ b/aleksis/apps/alsijil/frontend/components/extra_marks/ExtraMarkButtons.vue
@@ -1,5 +1,5 @@
 <script>
-import { extraMarks } from "./extra_marks.graphql";
+import { extraMarksList } from "./extra_marks.graphql";
 
 export default {
   name: "ExtraMarkButtons",
@@ -10,7 +10,7 @@ export default {
   },
   apollo: {
     extraMarks: {
-      query: extraMarks,
+      query: extraMarksList,
       update: (data) => data.items,
       skip() {
         return this.customExtraMarks.length > 0;
-- 
GitLab


From 7faa1dfbe012c141e6506ddf7ba6a36abe6db412 Mon Sep 17 00:00:00 2001
From: Jonathan Weth <git@jonathanweth.de>
Date: Fri, 24 Jan 2025 18:25:53 +0100
Subject: [PATCH 4/4] Add print button to coursebook group tab

---
 .../coursebook/CoursebookPrintDialog.vue        | 17 +++++++++++++++--
 .../statistics/StatisticsForGroupTab.vue        |  9 +++++++--
 2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/CoursebookPrintDialog.vue b/aleksis/apps/alsijil/frontend/components/coursebook/CoursebookPrintDialog.vue
index 976dccbeb..8a9058d6d 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/CoursebookPrintDialog.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/CoursebookPrintDialog.vue
@@ -20,9 +20,10 @@ import CancelButton from "aleksis.core/components/generic/buttons/CancelButton.v
       {{ $t("alsijil.coursebook.print.title") }}
     </template>
     <template #content>
-      {{ $t("alsijil.coursebook.print.groups") }}
       <v-autocomplete
+        v-if="!group"
         :items="availableGroups"
+        :label="$t('alsijil.coursebook.print.groups')"
         item-text="name"
         item-value="id"
         :value="value"
@@ -87,7 +88,16 @@ export default {
      */
     availableGroups: {
       type: Array,
-      required: true,
+      required: false,
+      default: () => [],
+    },
+    /**
+     * Set a group to use this dialog exclusively for
+     */
+    group: {
+      type: Object,
+      required: false,
+      default: null,
     },
     /**
      * Initially selected groups
@@ -121,6 +131,9 @@ export default {
   },
   computed: {
     selectedGroups() {
+      if (this.group) {
+        return [this.group.id];
+      }
       if (this.currentGroupSelection.length == 0) {
         return this.value.map((group) => group.id);
       } else {
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/statistics/StatisticsForGroupTab.vue b/aleksis/apps/alsijil/frontend/components/coursebook/statistics/StatisticsForGroupTab.vue
index 95d377ac6..1575348b9 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/statistics/StatisticsForGroupTab.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/statistics/StatisticsForGroupTab.vue
@@ -10,6 +10,9 @@
     :show-select="false"
     @items="items = $event"
   >
+    <template #additionalActions>
+      <coursebook-print-dialog :group="group" />
+    </template>
     <template
       v-for="(extraMark, index) in extraMarks"
       #[`extraMarks.${index}.count`]="{ item }"
@@ -67,7 +70,7 @@
         :to="{
           name: 'core.personById',
           params: {
-            personId: item.person.id,
+            id: item.person.id,
           },
           hash: '#' + MODE.PARTICIPATIONS,
         }"
@@ -81,13 +84,14 @@ import groupOverviewTabMixin from "aleksis.core/mixins/groupOverviewTabMixin.js"
 import CRUDList from "aleksis.core/components/generic/CRUDList.vue";
 import PersonChip from "aleksis.core/components/person/PersonChip.vue";
 import SecondaryActionButton from "aleksis.core/components/generic/buttons/SecondaryActionButton.vue";
+import CoursebookPrintDialog from "../CoursebookPrintDialog.vue";
 
 import AbsenceReasonChip from "aleksis.apps.kolego/components/AbsenceReasonChip.vue";
 import ExtraMarkChip from "aleksis.apps.alsijil/components/extra_marks/ExtraMarkChip.vue";
 
 import { statisticsByGroup } from "./statistics.graphql";
 import { absenceReasons } from "../queries/absenceReasons.graphql";
-import { extraMarks } from "../../extra_marks/extra_marks.graphql";
+import { extraMarks } from "../queries/extraMarks.graphql";
 import { MODE } from "./modes";
 
 export default {
@@ -99,6 +103,7 @@ export default {
     ExtraMarkChip,
     PersonChip,
     SecondaryActionButton,
+    CoursebookPrintDialog,
   },
   data() {
     return {
-- 
GitLab