Skip to content

Commit

Permalink
Introduce "too late" as an event presence status
Browse files Browse the repository at this point in the history
Similar to the "not present" status, the user will automatically recieve
a penalty. I figured all previous penalties can be removed since only
the newest one should matter.

I would like some input as to how this will affect other penalties,
e.g. given due to late payments (or other things?), as they will also
be removed if the presence is changed to something worthy of a penalty.
Should we consider to introduce "penalty types" stored on the record,
e.g. "presence", "payment", "other"?

Also, this resolves a bug, as it is currently not possible to auto delete
previous penalties related to the event due to the `.delete()` not being
at the end the atomic block. Not sure why it had to be atomic in the
first place.
  • Loading branch information
ivarnakken committed Mar 14, 2024
1 parent c48fb05 commit 9ed1443
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 16 deletions.
1 change: 1 addition & 0 deletions lego/apps/events/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
class PRESENCE_CHOICES(models.TextChoices):
UNKNOWN = "UNKNOWN"
PRESENT = "PRESENT"
LATE = "LATE"
NOT_PRESENT = "NOT_PRESENT"


Expand Down
26 changes: 26 additions & 0 deletions lego/apps/events/migrations/0040_alter_registration_presence.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 4.0.10 on 2024-03-06 22:04

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("events", "0039_remove_event_use_contact_tracing"),
]

operations = [
migrations.AlterField(
model_name="registration",
name="presence",
field=models.CharField(
choices=[
("UNKNOWN", "Unknown"),
("PRESENT", "Present"),
("LATE", "Late"),
("NOT_PRESENT", "Not Present"),
],
default="UNKNOWN",
max_length=20,
),
),
]
38 changes: 29 additions & 9 deletions lego/apps/events/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -930,26 +930,46 @@ def set_presence(self, presence: constants.PRESENCE_CHOICES) -> None:
"""Wrap this method in a transaction"""
if presence not in constants.PRESENCE_CHOICES:
raise ValueError("Illegal presence choice")

self.presence = presence
self.handle_user_penalty(presence)
self.save()

def delete_penalties_for_event(self) -> None:
for penalty in self.user.penalties.filter(source_event=self.event):
penalty.delete()

def handle_user_penalty(self, presence: constants.PRESENCE_CHOICES) -> None:
"""
Previous penalties related to the event are deleted since the
newest presence is the only one that matters
"""

if (
self.event.heed_penalties
and presence == constants.PRESENCE_CHOICES.NOT_PRESENT
and self.event.penalty_weight_on_not_present
):
if not self.user.penalties.filter(source_event=self.event).exists():
Penalty.objects.create(
user=self.user,
reason=f"Møtte ikke opp på {self.event.title}.",
weight=self.event.penalty_weight_on_not_present,
source_event=self.event,
)
self.delete_penalties_for_event()
Penalty.objects.create(
user=self.user,
reason=f"Møtte ikke opp på {self.event.title}.",
weight=self.event.penalty_weight_on_not_present,
source_event=self.event,
)
elif (
self.event.heed_penalties
and presence == constants.PRESENCE_CHOICES.TOO_LATE
):
self.delete_penalties_for_event()
Penalty.objects.create(
user=self.user,
reason=f"Møtte for sent opp på {self.event.title}.",
weight=1,
source_event=self.event,
)
else:
for penalty in self.user.penalties.filter(source_event=self.event):
penalty.delete()
self.delete_penalties_for_event()

def add_to_pool(self, pool: Pool) -> Registration:
allowed: bool = False
Expand Down
12 changes: 5 additions & 7 deletions lego/apps/events/serializers/registrations.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from django.db import transaction
from rest_framework import serializers

from rest_framework_jwt.serializers import ImpersonateAuthTokenSerializer
Expand Down Expand Up @@ -65,13 +64,12 @@ class Meta:
)

def update(self, instance, validated_data):
with transaction.atomic():
presence = validated_data.pop("presence", None)
super().update(instance, validated_data)
if presence:
instance.set_presence(presence)
presence = validated_data.pop("presence", None)
super().update(instance, validated_data)
if presence:
instance.set_presence(presence)

return instance
return instance


class RegistrationAnonymizedReadSerializer(BasisModelSerializer):
Expand Down

0 comments on commit 9ed1443

Please sign in to comment.