diff --git a/aleksis/apps/chronos/models.py b/aleksis/apps/chronos/models.py index ebb3fb7413251e22b6f59539e4d74e224f839baf..194b5fc9c4047efef384975978874102239cb64d 100644 --- a/aleksis/apps/chronos/models.py +++ b/aleksis/apps/chronos/models.py @@ -4,6 +4,7 @@ from collections import OrderedDict from datetime import date, datetime, timedelta, time from typing import Dict, Optional, Tuple, Union +from constance import config from django.core import validators from django.core.exceptions import ValidationError from django.db import models @@ -442,6 +443,18 @@ class Lesson(ExtensibleModel): def group_names(self, sep: Optional[str] = ", ") -> str: return sep.join([group.short_name for group in self.groups.all()]) + @property + def groups_to_show(self) -> models.QuerySet: + groups = self.groups.all() + if groups.count() == 1 and groups[0].parent_groups.all() and config.CHRONOS_USE_PARENT_GROUPS: + return groups[0].parent_groups.all() + else: + return groups + + @property + def groups_to_show_names(self, sep: Optional[str] = ", ") -> str: + return sep.join([group.short_name for group in self.groups_to_show]) + def get_calendar_week(self, week: int): year = self.date_start.year if week < int(self.date_start.strftime("%V")): @@ -485,9 +498,10 @@ class LessonSubstitution(ExtensibleModel): @property def type_(self): - # TODO: Add cases events and supervisions if self.cancelled: return "cancellation" + elif self.cancelled_for_teachers: + return "cancellation_for_teachers" else: return "substitution" diff --git a/aleksis/apps/chronos/templates/chronos/partials/lesson.html b/aleksis/apps/chronos/templates/chronos/partials/lesson.html index 2c5bcd7b829c95187f73ad6a970c59f797d7ae94..66da0b6295322292e5c491f13e54dc7c2c28a8f9 100644 --- a/aleksis/apps/chronos/templates/chronos/partials/lesson.html +++ b/aleksis/apps/chronos/templates/chronos/partials/lesson.html @@ -34,8 +34,7 @@ {% endif %} {# Badge #} - <span class="badge new green darken-2">{% if sub.cancelled_for_teachers %} - {% trans "Cancelled for teachers" %}{% else %}{% trans "Cancelled" %}{% endif %}</span> + {% include "chronos/partials/subs/badge.html" with sub=sub %} {% else %} {# Display sub #} diff --git a/aleksis/apps/chronos/templates/chronos/partials/subs/badge.html b/aleksis/apps/chronos/templates/chronos/partials/subs/badge.html new file mode 100644 index 0000000000000000000000000000000000000000..c04c9dd331eeb4f271ae5e7c212b43a776c71a51 --- /dev/null +++ b/aleksis/apps/chronos/templates/chronos/partials/subs/badge.html @@ -0,0 +1,7 @@ +{% load i18n %} + +{% 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/room.html b/aleksis/apps/chronos/templates/chronos/partials/subs/room.html index cf637b92303dfe31d1c19dc781809f1c3c10dac3..e7535af9d0a5e98e566c1e463ad924150b4dc278 100644 --- a/aleksis/apps/chronos/templates/chronos/partials/subs/room.html +++ b/aleksis/apps/chronos/templates/chronos/partials/subs/room.html @@ -1,47 +1,36 @@ -{% if not sub.is_event %} - {% if sub.sub.type == 3 %} - {# Supervisement #} - {{ sub.sub.corridor.name }} - {% elif sub.sub.type == 1 or sub.sub.type == 2 %} - {# Canceled lesson: no room #} - {% elif sub.room and sub.lesson_period.room %} - {# New and old room available #} - <span class="tooltipped" data-position="bottom" - data-tooltip="{{ sub.lesson_period.room.name }} → {{ sub.lesson_period.room.name }}"> - <a href="{% url "timetable" "room" sub.lesson_period.room.pk %}"> - <s>{{ sub.lesson_period.room.short_name }}</s> - </a> - → - <a href="{% url "timetable" "room" sub.room.pk %}"> - <strong>{{ sub.room.short_name }}</strong> - </a> - </span> - {% elif sub.room and not sub.lesson_period.room %} - {# Only new room available #} - <span class="tooltipped" data-position="bottom" - data-tooltip="{{ sub.room.name }}"> - <a href="{% url "timetable" "room" sub.room.pk %}"> - {{ sub.room.short_name }} - </a> - </span> - {% elif not sub.room and not sub.lesson_period.room %} - {# Nothing to view #} - {% else %} - {# Only old room available #} - <span class="tooltipped" data-position="bottom" - data-tooltip="{{ sub.lesson_period.room.name }}"> - <a href="{% url "timetable" "room" sub.lesson_period.room.pk %}"> - {{ sub.lesson_period.room.short_name }} - </a> - </span> - {% endif %} +{% if sub.cancelled or sub.cancelled_for_teachers %} + {# Canceled lesson: no room #} +{% elif sub.room and sub.lesson_period.room %} + {# New and old room available #} + <span class="tooltipped" data-position="bottom" + data-tooltip="{{ sub.lesson_period.room.name }} → {{ sub.lesson_period.room.name }}" + title="{{ sub.lesson_period.room.name }} → {{ sub.lesson_period.room.name }}"> + <a href="{% url "timetable" "room" sub.lesson_period.room.pk %}"> + <s>{{ sub.lesson_period.room.short_name }}</s> + </a> + → + <a href="{% url "timetable" "room" sub.room.pk %}"> + <strong>{{ sub.room.short_name }}</strong> + </a> + </span> +{% elif sub.room and not sub.lesson_period.room %} + {# Only new room available #} + <span class="tooltipped" data-position="bottom" + data-tooltip="{{ sub.room.name }}" + title="{{ sub.room.name }}"> + <a href="{% url "timetable" "room" sub.room.pk %}"> + {{ sub.room.short_name }} + </a> + </span> +{% elif not sub.room and not sub.lesson_period.room %} + {# Nothing to view #} {% else %} - {% for room in sub.rooms %} - <span class="tooltipped" data-position="bottom" - data-tooltip="{{ room.name }}"> - <a href="{% url "timetable_smart_plan" "room" room.id %}"> - <strong>{{ room.short_name }}{% if not forloop.last %},{% endif %}</strong> - </a> - </span> - {% endfor %} + {# Only old room available #} + <span class="tooltipped" data-position="bottom" + data-tooltip="{{ sub.lesson_period.room.name }}" + title="{{ sub.lesson_period.room.name }}"> + <a href="{% url "timetable" "room" sub.lesson_period.room.pk %}"> + {{ sub.lesson_period.room.short_name }} + </a> + </span> {% endif %} diff --git a/aleksis/apps/chronos/templates/chronos/partials/subs/subject.html b/aleksis/apps/chronos/templates/chronos/partials/subs/subject.html index 6fe8eb5a02bb7a6afb75adf50012efa9d2712239..2e61d4158cbd22fbeba05a1416defa6c8e7c047e 100644 --- a/aleksis/apps/chronos/templates/chronos/partials/subs/subject.html +++ b/aleksis/apps/chronos/templates/chronos/partials/subs/subject.html @@ -1,28 +1,24 @@ {% load i18n %} -{% if not sub.sub.is_event %} - {% if sub.sub.type == 3 %} - <strong>{% trans "Supervision" %}</strong> - {% elif not sub.lesson_period.lesson.subject and not sub.subject %} - {% elif sub.sub.type == 1 or sub.sub.type == 2 %} - <span data-position="bottom" class="tooltipped" data-tooltip="{{ sub.lesson_period.lesson.subject.name }}"> - <s>{{ sub.lesson_period.lesson.subject.abbrev }}</s> - </span> - {% elif sub.subject and sub.lesson_period.lesson.subject %} - <span data-position="bottom" class="tooltipped" data-tooltip="{{ sub.lesson_period.lesson.subject.name }}"> - <s>{{ sub.lesson_period.lesson.subject.abbrev }}</s> - </span> - → - <span data-position="bottom" class="tooltipped" data-tooltip="{{ sub.subject.name }}"> - <strong>{{ sub.subject.abbrev }}</strong> - </span> - {% elif sub.subject and not sub.lesson_period.lesson.subject %} - <span data-position="bottom" class="tooltipped" data-tooltip="{{ sub.subject.name }}"> - <strong>{{ sub.subject.abbrev }}</strong> - </span> - {% else %} - <span data-position="bottom" class="tooltipped" data-tooltip="{{ sub.lesson_period.lesson.subject.name }}"> - <strong>{{ sub.lesson_period.lesson.subject.abbrev }}</strong> - </span> - {% endif %} +{% if not sub.lesson_period.lesson.subject and not sub.subject %} +{% elif sub.cancelled or sub.cancelled_for_teachers %} + <span data-position="bottom" class="tooltipped" data-tooltip="{{ sub.lesson_period.lesson.subject.name }}"> + <s>{{ sub.lesson_period.lesson.subject.abbrev }}</s> + </span> +{% elif sub.subject and sub.lesson_period.lesson.subject %} + <span data-position="bottom" class="tooltipped" data-tooltip="{{ sub.lesson_period.lesson.subject.name }}"> + <s>{{ sub.lesson_period.lesson.subject.abbrev }}</s> + </span> + → + <span data-position="bottom" class="tooltipped" data-tooltip="{{ sub.subject.name }}"> + <strong>{{ sub.subject.abbrev }}</strong> + </span> +{% elif sub.subject and not sub.lesson_period.lesson.subject %} + <span data-position="bottom" class="tooltipped" data-tooltip="{{ sub.subject.name }}"> + <strong>{{ sub.subject.abbrev }}</strong> + </span> +{% else %} + <span data-position="bottom" class="tooltipped" data-tooltip="{{ sub.lesson_period.lesson.subject.name }}"> + <strong>{{ sub.lesson_period.lesson.subject.abbrev }}</strong> + </span> {% endif %} diff --git a/aleksis/apps/chronos/templates/chronos/partials/subs/teachers.html b/aleksis/apps/chronos/templates/chronos/partials/subs/teachers.html index ec17d8b811cfad34c1cad90d2a3302aa5752ba53..69002c5dcc9720d179fa89ec6099eb1268704439 100644 --- a/aleksis/apps/chronos/templates/chronos/partials/subs/teachers.html +++ b/aleksis/apps/chronos/templates/chronos/partials/subs/teachers.html @@ -1,19 +1,16 @@ -{% if not sub.is_event %} - {% if sub.sub.type == 1 and sub.lesson_period.lesson.teachers.all %} +{% if sub.cancelled and sub.lesson_period.lesson.teachers.all %} + {% include "chronos/partials/teachers.html" with teachers=sub.lesson_period.lesson.teachers.all %} +{% elif sub.teachers.all and sub.lesson_period.lesson.teachers.all %} + <s> {% include "chronos/partials/teachers.html" with teachers=sub.lesson_period.lesson.teachers.all %} - {% elif sub.teachers.all and sub.lesson_period.lesson.teachers.all %} - <s> - {% include "chronos/partials/teachers.html" with teachers=sub.lesson_period.lesson.teachers.all %} - </s> - → - <strong> - {% include "chronos/partials/teachers.html" with teachers=sub.teachers.all %} - </strong> - {% elif sub.teachers.all and not sub.lesson_period.lesson.teachers.all %} + </s> + → + <strong> {% include "chronos/partials/teachers.html" with teachers=sub.teachers.all %} - {% elif sub.lesson_period.lesson.teachers.all %} - {% include "chronos/partials/teachers.html" with teachers=sub.lesson_period.lesson.teachers.all %} - {% endif %} -{% else %} + </strong> +{% elif sub.teachers.all and not sub.lesson_period.lesson.teachers.all %} {% include "chronos/partials/teachers.html" with teachers=sub.teachers.all %} +{% elif sub.lesson_period.lesson.teachers.all %} + {% include "chronos/partials/teachers.html" with teachers=sub.lesson_period.lesson.teachers.all %} {% endif %} + diff --git a/aleksis/apps/chronos/templates/chronos/substitutions.html b/aleksis/apps/chronos/templates/chronos/substitutions.html index febc6aeb9313a6ac73e75bd2a720093f530ef2a4..931eac1d72367f2bbd1cd7471ff63d9c5ca2fe01 100644 --- a/aleksis/apps/chronos/templates/chronos/substitutions.html +++ b/aleksis/apps/chronos/templates/chronos/substitutions.html @@ -57,37 +57,38 @@ </p> </td> {% endif %} - {% for sub in substitutions %} - <tr class="{% if sub.type_ == "cancellation" %}green-text{% else %}black-text{% endif %}"> + {% for item in substitutions %} + <tr class=" + {% if item.type == "substitution" %} + {% if item.el.cancelled or item.el.cancelled_for_teachers %}green-text{% else %}black-text{% endif %} + {% endif %} + "> {# TODO: Extend support for blue and purple (supervisions and events) #} <td> - {% include "chronos/partials/groups.html" with groups=sub.lesson_period.lesson.groups.all %} + {% include "chronos/partials/groups.html" with groups=item.el.lesson_period.lesson.groups.all %} </td> <td> <strong> - {{ sub.lesson_period.period.period }}. + {{ item.el.lesson_period.period.period }}. </strong> </td> <td> - {% include "chronos/partials/subs/teachers.html" %} + {% include "chronos/partials/subs/teachers.html" with sub=item.el %} </td> <td> - {% include "chronos/partials/subs/subject.html" %} + {% include "chronos/partials/subs/subject.html" with sub=item.el %} </td> <td> - {% include "chronos/partials/subs/room.html" %} + {% include "chronos/partials/subs/room.html" with sub=item.el %} </td> <td> - {% if sub.cancelled %} - {# TODO: Support other cases#} - <span class="badge new green hide-on-med-and-up">{% trans "Cancelled" %}</span> - {% endif %} - {# <em>{{ sub.text|default:"" }}</em>#} + <span class="hide-on-med-and-up"> + {% include "chronos/partials/subs/badge.html" with sub=item.el %} + </span> + <em>{{ sub.comment|default:"" }}</em> </td> <td class="hide-on-small-and-down"> - {% if sub.cancelled %} - <span class="badge new green darken-2">{% trans "Cancelled" %}</span> - {% endif %} + {% include "chronos/partials/subs/badge.html" with sub=item.el %} </td> </tr> {% endfor %} diff --git a/aleksis/apps/chronos/templates/chronos/substitutions_print.html b/aleksis/apps/chronos/templates/chronos/substitutions_print.html index 400124f2391306d6353af0c2a5819d97ad89a228..1692efe75166c0dc2e6ec5e63f9171f480cea93f 100644 --- a/aleksis/apps/chronos/templates/chronos/substitutions_print.html +++ b/aleksis/apps/chronos/templates/chronos/substitutions_print.html @@ -46,38 +46,39 @@ {% endif %} <tbody> - {% for sub in c.substitutions %} - <tr class="{% if sub.type_ == "cancellation" %}green-text{% else %}black-text{% endif %} "> + {% for item in c.substitutions %} + {% ifchanged item.el.lesson_period.lesson.groups_to_show_names %} + </tbody> + <tbody class="{% cycle "striped" "not-striped" %}"> + {% endifchanged %} + + <tr class=" + {% if item.type == "substitution" %} + {% if item.el.cancelled or item.el.cancelled_for_teachers %}green-text{% else %}black-text{% endif %} + {% endif %} + "> <td> - {% include "chronos/partials/groups.html" with groups=sub.lesson_period.lesson.groups.all %} + {% include "chronos/partials/groups.html" with groups=item.el.lesson_period.lesson.groups.all %} </td> <td> <strong> - {{ sub.lesson_period.period.period }}. + {{ item.el.lesson_period.period.period }}. </strong> </td> <td> - {% include "chronos/partials/subs/teachers.html" %} + {% include "chronos/partials/subs/teachers.html" with sub=item.el %} </td> <td> - {% include "chronos/partials/subs/subject.html" %} + {% include "chronos/partials/subs/subject.html" with sub=item.el %} </td> <td> - {% include "chronos/partials/subs/room.html" %} + {% include "chronos/partials/subs/room.html" with sub=item.el %} </td> <td> - {% if sub.cancelled %} - {# TODO: Support other cases#} - <span class="badge new green">{% trans "Cancelled" %}</span> - {% endif %} - {# <em>{{ sub.text|default:"" }}</em>#} + {% include "chronos/partials/subs/badge.html" with sub=item.el %} + <em>{{ sub.comment|default:"" }}</em> </td> </tr> - - {% ifchanged sub.lesson_period.lesson.groups %} - </tbody> - <tbody class="{% cycle "not-striped" "striped" %}"> - {% endifchanged %} {% endfor %} </tbody> </table> diff --git a/aleksis/apps/chronos/util/build.py b/aleksis/apps/chronos/util/build.py index b45b8510b6a8ee60cc072c92a81dd8b403895d9a..57cd470767d6e685952d7f5bed3061a6cdaf65c5 100644 --- a/aleksis/apps/chronos/util/build.py +++ b/aleksis/apps/chronos/util/build.py @@ -1,6 +1,6 @@ from collections import OrderedDict from datetime import date -from typing import Union +from typing import Union, List from calendarweek import CalendarWeek from django.apps import apps @@ -11,6 +11,7 @@ LessonPeriod = apps.get_model("chronos", "LessonPeriod") TimePeriod = apps.get_model("chronos", "TimePeriod") Break = apps.get_model("chronos", "Break") Supervision = apps.get_model("chronos", "Supervision") +LessonSubstitution = apps.get_model("chronos", "LessonSubstitution") def build_timetable( @@ -155,3 +156,28 @@ def build_timetable( rows.append(row) return rows + + +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" + ) + + for sub in subs: + if not sub.cancelled_for_teachers: + sort_a = sub.lesson_period.lesson.group_names + else: + sort_a = "Z.{}".format(sub.lesson_period.lesson.teacher_names) + + row = { + "type": "substitution", + "sort_a": sort_a, + "sort_b": "{}".format(sub.lesson_period.period.period), + "el": sub, + } + + rows.append(row) + + return rows diff --git a/aleksis/apps/chronos/views.py b/aleksis/apps/chronos/views.py index de93182552fb5181e6a921d1d5557f65803a6fd2..b59262ac1ef23d03091f2fd3ccdecef4d02e27ca 100644 --- a/aleksis/apps/chronos/views.py +++ b/aleksis/apps/chronos/views.py @@ -18,7 +18,7 @@ from aleksis.core.util import messages from .forms import LessonSubstitutionForm from .models import LessonPeriod, LessonSubstitution, TimePeriod, Room from .tables import LessonsTable -from .util.build import build_timetable +from .util.build import build_timetable, build_substitutions_list from .util.js import date_unix from .util.date import CalendarWeek, get_weeks_for_year from aleksis.core.util.core_helpers import has_person @@ -295,12 +295,14 @@ def substitutions( day_contexts = {wanted_day: {"day": wanted_day}} for day in day_contexts: - subs = LessonSubstitution.objects.on_day(day).order_by("lesson_period__lesson__groups", "lesson_period__period") + subs = build_substitutions_list(day) day_contexts[day]["substitutions"] = subs day_contexts[day]["announcements"] = Announcement.for_timetables().on_date(day).filter(show_in_timetables=True) if config.CHRONOS_SUBSTITUTIONS_SHOW_HEADER_BOX: + subs = LessonSubstitution.objects.on_day(day).order_by("lesson_period__lesson__groups", + "lesson_period__period") day_contexts[day]["affected_teachers"] = subs.affected_teachers() day_contexts[day]["affected_groups"] = subs.affected_groups()