Skip to content
Snippets Groups Projects

Resolve "Add export functionality to course book"

Merged permcu requested to merge 258-add-export-functionality-to-course-book into master
1 file
+ 186
186
Compare changes
  • Side-by-side
  • Inline
+ 162
181
# from copy import deepcopy
# from datetime import date, timedelta
from datetime import date
from typing import List, Optional
# from django.db.models import Q
# from django.utils.translation import gettext as _
from django.db.models import Prefetch, Q
from django.utils.translation import gettext as _
# from calendarweek import CalendarWeek
# from celery.result import allow_join_result
# from celery.states import SUCCESS
from celery.result import allow_join_result
from celery.states import SUCCESS
# from aleksis.core.models import Group, PDFFile
from aleksis.apps.cursus.models import Course
from aleksis.apps.kolego.models.absence import AbsenceReason
from aleksis.core.models import Group, PDFFile
from aleksis.core.util.celery_progress import ProgressRecorder, recorded_task
from aleksis.core.util.pdf import generate_pdf_from_template
# from aleksis.core.util.pdf import generate_pdf_from_template
# from .models import ExtraMark
from .model_extensions import annotate_person_statistics_from_documentations
from .models import Documentation, ExtraMark, NewPersonalNote, ParticipationStatus
@recorded_task
def generate_full_register_printout(group: int, file_object: int, recorder: ProgressRecorder):
"""Generate a full register printout as PDF for a group."""
# context = {}
# _number_of_steps = 8
# recorder.set_progress(1, _number_of_steps, _("Load data ..."))
# group = Group.objects.get(pk=group)
# file_object = PDFFile.objects.get(pk=file_object)
# groups_q = (
# Q(lesson_period__lesson__groups=group)
# | Q(lesson_period__lesson__groups__parent_groups=group)
# | Q(extra_lesson__groups=group)
# | Q(extra_lesson__groups__parent_groups=group)
# | Q(event__groups=group)
# | Q(event__groups__parent_groups=group)
# )
# personal_notes = (
# PersonalNote.objects.prefetch_related(
# "lesson_period__substitutions", "lesson_period__lesson__teachers"
# )
# .not_empty()
# .filter(groups_q)
# .filter(groups_of_person=group)
# )
# documentations = LessonDocumentation.objects.not_empty().filter(groups_q)
# recorder.set_progress(2, _number_of_steps, _("Sort data ..."))
# sorted_documentations = {"extra_lesson": {}, "event": {}, "lesson_period": {}}
# sorted_personal_notes = {"extra_lesson": {}, "event": {}, "lesson_period": {}, "person": {}}
# for documentation in documentations:
# key = documentation.register_object.label_
# sorted_documentations[key][documentation.register_object_key] = documentation
# for note in personal_notes:
# key = note.register_object.label_
# sorted_personal_notes[key].setdefault(note.register_object_key, [])
# sorted_personal_notes[key][note.register_object_key].append(note)
# sorted_personal_notes["person"].setdefault(note.person.pk, [])
# sorted_personal_notes["person"][note.person.pk].append(note)
# recorder.set_progress(3, _number_of_steps, _("Load lesson data ..."))
# # Get all lesson periods for the selected group
# lesson_periods = LessonPeriod.objects.filter_group(group).distinct()
# events = Event.objects.filter_group(group).distinct()
# extra_lessons = ExtraLesson.objects.filter_group(group).distinct()
# weeks = CalendarWeek.weeks_within(group.school_term.date_start, group.school_term.date_end)
# register_objects_by_day = {}
# for extra_lesson in extra_lessons:
# day = extra_lesson.date
# register_objects_by_day.setdefault(day, []).append(
# (
# extra_lesson,
# sorted_documentations["extra_lesson"].get(extra_lesson.pk),
# sorted_personal_notes["extra_lesson"].get(extra_lesson.pk, []),
# None,
# )
# )
# for event in events:
# day_number = (event.date_end - event.date_start).days + 1
# for i in range(day_number):
# day = event.date_start + timedelta(days=i)
# event_copy = deepcopy(event)
# event_copy.annotate_day(day)
# # Skip event days if it isn't inside the timetable schema
# if not (event_copy.raw_period_from_on_day and event_copy.raw_period_to_on_day):
# continue
# register_objects_by_day.setdefault(day, []).append(
# (
# event_copy,
# sorted_documentations["event"].get(event.pk),
# sorted_personal_notes["event"].get(event.pk, []),
# None,
# )
# )
# recorder.set_progress(4, _number_of_steps, _("Sort lesson data ..."))
# weeks = CalendarWeek.weeks_within(
# group.school_term.date_start,
# group.school_term.date_end,
# )
# for lesson_period in lesson_periods:
# for week in weeks:
# day = week[lesson_period.period.weekday]
# if (
# lesson_period.lesson.validity.date_start
# <= day
# <= lesson_period.lesson.validity.date_end
# ):
# filtered_documentation = sorted_documentations["lesson_period"].get(
# f"{lesson_period.pk}_{week.week}_{week.year}"
# )
# filtered_personal_notes = sorted_personal_notes["lesson_period"].get(
# f"{lesson_period.pk}_{week.week}_{week.year}", []
# )
# substitution = lesson_period.get_substitution(week)
# register_objects_by_day.setdefault(day, []).append(
# (lesson_period, filtered_documentation, filtered_personal_notes, substitution)
# )
# recorder.set_progress(5, _number_of_steps, _("Load statistics ..."))
# persons = group.members.prefetch_related(None).select_related(None)
# persons = group.generate_person_list_with_class_register_statistics(persons)
# prefetched_persons = []
# for person in persons:
# person.filtered_notes = sorted_personal_notes["person"].get(person.pk, [])
# prefetched_persons.append(person)
# context["school_term"] = group.school_term
# context["persons"] = prefetched_persons
# 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
# context["register_objects_by_day"] = register_objects_by_day
# context["register_objects"] = list(lesson_periods) + list(events) + list(extra_lessons)
# context["today"] = date.today()
# context["lessons"] = (
# group.lessons.all()
# .select_related(None)
# .prefetch_related(None)
# .select_related("validity", "subject")
# .prefetch_related("teachers", "lesson_periods")
# )
# context["child_groups"] = (
# group.child_groups.all()
# .select_related(None)
# .prefetch_related(None)
# .prefetch_related(
# "lessons",
# "lessons__validity",
# "lessons__subject",
# "lessons__teachers",
# "lessons__lesson_periods",
# )
# )
# recorder.set_progress(6, _number_of_steps, _("Generate template ..."))
# file_object, result = generate_pdf_from_template(
# "alsijil/print/full_register.html", context, file_object=file_object
# )
# recorder.set_progress(7, _number_of_steps, _("Generate PDF ..."))
# with allow_join_result():
# result.wait()
# file_object.refresh_from_db()
# if not result.status == SUCCESS and file_object.file:
# raise Exception(_("PDF generation failed"))
# recorder.set_progress(8, _number_of_steps)
def generate_full_register_printout(
groups: List[int],
file_object: int,
recorder: ProgressRecorder,
include_cover: Optional[bool] = True,
include_abbreviations: Optional[bool] = True,
include_members_table: Optional[bool] = True,
include_teachers_and_subjects_table: Optional[bool] = True,
include_person_overviews: Optional[bool] = True,
include_coursebook: Optional[bool] = True,
):
"""Generate a configurable register printout as PDF for a group."""
def prefetch_notable_participations(select_related=None, prefetch_related=None):
if not select_related:
select_related = []
if not prefetch_related:
prefetch_related = []
return Prefetch(
"participations",
to_attr="notable_participations",
queryset=ParticipationStatus.objects.filter(
Q(absence_reason__tags__short_name="class_register") | Q(tardiness__isnull=False)
)
.select_related("absence_reason", *select_related)
.prefetch_related(*prefetch_related),
)
def prefetch_personal_notes(name, select_related=None, prefetch_related=None):
if not select_related:
select_related = []
if not prefetch_related:
prefetch_related = []
return Prefetch(
name,
queryset=NewPersonalNote.objects.filter(Q(note__gt="") | Q(extra_mark__isnull=False))
.select_related("extra_mark", *select_related)
.prefetch_related(*prefetch_related),
)
context = {}
context["include_cover"] = include_cover
context["include_abbreviations"] = include_abbreviations
context["include_members_table"] = include_members_table
context["include_teachers_and_subjects_table"] = include_teachers_and_subjects_table
context["include_person_overviews"] = include_person_overviews
context["include_coursebook"] = include_coursebook
context["today"] = date.today()
_number_of_steps = 5 + len(groups)
recorder.set_progress(1, _number_of_steps, _("Loading data ..."))
groups = Group.objects.filter(pk__in=groups).order_by("name")
if include_cover:
groups = groups.select_related("school_term")
if include_abbreviations or include_members_table:
context["absence_reasons"] = AbsenceReason.objects.filter(
tags__short_name="class_register", count_as_absent=True
)
context["absence_reasons_not_counted"] = AbsenceReason.objects.filter(
tags__short_name="class_register", count_as_absent=False
)
context["extra_marks"] = ExtraMark.objects.all()
if include_members_table or include_person_overviews:
groups = groups.prefetch_related("members")
if include_teachers_and_subjects_table:
groups = groups.prefetch_related(
Prefetch("courses", queryset=Course.objects.select_related("subject")),
"courses__teachers",
"child_groups",
Prefetch("child_groups__courses", queryset=Course.objects.select_related("subject")),
"child_groups__courses__teachers",
)
recorder.set_progress(2, _number_of_steps, _("Loading groups ..."))
for i, group in enumerate(groups, start=1):
recorder.set_progress(
2 + i, _number_of_steps, _(f"Loading group {group.short_name or group.name} ...")
)
if include_members_table or include_person_overviews or include_coursebook:
documentations = Documentation.objects.filter(
Q(datetime_start__date__gte=group.school_term.date_start)
& Q(datetime_end__date__lte=group.school_term.date_end)
& Q(
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)
)
)
)
if include_members_table or include_person_overviews:
group.members_with_stats = annotate_person_statistics_from_documentations(
group.members.all(), documentations
)
if include_person_overviews:
doc_query_set = documentations.select_related("subject").prefetch_related("teachers")
group.members_with_stats = group.members_with_stats.prefetch_related(
prefetch_notable_participations(
prefetch_related=[Prefetch("related_documentation", queryset=doc_query_set)]
),
prefetch_personal_notes(
"new_personal_notes",
prefetch_related=[Prefetch("documentation", queryset=doc_query_set)],
),
)
if include_teachers_and_subjects_table:
group.as_list = [group]
if include_coursebook:
group.documentations = documentations.order_by(
"datetime_start"
).prefetch_related(
prefetch_notable_participations(select_related=["person"]),
prefetch_personal_notes("personal_notes", select_related=["person"]),
)
context["groups"] = groups
recorder.set_progress(3 + len(groups), _number_of_steps, _("Generating template ..."))
file_object, result = generate_pdf_from_template(
"alsijil/print/register_for_group.html",
context,
file_object=PDFFile.objects.get(pk=file_object),
)
recorder.set_progress(4 + len(groups), _number_of_steps, _("Generating PDF ..."))
with allow_join_result():
result.wait()
file_object.refresh_from_db()
if not result.status == SUCCESS and file_object.file:
raise Exception(_("PDF generation failed"))
recorder.set_progress(5 + len(groups), _number_of_steps)
Loading