Skip to content
Snippets Groups Projects
Commit 29dd2846 authored by Nik | Klampfradler's avatar Nik | Klampfradler
Browse files

Merge branch 'feature/advanced-data-timetable-views' into 'master'

Advanced data in timetable views

Closes #72 and #73

See merge request !47
parents 6b05dfc0 fe3d00a7
No related branches found
No related tags found
1 merge request!47Advanced data in timetable views
Showing
with 724 additions and 236 deletions
# Generated by Django 3.0.5 on 2020-04-13 13:36
from django.db import migrations, models
from django.db.models import F
class Migration(migrations.Migration):
dependencies = [
('chronos', '0009_extended_data'),
]
operations = [
migrations.AddField(
model_name='absencereason',
name='name',
field=models.CharField(default=F("description"), blank=True, max_length=255, null=True, verbose_name='Name'),
),
migrations.AddField(
model_name='absencereason',
name='short_name',
field=models.CharField(default=F("title"), max_length=255, verbose_name='Short name'),
preserve_default=False,
),
migrations.RemoveField(
model_name='absencereason',
name='description',
),
migrations.RemoveField(
model_name='absencereason',
name='title',
),
]
# Generated by Django 3.0.5 on 2020-04-13 15:07
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('chronos', '0010_absence_reason_name'),
]
operations = [
migrations.RemoveField(
model_name='absence',
name='person',
),
migrations.AddField(
model_name='absence',
name='group',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='absences', to='core.Group'),
),
migrations.AddField(
model_name='absence',
name='room',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='absences', to='chronos.Room'),
),
migrations.AddField(
model_name='absence',
name='teacher',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='absences', to='core.Person'),
),
]
# Generated by Django 3.0.5 on 2020-04-13 16:07
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('chronos', '0011_absence_for_groups_and_rooms'),
]
operations = [
migrations.RemoveField(
model_name='event',
name='absence_reason',
),
]
# Generated by Django 3.0.5 on 2020-04-14 16:11
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('chronos', '0012_event_remove_absence_reason'),
]
operations = [
migrations.AlterField(
model_name='event',
name='title',
field=models.CharField(blank=True, max_length=255, null=True, verbose_name='Title'),
),
]
......@@ -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
......@@ -142,18 +143,18 @@ class LessonDataQuerySet(models.QuerySet):
def filter_teacher(self, teacher: Union[Person, int]):
""" Filter for all lessons given by a certain teacher. """
return self.filter(
Q(**{self._subst_path + "teachers": teacher, self._subst_path + "week": F("_week"),})
| Q(**{self._period_path + "lesson__teachers": teacher})
)
qs1 = self.filter(**{self._period_path + "lesson__teachers": teacher})
qs2 = self.filter(**{self._subst_path + "teachers": teacher, self._subst_path + "week": F("_week"), })
return qs1.union(qs2)
def filter_room(self, room: Union[Room, int]):
""" Filter for all lessons taking part in a certain room. """
return self.filter(
Q(**{self._subst_path + "room": room, self._subst_path + "week": F("_week"),})
| Q(**{self._period_path + "room": room})
)
qs1 = self.filter(**{self._period_path + "room": room})
qs2 = self.filter(**{self._subst_path + "room": room, self._subst_path + "week": F("_week"),})
return qs1.union(qs2)
def annotate_week(self, week: Union[CalendarWeek, int]):
""" Annotate all lessons in the QuerySet with the number of the provided calendar week. """
......@@ -221,24 +222,24 @@ class LessonPeriodQuerySet(LessonDataQuerySet):
if type_ == "teacher":
# Teacher
return person.lesson_periods_as_teacher
return self.filter_teacher(person)
elif type_ == "group":
# Student
return person.lesson_periods_as_participant
return self.filter(lesson__groups__members=person)
else:
# If no student or teacher
return None
def daily_lessons_for_person(self, person: Person, wanted_day: date) -> Optional[models.QuerySet]:
lesson_periods = LessonPeriod.objects.filter_from_person(person)
if lesson_periods is None:
if person.timetable_type is None:
return None
return lesson_periods.on_day(wanted_day)
lesson_periods = self.on_day(wanted_day).filter_from_person(person)
return lesson_periods
def per_period_one_day(self) -> OrderedDict:
""" Group selected lessons per period for one day """
......@@ -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"
......@@ -508,6 +522,8 @@ class LessonSubstitution(ExtensibleModel):
class LessonPeriod(ExtensibleModel):
label_ = "lesson_period"
objects = LessonPeriodManager.from_queryset(LessonPeriodQuerySet)()
lesson = models.ForeignKey("Lesson", models.CASCADE, related_name="lesson_periods")
......@@ -567,21 +583,25 @@ class TimetableWidget(DashboardWidget):
template = "chronos/widget.html"
def get_context(self):
from aleksis.apps.chronos.util.build import build_timetable # noqa
request = get_request()
context = {"has_plan": True}
wanted_day = TimePeriod.get_next_relevant_day(timezone.now().date(), datetime.now().time())
if has_person(request.user):
person = request.user.person
lesson_periods = LessonPeriod.objects.daily_lessons_for_person(person, wanted_day)
type_ = person.timetable_type
# Build timetable
timetable = build_timetable("person", person, wanted_day)
if type_ is None:
# If no student or teacher, redirect to all timetables
context["has_plan"] = False
else:
context["lesson_periods"] = lesson_periods.per_period_one_day()
context["timetable"] = timetable
context["holiday"] = Holiday.on_day(wanted_day)
context["type"] = type_
context["day"] = wanted_day
context["periods"] = TimePeriod.get_times_dict()
......@@ -600,9 +620,36 @@ class TimetableWidget(DashboardWidget):
verbose_name = _("Timetable widget")
class DateRangeQuerySet(models.QuerySet):
def within_dates(self, start: date, end: date):
""" Filter for all events within a date range. """
return self.filter(date_start__lte=end, date_end__gte=start)
def in_week(self, wanted_week: CalendarWeek):
""" Filter for all events within a calendar week. """
return self.within_dates(wanted_week[0], wanted_week[6])
def on_day(self, day: date):
""" Filter for all events on a certain day. """
return self.within_dates(day, day)
def at_time(self, when: Optional[datetime] = None):
""" Filter for the events taking place at a certain point in time. """
now = when or datetime.now()
return self.on_day(now.date()).filter(
period_from__time_start__lte=now.time(),
period_to__time_end__gte=now.time()
)
class AbsenceReason(ExtensibleModel):
title = models.CharField(verbose_name=_("Title"), max_length=50)
description = models.TextField(verbose_name=_("Description"), blank=True, null=True)
short_name = models.CharField(verbose_name=_("Short name"), max_length=255)
name = models.CharField(verbose_name=_("Name"), blank=True, null=True, max_length=255)
class Meta:
verbose_name = _("Absence reason")
......@@ -610,7 +657,10 @@ class AbsenceReason(ExtensibleModel):
class Absence(ExtensibleModel):
reason = models.ForeignKey("AbsenceReason", on_delete=models.CASCADE, related_name="absences")
person = models.ManyToManyField("core.Person", related_name="absences")
teacher = models.ForeignKey("core.Person", on_delete=models.CASCADE, related_name="absences", null=True, blank=True)
group = models.ForeignKey("core.Group", on_delete=models.CASCADE, related_name="absences", null=True, blank=True)
room = models.ForeignKey("Room", on_delete=models.CASCADE, related_name="absences", null=True, blank=True)
date_start = models.DateField(verbose_name=_("Effective start date of absence"), null=True)
date_end = models.DateField(verbose_name=_("Effective end date of absence"), null=True)
......@@ -642,12 +692,38 @@ class Exam(ExtensibleModel):
verbose_name_plural = _("Exams")
class HolidayQuerySet(DateRangeQuerySet):
pass
class Holiday(ExtensibleModel):
objects = models.Manager.from_queryset(HolidayQuerySet)()
title = models.CharField(verbose_name=_("Title of the holidays"), max_length=50)
date_start = models.DateField(verbose_name=_("Effective start date of holidays"), null=True)
date_end = models.DateField(verbose_name=_("Effective end date of holidays"), null=True)
comments = models.TextField(verbose_name=_("Comments"), null=True, blank=True)
@classmethod
def on_day(cls, day: date) -> Optional["Holiday"]:
holidays = cls.objects.on_day(day)
if holidays.exists():
return holidays[0]
else:
return None
@classmethod
def in_week(cls, week: CalendarWeek) -> Dict[int, Optional["Holiday"]]:
per_weekday = {}
for weekday in range(TimePeriod.weekday_min, TimePeriod.weekday_max + 1):
holiday_date = week[weekday]
holidays = Holiday.objects.on_day(holiday_date)
if holidays.exists():
per_weekday[weekday] = holidays[0]
return per_weekday
class Meta:
ordering = ["date_start"]
indexes = [models.Index(fields=["date_start", "date_end"])]
......@@ -686,6 +762,14 @@ class Break(ExtensibleModel):
else self.before_period.weekday
)
@property
def after_period_number(self):
return (
self.after_period.period
if self.after_period
else self.before_period.period - 1
)
@property
def before_period_number(self):
return (
......@@ -694,6 +778,22 @@ class Break(ExtensibleModel):
else self.after_period.period + 1
)
@property
def time_start(self):
return self.after_period.time_end if self.after_period else None
@property
def time_end(self):
return self.before_period.time_start if self.before_period else None
@classmethod
def get_breaks_dict(cls) -> Dict[int, Tuple[datetime, datetime]]:
breaks = {}
for break_ in cls.objects.all():
breaks[break_.before_period_number] = break_
return breaks
class Meta:
ordering = ["after_period"]
indexes = [models.Index(fields=["after_period", "before_period"])]
......@@ -701,11 +801,64 @@ class Break(ExtensibleModel):
verbose_name_plural = _("Breaks")
class SupervisionQuerySet(models.QuerySet):
def annotate_week(self, week: Union[CalendarWeek, int]):
""" Annotate all lessons in the QuerySet with the number of the provided calendar week. """
if isinstance(week, CalendarWeek):
week_num = week.week
else:
week_num = week
return self.annotate(_week=models.Value(week_num, models.IntegerField()))
def filter_by_weekday(self, weekday: int):
self.filter(
Q(break_item__before_period__weekday=weekday)
| Q(break_item__after_period__weekday=weekday)
)
def filter_by_teacher(self, teacher: Union[Person, int]):
""" Filter for all supervisions given by a certain teacher. """
if self.count() > 0:
if hasattr(self[0], "_week"):
week = CalendarWeek(week=self[0]._week)
else:
week = CalendarWeek.current_week()
dates = [week[w] for w in range(0, 7)]
return self.filter(Q(substitutions__teacher=teacher, substitutions__date__in=dates) | Q(teacher=teacher))
return self
class Supervision(ExtensibleModel):
objects = models.Manager.from_queryset(SupervisionQuerySet)()
area = models.ForeignKey(SupervisionArea, models.CASCADE, verbose_name=_("Supervision area"), related_name="supervisions")
break_item = models.ForeignKey(Break, models.CASCADE, verbose_name=_("Break"), related_name="supervisions")
teacher = models.ForeignKey("core.Person", models.CASCADE, related_name="supervisions", verbose_name=_("Teacher"))
def get_substitution(
self, week: Optional[int] = None
) -> Optional[SupervisionSubstitution]:
wanted_week = week or getattr(self, "_week", None) or CalendarWeek().week
wanted_week = CalendarWeek(week=wanted_week)
# We iterate over all substitutions because this can make use of
# prefetching when this model is loaded from outside, in contrast
# to .filter()
for substitution in self.substitutions.all():
for weekday in range(0, 7):
if substitution.date == wanted_week[weekday]:
return substitution
return None
@property
def teachers(self):
return [self.teacher]
class Meta:
ordering = ["area", "break_item"]
verbose_name= _("Supervision")
......@@ -717,17 +870,82 @@ class SupervisionSubstitution(ExtensibleModel):
supervision = models.ForeignKey(Supervision, models.CASCADE, verbose_name=_("Supervision"), related_name="substitutions")
teacher = models.ForeignKey("core.Person", models.CASCADE, related_name="substituted_supervisions", verbose_name=_("Teacher"))
@property
def teachers(self):
return [self.teacher]
class Meta:
ordering = ["date", "supervision"]
verbose_name = _("Supervision substitution")
verbose_name_plural = _("Supervision substitutions")
class EventQuerySet(DateRangeQuerySet):
def filter_participant(self, person: Union[Person, int]):
""" Filter for all lessons a participant (student) attends. """
return self.filter(Q(groups_members=person))
def filter_group(self, group: Union[Group, int]):
""" Filter for all events a group (class) attends. """
if isinstance(group, int):
group = Group.objects.get(pk=group)
if group.parent_groups.all():
# Prevent to show lessons multiple times
return self.filter(groups=group)
else:
return self.filter(Q(groups=group) | Q(groups__parent_groups=group))
def filter_teacher(self, teacher: Union[Person, int]):
""" Filter for all lessons given by a certain teacher. """
return self.filter(teachers=teacher)
def filter_room(self, room: Union[Room, int]):
""" Filter for all lessons taking part in a certain room. """
return self.filter(rooms=room)
def filter_from_type(self, type_: str, pk: int) -> Optional[models.QuerySet]:
if type_ == "group":
return self.filter_group(pk)
elif type_ == "teacher":
return self.filter_teacher(pk)
elif type_ == "room":
return self.filter_room(pk)
else:
return None
def filter_from_person(self, person: Person) -> Optional[models.QuerySet]:
type_ = person.timetable_type
if type_ == "teacher":
# Teacher
return self.filter_teacher(person)
elif type_ == "group":
# Student
return self.filter_participant(person)
else:
# If no student or teacher
return None
class Event(ExtensibleModel):
title = models.CharField(verbose_name=_("Title"), max_length=50)
label_ = "event"
objects = models.Manager.from_queryset(EventQuerySet)()
title = models.CharField(verbose_name=_("Title"), max_length=255, blank=True, null=True)
date_start = models.DateField(verbose_name=_("Effective start date of event"), null=True)
date_end = models.DateField(verbose_name=_("Effective end date of event"), null=True)
absence_reason = models.ForeignKey("AbsenceReason", on_delete=models.CASCADE, related_name="absence_reason", verbose_name=_("Absence reason"))
period_from = models.ForeignKey("TimePeriod", on_delete=models.CASCADE, verbose_name=_("Effective start period of event"), related_name="+")
period_to = models.ForeignKey("TimePeriod", on_delete=models.CASCADE, verbose_name=_("Effective end period of event"), related_name="+")
......
......@@ -26,6 +26,10 @@ li.active > a > .sidenav-badge {
min-height: 65px;
}
.supervision-card {
min-height: 35px;
}
.lesson-card .card-content {
padding: 0;
text-align: center;
......@@ -53,6 +57,8 @@ li.active > a > .sidenav-badge {
.timetable-mobile-title-card {
margin-top: 50px;
margin-bottom: .60rem;
display: flex;
flex-grow: 1;
}
.timetable-mobile-title-card:first-child {
......@@ -112,3 +118,23 @@ table.substitutions td, table.substitutions th {
.black-text-a a {
color: black;
}
.holiday-badge {
float: left !important;
position: relative;
margin-left: 0 !important;
left: 50%;
transform: translate(-50%);
width: auto;
height: auto !important;
min-height: 26px;
margin-top: 5px;
}
.holiday-card .card-content{
width: 100%;
}
.holiday-card .holiday-badge {
margin-top: 0;
}
<div class="card lesson-card">
<div class="card-content">
{% for element in elements %}
{% if element.label_ == "lesson_period" %}
{% include "chronos/partials/lesson.html" with lesson_period=element %}
{% elif element.label_ == "event" %}
{% include "chronos/partials/event.html" with event=element %}
{% endif %}
{% endfor %}
</div>
</div>
<div class="lesson-with-event">
<p>
{# Teacher or room > Display groups #}
{% if type == "teacher" or type == "room" %}
{% include "chronos/partials/groups.html" with groups=event.groups.all %}
{% endif %}
{# Class or room > Display teachers #}
{% if type == "room" or type == "group" %}
{% include "chronos/partials/teachers.html" with teachers=event.teachers.all %}
{% endif %}
{# Teacher or class > Display rooms #}
{% if type == "teacher" or type == "group" %}
{% for room in event.rooms.all %}
<span class="tooltipped" data-position="bottom" data-tooltip="{{ room.name }}">
<a href="{% url "timetable" "room" room.pk %}">
{{ room.short_name }}
</a>
</span>
{% endfor %}
{% endif %}
{% if type == "teacher" and not event.groups.all and not event.rooms.all and event.title %}
<em>{{ event.title }}</em>
{% elif type == "group" and not event.teachers.all and not event.groups.all and event.title %}
<em>{{ event.title }}</em>
{% elif type == "room" and not event.teachers.all and not event.groups.all and event.title %}
<em>{{ event.title }}</em>
{% elif event.title %}
<br/>
<small>
<em>{{ event.title }}</em>
</small>
{% endif %}
</p>
</div>
<span class="badge new blue center-align holiday-badge">{{ holiday.title }}</span>
{% load i18n %}
<div class="card lesson-card">
<div class="card-content">
{# Every element of the lesson #}
{% for lesson_period in lessons %}
<div style="
{# Display background color only if no badge exists and it is not the old room and there are no holidays #}
{% if not lesson_period.get_substitution.cancelled and not lesson_period.is_hol %}
{% if not lesson_period.room != lesson_period.get_room or type != 1 %}
{% if lesson_period.lesson.subject.colour_fg %}
color: {{ lesson_period.lesson.subject.colour_fg }};
{% endif %}
{% if lesson_period.lesson.subject.colour_bg %}
background-color: {{ lesson_period.lesson.subject.colour_bg }};
{% endif %}
{% endif %}
{% endif %}
"
{# Add CSS class for sub when it's a sub #}
class="{% if lesson_period.get_substitution and smart %}{% if lesson_period.substitution.table.is_event %}lesson-with-event{% else %}lesson-with-sub{% endif %}{% endif %}"
>
<p>
{% if lesson_period.is_hol and smart %}
{# Do nothing #}
{% elif lesson_period.get_substitution and smart %}
{% with sub=lesson_period.get_substitution %}
{# SUBSTITUTION #}
{% if type == "room" and lesson_period.room != lesson_period.get_room %}
{# When it's the old room, let it empty #}
{% elif lesson_period.get_substitution.cancelled %}
{# When a badge (cancellation, etc.) exists, then display it with the teacher#}
{# Class or room > Display teacher #}
{% if type == "group" or type == "room" and lesson_period.lesson.teachers.all %}
{% include "chronos/partials/teachers.html" with teachers=lesson_period.lesson.teachers.all %}<br/>
{% endif %}
{# Badge #}
<span class="badge new green darken-2">{% trans "Cancelled" %}</span>
{% else %}
{# Display sub #}
{# Teacher or room > display classes #}
{% if type == "teacher" or type == "room" %}
{% include "chronos/partials/groups.html" with groups=lesson_period.lesson.groups.all %}
{% endif %}
{# Display teacher with tooltip #}
{% include "chronos/partials/subs/teachers.html" %}
{# Display subject #}
{% include "chronos/partials/subs/subject.html" %}
{# Teacher or class > display room #}
{% if type == "teacher" or type == "group" %}
{% include "chronos/partials/subs/room.html" %}
{% endif %}
{% endif %}
{# When it isn't a room or the old plan, then display the extra text (e. g. work orders) AND NOT A EVENT#}
{% if not lesson_period.substitution.table.is_event %}
{% if not type == "room" or not lesson_period.is_old %}
<br>
<small>
<em>{{ lesson_period.substitution.table.text|default:"" }}</em>
</small>
{% endif %}
{% endif %}
{# Display the extra text for events #}
{% if lesson_period.substitution.table.is_event %}
{% if type == 0 and lesson_period.substitution.table.classes == "" and lesson_period.substitution.table.rooms|length == 0 and lesson_period.substitutions.table.teachers|length == 0 %}
<em>{{ lesson_period.substitution.table.text|default:"" }}</em>
{% elif type == 2 and lesson_period.substitution.table.teachers|length == 0 and lesson_period.substitution.table.rooms|length == 0 %}
<em>{{ lesson_period.substitution.table.text|default:"" }}</em>
{% elif type == 1 and lesson_period.substitution.table.teachers|length == 0 and lesson_period.substitution.table.classes == "" %}
<em>{{ lesson_period.substitution.table.text|default:"" }}</em>
{% else %}
<br>
<small>
<em>{{ lesson_period.substitution.table.text|default:"" }}</em>
</small>
{% endif %}
{% endif %}
{% endwith %}
{% else %}
{# Normal plan #}
{# Teacher or room > Display classes #}
{% if type == "teacher" or type == "room" %}
{# {{ element_container.element.classes }}#}
{% if lesson_period.lesson.groups %}
{% include "chronos/partials/groups.html" with groups=lesson_period.lesson.groups.all %}
{% endif %}
<div style="
{# Display background color only if no badge exists and it is not the old room and there are no holidays #}
{% if not lesson_period.get_substitution.cancelled and not lesson_period.get_substitution.cancelled_for_teachers %}
{% if not type == "room" or lesson_period.room == lesson_period.get_room or lesson_period.get_room == el %}
{% if lesson_period.lesson.subject.colour_fg %}
color: {{ lesson_period.lesson.subject.colour_fg }};
{% endif %}
{# Class or room > Display teacher #}
{% if type == "room" or type == "group" %}
{% include "chronos/partials/teachers.html" with teachers=lesson_period.lesson.teachers.all %}
{% if lesson_period.lesson.subject.colour_bg %}
background-color: {{ lesson_period.lesson.subject.colour_bg }};
{% endif %}
{% endif %}
{% endif %}
"
{# Add CSS class for sub when it's a sub #}
class="{% if lesson_period.get_substitution and smart %}lesson-with-sub{% endif %}"
>
<p>
{% if lesson_period.is_hol and smart %}
{# Do nothing #}
{% elif lesson_period.get_substitution and smart %}
{% with sub=lesson_period.get_substitution %}
{# SUBSTITUTION #}
{% if type == "room" and lesson_period.room != lesson_period.get_room and lesson_period.get_room != el %}
{# When it's the old room, let it empty #}
{% elif sub.cancelled or sub.cancelled_for_teachers %}
{# When a badge (cancellation, etc.) exists, then display it with the teacher#}
{# Class or room > Display teacher #}
{% if type == "group" or type == "room" and lesson_period.lesson.teachers.all %}
{% include "chronos/partials/teachers.html" with teachers=lesson_period.lesson.teachers.all %}<br/>
{% endif %}
{# Badge #}
{% include "chronos/partials/subs/badge.html" with sub=sub %}
{% else %}
{# Display sub #}
{# Teacher or room > display classes #}
{% if type == "teacher" or type == "room" %}
{% include "chronos/partials/groups.html" with groups=lesson_period.lesson.groups.all %}
{% endif %}
{# Display teacher with tooltip #}
{% include "chronos/partials/subs/teachers.html" with type="substitution" el=sub %}
{# Display subject #}
{% include "chronos/partials/subs/subject.html" with type="substitution" el=sub %}
{# Teacher or class > display room #}
{% if type == "teacher" or type == "group" %}
{% include "chronos/partials/subs/room.html" with type="substitution" el=sub %}
{% endif %}
{% endif %}
{# When it isn't a room or the old plan, then display the extra text (e. g. work orders) #}
{% if not lesson_period.room == lesson_period.get_room and lesson_period.get_room != el and sub.comment %}
<br>
<small>
<em>{{ lesson_period.get_substitution.comment }}</em>
</small>
{% endif %}
{% endwith %}
{% else %}
{# Normal plan #}
{# Display subject #}
<strong>
{# Teacher or room > Display classes #}
{% if type == "teacher" or type == "room" %}
{# {{ element_container.element.classes }}#}
{% if lesson_period.lesson.groups %}
{% include "chronos/partials/groups.html" with groups=lesson_period.lesson.groups.all %}
{% endif %}
{% endif %}
{# Class or room > Display teacher #}
{% if type == "room" or type == "group" %}
{% include "chronos/partials/teachers.html" with teachers=lesson_period.lesson.teachers.all %}
{% endif %}
{# Display subject #}
<strong>
<span data-position="bottom" class="tooltipped"
data-tooltip="{{ lesson_period.lesson.subject.name }}">{{ lesson_period.lesson.subject.abbrev }}</span>
</strong>
</strong>
{# Teacher or class > Display room #}
{% if type == "teacher" or type == "group" %}
{% if lesson_period.room %}
<span class="tooltipped" data-position="bottom"
data-tooltip="{{ lesson_period.room.name }}">
{# Teacher or class > Display room #}
{% if type == "teacher" or type == "group" %}
{% if lesson_period.room %}
<span class="tooltipped" data-position="bottom"
data-tooltip="{{ lesson_period.room.name }}">
<a href="{% url "timetable" "room" lesson_period.room.pk %}">
{{ lesson_period.room.short_name }}
</a>
</span>
{% endif %}
{% endif %}
{% endif %}
</p>
</div>
{% endfor %}
</div>
{% endif %}
{% endif %}
{% endif %}
</p>
</div>
{% for period, lessons in lesson_periods.items %}
{% if holiday %}
<div class="row">
<div class="col s4">
{% include "chronos/partials/period_time.html" with period=period periods=periods %}
</div>
<div class="col s8">
{% include "chronos/partials/lesson.html" with lessons=lessons %}
<div class="col s12">
<div class="card col s12 holiday-card">
<div class="card-content">
<p>
{% include "chronos/partials/holiday.html" with holiday=holiday %}<br/>
</p>
</div>
</div>
</div>
</div>
{% endfor %}
{% else %}
{% for row in timetable %}
<div class="row">
<div class="col s4">
{% if row.type == "period" %}
{% include "chronos/partials/period_time.html" with period=row.period periods=periods %}
{% endif %}
</div>
<div class="col s8">
{% if row.type == "period" %}
{% include "chronos/partials/elements.html" with elements=row.col %}
{% else %}
{% include "chronos/partials/supervision.html" with supervision=row.col %}
{% endif %}
</div>
</div>
{% endfor %}
{% endif %}
{% 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 %}
{% 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
{% endif %}
<strong>
{% if type == "substitution" %}
{{ el.lesson_period.period.period }}.
{% elif type == "supervision_substitution" %}
{% with break=el.supervision.break_item %}
{{ break.after_period_number }}./{{ break.before_period_number }}.
{% endwith %}
{% endif %}
</strong>
{% 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 %}
{% if type == "substitution" %}
{% if el.cancelled or el.cancelled_for_teachers %}
{# Canceled lesson: no room #}
{% elif sub.room and sub.lesson_period.room %}
{% elif el.room and el.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 %}
data-tooltip="{{ el.lesson_period.room.name }} → {{ el.lesson_period.room.name }}"
title="{{ el.lesson_period.room.name }} → {{ el.lesson_period.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 #}
<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 %}
data-tooltip="{{ el.room.name }}"
title="{{ el.room.name }}">
<a href="{% url "timetable" "room" el.room.pk %}">
{{ el.room.short_name }}
</a>
</span>
{% elif not el.room and not el.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>
data-tooltip="{{ el.lesson_period.room.name }}"
title="{{ el.lesson_period.room.name }}">
<a href="{% url "timetable" "room" el.lesson_period.room.pk %}">
{{ el.lesson_period.room.short_name }}
</a>
</span>
{% endif %}
{% 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 %}
{% 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 %}
{% endif %}
{% 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>
{% 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.abbrev }}</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.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>
<span data-position="bottom" class="tooltipped" data-tooltip="{{ el.subject.name }}">
<strong>{{ el.subject.abbrev }}</strong>
</span>
{% elif el.subject and not el.lesson_period.lesson.subject %}
<span data-position="bottom" class="tooltipped" data-tooltip="{{ el.subject.name }}">
<strong>{{ el.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>
<span data-position="bottom" class="tooltipped" data-tooltip="{{ el.lesson_period.lesson.subject.name }}">
<strong>{{ el.lesson_period.lesson.subject.abbrev }}</strong>
</span>
{% endif %}
{% elif type == "supervision_substitution" %}
{% trans "Supervision" %}
{% endif %}
{% if not sub.is_event %}
{% if sub.sub.type == 1 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 %}
{% 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=sub.lesson_period.lesson.teachers.all %}
{% include "chronos/partials/teachers.html" with teachers=el.lesson_period.lesson.teachers.all %}
</s>
<strong>
{% include "chronos/partials/teachers.html" with teachers=sub.teachers.all %}
{% include "chronos/partials/teachers.html" with teachers=el.teachers.all %}
</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 %}
{% 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 %}
{% else %}
{% include "chronos/partials/teachers.html" with teachers=sub.teachers.all %}
{% elif type == "supervision_substitution" %}
<s>
{% include "chronos/partials/teachers.html" with teachers=el.supervision.teachers %}
</s>
<strong>
{% include "chronos/partials/teachers.html" with teachers=el.teachers %}
</strong>
{% endif %}
{% load i18n %}
<div class="card lesson-card supervision-card">
<div class="card-content">
{% if supervision %}
<div style="
{% if supervision.area.colour_fg %}
color: {{ supervision.area.colour_fg }};
{% endif %}
{% if supervision.area.colour_bg %}
background-color: {{ supervision.area.colour_bg }};
{% endif %}
" class="{% if supervision.get_substitution and smart %}lesson-with-sub{% endif %}">
<p>
<strong>{% trans "Supervision" %}</strong>
<span data-position="bottom" class="tooltipped"
data-tooltip="{{ supervision.area.name }}" title="{{ supervision.area.name }}">
{{ supervision.area.short_name }}
</span>
{% if supervision.get_substitution and smart %}
{% include "chronos/partials/subs/teachers.html" with type="supervision_substitution" el=supervision.get_substitution %}
{% elif type == "supervision_area" %}
{% include "chronos/partials/teachers.html" with teachers=supervision.teachers %}
{% endif %}
</p>
</div>
{% endif %}
</div>
</div>
{% load i18n %}
<div class="col s12 m6 right">
<div class="col s2 no-print">
<a class="waves-effect waves-teal btn-flat btn-flat-medium right" href="{{ url_prev }}">
<i class="material-icons center">navigate_before</i>
</a>
</div>
<div class="input-field col s8 no-margin hide-on-med-and-up">
<select id="calendar-week-1">
{% for week in weeks %}
<option value="{{ week.week }}" {% if week == wanted_week %}
selected {% endif %}>{% trans "CW" %} {{ week.week }} ({{ week.0|date:"SHORT_DATE_FORMAT" }}–{{ week.6|date:"SHORT_DATE_FORMAT" }})
</option>
{% endfor %}
</select>
</div>
<div class="input-field col s8 no-margin hide-on-med-and-down">
<select id="calendar-week-2">
{% for week in weeks %}
<option value="{{ week.week }}" {% if week == wanted_week %}
selected {% endif %}>{% trans "CW" %} {{ week.week }} ({{ week.0|date:"j.n." }}–{{ week.6|date:"SHORT_DATE_FORMAT" }})
</option>
{% endfor %}
</select>
</div>
<div class="input-field col s8 no-margin hide-on-small-and-down hide-on-large-only">
<select id="calendar-week-3">
{% for week in weeks %}
<option value="{{ week.week }}" {% if week == wanted_week %}
selected {% endif %}>{% trans "CW" %} {{ week.week }} ({{ week.0|date:"j.n." }}–{{ week.6|date:"j.n." }})
</option>
{% endfor %}
</select>
</div>
<div class="col s2 no-print">
<a class="waves-effect waves-teal btn-flat btn-flat-medium left" href="{{ url_next }}">
<i class="material-icons center">navigate_next</i>
</a>
</div>
</div>
......@@ -57,37 +57,34 @@
</p>
</td>
{% endif %}
{% for sub in substitutions %}
<tr class="{% if sub.type_ == "cancellation" %}green-text{% else %}black-text{% endif %}">
{# TODO: Extend support for blue and purple (supervisions and events) #}
{% for item in substitutions %}
<tr class="{% include "chronos/partials/subs/colour.html" with item=item %}">
{# TODO: Extend support for purple (events) #}
<td>
{% include "chronos/partials/groups.html" with groups=sub.lesson_period.lesson.groups.all %}
{% if item.type == "substitution" %}
{% include "chronos/partials/groups.html" with groups=item.el.lesson_period.lesson.groups.all %}
{% endif %}
</td>
<td>
<strong>
{{ sub.lesson_period.period.period }}.
</strong>
{% include "chronos/partials/subs/period.html" with type=item.type el=item.el %}
</td>
<td>
{% include "chronos/partials/subs/teachers.html" %}
{% include "chronos/partials/subs/teachers.html" with type=item.type el=item.el %}
</td>
<td>
{% include "chronos/partials/subs/subject.html" %}
{% include "chronos/partials/subs/subject.html" with type=item.type el=item.el %}
</td>
<td>
{% include "chronos/partials/subs/room.html" %}
{% include "chronos/partials/subs/room.html" with type=item.type el=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 %}
......
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