agendas: methods to compute start and end times from check times (#80842)
This commit is contained in:
parent
df0223abf2
commit
16e3602391
|
@ -2903,6 +2903,63 @@ class Booking(models.Model):
|
|||
def get_backoffice_url(self):
|
||||
return translate_from_publik_url(self.backoffice_url)
|
||||
|
||||
def _get_previous_and_next_slots(self, _time):
|
||||
minutes = {
|
||||
'hour': 60,
|
||||
'half_hour': 30,
|
||||
'quarter': 15,
|
||||
}[self.event.agenda.invoicing_unit]
|
||||
|
||||
time_minutes = _time.hour * 60 + _time.minute
|
||||
previous_slot_minutes = math.trunc(time_minutes / minutes) * minutes
|
||||
previous_slot = datetime.time(*divmod(previous_slot_minutes, 60))
|
||||
next_slot = datetime.time(*divmod(previous_slot_minutes + minutes, 60))
|
||||
return previous_slot, next_slot
|
||||
|
||||
def get_computed_start_time(self):
|
||||
if self.user_check_start_time is None:
|
||||
return None
|
||||
|
||||
start_time = self.user_check_start_time
|
||||
if self.start_time:
|
||||
start_time = min(start_time, self.start_time)
|
||||
if self.event.agenda.invoicing_unit == 'minute':
|
||||
return start_time
|
||||
|
||||
tolerance = self.event.agenda.invoicing_tolerance
|
||||
|
||||
# compute previous and next slot
|
||||
previous_slot, next_slot = self._get_previous_and_next_slots(start_time)
|
||||
|
||||
# in tolerance ? take next_slot
|
||||
if (next_slot.minute or 60 - start_time.minute) <= tolerance:
|
||||
return next_slot
|
||||
|
||||
# else take previous_slot
|
||||
return previous_slot
|
||||
|
||||
def get_computed_end_time(self):
|
||||
if self.user_check_end_time is None:
|
||||
return None
|
||||
|
||||
end_time = self.user_check_end_time
|
||||
if self.end_time:
|
||||
end_time = max(end_time, self.end_time)
|
||||
if self.event.agenda.invoicing_unit == 'minute':
|
||||
return end_time
|
||||
|
||||
tolerance = self.event.agenda.invoicing_tolerance
|
||||
|
||||
# compute previous and next slot
|
||||
previous_slot, next_slot = self._get_previous_and_next_slots(end_time)
|
||||
|
||||
# in tolerance ? take previous_slot
|
||||
if (end_time.minute - previous_slot.minute) <= tolerance:
|
||||
return previous_slot
|
||||
|
||||
# else take next_slot
|
||||
return next_slot
|
||||
|
||||
|
||||
OpeningHour = collections.namedtuple('OpeningHour', ['begin', 'end'])
|
||||
|
||||
|
|
|
@ -3917,3 +3917,117 @@ def test_agenda_event_overlaps_recurring():
|
|||
# normal event, after not on a recurrence day
|
||||
event_kwargs['start_datetime'] = make_aware(datetime.datetime(2023, 5, 10, 14, 00))
|
||||
assert agenda.event_overlaps(**event_kwargs) is False
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'start_time, user_check_start_time, tolerance, unit, expected',
|
||||
[
|
||||
# no check
|
||||
(None, None, 0, 'hour', None),
|
||||
(None, None, 0, 'half_hour', None),
|
||||
(None, None, 0, 'quarter', None),
|
||||
(None, None, 0, 'minutes', None),
|
||||
# hour unit - no booking
|
||||
(None, datetime.time(7, 50), 10, 'hour', datetime.time(8, 0)),
|
||||
(None, datetime.time(7, 49), 10, 'hour', datetime.time(7, 0)),
|
||||
(None, datetime.time(7, 50), 0, 'hour', datetime.time(7, 0)),
|
||||
# hour unit - with booking
|
||||
(datetime.time(8, 0), datetime.time(7, 50), 10, 'hour', datetime.time(8, 0)),
|
||||
(datetime.time(8, 0), datetime.time(7, 49), 10, 'hour', datetime.time(7, 0)),
|
||||
(datetime.time(8, 0), datetime.time(8, 30), 10, 'hour', datetime.time(8, 0)),
|
||||
(datetime.time(8, 0), datetime.time(7, 50), 0, 'hour', datetime.time(7, 0)),
|
||||
# half_hour unit - no booking
|
||||
(None, datetime.time(7, 50), 10, 'half_hour', datetime.time(8, 0)),
|
||||
(None, datetime.time(7, 49), 10, 'half_hour', datetime.time(7, 30)),
|
||||
(None, datetime.time(7, 50), 0, 'half_hour', datetime.time(7, 30)),
|
||||
# half_hour unit - with booking
|
||||
(datetime.time(8, 0), datetime.time(7, 50), 10, 'half_hour', datetime.time(8, 0)),
|
||||
(datetime.time(8, 0), datetime.time(7, 49), 10, 'half_hour', datetime.time(7, 30)),
|
||||
(datetime.time(8, 0), datetime.time(8, 30), 10, 'half_hour', datetime.time(8, 0)),
|
||||
(datetime.time(8, 0), datetime.time(7, 50), 0, 'half_hour', datetime.time(7, 30)),
|
||||
# quarter unit - no booking
|
||||
(None, datetime.time(7, 50), 10, 'quarter', datetime.time(8, 0)),
|
||||
(None, datetime.time(7, 49), 10, 'quarter', datetime.time(7, 45)),
|
||||
(None, datetime.time(7, 50), 0, 'quarter', datetime.time(7, 45)),
|
||||
# quarter unit - with booking
|
||||
(datetime.time(8, 0), datetime.time(7, 50), 10, 'quarter', datetime.time(8, 0)),
|
||||
(datetime.time(8, 0), datetime.time(7, 49), 10, 'quarter', datetime.time(7, 45)),
|
||||
(datetime.time(8, 0), datetime.time(8, 30), 10, 'quarter', datetime.time(8, 0)),
|
||||
(datetime.time(8, 0), datetime.time(7, 50), 0, 'quarter', datetime.time(7, 45)),
|
||||
# minute unit - no booking
|
||||
(None, datetime.time(7, 50), 0, 'minute', datetime.time(7, 50)),
|
||||
# minute unit - with booking
|
||||
(datetime.time(8, 0), datetime.time(7, 50), 0, 'minute', datetime.time(7, 50)),
|
||||
(datetime.time(8, 0), datetime.time(8, 5), 0, 'minute', datetime.time(8, 0)),
|
||||
],
|
||||
)
|
||||
def test_booking_get_computed_start_time(start_time, user_check_start_time, tolerance, unit, expected):
|
||||
agenda = Agenda.objects.create(
|
||||
label='Agenda', kind='events', invoicing_unit=unit, invoicing_tolerance=tolerance
|
||||
)
|
||||
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=start_time, user_check_start_time=user_check_start_time
|
||||
)
|
||||
assert booking.get_computed_start_time() == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'end_time, user_check_end_time, tolerance, unit, expected',
|
||||
[
|
||||
# no check
|
||||
(None, None, 0, 'hour', None),
|
||||
(None, None, 0, 'half_hour', None),
|
||||
(None, None, 0, 'quarter', None),
|
||||
(None, None, 0, 'minutes', None),
|
||||
# hour unit - no booking
|
||||
(None, datetime.time(17, 10), 10, 'hour', datetime.time(17, 0)),
|
||||
(None, datetime.time(17, 11), 10, 'hour', datetime.time(18, 0)),
|
||||
(None, datetime.time(17, 10), 0, 'hour', datetime.time(18, 0)),
|
||||
# hour unit - with booking
|
||||
(datetime.time(17, 0), datetime.time(17, 10), 10, 'hour', datetime.time(17, 0)),
|
||||
(datetime.time(17, 0), datetime.time(17, 11), 10, 'hour', datetime.time(18, 0)),
|
||||
(datetime.time(17, 0), datetime.time(16, 30), 10, 'hour', datetime.time(17, 0)),
|
||||
(datetime.time(17, 0), datetime.time(17, 10), 0, 'hour', datetime.time(18, 0)),
|
||||
# half_hour unit - no booking
|
||||
(None, datetime.time(17, 10), 10, 'half_hour', datetime.time(17, 0)),
|
||||
(None, datetime.time(17, 11), 10, 'half_hour', datetime.time(17, 30)),
|
||||
(None, datetime.time(17, 10), 0, 'half_hour', datetime.time(17, 30)),
|
||||
# half_hour unit - with booking
|
||||
(datetime.time(17, 0), datetime.time(17, 10), 10, 'half_hour', datetime.time(17, 0)),
|
||||
(datetime.time(17, 0), datetime.time(17, 11), 10, 'half_hour', datetime.time(17, 30)),
|
||||
(datetime.time(17, 0), datetime.time(16, 30), 10, 'half_hour', datetime.time(17, 0)),
|
||||
(datetime.time(17, 0), datetime.time(17, 10), 0, 'half_hour', datetime.time(17, 30)),
|
||||
# quarter unit - no booking
|
||||
(None, datetime.time(17, 10), 10, 'quarter', datetime.time(17, 0)),
|
||||
(None, datetime.time(17, 11), 10, 'quarter', datetime.time(17, 15)),
|
||||
(None, datetime.time(17, 10), 0, 'quarter', datetime.time(17, 15)),
|
||||
# quarter unit - with booking
|
||||
(datetime.time(17, 0), datetime.time(17, 10), 10, 'quarter', datetime.time(17, 0)),
|
||||
(datetime.time(17, 0), datetime.time(17, 11), 10, 'quarter', datetime.time(17, 15)),
|
||||
(datetime.time(17, 0), datetime.time(16, 30), 10, 'quarter', datetime.time(17, 0)),
|
||||
(datetime.time(17, 0), datetime.time(17, 10), 0, 'quarter', datetime.time(17, 15)),
|
||||
# minute unit - no booking
|
||||
(None, datetime.time(17, 10), 0, 'minute', datetime.time(17, 10)),
|
||||
# minute unit - with booking
|
||||
(datetime.time(17, 0), datetime.time(17, 10), 0, 'minute', datetime.time(17, 10)),
|
||||
(datetime.time(17, 0), datetime.time(16, 50), 0, 'minute', datetime.time(17, 0)),
|
||||
],
|
||||
)
|
||||
def test_booking_get_computed_end_time(end_time, user_check_end_time, tolerance, unit, expected):
|
||||
agenda = Agenda.objects.create(
|
||||
label='Agenda', kind='events', invoicing_unit=unit, invoicing_tolerance=tolerance
|
||||
)
|
||||
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, end_time=end_time, user_check_end_time=user_check_end_time)
|
||||
assert booking.get_computed_end_time() == expected
|
||||
|
|
Loading…
Reference in New Issue