52b2c31c10
We round this number to avoid people not registering for an event because the event is at max capacity and they would bump it to an online event. We don't hide the number entirely in order to not put off people when there aren't a lot of people interested/admitted.
108 lines
3.1 KiB
Python
108 lines
3.1 KiB
Python
from django.db import models
|
|
|
|
from users.models import CustomUser
|
|
|
|
|
|
class Event(models.Model):
|
|
date = models.DateField()
|
|
capacity = models.IntegerField(default=6)
|
|
note = models.TextField(max_length=1024, default="")
|
|
responsible_person = models.ForeignKey(CustomUser, null=True, on_delete=models.SET_NULL)
|
|
|
|
def __str__(self):
|
|
return f"{self.date}"
|
|
|
|
|
|
class TimeSlot(models.Model):
|
|
MORNING, AFTERNOON, EVENING = range(3)
|
|
TIME_SLOTS = {
|
|
MORNING: "voormiddag",
|
|
AFTERNOON: "namiddag",
|
|
EVENING: "avond",
|
|
}
|
|
time = models.IntegerField(choices=TIME_SLOTS.items(), default=MORNING)
|
|
event = models.ForeignKey(Event, on_delete=models.CASCADE)
|
|
|
|
class Meta:
|
|
constraints = [
|
|
models.UniqueConstraint(
|
|
fields=["time", "event"], name="no_duplicate_timeslots"
|
|
),
|
|
]
|
|
|
|
def __str__(self):
|
|
return f"{self.event.date} {self.TIME_SLOTS[self.time]}"
|
|
|
|
def time_str(self):
|
|
return TimeSlot.TIME_SLOTS[self.time]
|
|
|
|
def count_with_status(self, status):
|
|
return self.eventregistration_set.filter(state=status).count()
|
|
|
|
def count_interested(self):
|
|
return self.count_with_status(EventRegistration.INTERESTED)
|
|
|
|
def count_admitted(self):
|
|
return self.count_with_status(EventRegistration.ADMITTED)
|
|
|
|
|
|
def precision(self):
|
|
# TODO put this in a database field?
|
|
return 10
|
|
|
|
def lower_round(self, n):
|
|
return (n // self.precision()) * self.precision()
|
|
|
|
def upper_round(self, n):
|
|
return ((n + self.precision()) // self.precision()) * self.precision()
|
|
|
|
# Unfortunately, Django doesn't support arguments in templates
|
|
|
|
def lower_interested(self):
|
|
return self.lower_round(self.count_interested())
|
|
|
|
def upper_interested(self):
|
|
return self.upper_round(self.count_interested())
|
|
|
|
def lower_admitted(self):
|
|
return self.lower_round(self.count_admitted())
|
|
|
|
def upper_admitted(self):
|
|
return self.upper_round(self.count_admitted())
|
|
|
|
|
|
def registration_of(self, user):
|
|
if not user.is_authenticated:
|
|
return None
|
|
|
|
registrations = self.eventregistration_set.filter(user=user).all()
|
|
if not registrations:
|
|
return None
|
|
assert len(registrations) == 1, "Registrations should be unique per user and timeslot"
|
|
return registrations[0]
|
|
|
|
|
|
class EventRegistration(models.Model):
|
|
INTERESTED = "I"
|
|
ADMITTED = "A"
|
|
REGISTRATION_STATE = {
|
|
INTERESTED: "op wachtlijst",
|
|
ADMITTED: "bevestigd",
|
|
}
|
|
time_slot = models.ForeignKey(TimeSlot, on_delete=models.CASCADE)
|
|
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
|
|
state = models.CharField(max_length=1, choices=REGISTRATION_STATE.items())
|
|
|
|
class Meta:
|
|
constraints = [
|
|
models.UniqueConstraint(
|
|
fields=["time_slot", "user"], name="register_only_once_per_timeslot"
|
|
),
|
|
]
|
|
|
|
def __str__(self):
|
|
return f"Reservation[{self.user.username}:{self.time_slot.event.date}:{self.state}]"
|
|
|
|
def state_str(self):
|
|
return EventRegistration.REGISTRATION_STATE[self.state]
|