agendas: forbid having more than two checks on booking (#83544)

This commit is contained in:
Valentin Deniaud 2023-11-22 11:08:17 +01:00
parent d9a93ac2e3
commit 46e6fbcf5b
3 changed files with 50 additions and 84 deletions

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.21 on 2023-11-22 09:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('agendas', '0166_lease'),
]
operations = [
migrations.AddConstraint(
model_name='bookingcheck',
constraint=models.UniqueConstraint(
fields=('booking', 'presence'), name='max_2_checks_on_booking'
),
),
]

View File

@ -3021,28 +3021,18 @@ class Booking(models.Model):
def refresh_computed_times(self, commit=False):
to_update = []
user_checks = sorted(self.user_checks.all(), key=lambda a: a.start_time or datetime.time(0))
many_user_checks = len(user_checks) > 1
assert len(user_checks) < 3 # 2 user_checks max !
if user_checks and not many_user_checks:
# only one user_check
if len(user_checks) == 1:
user_check = user_checks[0]
changed = user_check._refresh_computed_times()
if changed:
to_update.append(user_check)
elif many_user_checks:
# two user_checks
user_check1 = user_checks[0]
user_check2 = user_checks[1]
compute_one_first = True
if user_check1.presence != user_check2.presence:
# one user check is presence, the other is absence
if user_check1.presence is False:
# the second check is presence, it should be computed first
compute_one_first = False
elif len(user_checks) == 2:
user_check1, user_check2 = user_checks
if compute_one_first:
if user_check1.presence is True:
# first check is presence, compute it first
changed = user_check1._refresh_computed_times(adjust_end_to_booking=False)
if changed:
to_update.append(user_check1)
@ -3050,6 +3040,7 @@ class Booking(models.Model):
if changed:
to_update.append(user_check2)
else:
# second check is presence, compute it first
changed = user_check2._refresh_computed_times(adjust_start_to_booking=False)
if changed:
to_update.append(user_check2)
@ -3166,6 +3157,11 @@ class BookingCheck(models.Model):
type_slug = models.CharField(max_length=160, blank=True, null=True)
type_label = models.CharField(max_length=150, blank=True, null=True)
class Meta:
constraints = [
models.UniqueConstraint(fields=['booking', 'presence'], name='max_2_checks_on_booking')
]
def _get_previous_and_next_slots(self, _time):
minutes = {
'hour': 60,

View File

@ -4119,56 +4119,6 @@ def test_booking_refresh_computed_times_only_one_user_check():
datetime.time(12, 30),
datetime.time(17, 0),
),
# both absence
(
True,
datetime.time(7, 45),
datetime.time(12, 15),
True,
datetime.time(13, 0), # no overlapping
datetime.time(15, 0),
datetime.time(7, 30),
datetime.time(12, 30),
datetime.time(12, 30),
datetime.time(17, 0),
),
(
True,
datetime.time(7, 45),
datetime.time(12, 15),
True,
datetime.time(12, 15), # computed start should be 12H00
datetime.time(15, 0),
datetime.time(7, 30),
datetime.time(12, 30),
datetime.time(12, 30), # but it is adjusted to 12H30
datetime.time(17, 0),
),
# both presence
(
False,
datetime.time(7, 45),
datetime.time(12, 15),
False,
datetime.time(13, 0), # no overlapping
datetime.time(15, 0),
datetime.time(7, 30),
datetime.time(12, 30),
datetime.time(12, 30),
datetime.time(17, 0),
),
(
False,
datetime.time(7, 45),
datetime.time(12, 15),
False,
datetime.time(12, 15), # computed start should be 12H00
datetime.time(15, 0),
datetime.time(7, 30),
datetime.time(12, 30),
datetime.time(12, 30), # but it is adjusted to 12H30
datetime.time(17, 0),
),
],
)
def test_booking_refresh_computed_times_two_user_check(
@ -4209,25 +4159,6 @@ def test_booking_refresh_computed_times_two_user_check(
assert user_check2.computed_end_time == expected_end2
def test_booking_refresh_computed_times_more_than_two_user_check():
agenda = Agenda.objects.create(
label='Agenda', kind='events', invoicing_unit='half_hour', invoicing_tolerance=10
)
event = Event.objects.create(
agenda=agenda,
start_datetime=make_aware(datetime.datetime(2023, 5, 1, 14, 00)),
places=10,
)
booking = Booking.objects.create(
event=event, start_time=datetime.time(8, 0), end_time=datetime.time(17, 0)
)
BookingCheck.objects.create(booking=booking, presence=True)
BookingCheck.objects.create(booking=booking, presence=True)
BookingCheck.objects.create(booking=booking, presence=True)
with pytest.raises(AssertionError):
booking.refresh_computed_times(commit=True)
def test_agenda_refresh_booking_computed_times():
agenda = Agenda.objects.create(
label='Agenda',
@ -4437,3 +4368,24 @@ def test_agenda_booking_user_check_property():
with pytest.raises(AttributeError):
# pylint: disable=pointless-statement
booking.user_check
def test_agenda_booking_max_two_user_checks():
agenda = Agenda.objects.create(label='Agenda', kind='events')
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10)
booking = Booking.objects.create(event=event)
BookingCheck.objects.create(booking=booking, presence=True)
# cannot create second check with presence=True
with pytest.raises(IntegrityError):
with transaction.atomic():
BookingCheck.objects.create(booking=booking, presence=True)
# allow to create second check with presence=False
BookingCheck.objects.create(booking=booking, presence=False)
# cannot create second check with presence=False
with pytest.raises(IntegrityError):
with transaction.atomic():
BookingCheck.objects.create(booking=booking, presence=False)