Skip to content
Snippets Groups Projects
  • magicfelix's avatar
    c9a56bb2
    Adapt substitution PDF to new data model · c9a56bb2
    magicfelix authored and Jonathan Weth's avatar Jonathan Weth committed
    diff --git a/aleksis/apps/chronos/models.py b/aleksis/apps/chronos/models.py
    index 35f4e01..f348c00 100644
    --- a/aleksis/apps/chronos/models.py
    +++ b/aleksis/apps/chronos/models.py
    @@ -1221,6 +1221,7 @@ class AutomaticPlan(LiveDocument):
             from aleksis.apps.chronos.util.chronos_helpers import get_substitutions_context_data  # noqa
    
             context = get_substitutions_context_data(
    +            wanted_day=date.today(),
                 request=None,
                 is_print=True,
                 number_of_days=self.number_of_days,
    diff --git a/aleksis/apps/chronos/templates/chronos/partials/rooms.html b/aleksis/apps/chronos/templates/chronos/partials/rooms.html
    new file mode 100644
    index 0000000..1e42988
    --- /dev/null
    +++ b/aleksis/apps/chronos/templates/chronos/partials/rooms.html
    @@ -0,0 +1,8 @@
    +{% for room in rooms %}
    +  <span data-position="bottom" class="tooltipped"
    +        data-tooltip="{{ room }}">
    +      <a href="{% url "timetable" "room" room.pk %}">
    +          {{ room.short_name }}{% if not forloop.last %},{% endif %}
    +      </a>
    +  </span>
    +{% endfor %}
    diff --git a/aleksis/apps/chronos/templates/chronos/partials/subs/badge.html b/aleksis/apps/chronos/templates/chronos/partials/subs/badge.html
    index c04c9dd..c807244 100644
    --- a/aleksis/apps/chronos/templates/chronos/partials/subs/badge.html
    +++ b/aleksis/apps/chronos/templates/chronos/partials/subs/badge.html
    @@ -2,6 +2,4 @@
    
     {% if sub.cancelled %}
       <span class="badge new green">{% trans "Cancelled" %}</span>
    -{% elif item.el.cancelled_for_teachers %}
    -  <span class="badge new green">{% trans "Cancelled for teachers" %}</span>
     {% endif %}
    diff --git a/aleksis/apps/chronos/templates/chronos/partials/subs/colour.html b/aleksis/apps/chronos/templates/chronos/partials/subs/colour.html
    index 833a24b..e59b37f 100644
    --- a/aleksis/apps/chronos/templates/chronos/partials/subs/colour.html
    +++ b/aleksis/apps/chronos/templates/chronos/partials/subs/colour.html
    @@ -1,11 +1,5 @@
    -{% if item.type == "substitution" %}
    -  {% if item.el.cancelled or item.el.cancelled_for_teachers %}
    -    green-text
    -  {% else %}
    -    black-text
    -  {% endif %}
    -{% elif item.type == "supervision_substitution" %}
    -  blue-text
    -{% elif item.type == "event" %}
    -  purple-text
    +{% if item.el.cancelled %}
    +  green-text
    +{% else %}
    +  black-text
     {% endif %}
    diff --git a/aleksis/apps/chronos/templates/chronos/partials/subs/groups.html b/aleksis/apps/chronos/templates/chronos/partials/subs/groups.html
    index d1a4da9..079e0f0 100644
    --- a/aleksis/apps/chronos/templates/chronos/partials/subs/groups.html
    +++ b/aleksis/apps/chronos/templates/chronos/partials/subs/groups.html
    @@ -1,5 +1,15 @@
    -{% if type == "substitution" %}
    -  {% include "chronos/partials/groups.html" with groups=el.lesson_period.lesson.groups.all %}
    -{% elif type == "extra_lesson" or type == "event" %}
    +{% if el.cancelled and el.amends.groups.all %}
    +  {% include "chronos/partials/groups.html" with groups=el.amends.groups.all %}
    +{% elif el.groups.all and el.amends.groups.all %}
    +  <s>
    +    {% include "chronos/partials/groups.html" with groups=el.amends.groups.all %}
    +  </s>
    +  →
    +  <strong>
    +    {% include "chronos/partials/groups.html" with groups=el.groups.all %}
    +  </strong>
    +{% elif el.groups.all and not el.amends.groups.all %}
       {% include "chronos/partials/groups.html" with groups=el.groups.all %}
    +{% elif el.amends.groups.all %}
    +  {% include "chronos/partials/groups.html" with groups=el.amends.groups.all %}
     {% endif %}
    diff --git a/aleksis/apps/chronos/templates/chronos/partials/subs/period.html b/aleksis/apps/chronos/templates/chronos/partials/subs/period.html
    index ef1d283..4ba7706 100644
    --- a/aleksis/apps/chronos/templates/chronos/partials/subs/period.html
    +++ b/aleksis/apps/chronos/templates/chronos/partials/subs/period.html
    @@ -1,19 +1,7 @@
     <strong>
    -  {% if type == "substitution" and item.start_period == item.end_period %}
    -    {{ el.lesson_period.period.period }}.
    -  {% elif type == "substitution"  %}
    -    {{ item.start_period }}.–{{ item.end_period }}.
    -  {% elif type == "extra_lesson" %}
    -    {{ el.period.period }}.
    -  {% elif type == "event" %}
    -    {% if el.period_from_on_day == el.period_to_on_day %}
    -      {{ el.period_from_on_day }}.
    -    {% else %}
    -      {{ el.period_from_on_day }}.–{{ el.period_to_on_day }}.
    -    {% endif %}
    -  {% elif type == "supervision_substitution" %}
    -    {% with break=el.supervision.break_item %}
    -      {{ break.after_period_number }}./{{ break.before_period_number }}.
    -    {% endwith %}
    +  {% if el.datetime_start %}
    +    {{ el.datetime_start.time }} - {{ el.datetime_end.time }}
    +  {% elif el.date_start %}
    +    {{ el.date_start }} - {{ el.date_end }}
       {% endif %}
     </strong>
    diff --git a/aleksis/apps/chronos/templates/chronos/partials/subs/room.html b/aleksis/apps/chronos/templates/chronos/partials/subs/room.html
    index 94f2d35..123faba 100644
    --- a/aleksis/apps/chronos/templates/chronos/partials/subs/room.html
    +++ b/aleksis/apps/chronos/templates/chronos/partials/subs/room.html
    @@ -1,39 +1,15 @@
    -{% if type == "substitution" %}
    -  {% if el.cancelled or el.cancelled_for_teachers %}
    -    {# Cancelled lesson: no room #}
    -  {% elif el.room and el.lesson_period.room %}
    -    {# New and old room available #}
    -    <span class="tooltipped" data-position="bottom"
    -          data-tooltip="{{ el.lesson_period.room.name }} → {{ el.room.name }}"
    -          title="{{ el.lesson_period.room.name }} → {{ el.room.name }}">
    -      <a href="{% url "timetable" "room" el.lesson_period.room.pk %}">
    -          <s>{{ el.lesson_period.room.short_name }}</s>
    -      </a>
    -      →
    -      <a href="{% url "timetable" "room" el.room.pk %}">
    -          <strong>{{ el.room.short_name }}</strong>
    -      </a>
    -    </span>
    -  {% elif el.room and not el.lesson_period.room %}
    -    {# Only new room available #}
    -    {% include "chronos/partials/room.html" with room=el.room %}
    -  {% elif not el.room and not el.lesson_period.room %}
    -    {# Nothing to view #}
    -  {% else %}
    -    {# Only old room available #}
    -    {% include "chronos/partials/room.html" with room=el.lesson_period.room %}
    -  {% endif %}
    -{% elif type == "supervision_substitution" %}
    -  {% with supervision=el.supervision %}
    -    <span data-position="bottom" class="tooltipped"
    -          data-tooltip="{{ supervision.area.name }}" title="{{ supervision.area.name }}">
    -      {{ supervision.area.short_name }}
    -    </span>
    -  {% endwith %}
    -{% elif type == "extra_lesson" %}
    -  {% include "chronos/partials/room.html" with room=el.room %}
    -{% elif type == "event" %}
    -  {% for room in el.rooms.all %}
    -    {% include "chronos/partials/room.html" with room=room %}{% if not forloop.last %},{% endif %}
    -  {% endfor %}
    +{% if el.cancelled and el.amends.rooms.all %}
    +  {% include "chronos/partials/rooms.html" with rooms=el.amends.rooms.all %}
    +{% elif el.rooms.all and el.amends.rooms.all %}
    +  <s>
    +    {% include "chronos/partials/rooms.html" with rooms=el.amends.rooms.all %}
    +  </s>
    +  →
    +  <strong>
    +    {% include "chronos/partials/rooms.html" with rooms=el.rooms.all %}
    +  </strong>
    +{% elif el.rooms.all and not el.amends.rooms.all %}
    +  {% include "chronos/partials/rooms.html" with rooms=el.rooms.all %}
    +{% elif el.amends.rooms.all %}
    +  {% include "chronos/partials/rooms.html" with rooms=el.amends.rooms.all %}
     {% endif %}
    diff --git a/aleksis/apps/chronos/templates/chronos/partials/subs/rooms.html b/aleksis/apps/chronos/templates/chronos/partials/subs/rooms.html
    new file mode 100644
    index 0000000..123faba
    --- /dev/null
    +++ b/aleksis/apps/chronos/templates/chronos/partials/subs/rooms.html
    @@ -0,0 +1,15 @@
    +{% if el.cancelled and el.amends.rooms.all %}
    +  {% include "chronos/partials/rooms.html" with rooms=el.amends.rooms.all %}
    +{% elif el.rooms.all and el.amends.rooms.all %}
    +  <s>
    +    {% include "chronos/partials/rooms.html" with rooms=el.amends.rooms.all %}
    +  </s>
    +  →
    +  <strong>
    +    {% include "chronos/partials/rooms.html" with rooms=el.rooms.all %}
    +  </strong>
    +{% elif el.rooms.all and not el.amends.rooms.all %}
    +  {% include "chronos/partials/rooms.html" with rooms=el.rooms.all %}
    +{% elif el.amends.rooms.all %}
    +  {% include "chronos/partials/rooms.html" with rooms=el.amends.rooms.all %}
    +{% endif %}
    diff --git a/aleksis/apps/chronos/templates/chronos/partials/subs/subject.html b/aleksis/apps/chronos/templates/chronos/partials/subs/subject.html
    index 1b7a3c5..dcbfa4b 100644
    --- a/aleksis/apps/chronos/templates/chronos/partials/subs/subject.html
    +++ b/aleksis/apps/chronos/templates/chronos/partials/subs/subject.html
    @@ -1,28 +1,28 @@
     {% load i18n %}
    
    -{% if type == "substitution" %}
    -  {% if not el.lesson_period.lesson.subject and not el.subject %}
    -  {% elif el.cancelled or el.cancelled_for_teachers %}
    -    <span data-position="bottom" class="tooltipped" data-tooltip="{{ el.lesson_period.lesson.subject.name }}">
    -    <s>{{ el.lesson_period.lesson.subject.short_name }}</s>
    -  </span>
    -  {% elif el.subject and el.lesson_period.lesson.subject %}
    -    <span data-position="bottom" class="tooltipped" data-tooltip="{{ el.lesson_period.lesson.subject.name }}">
    -    <s>{{ el.lesson_period.lesson.subject.short_name }}</s>
    -  </span>
    -    →
    -    <span data-position="bottom" class="tooltipped" data-tooltip="{{ el.subject.name }}">
    -    <strong>{{ el.subject.short_name }}</strong>
    -  </span>
    -  {% elif el.subject and not el.lesson_period.lesson.subject %}
    -    {% include "chronos/partials/subject.html" with subject=el.subject %}
    -  {% else %}
    -    {% include "chronos/partials/subject.html" with subject=el.lesson_period.lesson.subject %}
    +{% if not el.amends.subject and not el.subject %}
    +  {% if el.amends.title %}
    +    <span data-position="bottom" class="tooltipped" data-tooltip="{{ el.amends.title }}">
    +    <s>{{ el.amends.title }}</s>
       {% endif %}
    -{% elif type == "supervision_substitution" %}
    -  {% trans "Supervision" %}
    -{% elif type == "extra_lesson" %}
    +  {% if el.title %}
    +    <span data-position="bottom" class="tooltipped" data-tooltip="{{ el.title }}">
    +    <s>{{ el.title }}</s>
    +  {% endif %}
    +{% elif el.cancelled %}
    +  <span data-position="bottom" class="tooltipped" data-tooltip="{{ el.subject.short_name }}">
    +  <s>{{ el.subject.short_name }}</s>
    +</span>
    +{% elif el.subject and el.amends.subject %}
    +  <span data-position="bottom" class="tooltipped" data-tooltip="{{ el.amends.subject.name }}">
    +  <s>{{ el.amends.subject.short_name }}</s>
    +</span>
    +  →
    +  <span data-position="bottom" class="tooltipped" data-tooltip="{{ el.subject.name }}">
    +  <strong>{{ el.subject.short_name }}</strong>
    +</span>
    +{% elif el.subject and not el.amends.subject %}
       {% include "chronos/partials/subject.html" with subject=el.subject %}
    -{% elif type == "event" %}
    -  {% trans "Event" %}
    +{% else %}
    +  {% include "chronos/partials/subject.html" with subject=el.amends.subject %}
     {% endif %}
    diff --git a/aleksis/apps/chronos/templates/chronos/partials/subs/teachers.html b/aleksis/apps/chronos/templates/chronos/partials/subs/teachers.html
    index 4fa80d8..9e08eeb 100644
    --- a/aleksis/apps/chronos/templates/chronos/partials/subs/teachers.html
    +++ b/aleksis/apps/chronos/templates/chronos/partials/subs/teachers.html
    @@ -1,27 +1,15 @@
    -{% if type == "substitution" %}
    -  {% if el.cancelled and el.lesson_period.lesson.teachers.all %}
    -    {% include "chronos/partials/teachers.html" with teachers=el.lesson_period.lesson.teachers.all %}
    -  {% elif el.teachers.all and el.lesson_period.lesson.teachers.all %}
    -    <s>
    -      {% include "chronos/partials/teachers.html" with teachers=el.lesson_period.lesson.teachers.all %}
    -    </s>
    -    →
    -    <strong>
    -      {% include "chronos/partials/teachers.html" with teachers=el.teachers.all %}
    -    </strong>
    -  {% elif el.teachers.all and not el.lesson_period.lesson.teachers.all %}
    -    {% include "chronos/partials/teachers.html" with teachers=el.teachers.all %}
    -  {% elif el.lesson_period.lesson.teachers.all %}
    -    {% include "chronos/partials/teachers.html" with teachers=el.lesson_period.lesson.teachers.all %}
    -  {% endif %}
    -{% elif type == "supervision_substitution" %}
    +{% if el.cancelled and el.amends.teachers.all %}
    +  {% include "chronos/partials/teachers.html" with teachers=el.amends.teachers.all %}
    +{% elif el.teachers.all and el.amends.teachers.all %}
       <s>
    -    {% include "chronos/partials/teachers.html" with teachers=el.supervision.teachers %}
    +    {% include "chronos/partials/teachers.html" with teachers=el.amends.teachers.all %}
       </s>
       →
       <strong>
    -    {% include "chronos/partials/teachers.html" with teachers=el.teachers %}
    +    {% include "chronos/partials/teachers.html" with teachers=el.teachers.all %}
       </strong>
    -{% elif type == "extra_lesson" or type == "event" %}
    +{% elif el.teachers.all and not el.amends.teachers.all %}
       {% include "chronos/partials/teachers.html" with teachers=el.teachers.all %}
    +{% elif el.amends.teachers.all %}
    +  {% include "chronos/partials/teachers.html" with teachers=el.amends.teachers.all %}
     {% endif %}
    diff --git a/aleksis/apps/chronos/templates/chronos/substitutions_print.html b/aleksis/apps/chronos/templates/chronos/substitutions_print.html
    index 743a223..10243a1 100644
    --- a/aleksis/apps/chronos/templates/chronos/substitutions_print.html
    +++ b/aleksis/apps/chronos/templates/chronos/substitutions_print.html
    @@ -18,13 +18,13 @@
    
         {% include "core/partials/announcements.html" with announcements=c.announcements show_recipients=1 %}
    
    -    {% include "chronos/partials/headerbox.html" with affected_teachers=c.affected_teachers affected_groups=c.affected_groups absent_teachers=c.absent_teachers absent_groups=c.absent_groups print=1 %}
    +    {% include "chronos/partials/headerbox.html" with absent_teachers=c.absent_teachers absent_groups=c.absent_groups print=1 %}
    
         <table class="substitutions">
           <thead>
           <tr>
    -        <th><i class="material-icons iconify center" data-icon="mdi:account-multiple-outline"></i></th>
    -        <th><i class="material-icons iconify center" data-icon="mdi:clock-outline"></i></th>
    +        <th>{% blocktrans %}Groups{% endblocktrans %}</th>
    +        <th>{% blocktrans %}Time{% endblocktrans %}</th>
             <th>{% blocktrans %}Teachers{% endblocktrans %}</th>
             <th>{% blocktrans %}Subject{% endblocktrans %}</th>
             <th>{% blocktrans %}Room{% endblocktrans %}</th>
    @@ -47,7 +47,7 @@
    
           <tbody>
           {% for item in c.substitutions %}
    -        {% ifchanged item.el.lesson_period.lesson.groups_to_show_names %}
    +        {% ifchanged item.el.group_names %}
               </tbody>
               <tbody class="{% cycle "striped" "not-striped" %}">
             {% endifchanged %}
    @@ -66,7 +66,7 @@
                 {% include "chronos/partials/subs/subject.html" with type=item.type el=item.el %}
               </td>
               <td>
    -            {% include "chronos/partials/subs/room.html" with type=item.type el=item.el %}
    +            {% include "chronos/partials/subs/rooms.html" with type=item.type el=item.el %}
               </td>
               <td>
                 {% include "chronos/partials/subs/badge.html" with sub=item.el %}
    diff --git a/aleksis/apps/chronos/util/build.py b/aleksis/apps/chronos/util/build.py
    index 625998d..7946a3e 100644
    --- a/aleksis/apps/chronos/util/build.py
    +++ b/aleksis/apps/chronos/util/build.py
    @@ -3,6 +3,7 @@ from datetime import date
     from typing import Union
    
     from django.apps import apps
    +from django.db.models import Q
    
     from calendarweek import CalendarWeek
    
    @@ -10,6 +11,7 @@ from aleksis.apps.chronos.managers import TimetableType
     from aleksis.core.models import Group, Person, Room
    
     LessonPeriod = apps.get_model("chronos", "LessonPeriod")
    +LessonEvent = apps.get_model("chronos", "LessonEvent")
     TimePeriod = apps.get_model("chronos", "TimePeriod")
     Break = apps.get_model("chronos", "Break")
     Supervision = apps.get_model("chronos", "Supervision")
    @@ -383,84 +385,25 @@ def build_timetable(
     def build_substitutions_list(wanted_day: date) -> list[dict]:
         rows = []
    
    -    subs = LessonSubstitution.objects.on_day(wanted_day).order_by(
    -        "lesson_period__lesson__groups", "lesson_period__period"
    +    subs = (
    +        LessonEvent.objects.exclude(amends=None)
    +        .filter(Q(datetime_start__date=wanted_day) | Q(date_start=wanted_day))
    +        .order_by("datetime_start", "date_start")
         )
    
    -    start_period = None
         for i, sub in enumerate(subs):
    -        if not sub.cancelled_for_teachers:
    -            sort_a = sub.lesson_period.lesson.groups_to_show_names
    -        else:
    -            sort_a = f"Z.{sub.lesson_period.lesson.teacher_names}"
    -
    -        # Get next substitution
    -        next_sub = subs[i + 1] if i + 1 < len(subs) else None
    -
    -        # Check if next substitution is equal with this substitution
    -        if (
    -            next_sub
    -            and sub.comment == next_sub.comment
    -            and sub.cancelled == next_sub.cancelled
    -            and sub.subject == next_sub.subject
    -            and sub.room == next_sub.room
    -            and sub.lesson_period.lesson == next_sub.lesson_period.lesson
    -            and set(sub.teachers.all()) == set(next_sub.teachers.all())
    -        ):
    -            if not start_period:
    -                start_period = sub.lesson_period.period.period
    -            continue
    +        sort_a = sub.group_names
    +
    +        # FIXME? Looks hacky. sub.amends returns a CalendarEvent, but a LessonEvent is needed
    +        sub.amends = LessonEvent.objects.get(pk=sub.amends.pk)
    
             row = {
                 "type": "substitution",
                 "sort_a": sort_a,
    -            "sort_b": str(sub.lesson_period.period.period),
    +            "sort_b": str(sub.datetime_start if sub.datetime_start else sub.date_start),
                 "el": sub,
    -            "start_period": start_period if start_period else sub.lesson_period.period.period,
    -            "end_period": sub.lesson_period.period.period,
    -        }
    -
    -        if start_period:
    -            start_period = None
    -
    -        rows.append(row)
    -
    -    # Get supervision substitutions
    -    super_subs = SupervisionSubstitution.objects.filter(date=wanted_day)
    -
    -    for super_sub in super_subs:
    -        row = {
    -            "type": "supervision_substitution",
    -            "sort_a": f"Z.{super_sub.teacher}",
    -            "sort_b": str(super_sub.supervision.break_item.after_period_number),
    -            "el": super_sub,
    -        }
    -        rows.append(row)
    -
    -    # Get extra lessons
    -    extra_lessons = ExtraLesson.objects.on_day(wanted_day)
    -
    -    for extra_lesson in extra_lessons:
    -        row = {
    -            "type": "extra_lesson",
    -            "sort_a": str(extra_lesson.group_names),
    -            "sort_b": str(extra_lesson.period.period),
    -            "el": extra_lesson,
             }
    -        rows.append(row)
    -
    -    # Get events
    -    events = Event.objects.on_day(wanted_day).annotate_day(wanted_day)
    
    -    for event in events:
    -        sort_a = event.group_names if event.groups.all() else f"Z.{event.teacher_names}"
    -
    -        row = {
    -            "type": "event",
    -            "sort_a": sort_a,
    -            "sort_b": str(event.period_from_on_day),
    -            "el": event,
    -        }
             rows.append(row)
    
         # Sort all items
    diff --git a/aleksis/apps/chronos/util/chronos_helpers.py b/aleksis/apps/chronos/util/chronos_helpers.py
    index 8e16401..4c36d3a 100644
    --- a/aleksis/apps/chronos/util/chronos_helpers.py
    +++ b/aleksis/apps/chronos/util/chronos_helpers.py
    @@ -1,4 +1,4 @@
    -from datetime import datetime, timedelta
    +from datetime import date, datetime, timedelta
     from typing import TYPE_CHECKING, Optional
    
     from django.db.models import Count, Q
    @@ -160,10 +160,8 @@ def get_rooms(user: "User"):
    
     def get_substitutions_context_data(
    +    wanted_day: date,
         request: Optional[HttpRequest] = None,
    -    year: Optional[int] = None,
    -    month: Optional[int] = None,
    -    day: Optional[int] = None,
         is_print: bool = False,
         number_of_days: Optional[int] = None,
         show_header_box: Optional[bool] = None,
    @@ -171,12 +169,6 @@ def get_substitutions_context_data(
         """Get context data for the substitutions table."""
         context = {}
    
    -    if day:
    -        wanted_day = timezone.datetime(year=year, month=month, day=day).date()
    -        wanted_day = TimePeriod.get_next_relevant_day(wanted_day)
    -    else:
    -        wanted_day = TimePeriod.get_next_relevant_day(timezone.now().date(), timezone.now().time())
    -
         day_number = (
             number_of_days or get_site_preferences()["chronos__substitutions_print_number_of_days"]
         )
    @@ -191,7 +183,7 @@ def get_substitutions_context_data(
             next_day = wanted_day
             for _i in range(day_number):
                 day_contexts[next_day] = {"day": next_day}
    -            next_day = TimePeriod.get_next_relevant_day(next_day + timedelta(days=1))
    +            next_day = next_day + timedelta(days=1)
         else:
             day_contexts = {wanted_day: {"day": wanted_day}}
    
    @@ -202,22 +194,9 @@ def get_substitutions_context_data(
             day_contexts[day]["announcements"] = Announcement.for_timetables().on_date(day)
    
             if show_header_box:
    -            subs = LessonSubstitution.objects.on_day(day).order_by(
    -                "lesson_period__lesson__groups", "lesson_period__period"
    -            )
                 absences = Absence.objects.on_day(day)
                 day_contexts[day]["absent_teachers"] = absences.absent_teachers()
                 day_contexts[day]["absent_groups"] = absences.absent_groups()
    -            day_contexts[day]["affected_teachers"] = subs.affected_teachers()
    -            affected_groups = subs.affected_groups()
    -            if get_site_preferences()["chronos__affected_groups_parent_groups"]:
    -                groups_with_parent_groups = affected_groups.filter(parent_groups__isnull=False)
    -                groups_without_parent_groups = affected_groups.filter(parent_groups__isnull=True)
    -                affected_groups = Group.objects.filter(
    -                    Q(child_groups__pk__in=groups_with_parent_groups.values_list("pk", flat=True))
    -                    | Q(pk__in=groups_without_parent_groups.values_list("pk", flat=True))
    -                ).distinct()
    -            day_contexts[day]["affected_groups"] = affected_groups
    
         if not is_print:
             context = day_contexts[wanted_day]
    @@ -226,10 +205,6 @@ def get_substitutions_context_data(
                 "dest": reverse("substitutions"),
             }
    
    -        context["url_prev"], context["url_next"] = TimePeriod.get_prev_next_by_day(
    -            wanted_day, "substitutions_by_date"
    -        )
    -
         else:
             context["days"] = day_contexts
    
    diff --git a/aleksis/apps/chronos/views.py b/aleksis/apps/chronos/views.py
    index a45997c..ee01e35 100644
    --- a/aleksis/apps/chronos/views.py
    +++ b/aleksis/apps/chronos/views.py
    @@ -1,3 +1,4 @@
    +from datetime import date, datetime
     from typing import Optional
    
     from django.http import HttpRequest, HttpResponse
    Verified
    c9a56bb2
    History
    Adapt substitution PDF to new data model
    magicfelix authored and Jonathan Weth's avatar Jonathan Weth committed
    diff --git a/aleksis/apps/chronos/models.py b/aleksis/apps/chronos/models.py
    index 35f4e01..f348c00 100644
    --- a/aleksis/apps/chronos/models.py
    +++ b/aleksis/apps/chronos/models.py
    @@ -1221,6 +1221,7 @@ class AutomaticPlan(LiveDocument):
             from aleksis.apps.chronos.util.chronos_helpers import get_substitutions_context_data  # noqa
    
             context = get_substitutions_context_data(
    +            wanted_day=date.today(),
                 request=None,
                 is_print=True,
                 number_of_days=self.number_of_days,
    diff --git a/aleksis/apps/chronos/templates/chronos/partials/rooms.html b/aleksis/apps/chronos/templates/chronos/partials/rooms.html
    new file mode 100644
    index 0000000..1e42988
    --- /dev/null
    +++ b/aleksis/apps/chronos/templates/chronos/partials/rooms.html
    @@ -0,0 +1,8 @@
    +{% for room in rooms %}
    +  <span data-position="bottom" class="tooltipped"
    +        data-tooltip="{{ room }}">
    +      <a href="{% url "timetable" "room" room.pk %}">
    +          {{ room.short_name }}{% if not forloop.last %},{% endif %}
    +      </a>
    +  </span>
    +{% endfor %}
    diff --git a/aleksis/apps/chronos/templates/chronos/partials/subs/badge.html b/aleksis/apps/chronos/templates/chronos/partials/subs/badge.html
    index c04c9dd..c807244 100644
    --- a/aleksis/apps/chronos/templates/chronos/partials/subs/badge.html
    +++ b/aleksis/apps/chronos/templates/chronos/partials/subs/badge.html
    @@ -2,6 +2,4 @@
    
     {% if sub.cancelled %}
       <span class="badge new green">{% trans "Cancelled" %}</span>
    -{% elif item.el.cancelled_for_teachers %}
    -  <span class="badge new green">{% trans "Cancelled for teachers" %}</span>
     {% endif %}
    diff --git a/aleksis/apps/chronos/templates/chronos/partials/subs/colour.html b/aleksis/apps/chronos/templates/chronos/partials/subs/colour.html
    index 833a24b..e59b37f 100644
    --- a/aleksis/apps/chronos/templates/chronos/partials/subs/colour.html
    +++ b/aleksis/apps/chronos/templates/chronos/partials/subs/colour.html
    @@ -1,11 +1,5 @@
    -{% if item.type == "substitution" %}
    -  {% if item.el.cancelled or item.el.cancelled_for_teachers %}
    -    green-text
    -  {% else %}
    -    black-text
    -  {% endif %}
    -{% elif item.type == "supervision_substitution" %}
    -  blue-text
    -{% elif item.type == "event" %}
    -  purple-text
    +{% if item.el.cancelled %}
    +  green-text
    +{% else %}
    +  black-text
     {% endif %}
    diff --git a/aleksis/apps/chronos/templates/chronos/partials/subs/groups.html b/aleksis/apps/chronos/templates/chronos/partials/subs/groups.html
    index d1a4da9..079e0f0 100644
    --- a/aleksis/apps/chronos/templates/chronos/partials/subs/groups.html
    +++ b/aleksis/apps/chronos/templates/chronos/partials/subs/groups.html
    @@ -1,5 +1,15 @@
    -{% if type == "substitution" %}
    -  {% include "chronos/partials/groups.html" with groups=el.lesson_period.lesson.groups.all %}
    -{% elif type == "extra_lesson" or type == "event" %}
    +{% if el.cancelled and el.amends.groups.all %}
    +  {% include "chronos/partials/groups.html" with groups=el.amends.groups.all %}
    +{% elif el.groups.all and el.amends.groups.all %}
    +  <s>
    +    {% include "chronos/partials/groups.html" with groups=el.amends.groups.all %}
    +  </s>
    +  →
    +  <strong>
    +    {% include "chronos/partials/groups.html" with groups=el.groups.all %}
    +  </strong>
    +{% elif el.groups.all and not el.amends.groups.all %}
       {% include "chronos/partials/groups.html" with groups=el.groups.all %}
    +{% elif el.amends.groups.all %}
    +  {% include "chronos/partials/groups.html" with groups=el.amends.groups.all %}
     {% endif %}
    diff --git a/aleksis/apps/chronos/templates/chronos/partials/subs/period.html b/aleksis/apps/chronos/templates/chronos/partials/subs/period.html
    index ef1d283..4ba7706 100644
    --- a/aleksis/apps/chronos/templates/chronos/partials/subs/period.html
    +++ b/aleksis/apps/chronos/templates/chronos/partials/subs/period.html
    @@ -1,19 +1,7 @@
     <strong>
    -  {% if type == "substitution" and item.start_period == item.end_period %}
    -    {{ el.lesson_period.period.period }}.
    -  {% elif type == "substitution"  %}
    -    {{ item.start_period }}.–{{ item.end_period }}.
    -  {% elif type == "extra_lesson" %}
    -    {{ el.period.period }}.
    -  {% elif type == "event" %}
    -    {% if el.period_from_on_day == el.period_to_on_day %}
    -      {{ el.period_from_on_day }}.
    -    {% else %}
    -      {{ el.period_from_on_day }}.–{{ el.period_to_on_day }}.
    -    {% endif %}
    -  {% elif type == "supervision_substitution" %}
    -    {% with break=el.supervision.break_item %}
    -      {{ break.after_period_number }}./{{ break.before_period_number }}.
    -    {% endwith %}
    +  {% if el.datetime_start %}
    +    {{ el.datetime_start.time }} - {{ el.datetime_end.time }}
    +  {% elif el.date_start %}
    +    {{ el.date_start }} - {{ el.date_end }}
       {% endif %}
     </strong>
    diff --git a/aleksis/apps/chronos/templates/chronos/partials/subs/room.html b/aleksis/apps/chronos/templates/chronos/partials/subs/room.html
    index 94f2d35..123faba 100644
    --- a/aleksis/apps/chronos/templates/chronos/partials/subs/room.html
    +++ b/aleksis/apps/chronos/templates/chronos/partials/subs/room.html
    @@ -1,39 +1,15 @@
    -{% if type == "substitution" %}
    -  {% if el.cancelled or el.cancelled_for_teachers %}
    -    {# Cancelled lesson: no room #}
    -  {% elif el.room and el.lesson_period.room %}
    -    {# New and old room available #}
    -    <span class="tooltipped" data-position="bottom"
    -          data-tooltip="{{ el.lesson_period.room.name }} → {{ el.room.name }}"
    -          title="{{ el.lesson_period.room.name }} → {{ el.room.name }}">
    -      <a href="{% url "timetable" "room" el.lesson_period.room.pk %}">
    -          <s>{{ el.lesson_period.room.short_name }}</s>
    -      </a>
    -      →
    -      <a href="{% url "timetable" "room" el.room.pk %}">
    -          <strong>{{ el.room.short_name }}</strong>
    -      </a>
    -    </span>
    -  {% elif el.room and not el.lesson_period.room %}
    -    {# Only new room available #}
    -    {% include "chronos/partials/room.html" with room=el.room %}
    -  {% elif not el.room and not el.lesson_period.room %}
    -    {# Nothing to view #}
    -  {% else %}
    -    {# Only old room available #}
    -    {% include "chronos/partials/room.html" with room=el.lesson_period.room %}
    -  {% endif %}
    -{% elif type == "supervision_substitution" %}
    -  {% with supervision=el.supervision %}
    -    <span data-position="bottom" class="tooltipped"
    -          data-tooltip="{{ supervision.area.name }}" title="{{ supervision.area.name }}">
    -      {{ supervision.area.short_name }}
    -    </span>
    -  {% endwith %}
    -{% elif type == "extra_lesson" %}
    -  {% include "chronos/partials/room.html" with room=el.room %}
    -{% elif type == "event" %}
    -  {% for room in el.rooms.all %}
    -    {% include "chronos/partials/room.html" with room=room %}{% if not forloop.last %},{% endif %}
    -  {% endfor %}
    +{% if el.cancelled and el.amends.rooms.all %}
    +  {% include "chronos/partials/rooms.html" with rooms=el.amends.rooms.all %}
    +{% elif el.rooms.all and el.amends.rooms.all %}
    +  <s>
    +    {% include "chronos/partials/rooms.html" with rooms=el.amends.rooms.all %}
    +  </s>
    +  →
    +  <strong>
    +    {% include "chronos/partials/rooms.html" with rooms=el.rooms.all %}
    +  </strong>
    +{% elif el.rooms.all and not el.amends.rooms.all %}
    +  {% include "chronos/partials/rooms.html" with rooms=el.rooms.all %}
    +{% elif el.amends.rooms.all %}
    +  {% include "chronos/partials/rooms.html" with rooms=el.amends.rooms.all %}
     {% endif %}
    diff --git a/aleksis/apps/chronos/templates/chronos/partials/subs/rooms.html b/aleksis/apps/chronos/templates/chronos/partials/subs/rooms.html
    new file mode 100644
    index 0000000..123faba
    --- /dev/null
    +++ b/aleksis/apps/chronos/templates/chronos/partials/subs/rooms.html
    @@ -0,0 +1,15 @@
    +{% if el.cancelled and el.amends.rooms.all %}
    +  {% include "chronos/partials/rooms.html" with rooms=el.amends.rooms.all %}
    +{% elif el.rooms.all and el.amends.rooms.all %}
    +  <s>
    +    {% include "chronos/partials/rooms.html" with rooms=el.amends.rooms.all %}
    +  </s>
    +  →
    +  <strong>
    +    {% include "chronos/partials/rooms.html" with rooms=el.rooms.all %}
    +  </strong>
    +{% elif el.rooms.all and not el.amends.rooms.all %}
    +  {% include "chronos/partials/rooms.html" with rooms=el.rooms.all %}
    +{% elif el.amends.rooms.all %}
    +  {% include "chronos/partials/rooms.html" with rooms=el.amends.rooms.all %}
    +{% endif %}
    diff --git a/aleksis/apps/chronos/templates/chronos/partials/subs/subject.html b/aleksis/apps/chronos/templates/chronos/partials/subs/subject.html
    index 1b7a3c5..dcbfa4b 100644
    --- a/aleksis/apps/chronos/templates/chronos/partials/subs/subject.html
    +++ b/aleksis/apps/chronos/templates/chronos/partials/subs/subject.html
    @@ -1,28 +1,28 @@
     {% load i18n %}
    
    -{% if type == "substitution" %}
    -  {% if not el.lesson_period.lesson.subject and not el.subject %}
    -  {% elif el.cancelled or el.cancelled_for_teachers %}
    -    <span data-position="bottom" class="tooltipped" data-tooltip="{{ el.lesson_period.lesson.subject.name }}">
    -    <s>{{ el.lesson_period.lesson.subject.short_name }}</s>
    -  </span>
    -  {% elif el.subject and el.lesson_period.lesson.subject %}
    -    <span data-position="bottom" class="tooltipped" data-tooltip="{{ el.lesson_period.lesson.subject.name }}">
    -    <s>{{ el.lesson_period.lesson.subject.short_name }}</s>
    -  </span>
    -    →
    -    <span data-position="bottom" class="tooltipped" data-tooltip="{{ el.subject.name }}">
    -    <strong>{{ el.subject.short_name }}</strong>
    -  </span>
    -  {% elif el.subject and not el.lesson_period.lesson.subject %}
    -    {% include "chronos/partials/subject.html" with subject=el.subject %}
    -  {% else %}
    -    {% include "chronos/partials/subject.html" with subject=el.lesson_period.lesson.subject %}
    +{% if not el.amends.subject and not el.subject %}
    +  {% if el.amends.title %}
    +    <span data-position="bottom" class="tooltipped" data-tooltip="{{ el.amends.title }}">
    +    <s>{{ el.amends.title }}</s>
       {% endif %}
    -{% elif type == "supervision_substitution" %}
    -  {% trans "Supervision" %}
    -{% elif type == "extra_lesson" %}
    +  {% if el.title %}
    +    <span data-position="bottom" class="tooltipped" data-tooltip="{{ el.title }}">
    +    <s>{{ el.title }}</s>
    +  {% endif %}
    +{% elif el.cancelled %}
    +  <span data-position="bottom" class="tooltipped" data-tooltip="{{ el.subject.short_name }}">
    +  <s>{{ el.subject.short_name }}</s>
    +</span>
    +{% elif el.subject and el.amends.subject %}
    +  <span data-position="bottom" class="tooltipped" data-tooltip="{{ el.amends.subject.name }}">
    +  <s>{{ el.amends.subject.short_name }}</s>
    +</span>
    +  →
    +  <span data-position="bottom" class="tooltipped" data-tooltip="{{ el.subject.name }}">
    +  <strong>{{ el.subject.short_name }}</strong>
    +</span>
    +{% elif el.subject and not el.amends.subject %}
       {% include "chronos/partials/subject.html" with subject=el.subject %}
    -{% elif type == "event" %}
    -  {% trans "Event" %}
    +{% else %}
    +  {% include "chronos/partials/subject.html" with subject=el.amends.subject %}
     {% endif %}
    diff --git a/aleksis/apps/chronos/templates/chronos/partials/subs/teachers.html b/aleksis/apps/chronos/templates/chronos/partials/subs/teachers.html
    index 4fa80d8..9e08eeb 100644
    --- a/aleksis/apps/chronos/templates/chronos/partials/subs/teachers.html
    +++ b/aleksis/apps/chronos/templates/chronos/partials/subs/teachers.html
    @@ -1,27 +1,15 @@
    -{% if type == "substitution" %}
    -  {% if el.cancelled and el.lesson_period.lesson.teachers.all %}
    -    {% include "chronos/partials/teachers.html" with teachers=el.lesson_period.lesson.teachers.all %}
    -  {% elif el.teachers.all and el.lesson_period.lesson.teachers.all %}
    -    <s>
    -      {% include "chronos/partials/teachers.html" with teachers=el.lesson_period.lesson.teachers.all %}
    -    </s>
    -    →
    -    <strong>
    -      {% include "chronos/partials/teachers.html" with teachers=el.teachers.all %}
    -    </strong>
    -  {% elif el.teachers.all and not el.lesson_period.lesson.teachers.all %}
    -    {% include "chronos/partials/teachers.html" with teachers=el.teachers.all %}
    -  {% elif el.lesson_period.lesson.teachers.all %}
    -    {% include "chronos/partials/teachers.html" with teachers=el.lesson_period.lesson.teachers.all %}
    -  {% endif %}
    -{% elif type == "supervision_substitution" %}
    +{% if el.cancelled and el.amends.teachers.all %}
    +  {% include "chronos/partials/teachers.html" with teachers=el.amends.teachers.all %}
    +{% elif el.teachers.all and el.amends.teachers.all %}
       <s>
    -    {% include "chronos/partials/teachers.html" with teachers=el.supervision.teachers %}
    +    {% include "chronos/partials/teachers.html" with teachers=el.amends.teachers.all %}
       </s>
       →
       <strong>
    -    {% include "chronos/partials/teachers.html" with teachers=el.teachers %}
    +    {% include "chronos/partials/teachers.html" with teachers=el.teachers.all %}
       </strong>
    -{% elif type == "extra_lesson" or type == "event" %}
    +{% elif el.teachers.all and not el.amends.teachers.all %}
       {% include "chronos/partials/teachers.html" with teachers=el.teachers.all %}
    +{% elif el.amends.teachers.all %}
    +  {% include "chronos/partials/teachers.html" with teachers=el.amends.teachers.all %}
     {% endif %}
    diff --git a/aleksis/apps/chronos/templates/chronos/substitutions_print.html b/aleksis/apps/chronos/templates/chronos/substitutions_print.html
    index 743a223..10243a1 100644
    --- a/aleksis/apps/chronos/templates/chronos/substitutions_print.html
    +++ b/aleksis/apps/chronos/templates/chronos/substitutions_print.html
    @@ -18,13 +18,13 @@
    
         {% include "core/partials/announcements.html" with announcements=c.announcements show_recipients=1 %}
    
    -    {% include "chronos/partials/headerbox.html" with affected_teachers=c.affected_teachers affected_groups=c.affected_groups absent_teachers=c.absent_teachers absent_groups=c.absent_groups print=1 %}
    +    {% include "chronos/partials/headerbox.html" with absent_teachers=c.absent_teachers absent_groups=c.absent_groups print=1 %}
    
         <table class="substitutions">
           <thead>
           <tr>
    -        <th><i class="material-icons iconify center" data-icon="mdi:account-multiple-outline"></i></th>
    -        <th><i class="material-icons iconify center" data-icon="mdi:clock-outline"></i></th>
    +        <th>{% blocktrans %}Groups{% endblocktrans %}</th>
    +        <th>{% blocktrans %}Time{% endblocktrans %}</th>
             <th>{% blocktrans %}Teachers{% endblocktrans %}</th>
             <th>{% blocktrans %}Subject{% endblocktrans %}</th>
             <th>{% blocktrans %}Room{% endblocktrans %}</th>
    @@ -47,7 +47,7 @@
    
           <tbody>
           {% for item in c.substitutions %}
    -        {% ifchanged item.el.lesson_period.lesson.groups_to_show_names %}
    +        {% ifchanged item.el.group_names %}
               </tbody>
               <tbody class="{% cycle "striped" "not-striped" %}">
             {% endifchanged %}
    @@ -66,7 +66,7 @@
                 {% include "chronos/partials/subs/subject.html" with type=item.type el=item.el %}
               </td>
               <td>
    -            {% include "chronos/partials/subs/room.html" with type=item.type el=item.el %}
    +            {% include "chronos/partials/subs/rooms.html" with type=item.type el=item.el %}
               </td>
               <td>
                 {% include "chronos/partials/subs/badge.html" with sub=item.el %}
    diff --git a/aleksis/apps/chronos/util/build.py b/aleksis/apps/chronos/util/build.py
    index 625998d..7946a3e 100644
    --- a/aleksis/apps/chronos/util/build.py
    +++ b/aleksis/apps/chronos/util/build.py
    @@ -3,6 +3,7 @@ from datetime import date
     from typing import Union
    
     from django.apps import apps
    +from django.db.models import Q
    
     from calendarweek import CalendarWeek
    
    @@ -10,6 +11,7 @@ from aleksis.apps.chronos.managers import TimetableType
     from aleksis.core.models import Group, Person, Room
    
     LessonPeriod = apps.get_model("chronos", "LessonPeriod")
    +LessonEvent = apps.get_model("chronos", "LessonEvent")
     TimePeriod = apps.get_model("chronos", "TimePeriod")
     Break = apps.get_model("chronos", "Break")
     Supervision = apps.get_model("chronos", "Supervision")
    @@ -383,84 +385,25 @@ def build_timetable(
     def build_substitutions_list(wanted_day: date) -> list[dict]:
         rows = []
    
    -    subs = LessonSubstitution.objects.on_day(wanted_day).order_by(
    -        "lesson_period__lesson__groups", "lesson_period__period"
    +    subs = (
    +        LessonEvent.objects.exclude(amends=None)
    +        .filter(Q(datetime_start__date=wanted_day) | Q(date_start=wanted_day))
    +        .order_by("datetime_start", "date_start")
         )
    
    -    start_period = None
         for i, sub in enumerate(subs):
    -        if not sub.cancelled_for_teachers:
    -            sort_a = sub.lesson_period.lesson.groups_to_show_names
    -        else:
    -            sort_a = f"Z.{sub.lesson_period.lesson.teacher_names}"
    -
    -        # Get next substitution
    -        next_sub = subs[i + 1] if i + 1 < len(subs) else None
    -
    -        # Check if next substitution is equal with this substitution
    -        if (
    -            next_sub
    -            and sub.comment == next_sub.comment
    -            and sub.cancelled == next_sub.cancelled
    -            and sub.subject == next_sub.subject
    -            and sub.room == next_sub.room
    -            and sub.lesson_period.lesson == next_sub.lesson_period.lesson
    -            and set(sub.teachers.all()) == set(next_sub.teachers.all())
    -        ):
    -            if not start_period:
    -                start_period = sub.lesson_period.period.period
    -            continue
    +        sort_a = sub.group_names
    +
    +        # FIXME? Looks hacky. sub.amends returns a CalendarEvent, but a LessonEvent is needed
    +        sub.amends = LessonEvent.objects.get(pk=sub.amends.pk)
    
             row = {
                 "type": "substitution",
                 "sort_a": sort_a,
    -            "sort_b": str(sub.lesson_period.period.period),
    +            "sort_b": str(sub.datetime_start if sub.datetime_start else sub.date_start),
                 "el": sub,
    -            "start_period": start_period if start_period else sub.lesson_period.period.period,
    -            "end_period": sub.lesson_period.period.period,
    -        }
    -
    -        if start_period:
    -            start_period = None
    -
    -        rows.append(row)
    -
    -    # Get supervision substitutions
    -    super_subs = SupervisionSubstitution.objects.filter(date=wanted_day)
    -
    -    for super_sub in super_subs:
    -        row = {
    -            "type": "supervision_substitution",
    -            "sort_a": f"Z.{super_sub.teacher}",
    -            "sort_b": str(super_sub.supervision.break_item.after_period_number),
    -            "el": super_sub,
    -        }
    -        rows.append(row)
    -
    -    # Get extra lessons
    -    extra_lessons = ExtraLesson.objects.on_day(wanted_day)
    -
    -    for extra_lesson in extra_lessons:
    -        row = {
    -            "type": "extra_lesson",
    -            "sort_a": str(extra_lesson.group_names),
    -            "sort_b": str(extra_lesson.period.period),
    -            "el": extra_lesson,
             }
    -        rows.append(row)
    -
    -    # Get events
    -    events = Event.objects.on_day(wanted_day).annotate_day(wanted_day)
    
    -    for event in events:
    -        sort_a = event.group_names if event.groups.all() else f"Z.{event.teacher_names}"
    -
    -        row = {
    -            "type": "event",
    -            "sort_a": sort_a,
    -            "sort_b": str(event.period_from_on_day),
    -            "el": event,
    -        }
             rows.append(row)
    
         # Sort all items
    diff --git a/aleksis/apps/chronos/util/chronos_helpers.py b/aleksis/apps/chronos/util/chronos_helpers.py
    index 8e16401..4c36d3a 100644
    --- a/aleksis/apps/chronos/util/chronos_helpers.py
    +++ b/aleksis/apps/chronos/util/chronos_helpers.py
    @@ -1,4 +1,4 @@
    -from datetime import datetime, timedelta
    +from datetime import date, datetime, timedelta
     from typing import TYPE_CHECKING, Optional
    
     from django.db.models import Count, Q
    @@ -160,10 +160,8 @@ def get_rooms(user: "User"):
    
     def get_substitutions_context_data(
    +    wanted_day: date,
         request: Optional[HttpRequest] = None,
    -    year: Optional[int] = None,
    -    month: Optional[int] = None,
    -    day: Optional[int] = None,
         is_print: bool = False,
         number_of_days: Optional[int] = None,
         show_header_box: Optional[bool] = None,
    @@ -171,12 +169,6 @@ def get_substitutions_context_data(
         """Get context data for the substitutions table."""
         context = {}
    
    -    if day:
    -        wanted_day = timezone.datetime(year=year, month=month, day=day).date()
    -        wanted_day = TimePeriod.get_next_relevant_day(wanted_day)
    -    else:
    -        wanted_day = TimePeriod.get_next_relevant_day(timezone.now().date(), timezone.now().time())
    -
         day_number = (
             number_of_days or get_site_preferences()["chronos__substitutions_print_number_of_days"]
         )
    @@ -191,7 +183,7 @@ def get_substitutions_context_data(
             next_day = wanted_day
             for _i in range(day_number):
                 day_contexts[next_day] = {"day": next_day}
    -            next_day = TimePeriod.get_next_relevant_day(next_day + timedelta(days=1))
    +            next_day = next_day + timedelta(days=1)
         else:
             day_contexts = {wanted_day: {"day": wanted_day}}
    
    @@ -202,22 +194,9 @@ def get_substitutions_context_data(
             day_contexts[day]["announcements"] = Announcement.for_timetables().on_date(day)
    
             if show_header_box:
    -            subs = LessonSubstitution.objects.on_day(day).order_by(
    -                "lesson_period__lesson__groups", "lesson_period__period"
    -            )
                 absences = Absence.objects.on_day(day)
                 day_contexts[day]["absent_teachers"] = absences.absent_teachers()
                 day_contexts[day]["absent_groups"] = absences.absent_groups()
    -            day_contexts[day]["affected_teachers"] = subs.affected_teachers()
    -            affected_groups = subs.affected_groups()
    -            if get_site_preferences()["chronos__affected_groups_parent_groups"]:
    -                groups_with_parent_groups = affected_groups.filter(parent_groups__isnull=False)
    -                groups_without_parent_groups = affected_groups.filter(parent_groups__isnull=True)
    -                affected_groups = Group.objects.filter(
    -                    Q(child_groups__pk__in=groups_with_parent_groups.values_list("pk", flat=True))
    -                    | Q(pk__in=groups_without_parent_groups.values_list("pk", flat=True))
    -                ).distinct()
    -            day_contexts[day]["affected_groups"] = affected_groups
    
         if not is_print:
             context = day_contexts[wanted_day]
    @@ -226,10 +205,6 @@ def get_substitutions_context_data(
                 "dest": reverse("substitutions"),
             }
    
    -        context["url_prev"], context["url_next"] = TimePeriod.get_prev_next_by_day(
    -            wanted_day, "substitutions_by_date"
    -        )
    -
         else:
             context["days"] = day_contexts
    
    diff --git a/aleksis/apps/chronos/views.py b/aleksis/apps/chronos/views.py
    index a45997c..ee01e35 100644
    --- a/aleksis/apps/chronos/views.py
    +++ b/aleksis/apps/chronos/views.py
    @@ -1,3 +1,4 @@
    +from datetime import date, datetime
     from typing import Optional
    
     from django.http import HttpRequest, HttpResponse