Newer
Older
from collections import OrderedDict

Jonathan Weth
committed
from datetime import date
from calendarweek import CalendarWeek

Jonathan Weth
committed
from django.apps import apps
from django.db.models import QuerySet

Jonathan Weth
committed
from aleksis.core.models import Person

Jonathan Weth
committed
LessonPeriod = apps.get_model("chronos", "LessonPeriod")
TimePeriod = apps.get_model("chronos", "TimePeriod")
Break = apps.get_model("chronos", "Break")
Supervision = apps.get_model("chronos", "Supervision")

Jonathan Weth
committed
LessonSubstitution = apps.get_model("chronos", "LessonSubstitution")
SupervisionSubstitution = apps.get_model("chronos", "SupervisionSubstitution")
Event = apps.get_model("chronos", "Event")
ExtraLesson = apps.get_model("chronos", "ExtraLesson")
def group_by_periods(objs: QuerySet, is_person: bool =False) -> dict:
per_period = {}
for obj in objs:
period = obj.period.period
weekday = obj.period.weekday
if period not in per_period:
per_period[period] = [] if is_person else {}
if not is_person and weekday not in per_period[period]:
per_period[period][weekday] = []
if is_person:
per_period[period].append(obj)
else:
per_period[period][weekday].append(obj)
return per_period

Jonathan Weth
committed
def build_timetable(
type_: str, obj: Union[int, Person], date_ref: Union[CalendarWeek, date]
):
needed_breaks = []

Jonathan Weth
committed
if not isinstance(obj, int):
pk = obj.pk
else:
pk = obj
is_person = False
if type_ == "person":
is_person = True
type_ = obj.timetable_type
# Get matching holidays
if is_person:
holiday = Holiday.on_day(date_ref)
else:
holidays_per_weekday = Holiday.in_week(date_ref)
# Get matching lesson periods

Jonathan Weth
committed
if is_person:
lesson_periods = LessonPeriod.objects.daily_lessons_for_person(obj, date_ref)
else:
lesson_periods = LessonPeriod.objects.in_week(date_ref).filter_from_type(
type_, obj
)
# Sort lesson periods in a dict
lesson_periods_per_period = group_by_periods(lesson_periods, is_person=is_person)
# Get events
if is_person:
extra_lessons = ExtraLesson.objects.on_day(date_ref).filter_from_person(obj)
else:
extra_lessons = ExtraLesson.objects.filter(week=date_ref.week).filter_from_type(type_, obj)
# Sort lesson periods in a dict
extra_lessons_per_period = group_by_periods(extra_lessons, is_person=is_person)
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# Get events
if is_person:
events = Event.objects.on_day(date_ref).filter_from_person(obj)
else:
events = Event.objects.in_week(date_ref).filter_from_type(type_, obj)
# Sort events in a dict
events_per_period = {}
for event in events:
if not is_person and event.date_start < date_ref[TimePeriod.weekday_min]:
# If start date not in current week, set weekday and period to min
weekday_from = TimePeriod.weekday_min
period_from_first_weekday = TimePeriod.period_min
else:
weekday_from = event.date_start.weekday()
period_from_first_weekday = event.period_from.period
if not is_person and event.date_end > date_ref[TimePeriod.weekday_max]:
# If end date not in current week, set weekday and period to max
weekday_to = TimePeriod.weekday_max
period_to_last_weekday = TimePeriod.period_max
else:
weekday_to = event.date_end.weekday()
period_to_last_weekday = event.period_to.period
for weekday in range(weekday_from, weekday_to + 1):
if is_person and weekday != date_ref.weekday():
# If daily timetable for person, skip other weekdays
continue
if weekday == weekday_from:
# If start day, use start period
period_from = period_from_first_weekday
else:
# If not start day, use min period
period_from = TimePeriod.period_min
if weekday == weekday_to:
# If end day, use end period
period_to = period_to_last_weekday
else:
# If not end day, use max period
period_to = TimePeriod.period_max
for period in range(period_from, period_to +1):
if period not in events_per_period:
events_per_period[period] = [] if is_person else {}
if not is_person and weekday not in events_per_period[period]:
events_per_period[period][weekday] = []
if is_person:
events_per_period[period].append(event)
else:
events_per_period[period][weekday].append(event)
if type_ == "teacher":
# Get matching supervisions

Jonathan Weth
committed
if is_person:
week = CalendarWeek.from_date(date_ref)
else:
week = date_ref

Jonathan Weth
committed
supervisions = Supervision.objects.all().annotate_week(week).filter_by_teacher(obj)

Jonathan Weth
committed
if is_person:
supervisions.filter_by_weekday(date_ref.weekday())
supervisions_per_period_after = {}
for supervision in supervisions:
weekday = supervision.break_item.weekday
period_after_break = supervision.break_item.before_period_number
print(supervision, weekday, period_after_break)
if period_after_break not in needed_breaks:
needed_breaks.append(period_after_break)

Jonathan Weth
committed
if (
not is_person
and period_after_break not in supervisions_per_period_after
):
supervisions_per_period_after[period_after_break] = {}

Jonathan Weth
committed
if is_person:
supervisions_per_period_after[period_after_break] = supervision
else:
supervisions_per_period_after[period_after_break][weekday] = supervision
# Get ordered breaks
breaks = OrderedDict(sorted(Break.get_breaks_dict().items()))
rows = []
for period, break_ in breaks.items(): # period is period after break
# Break
if type_ == "teacher" and period in needed_breaks:
row = {
"type": "break",
"after_period": break_.after_period_number,
"before_period": break_.before_period_number,
"time_start": break_.time_start,
"time_end": break_.time_end,
}

Jonathan Weth
committed
if not is_person:
cols = []
for weekday in range(
TimePeriod.weekday_min, TimePeriod.weekday_max + 1
):
col = None
if (
period in supervisions_per_period_after
and weekday not in holidays_per_weekday
):

Jonathan Weth
committed
if weekday in supervisions_per_period_after[period]:
col = supervisions_per_period_after[period][weekday]
cols.append(col)

Jonathan Weth
committed
row["cols"] = cols
else:
if period in supervisions_per_period_after and not holiday:

Jonathan Weth
committed
col = supervisions_per_period_after[period]
row["col"] = col
rows.append(row)
if period <= TimePeriod.period_max:
row = {
"type": "period",
"period": period,
"time_start": break_.before_period.time_start,
"time_end": break_.before_period.time_end,
}

Jonathan Weth
committed
if not is_person:
cols = []
for weekday in range(
TimePeriod.weekday_min, TimePeriod.weekday_max + 1
):
col = []
# Add lesson periods
if (
period in lesson_periods_per_period
and weekday not in holidays_per_weekday
):

Jonathan Weth
committed
if weekday in lesson_periods_per_period[period]:
col += lesson_periods_per_period[period][weekday]
# Add extra lessons
if (
period in extra_lessons_per_period
and weekday not in holidays_per_weekday
):
if weekday in extra_lessons_per_period[period]:
col += extra_lessons_per_period[period][weekday]
if (
period in events_per_period
and weekday not in holidays_per_weekday
):
if weekday in events_per_period[period]:
col += events_per_period[period][weekday]

Jonathan Weth
committed
cols.append(col)
row["cols"] = cols
else:
col = []

Jonathan Weth
committed
col += lesson_periods_per_period[period]
col += events_per_period[period]

Jonathan Weth
committed
row["col"] = col
rows.append(row)
return rows

Jonathan Weth
committed
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)
# Get supervision substitutions
super_subs = SupervisionSubstitution.objects.filter(date=wanted_day)
for super_sub in super_subs:
row = {
"type": "supervision_substitution",
"sort_a": "Z.{}".format(super_sub.teacher),
"sort_b": "{}".format(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": "{}".format(extra_lesson.group_names),
"sort_b": "{}".format(extra_lesson.period.period),
"el": extra_lesson,
}
rows.append(row)
# Sort all items
def sorter(row: dict):
return row["sort_a"] + row["sort_b"]
rows.sort(key=sorter)

Jonathan Weth
committed
return rows
def build_weekdays(
base: List[Tuple[int, str]], wanted_week: CalendarWeek
) -> List[dict]:
holidays_per_weekday = Holiday.in_week(wanted_week)
weekdays = []
for key, name in base[TimePeriod.weekday_min : TimePeriod.weekday_max + 1]:
weekday = {
"key": key,
"name": name,
"date": wanted_week[key],
"holiday": holidays_per_weekday[key]
if key in holidays_per_weekday
else None,
}
weekdays.append(weekday)
return weekdays