Skip to content
Snippets Groups Projects
Commit 24182767 authored by Benjamin Hättasch's avatar Benjamin Hättasch Committed by Nadja Geisler
Browse files

Implement more violation checks and extract common code into a function

Implement check for overlapping AK slots in the same room
Implement check for overlapping AK slots by the same owner triggered by changing the slot
parent cbbd0475
No related branches found
No related tags found
2 merge requests!100Scheduling Constraints WIP WIP WIP,!99Constraint Violation checking & visualization
...@@ -5,6 +5,35 @@ from AKModel.availability.models import Availability ...@@ -5,6 +5,35 @@ from AKModel.availability.models import Availability
from AKModel.models import AK, AKSlot, Room, Event, AKOwner, ConstraintViolation from AKModel.models import AK, AKSlot, Room, Event, AKOwner, ConstraintViolation
def update_constraint_violations(new_violations, existing_violations_to_check):
"""
Update existing constraint violations (subset for which new violations were computed) based on these new violations.
This will add all new violations without a match, preserve the matching ones
and delete the obsolete ones (those without a match from the newly calculated violations).
:param new_violations: list of new (not yet saved) violations that exist after the last change
:type new_violations: list[ConstraintViolation]
:param existing_violations_to_check: list of related violations currently in the db
:type existing_violations_to_check: list[ConstraintViolation]
"""
for new_violation in new_violations:
found_match = False
for existing_violation in existing_violations_to_check:
if existing_violation.matches(new_violation):
# Remove from existing violations set since it should stay in db
existing_violations_to_check.remove(existing_violation)
found_match = True
break
# Only save new violation if no match was found
if not found_match:
new_violation.save()
# Cleanup obsolete violations (ones without matches computed under current conditions)
for outdated_violation in existing_violations_to_check:
outdated_violation.delete()
@receiver(post_save, sender=AK) @receiver(post_save, sender=AK)
def ak_changed_handler(sender, instance: AK, **kwargs): def ak_changed_handler(sender, instance: AK, **kwargs):
# Changes might affect: Owner(s), Requirements, Conflicts, Prerequisites, Category, Interest # Changes might affect: Owner(s), Requirements, Conflicts, Prerequisites, Category, Interest
...@@ -59,30 +88,78 @@ def ak_changed_handler(sender, instance: AK, action: str, **kwargs): ...@@ -59,30 +88,78 @@ def ak_changed_handler(sender, instance: AK, action: str, **kwargs):
# belonging to the AK that was recently changed (important!) # belonging to the AK that was recently changed (important!)
existing_violations_to_check = list(instance.constraintviolation_set.filter(type=violation_type)) existing_violations_to_check = list(instance.constraintviolation_set.filter(type=violation_type))
# print(existing_violations_to_check) # print(existing_violations_to_check)
update_constraint_violations(new_violations, existing_violations_to_check)
for new_violation in new_violations:
found_match = False
for existing_violation in existing_violations_to_check:
if existing_violation.matches(new_violation):
# Remove from existing violations set since it should stay in db
existing_violations_to_check.remove(existing_violation)
found_match = True
break
# Only save new violation if no match was found
if not found_match:
new_violation.save()
# Cleanup obsolete violations (ones without matches computed under current conditions)
for outdated_violation in existing_violations_to_check:
outdated_violation.delete()
@receiver(post_save, sender=AKSlot) @receiver(post_save, sender=AKSlot)
def akslot_changed_handler(sender, instance, **kwargs): def akslot_changed_handler(sender, instance: AKSlot, **kwargs):
# Changes might affect: Duplicate parallel, Two in room, Resodeadline # Changes might affect: Duplicate parallel, Two in room, Resodeadline
print(f"{sender} changed") print(f"{sender} changed")
# TODO Replace with real handling event = instance.event
# == Check for two parallel slots by one of the owners ==
violation_type = ConstraintViolation.ViolationType.OWNER_TWO_SLOTS
new_violations = []
# For all owners (after recent change)...
for owner in instance.ak.owners.all():
# ...find other slots that might be overlapping...
for ak in owner.ak_set.all():
# ...find overlapping slots...
if ak != instance.ak:
for other_slot in ak.akslot_set.filter(start__isnull=False):
if instance.overlaps(other_slot):
# ...and create a temporary violation if necessary...
c = ConstraintViolation(
type=violation_type,
level=ConstraintViolation.ViolationLevel.VIOLATION,
event=event,
ak_owner=owner
)
c.aks_tmp.add(instance.ak)
c.aks_tmp.add(other_slot.ak)
c.ak_slots_tmp.add(instance)
c.ak_slots_tmp.add(other_slot)
new_violations.append(c)
print(f"{owner} has the following conflicts: {new_violations}")
# ... and compare to/update list of existing violations of this type
# belonging to the AK that was recently changed (important!)
existing_violations_to_check = list(instance.constraintviolation_set.filter(type=violation_type))
print(existing_violations_to_check)
update_constraint_violations(new_violations, existing_violations_to_check)
# == Check for two aks in the same room at the same time ==
violation_type = ConstraintViolation.ViolationType.ROOM_TWO_SLOTS
new_violations = []
# For all slots in this room...
for other_slot in instance.room.akslot_set.all():
if other_slot != instance:
# ... find overlapping slots...
if instance.overlaps(other_slot):
# ...and create a temporary violation if necessary...
c = ConstraintViolation(
type=violation_type,
level=ConstraintViolation.ViolationLevel.WARNING,
event=event,
room=instance.room
)
c.ak_slots_tmp.add(instance)
c.ak_slots_tmp.add(other_slot)
new_violations.append(c)
print(f"Multiple slots in room {instance.room}: {new_violations}")
# ... and compare to/update list of existing violations of this type
# belonging to the AK that was recently changed (important!)
existing_violations_to_check = list(instance.room.constraintviolation_set.filter(type=violation_type))
print(existing_violations_to_check)
update_constraint_violations(new_violations, existing_violations_to_check)
@receiver(post_save, sender=Room) @receiver(post_save, sender=Room)
......
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