Skip to content
Snippets Groups Projects
Verified Commit 46a485e8 authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Add first real queries for class register statistics

parent d05affe7
No related branches found
No related tags found
1 merge request!361Resolve "Add statistics page for absences"
Pipeline #190337 failed
...@@ -91,6 +91,9 @@ export default { ...@@ -91,6 +91,9 @@ export default {
...term, ...term,
}; };
}, },
skip() {
return !this.schoolTerm;
},
}, },
}, },
methods: { methods: {
......
fragment statistics on StatisticsByPersonType { fragment statistics on StatisticsByPersonType {
schoolTerm
participationCount participationCount
absenceCount absenceCount
absenceReasons { absenceReasons {
...@@ -27,7 +26,7 @@ fragment statistics on StatisticsByPersonType { ...@@ -27,7 +26,7 @@ fragment statistics on StatisticsByPersonType {
} }
} }
query statisticsByPerson($person: ID!, $term: ID) { query statisticsByPerson($person: ID!, $term: ID!) {
statistics: statisticsByPerson(person: $person, term: $term) { statistics: statisticsByPerson(person: $person, term: $term) {
...statistics ...statistics
} }
......
...@@ -10,10 +10,11 @@ from calendarweek import CalendarWeek ...@@ -10,10 +10,11 @@ from calendarweek import CalendarWeek
from aleksis.apps.alsijil.managers import PersonalNoteQuerySet from aleksis.apps.alsijil.managers import PersonalNoteQuerySet
from aleksis.apps.chronos.models import Event, ExtraLesson, LessonPeriod from aleksis.apps.chronos.models import Event, ExtraLesson, LessonPeriod
from aleksis.core.models import Group, Person from aleksis.apps.kolego.models import AbsenceReason
from aleksis.core.models import Group, Person, SchoolTerm
from aleksis.core.util.core_helpers import get_site_preferences from aleksis.core.util.core_helpers import get_site_preferences
from .models import ExcuseType, ExtraMark, LessonDocumentation, PersonalNote from .models import Documentation, ExcuseType, ExtraMark, LessonDocumentation, PersonalNote
def alsijil_url( def alsijil_url(
...@@ -493,3 +494,81 @@ def generate_person_list_with_class_register_statistics( ...@@ -493,3 +494,81 @@ def generate_person_list_with_class_register_statistics(
) )
return persons return persons
def annotate_person_statistics(
persons: QuerySet[Person], participations_filter: Q, personal_notes_filter: Q
) -> QuerySet[Person]:
"""Annotate a queryset of persons with class register statistics."""
persons = persons.annotate(
filtered_participation_statuses=FilteredRelation(
"participations",
condition=(participations_filter),
),
filtered_personal_notes=FilteredRelation(
"new_personal_notes",
condition=(personal_notes_filter),
),
).annotate(
participation_count=Count(
"filtered_participation_statuses",
filter=Q(filtered_participation_statuses__absence_reason__isnull=True),
distinct=True,
),
absence_count=Count(
"filtered_participation_statuses",
filter=Q(filtered_participation_statuses__absence_reason__count_as_absent=True),
distinct=True,
),
# tardiness=Sum("filtered_participation_statuses__tardiness"),
# tardiness_count=Count(
# "filtered_personal_notes",
# filter=Q(filtered_personal_notes__tardiness__gt=0),
# distinct=True,
# ),
)
persons = persons.order_by("last_name", "first_name")
for absence_reason in AbsenceReason.objects.all():
persons = persons.annotate(
**{
absence_reason.count_label: Count(
"filtered_participation_statuses",
filter=Q(
filtered_participation_statuses__absence_reason=absence_reason,
),
distinct=True,
)
}
)
for extra_mark in ExtraMark.objects.all():
persons = persons.annotate(
**{
extra_mark.count_label: Count(
"filtered_personal_notes",
filter=Q(filtered_personal_notes__extra_mark=extra_mark),
distinct=True,
)
}
)
return persons
def annotate_person_statistics_for_school_term(
persons: QuerySet[Person], school_term: SchoolTerm
) -> QuerySet[Person]:
"""Annotate a queryset of persons with class register statistics for a school term."""
documentations = Documentation.objects.filter(
participations__person__in=persons,
datetime_start__date__gte=school_term.date_start,
datetime_end__date__lte=school_term.date_end,
)
docs = list(documentations.values_list("pk", flat=True))
return annotate_person_statistics(
persons,
Q(participations__related_documentation__in=docs),
Q(new_personal_notes__documentation__in=docs),
)
...@@ -8,11 +8,12 @@ import graphene ...@@ -8,11 +8,12 @@ import graphene
from aleksis.apps.chronos.models import LessonEvent from aleksis.apps.chronos.models import LessonEvent
from aleksis.apps.cursus.models import Course from aleksis.apps.cursus.models import Course
from aleksis.apps.cursus.schema import CourseType from aleksis.apps.cursus.schema import CourseType
from aleksis.core.models import Group, Person from aleksis.core.models import Group, Person, SchoolTerm
from aleksis.core.schema.base import FilterOrderList from aleksis.core.schema.base import FilterOrderList
from aleksis.core.schema.group import GroupType from aleksis.core.schema.group import GroupType
from aleksis.core.util.core_helpers import has_person from aleksis.core.util.core_helpers import has_person
from ..model_extensions import annotate_person_statistics_for_school_term
from ..models import Documentation from ..models import Documentation
from .absences import ( from .absences import (
AbsencesBatchCreateMutation, AbsencesBatchCreateMutation,
...@@ -58,7 +59,7 @@ class Query(graphene.ObjectType): ...@@ -58,7 +59,7 @@ class Query(graphene.ObjectType):
statistics_by_person = graphene.Field( statistics_by_person = graphene.Field(
StatisticsByPersonType, StatisticsByPersonType,
person=graphene.ID(required=True), person=graphene.ID(required=True),
term=graphene.ID(required=False), term=graphene.ID(required=True),
) )
documentations_by_person = graphene.List( documentations_by_person = graphene.List(
DocumentationByPersonType, DocumentationByPersonType,
...@@ -68,7 +69,7 @@ class Query(graphene.ObjectType): ...@@ -68,7 +69,7 @@ class Query(graphene.ObjectType):
statistics_by_group = graphene.List( statistics_by_group = graphene.List(
StatisticsByPersonType, StatisticsByPersonType,
group=graphene.ID(required=True), group=graphene.ID(required=True),
term=graphene.ID(required=False), term=graphene.ID(required=True),
) )
def resolve_documentations_by_course_id(root, info, course_id, **kwargs): def resolve_documentations_by_course_id(root, info, course_id, **kwargs):
...@@ -190,9 +191,11 @@ class Query(graphene.ObjectType): ...@@ -190,9 +191,11 @@ class Query(graphene.ObjectType):
return lessons_for_person return lessons_for_person
@staticmethod @staticmethod
def resolve_statistics_by_person(root, info, person, term=None): def resolve_statistics_by_person(root, info, person, term):
# TODO: Annotate person with necessary information for term. school_term = SchoolTerm.objects.get(id=term)
return Person.objects.get(id=person) return annotate_person_statistics_for_school_term(
Person.objects.filter(id=person), school_term
).first()
@staticmethod @staticmethod
def resolve_documentations_by_person(root, info, person, term=None): def resolve_documentations_by_person(root, info, person, term=None):
...@@ -200,9 +203,11 @@ class Query(graphene.ObjectType): ...@@ -200,9 +203,11 @@ class Query(graphene.ObjectType):
return Person.objects.get(id=person) return Person.objects.get(id=person)
@staticmethod @staticmethod
def resolve_statistics_by_group(root, info, group, term=None): def resolve_statistics_by_group(root, info, group, term):
# TODO: Annotate persons with necessary information for term. school_term = SchoolTerm.objects.get(id=term)
return Group.objects.get(id=group).members.all()
members = Group.objects.get(id=group).members.all()
return annotate_person_statistics_for_school_term(members, school_term)
class Mutation(graphene.ObjectType): class Mutation(graphene.ObjectType):
......
import graphene import graphene
from aleksis.apps.cursus.models import Subject
from aleksis.apps.cursus.schema import SubjectType from aleksis.apps.cursus.schema import SubjectType
from aleksis.apps.kolego.models.absence import AbsenceReason from aleksis.apps.kolego.models.absence import AbsenceReason
from aleksis.apps.kolego.schema.absence import AbsenceReasonType from aleksis.apps.kolego.schema.absence import AbsenceReasonType
...@@ -15,10 +16,10 @@ class AbsenceReasonWithCountType(graphene.ObjectType): ...@@ -15,10 +16,10 @@ class AbsenceReasonWithCountType(graphene.ObjectType):
count = graphene.Int() count = graphene.Int()
def resolve_absence_reason(root, info): def resolve_absence_reason(root, info):
return root return root["absence_reason"]
def resolve_count(root, info): def resolve_count(root, info):
return 6 return root["count"]
class ExtraMarkWithCountType(graphene.ObjectType): class ExtraMarkWithCountType(graphene.ObjectType):
...@@ -26,14 +27,13 @@ class ExtraMarkWithCountType(graphene.ObjectType): ...@@ -26,14 +27,13 @@ class ExtraMarkWithCountType(graphene.ObjectType):
count = graphene.Int() count = graphene.Int()
def resolve_extra_mark(root, info): def resolve_extra_mark(root, info):
return root return root["extra_mark"]
def resolve_count(root, info): def resolve_count(root, info):
return 7 return root["count"]
class StatisticsByPersonType(graphene.ObjectType): class StatisticsByPersonType(graphene.ObjectType):
school_term = graphene.Int()
participation_count = graphene.Int() participation_count = graphene.Int()
absence_count = graphene.Int() absence_count = graphene.Int()
absence_reasons = graphene.List(AbsenceReasonWithCountType) absence_reasons = graphene.List(AbsenceReasonWithCountType)
...@@ -41,19 +41,11 @@ class StatisticsByPersonType(graphene.ObjectType): ...@@ -41,19 +41,11 @@ class StatisticsByPersonType(graphene.ObjectType):
tardiness_count = graphene.Int() tardiness_count = graphene.Int()
extra_marks = graphene.List(ExtraMarkWithCountType) extra_marks = graphene.List(ExtraMarkWithCountType)
def resolve_school_term(root, info):
return 4
def resolve_participation_count(root, info):
return 3
def resolve_absence_count(root, info):
return 1
def resolve_absence_reasons(root, info): def resolve_absence_reasons(root, info):
# TODO: Return actual AbsenceReasons return [
# Needed by resolve_absence_count as well. dict(absence_reason=reason, count=getattr(root, reason.count_label))
return AbsenceReason.objects.all() for reason in AbsenceReason.objects.all()
]
def resolve_tardiness_sum(root, info): def resolve_tardiness_sum(root, info):
return 17 return 17
...@@ -62,8 +54,10 @@ class StatisticsByPersonType(graphene.ObjectType): ...@@ -62,8 +54,10 @@ class StatisticsByPersonType(graphene.ObjectType):
return 5 return 5
def resolve_extra_marks(root, info): def resolve_extra_marks(root, info):
# TODO: Return actual ExtraMarks return [
return ExtraMark.objects.all() dict(extra_mark=extra_mark, count=getattr(root, extra_mark.count_label))
for extra_mark in ExtraMark.objects.all()
]
class DocumentationByPersonType(graphene.ObjectType): class DocumentationByPersonType(graphene.ObjectType):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment