Skip to content
Snippets Groups Projects
Commit 2fb590f3 authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Merge branch 'show-events-current-changes-substitutions-table' into 'master'

Show events with current changes in substitutions table

See merge request !394
parents a15f2aa4 5b37776a
No related branches found
No related tags found
1 merge request!394Show events with current changes in substitutions table
Pipeline #194042 failed
...@@ -11,6 +11,18 @@ export default { ...@@ -11,6 +11,18 @@ export default {
required: false, required: false,
default: "name", default: "name",
}, },
alternativeAttr: {
type: String,
required: false,
default: null,
},
},
methods: {
getAttr(item) {
let val = item[this.attr];
if (val) return val;
return this.alternativeAttr ? item[this.alternativeAttr] : val;
},
}, },
}; };
</script> </script>
...@@ -19,7 +31,7 @@ export default { ...@@ -19,7 +31,7 @@ export default {
<span v-bind="$attrs"> <span v-bind="$attrs">
<span v-for="(item, idx) in items" :key="idx"> <span v-for="(item, idx) in items" :key="idx">
<!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text --> <!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
{{ item[attr] }}{{ idx + 1 < items.length ? "," : "" }} {{ getAttr(item) }}{{ idx + 1 < items.length ? "," : "" }}
</span> </span>
</span> </span>
</template> </template>
...@@ -99,14 +99,30 @@ import DateSelectFooter from "aleksis.core/components/generic/DateSelectFooter.v ...@@ -99,14 +99,30 @@ import DateSelectFooter from "aleksis.core/components/generic/DateSelectFooter.v
<!-- component and reuse? --> <!-- component and reuse? -->
<template #groups="{ item: { oldGroups, newGroups } }"> <template #groups="{ item: { oldGroups, newGroups } }">
<span v-if="newGroups.length > 0"> <span v-if="newGroups.length > 0">
<span class="strike-through" v-for="g in oldGroups" :key="g.id">{{ <span class="strike-through">
g.shortName <lesson-event-link-iterator
}}</span> :items="oldGroups"
attr="shortName"
alternative-attr="name"
/>
</span>
<!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text --> <!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
<span>&nbsp;&nbsp;</span> <span>&nbsp;&nbsp;</span>
<strong v-for="g in newGroups" :key="g.id">{{ g.shortName }}</strong> <strong>
<lesson-event-link-iterator
:items="newGroups"
attr="shortName"
alternative-attr="name"
/>
</strong>
</span>
<span v-else>
<lesson-event-link-iterator
:items="oldGroups"
attr="shortName"
alternative-attr="name"
/>
</span> </span>
<span v-else v-for="g in oldGroups" :key="g.id">{{ g.shortName }}</span>
</template> </template>
<template #time="{ item: { startSlot, endSlot, startTime, endTime } }"> <template #time="{ item: { startSlot, endSlot, startTime, endTime } }">
<span v-if="startSlot && endSlot && startSlot === endSlot"> <span v-if="startSlot && endSlot && startSlot === endSlot">
...@@ -124,17 +140,29 @@ import DateSelectFooter from "aleksis.core/components/generic/DateSelectFooter.v ...@@ -124,17 +140,29 @@ import DateSelectFooter from "aleksis.core/components/generic/DateSelectFooter.v
</template> </template>
<template #teachers="{ item: { oldTeachers, newTeachers } }"> <template #teachers="{ item: { oldTeachers, newTeachers } }">
<span v-if="newTeachers.length > 0"> <span v-if="newTeachers.length > 0">
<span class="strike-through" v-for="t in oldTeachers" :key="t.id"> <span class="strike-through">
{{ t.shortName || t.fullName }} <lesson-event-link-iterator
:items="oldTeachers"
attr="shortName"
alternative-attr="fullName"
/>
</span> </span>
<!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text --> <!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
<span>&nbsp;&nbsp;</span> <span>&nbsp;&nbsp;</span>
<strong v-for="t in newTeachers" :key="t.id"> <strong>
{{ t.shortName || t.fullName }} <lesson-event-link-iterator
:items="newTeachers"
attr="shortName"
alternative-attr="fullName"
/>
</strong> </strong>
</span> </span>
<span v-else v-for="t in oldTeachers" :key="t.id"> <span v-else>
{{ t.shortName || t.fullName }} <lesson-event-link-iterator
:items="oldTeachers"
attr="shortName"
alternative-attr="fullName"
/>
</span> </span>
</template> </template>
<template #subject="{ item: { oldSubject, newSubject } }"> <template #subject="{ item: { oldSubject, newSubject } }">
...@@ -151,18 +179,30 @@ import DateSelectFooter from "aleksis.core/components/generic/DateSelectFooter.v ...@@ -151,18 +179,30 @@ import DateSelectFooter from "aleksis.core/components/generic/DateSelectFooter.v
</template> </template>
<template #rooms="{ item: { oldRooms, newRooms } }"> <template #rooms="{ item: { oldRooms, newRooms } }">
<span v-if="newRooms.length > 0"> <span v-if="newRooms.length > 0">
<span class="strike-through" v-for="r in oldRooms" :key="r.id">{{ <span class="strike-through">
r.shortName || r.name <lesson-event-link-iterator
}}</span> :items="oldRooms"
attr="shortName"
alternative-attr="name"
/>
</span>
<!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text --> <!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
<span>&nbsp;&nbsp;</span> <span>&nbsp;&nbsp;</span>
<strong v-for="r in newRooms" :key="r.id">{{ <strong>
r.shortName || r.name <lesson-event-link-iterator
}}</strong> :items="newRooms"
attr="shortName"
alternative-attr="name"
/>
</strong>
</span>
<span v-else>
<lesson-event-link-iterator
:items="oldRooms"
attr="shortName"
alternative-attr="name"
/>
</span> </span>
<span v-else v-for="r in oldRooms" :key="r.id">{{
r.shortName || r.name
}}</span>
</template> </template>
<template #notes="{ item: { cancelled, notes } }"> <template #notes="{ item: { cancelled, notes } }">
<v-chip v-if="cancelled" color="green" text-color="white" small> <v-chip v-if="cancelled" color="green" text-color="white" small>
...@@ -189,8 +229,11 @@ import DateSelectFooter from "aleksis.core/components/generic/DateSelectFooter.v ...@@ -189,8 +229,11 @@ import DateSelectFooter from "aleksis.core/components/generic/DateSelectFooter.v
import { substitutionsForDate } from "./substitutions.graphql"; import { substitutionsForDate } from "./substitutions.graphql";
import { DateTime } from "luxon"; import { DateTime } from "luxon";
import LessonEventLinkIterator from "./LessonEventLinkIterator.vue";
export default { export default {
name: "Substitutions", name: "Substitutions",
components: { LessonEventLinkIterator },
props: { props: {
date: { date: {
type: String, type: String,
......
...@@ -212,6 +212,15 @@ class LessonEventQuerySet(RecurrencePolymorphicQuerySet): ...@@ -212,6 +212,15 @@ class LessonEventQuerySet(RecurrencePolymorphicQuerySet):
"""Get all lesson events that are amending other events.""" """Get all lesson events that are amending other events."""
return self.filter(self.amending_q()) return self.filter(self.amending_q())
@staticmethod
def current_changes_q() -> Q:
"""Get all lesson events that are current changes."""
return Q(amends__isnull=False) | Q(current_change=True)
def current_changes(self) -> "LessonEventQuerySet":
"""Get all lesson events that are current changes."""
return self.filter(self.current_changes_q())
class SupervisionEventQuerySet(LessonEventQuerySet): class SupervisionEventQuerySet(LessonEventQuerySet):
pass pass
# Generated by Django 5.1.3 on 2024-11-30 10:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('chronos', '0020_add_global_permissions'),
]
operations = [
migrations.AddField(
model_name='lessonevent',
name='current_change',
field=models.BooleanField(default=False, verbose_name='Is this a current change?'),
),
]
...@@ -215,6 +215,9 @@ class LessonEvent(CalendarEvent): ...@@ -215,6 +215,9 @@ class LessonEvent(CalendarEvent):
blank=True, blank=True,
) )
# current_change=True will show this event in substitutions table
current_change = models.BooleanField(default=False, verbose_name=_("Is this a current change?"))
@property @property
def actual_groups(self: LessonEvent) -> QuerySet[Group]: def actual_groups(self: LessonEvent) -> QuerySet[Group]:
"""Get list of the groups of this lesson event.""" """Get list of the groups of this lesson event."""
...@@ -431,6 +434,7 @@ class LessonEvent(CalendarEvent): ...@@ -431,6 +434,7 @@ class LessonEvent(CalendarEvent):
not_amended = params.get("not_amended", False) not_amended = params.get("not_amended", False)
not_amending = params.get("not_amending", False) not_amending = params.get("not_amending", False)
amending = params.get("amending", False) amending = params.get("amending", False)
current_changes = params.get("current_changes", False)
own = params.get("own", False) own = params.get("own", False)
if not_amended: if not_amended:
...@@ -442,6 +446,9 @@ class LessonEvent(CalendarEvent): ...@@ -442,6 +446,9 @@ class LessonEvent(CalendarEvent):
if amending: if amending:
q = q & LessonEventQuerySet.amending_q() q = q & LessonEventQuerySet.amending_q()
if current_changes:
q = q & LessonEventQuerySet.current_changes_q()
if request and "own" in params: if request and "own" in params:
if own: if own:
q = q & LessonEventQuerySet.for_person_q(request.user.person) q = q & LessonEventQuerySet.for_person_q(request.user.person)
......
...@@ -153,11 +153,13 @@ class SubstitutionType(graphene.ObjectType): ...@@ -153,11 +153,13 @@ class SubstitutionType(graphene.ObjectType):
def resolve_old_groups(root, info): def resolve_old_groups(root, info):
le = root["REFERENCE_OBJECT"] le = root["REFERENCE_OBJECT"]
return le.amends.groups.all() or le.groups.all() if le.amends and le.amends.groups.all():
return le.amends.groups.all()
return le.groups.all()
def resolve_new_groups(root, info): def resolve_new_groups(root, info):
le = root["REFERENCE_OBJECT"] le = root["REFERENCE_OBJECT"]
if le.groups.all() and le.amends.groups.all(): if le.groups.all() and le.amends and le.amends.groups.all():
return le.groups.all() return le.groups.all()
else: else:
return [] return []
...@@ -176,11 +178,13 @@ class SubstitutionType(graphene.ObjectType): ...@@ -176,11 +178,13 @@ class SubstitutionType(graphene.ObjectType):
def resolve_old_teachers(root, info): def resolve_old_teachers(root, info):
le = root["REFERENCE_OBJECT"] le = root["REFERENCE_OBJECT"]
return le.amends.teachers.all() or le.teachers.all() if le.amends and le.amends.teachers.all():
return le.amends.teachers.all()
return le.teachers.all()
def resolve_new_teachers(root, info): def resolve_new_teachers(root, info):
le = root["REFERENCE_OBJECT"] le = root["REFERENCE_OBJECT"]
if le.teachers.all() and le.amends.teachers.all(): if le.teachers.all() and le.amends and le.amends.teachers.all():
return le.teachers.all() return le.teachers.all()
else: else:
return [] return []
...@@ -189,30 +193,32 @@ class SubstitutionType(graphene.ObjectType): ...@@ -189,30 +193,32 @@ class SubstitutionType(graphene.ObjectType):
le = root["REFERENCE_OBJECT"] le = root["REFERENCE_OBJECT"]
if le.name == "supervision": if le.name == "supervision":
return "SUPERVISION" return "SUPERVISION"
elif not le.amends.subject and not le.subject: elif not (le.amends and le.amends.subject) and not le.subject:
return le.amends.title if le.amends:
return le.amends.title
return le.title
else: else:
subject = le.amends.subject or le.subject subject = le.amends.subject if le.amends and le.amends.subject else le.subject
return subject.short_name or subject.name return subject.short_name or subject.name
def resolve_new_subject(root, info): def resolve_new_subject(root, info):
le = root["REFERENCE_OBJECT"] le = root["REFERENCE_OBJECT"]
if le.name == "supervision": if le.name == "supervision":
return None return None
elif not le.amends.subject and not le.subject: elif le.subject and le.amends and le.amends.subject:
return le.title
elif le.subject and le.amends.subject:
return le.subject.short_name or le.subject.name return le.subject.short_name or le.subject.name
else: else:
return None return None
def resolve_old_rooms(root, info): def resolve_old_rooms(root, info):
le = root["REFERENCE_OBJECT"] le = root["REFERENCE_OBJECT"]
return le.amends.rooms.all() or le.rooms.all() if le.amends and le.amends.rooms.all():
return le.amends.rooms.all()
return le.rooms.all()
def resolve_new_rooms(root, info): def resolve_new_rooms(root, info):
le = root["REFERENCE_OBJECT"] le = root["REFERENCE_OBJECT"]
if le.rooms.all() and le.amends.rooms.all(): if le.rooms.all() and le.amends and le.amends.rooms.all():
return le.rooms.all() return le.rooms.all()
else: else:
return [] return []
...@@ -221,7 +227,7 @@ class SubstitutionType(graphene.ObjectType): ...@@ -221,7 +227,7 @@ class SubstitutionType(graphene.ObjectType):
return root["REFERENCE_OBJECT"].cancelled return root["REFERENCE_OBJECT"].cancelled
def resolve_notes(root, info): def resolve_notes(root, info):
return root["REFERENCE_OBJECT"].title or root["REFERENCE_OBJECT"].comment return root["REFERENCE_OBJECT"].comment
class SubstitutionsForDateType(graphene.ObjectType): class SubstitutionsForDateType(graphene.ObjectType):
......
{% if el.title %} {% if el.comment %}
<em>{{ el.title }}</em>
{% elif el.comment %}
<em>{{ el.comment }}</em> <em>{{ el.comment }}</em>
{% endif %} {% endif %}
...@@ -3,10 +3,9 @@ ...@@ -3,10 +3,9 @@
{% trans "Supervision" %} {% trans "Supervision" %}
{% elif not el.amends.subject and not el.subject %} {% elif not el.amends.subject and not el.subject %}
{% if el.amends.title %} {% if el.amends.title %}
<s>{{ el.amends.title }}</s> {{ el.amends.title }}
{% endif %} {% elif el.title %}
{% if el.title %} {{ el.title }}
<s>{{ el.title }}</s>
{% endif %} {% endif %}
{% elif el.cancelled %} {% elif el.cancelled %}
<s>{% include "chronos/partials/subject.html" with subject=el.amends.subject %}</s> <s>{% include "chronos/partials/subject.html" with subject=el.amends.subject %}</s>
......
...@@ -4,7 +4,7 @@ from aleksis.apps.chronos.models import LessonEvent, SupervisionEvent ...@@ -4,7 +4,7 @@ from aleksis.apps.chronos.models import LessonEvent, SupervisionEvent
from aleksis.core.models import Group, Person from aleksis.core.models import Group, Person
def build_substitutions_list(wanted_day: date) -> tuple[list[dict], set[Person], set[Group]]: def build_substitutions_list(wanted_day: date) -> tuple[list[dict], list[Person], list[Group]]:
rows = [] rows = []
affected_teachers = set() affected_teachers = set()
affected_groups = set() affected_groups = set()
...@@ -12,19 +12,21 @@ def build_substitutions_list(wanted_day: date) -> tuple[list[dict], set[Person], ...@@ -12,19 +12,21 @@ def build_substitutions_list(wanted_day: date) -> tuple[list[dict], set[Person],
lesson_events = LessonEvent.get_single_events( lesson_events = LessonEvent.get_single_events(
datetime.combine(wanted_day, time.min), datetime.combine(wanted_day, time.min),
datetime.combine(wanted_day, time.max), datetime.combine(wanted_day, time.max),
params={"amending": True}, params={"current_changes": True},
with_reference_object=True, with_reference_object=True,
) )
for lesson_event in lesson_events: for lesson_event in lesson_events:
ref_object = lesson_event["REFERENCE_OBJECT"]
affected_teachers.update(lesson_event["REFERENCE_OBJECT"].teachers.all()) affected_teachers.update(lesson_event["REFERENCE_OBJECT"].teachers.all())
affected_teachers.update(lesson_event["REFERENCE_OBJECT"].amends.teachers.all())
affected_groups.update(lesson_event["REFERENCE_OBJECT"].groups.all()) affected_groups.update(lesson_event["REFERENCE_OBJECT"].groups.all())
affected_groups.update(lesson_event["REFERENCE_OBJECT"].amends.groups.all()) if ref_object.amends:
affected_teachers.update(ref_object.amends.teachers.all())
affected_groups.update(ref_object.amends.groups.all())
row = { row = {
"type": "substitution", "type": "substitution",
"sort_a": lesson_event["REFERENCE_OBJECT"].group_names, "sort_a": ref_object.group_names,
"sort_b": str(lesson_event["DTSTART"]), "sort_b": str(lesson_event["DTSTART"]),
"el": lesson_event, "el": lesson_event,
} }
...@@ -34,13 +36,15 @@ def build_substitutions_list(wanted_day: date) -> tuple[list[dict], set[Person], ...@@ -34,13 +36,15 @@ def build_substitutions_list(wanted_day: date) -> tuple[list[dict], set[Person],
supervision_events = SupervisionEvent.get_single_events( supervision_events = SupervisionEvent.get_single_events(
datetime.combine(wanted_day, time.min), datetime.combine(wanted_day, time.min),
datetime.combine(wanted_day, time.max), datetime.combine(wanted_day, time.max),
params={"amending": True}, params={"current_changes": True},
with_reference_object=True, with_reference_object=True,
) )
for supervision_event in supervision_events: for supervision_event in supervision_events:
affected_teachers.update(supervision_event["REFERENCE_OBJECT"].teachers.all()) ref_object = supervision_event["REFERENCE_OBJECT"]
affected_teachers.update(supervision_event["REFERENCE_OBJECT"].amends.teachers.all()) affected_teachers.update(ref_object.teachers.all())
if ref_object.amends:
affected_teachers.update(ref_object.amends.teachers.all())
row = { row = {
"type": "supervision_substitution", "type": "supervision_substitution",
...@@ -53,4 +57,7 @@ def build_substitutions_list(wanted_day: date) -> tuple[list[dict], set[Person], ...@@ -53,4 +57,7 @@ def build_substitutions_list(wanted_day: date) -> tuple[list[dict], set[Person],
rows.sort(key=lambda row: row["sort_a"] + row["sort_b"]) rows.sort(key=lambda row: row["sort_a"] + row["sort_b"])
affected_teachers = sorted(affected_teachers, key=lambda p: p.short_name or p.last_name)
affected_groups = sorted(affected_groups, key=lambda g: g.short_name or g.name)
return rows, affected_teachers, affected_groups return rows, affected_teachers, affected_groups
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