agendas: do not use minimal_booking_time in min_booking_datetime computation (#76303) #65

Merged
ecazenave merged 3 commits from wip/76303-minimal-booking-time into main 2023-04-11 15:53:54 +02:00
8 changed files with 420 additions and 79 deletions

View File

@ -19,7 +19,7 @@ class Migration(migrations.Migration):
default=datetime.time(0, 0),
null=True,
help_text='Ex.: 08:00:00. If left empty, available events will be those that are later than the current time.',
verbose_name='Minimal booking time',
verbose_name='Booking opening time',
),
),
]

View File

@ -276,7 +276,7 @@ class Agenda(models.Model):
blank=True,
)
minimal_booking_time = models.TimeField(
verbose_name=_('Minimal booking time'),
verbose_name=_('Booking opening time'),
default=datetime.time(0, 0, 0), # booking is possible starting and finishin at 00:00
help_text=_(
'Ex.: 08:00:00. If left empty, available events will be those that are later than the current time.'
@ -659,12 +659,14 @@ class Agenda(models.Model):
# reference is now, in local timezone
t = localtime(now())
# add delay
t += datetime.timedelta(days=self.maximal_booking_delay)
maximal_booking_delay = self.maximal_booking_delay
if self.minimal_booking_time is None or t.time() < self.minimal_booking_time:
maximal_booking_delay -= 1
t += datetime.timedelta(days=maximal_booking_delay)
# replace time if needed
if self.minimal_booking_time:
t = datetime.datetime.combine(t.date(), self.minimal_booking_time, tzinfo=t.tzinfo)
t = t.replace(hour=0, minute=0, second=0, microsecond=0)
# t could not exist, recompute it as an existing datetime by converting to UTC then to localtime
return localtime(t.astimezone(utc))
@ -684,9 +686,7 @@ class Agenda(models.Model):
else:
t += datetime.timedelta(days=self.minimal_booking_delay)
# replace time if needed
if self.minimal_booking_time:
t = datetime.datetime.combine(t.date(), self.minimal_booking_time, tzinfo=t.tzinfo)
t = t.replace(hour=0, minute=0, second=0, microsecond=0)
# t could not exist, recompute it as an existing datetime by converting to UTC then to localtime
return localtime(t.astimezone(utc))

View File

@ -256,8 +256,8 @@ msgid "Events type"
msgstr "Type dévénements"
#: agendas/models.py
msgid "Minimal booking time"
msgstr "Heure de réservation minimale"
msgid "Booking opening time"
msgstr "Horaire douverture des réservations"
#: agendas/models.py
msgid ""
@ -2213,8 +2213,8 @@ msgid "Maximal booking delay:"
msgstr "Délai de réservation maximal :"
#: manager/templates/chrono/manager_agenda_settings.html
msgid "Minimal booking time:"
msgstr "Heure de réservation minimale :"
msgid "Booking opening time:"
msgstr "Horaire douverture des réservations :"
#: manager/templates/chrono/manager_agenda_settings.html
msgid "current time"

View File

@ -90,7 +90,7 @@
{% blocktrans count count=agenda.maximal_booking_delay %}{{ count }} day{% plural %}{{ count }} days{% endblocktrans %}
{% else %}<i>{% trans "undefined" %}</i>{% endif %}</li>
{% if agenda.minimal_booking_delay is not None or agenda.maximal_booking_delay is not None %}
<li>{% trans "Minimal booking time:" %}
<li>{% trans "Booking opening time:" %}
{% if agenda.minimal_booking_time is not None %}{{ agenda.minimal_booking_time }}{% else %}{% trans "current time" %}{% endif %}</li>
{% endif %}
</ul>

View File

@ -1363,3 +1363,195 @@ def test_past_datetimes_recurring_event(app, user):
)
data = resp.json['data']
assert len(data) == 7
@pytest.mark.freeze_time('2023-04-03')
def test_events_datetimes_min_booking_datetime_with_minimal_booking_time(app):
agenda = Agenda.objects.create(label='Foo bar', kind='events', minimal_booking_delay=0)
Event.objects.create(
slug='event-slug',
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=3, hour=9)),
places=5,
agenda=agenda,
)
Event.objects.create(
slug='event-slug-2',
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=3, hour=11)),
places=5,
agenda=agenda,
)
api_url = '/api/agenda/%s/datetimes/' % agenda.slug
resp = app.get(api_url)
assert resp.json['data'][0]['datetime'] == '2023-04-03 09:00:00'
assert resp.json['data'][1]['datetime'] == '2023-04-03 11:00:00'
# set a minimal minimal_booking_time and check that it has no impact
agenda.minimal_booking_time = datetime.time(10, 0, 0)
agenda.save()
resp = app.get(api_url)
assert resp.json['data'][0]['datetime'] == '2023-04-03 09:00:00'
assert resp.json['data'][1]['datetime'] == '2023-04-03 11:00:00'
# set a minimal minimal_booking_time to None check that it has no impact
agenda.minimal_booking_time = None
agenda.save()
resp = app.get(api_url)
assert resp.json['data'][0]['datetime'] == '2023-04-03 09:00:00'
assert resp.json['data'][1]['datetime'] == '2023-04-03 11:00:00'
def test_events_datetimes_max_booking_datetime_with_minimal_booking_time(app, freezer):
agenda = Agenda.objects.create(
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=3
)
Event.objects.create(
slug='event-slug-0',
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=4, hour=9)),
places=5,
agenda=agenda,
)
Event.objects.create(
slug='event-slug-1',
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=4, hour=11)),
places=5,
agenda=agenda,
)
Event.objects.create(
slug='event-slug-2',
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=5, hour=9)),
places=5,
agenda=agenda,
)
Event.objects.create(
slug='event-slug-3',
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=5, hour=11)),
places=5,
agenda=agenda,
)
Event.objects.create(
slug='event-slug-4',
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=6, hour=9)),
places=5,
agenda=agenda,
)
Event.objects.create(
slug='event-slug-5',
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=6, hour=11)),
places=5,
agenda=agenda,
)
# last slots visible are the one on J + maximal_booking_delay (3) -1
freezer.move_to('2023-04-03T00:00:00+02:00')
api_url = '/api/agenda/%s/datetimes/' % agenda.slug
resp = app.get(api_url)
assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2023-04-05 11:00:00'
# # move to noon, no changes
freezer.move_to('2023-04-03T12:00:00+02:00')
resp = app.get(api_url)
assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2023-04-05 11:00:00'
# set a minimal minimal_booking_time earlier than current time, no changes
agenda.minimal_booking_time = datetime.time(10, 0, 0)
agenda.save()
resp = app.get(api_url)
assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2023-04-05 11:00:00'
# set a minimal minimal_booking_time later than current time, slots of 2023-04-05 disappear
agenda.minimal_booking_time = datetime.time(14, 0, 0)
agenda.save()
resp = app.get(api_url)
assert resp.json['data'][-2]['datetime'] == '2023-04-04 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2023-04-04 11:00:00'
# move to a time superior to minimal_booking_time (14:00), slots of 2023-04-05 re-appear
freezer.move_to('2023-04-03T15:00:00+02:00')
resp = app.get(api_url)
assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2023-04-05 11:00:00'
# move to the day after, prior to minimal_booking_time (14:00), no changes
freezer.move_to('2023-04-04T12:00:00+02:00')
resp = app.get(api_url)
assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2023-04-05 11:00:00'
# move to the day after, after minimal_booking_time (14:00), new slots available
freezer.move_to('2023-04-04T15:00:00+02:00')
resp = app.get(api_url)
assert resp.json['data'][-2]['datetime'] == '2023-04-06 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2023-04-06 11:00:00'
def test_events_datetimes_max_booking_datetime_with_minimal_booking_time_to_none(app, freezer):
agenda = Agenda.objects.create(
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=3
)
Event.objects.create(
slug='event-slug-0',
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=4, hour=9)),
places=5,
agenda=agenda,
)
Event.objects.create(
slug='event-slug-1',
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=4, hour=11)),
places=5,
agenda=agenda,
)
Event.objects.create(
slug='event-slug-2',
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=5, hour=9)),
places=5,
agenda=agenda,
)
Event.objects.create(
slug='event-slug-3',
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=5, hour=11)),
places=5,
agenda=agenda,
)
Event.objects.create(
slug='event-slug-4',
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=6, hour=9)),
places=5,
agenda=agenda,
)
Event.objects.create(
slug='event-slug-5',
start_datetime=make_aware(datetime.datetime(year=2023, month=4, day=6, hour=11)),
places=5,
agenda=agenda,
)
# last slots visible are the one on J + maximal_booking_delay (3) -1
freezer.move_to('2023-04-03T00:00:00+02:00')
api_url = '/api/agenda/%s/datetimes/' % agenda.slug
resp = app.get(api_url)
assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2023-04-05 11:00:00'
# set a minimal minimal_booking_time to None, 2023-04-05 disappear
# because current time is 00:00 and slots starts later
agenda.minimal_booking_time = None
agenda.save()
resp = app.get(api_url)
assert resp.json['data'][-2]['datetime'] == '2023-04-04 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2023-04-04 11:00:00'
# move a few hours later, juste after the first slot time of a day

2023-04-03 ?

2023-04-03 ?

Heu non. Déjà pas d'évènements déclaré le 3 avril dans le test.

Et sur le fond, l'idée est :

  • les deux assert d'avant vérifient que les derniers crénaux visibles sont le le 5 avril
  • ensuite agenda.minimal_booking_time = None qui passe l'horaire d'ouverture des réservation en mode glissant
  • ces deux assert que tu pointes vérifient que le passage en mode glissant fait disparaître les créneaux du 5 (parce que via freezer il est 00h00)
  • les assert suivants vérifient que à mesure que la journée avance, les créneaux du 5 re-apparaissent
Heu non. Déjà pas d'évènements déclaré le 3 avril dans le test. Et sur le fond, l'idée est : * les deux assert d'avant vérifient que les derniers crénaux visibles sont le le 5 avril * ensuite agenda.minimal_booking_time = None qui passe l'horaire d'ouverture des réservation en mode glissant * ces deux assert que tu pointes vérifient que le passage en mode glissant fait disparaître les créneaux du 5 (parce que via freezer il est 00h00) * les assert suivants vérifient que à mesure que la journée avance, les créneaux du 5 re-apparaissent

Oui mais non, je ne comprends pas. Tu écris "move after 2023-04-05", et juste dessous, "freezer.move_to('2023-04-03T09:01:00+02:00')"

Oui mais non, je ne comprends pas. Tu écris "move after 2023-04-05", et juste dessous, "freezer.move_to('2023-04-03T09:01:00+02:00')"

Le commentaire était : "move juste after the first 2023-04-05 slot time".

J'ai changé pour "move a few hours later, juste after the first slot time of a day".

Le commentaire était : "move juste after the first 2023-04-05 slot time". J'ai changé pour "move a few hours later, juste after the first slot time of a day".
# a new slot becomes available
freezer.move_to('2023-04-03T09:01:00+02:00')
resp = app.get(api_url)
assert resp.json['data'][-1]['datetime'] == '2023-04-05 09:00:00'
# at 12:00, every slots are available
freezer.move_to('2023-04-03T12:00:00+02:00')
resp = app.get(api_url)
assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2023-04-05 11:00:00'

View File

@ -2660,3 +2660,150 @@ def test_datetimes_api_meetings_agenda_filter_minutes(app):
assert datetime_from_str(resp.json['data'][1]['datetime']).minute == 30
assert datetime_from_str(resp.json['data'][2]['datetime']).minute == 0
assert datetime_from_str(resp.json['data'][3]['datetime']).minute == 30
@pytest.mark.freeze_time('2023-04-03')
def test_datetimes_api_meetings_min_booking_datetime_with_minimal_booking_time(app):
agenda = Agenda.objects.create(
label='Agenda', kind='meetings', minimal_booking_delay=0, maximal_booking_delay=3
)
desk = Desk.objects.create(agenda=agenda, slug='desk')
meeting_type = MeetingType.objects.create(agenda=agenda, slug='foo', duration=30)
for weekday in [0, 1, 2]: # monday, tuesday, wednesday
TimePeriod.objects.create(
weekday=weekday,
start_time=datetime.time(9, 0),
end_time=datetime.time(10, 00),
desk=desk,
)
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug)
resp = app.get(api_url)
assert resp.json['data'][0]['datetime'] == '2023-04-03 09:00:00'
# set a minimal minimal_booking_time and check that it has no impact
agenda.minimal_booking_time = datetime.time(10, 0, 0)
agenda.save()
resp = app.get(api_url)
assert resp.json['data'][0]['datetime'] == '2023-04-03 09:00:00'
# set a minimal minimal_booking_time to None check that it has no impact
agenda.minimal_booking_time = None
agenda.save()
resp = app.get(api_url)
assert resp.json['data'][0]['datetime'] == '2023-04-03 09:00:00'
def test_datetimes_api_meetings_max_booking_datetime_with_minimal_booking_time(app, freezer):
agenda = Agenda.objects.create(
label='Agenda', kind='meetings', minimal_booking_delay=0, maximal_booking_delay=3
)
desk = Desk.objects.create(agenda=agenda, slug='desk')
meeting_type = MeetingType.objects.create(agenda=agenda, slug='foo', duration=30)
for weekday in [0, 1, 2, 3, 4, 5]:
TimePeriod.objects.create(
weekday=weekday,
start_time=datetime.time(9, 0),
end_time=datetime.time(10, 00),
desk=desk,
)
# last slots visible are the one on J + maximal_booking_delay (3) -1
freezer.move_to('2023-04-03T00:00:00+02:00') # 2023-04-03 is a monday
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug)
resp = app.get(api_url)
assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2023-04-05 09:30:00'
# move to noon, no changes
freezer.move_to('2023-04-03T12:00:00+02:00')
resp = app.get(api_url)
assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2023-04-05 09:30:00'
# set a minimal minimal_booking_time earlier than current time, no changes
agenda.minimal_booking_time = datetime.time(10, 0, 0)
agenda.save()
resp = app.get(api_url)
assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2023-04-05 09:30:00'
# set a minimal minimal_booking_time later than current time, slots of 2023-04-05 disappear
agenda.minimal_booking_time = datetime.time(14, 0, 0)
agenda.save()
resp = app.get(api_url)
assert resp.json['data'][-2]['datetime'] == '2023-04-04 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2023-04-04 09:30:00'
# move to a time superior to minimal_booking_time (14:00), slots of 2023-04-05 re-appear
freezer.move_to('2023-04-03T15:00:00+02:00')
resp = app.get(api_url)
assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2023-04-05 09:30:00'
# move to the day after, prior to minimal_booking_time (14:00), no changes
freezer.move_to('2023-04-04T12:00:00+02:00')
resp = app.get(api_url)
assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2023-04-05 09:30:00'
# move to the day after, after minimal_booking_time (14:00), new slots available
freezer.move_to('2023-04-04T15:00:00+02:00')
resp = app.get(api_url)
assert resp.json['data'][-2]['datetime'] == '2023-04-06 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2023-04-06 09:30:00'
def test_datetimes_api_meetings_max_booking_datetime_with_minimal_booking_time_to_none(app, freezer):
agenda = Agenda.objects.create(
label='Agenda', kind='meetings', minimal_booking_delay=0, maximal_booking_delay=3
)
desk = Desk.objects.create(agenda=agenda, slug='desk')
meeting_type = MeetingType.objects.create(agenda=agenda, slug='foo', duration=30)
for weekday in [0, 1, 2, 3, 4, 5]:
TimePeriod.objects.create(
weekday=weekday,
start_time=datetime.time(11, 00),
end_time=datetime.time(14, 00),
desk=desk,
)
# last slots visible are the one on J + maximal_booking_delay (3) -1
freezer.move_to('2023-04-03T00:00:00+02:00') # 2023-04-03 is a monday
api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meeting_type.slug)
resp = app.get(api_url)
assert resp.json['data'][-6]['datetime'] == '2023-04-05 11:00:00'
assert resp.json['data'][-5]['datetime'] == '2023-04-05 11:30:00'
assert resp.json['data'][-4]['datetime'] == '2023-04-05 12:00:00'
assert resp.json['data'][-3]['datetime'] == '2023-04-05 12:30:00'
assert resp.json['data'][-2]['datetime'] == '2023-04-05 13:00:00'
assert resp.json['data'][-1]['datetime'] == '2023-04-05 13:30:00'
# set a minimal minimal_booking_time to None, 2023-04-05 disappear
# because current time is 00:00 and slots starts later
agenda.minimal_booking_time = None
agenda.save()
resp = app.get(api_url)
assert resp.json['data'][-1]['datetime'] == '2023-04-04 13:30:00'
# move a few hours later, juste after the first slot time of a day

2023-04-03 ?

2023-04-03 ?

Même réponse que précédemment.

Même réponse que précédemment.
# a new slot becomes available
freezer.move_to('2023-04-03T11:01:00+02:00')

j'ai un doute ici, on ne devrait pas aller jusqu'à 3*24H ? donc jusqu'au 6 avril 2023 à 11H01 ?

j'ai un doute ici, on ne devrait pas aller jusqu'à 3*24H ? donc jusqu'au 6 avril 2023 à 11H01 ?

Je ne comprends pas ce que tu veux dire.

J'ai vaguement l'impression que ça a un rapport avec le fait que tu supposerais que la borne maximale (jour J + délai de réservation maximal) devrait être incluse.

Si c'est ça, non, elle est bien exclue actuellement (au passage https://dev.entrouvert.org/issues/76360).

Je ne comprends pas ce que tu veux dire. J'ai vaguement l'impression que ça a un rapport avec le fait que tu supposerais que la borne maximale (jour J + délai de réservation maximal) devrait être incluse. Si c'est ça, non, elle est bien exclue actuellement (au passage https://dev.entrouvert.org/issues/76360).
resp = app.get(api_url)
assert resp.json['data'][-1]['datetime'] == '2023-04-05 11:00:00'
# move juste after the second slot time, one more slot availalbe
freezer.move_to('2023-04-03T11:31:00+02:00')
resp = app.get(api_url)
assert resp.json['data'][-2]['datetime'] == '2023-04-05 11:00:00'
assert resp.json['data'][-1]['datetime'] == '2023-04-05 11:30:00'
# at 15:00, every slots are available
freezer.move_to('2023-04-03T15:00:00+02:00')
resp = app.get(api_url)
assert resp.json['data'][-6]['datetime'] == '2023-04-05 11:00:00'
assert resp.json['data'][-5]['datetime'] == '2023-04-05 11:30:00'
assert resp.json['data'][-4]['datetime'] == '2023-04-05 12:00:00'
assert resp.json['data'][-3]['datetime'] == '2023-04-05 12:30:00'
assert resp.json['data'][-2]['datetime'] == '2023-04-05 13:00:00'
assert resp.json['data'][-1]['datetime'] == '2023-04-05 13:30:00'

View File

@ -613,7 +613,9 @@ def test_add_agenda(app, user, settings):
agenda = Agenda.objects.get(slug='foo-events')
assert agenda.edit_role == edit_group
assert agenda.view_role == view_group
assert agenda.min_booking_datetime == localtime(now()).replace(day=12)
assert agenda.min_booking_datetime == localtime(now()).replace(
day=12, hour=0, minute=0, second=0, microsecond=0
)
assert agenda.minimal_booking_time is None
assert agenda.category == category_a
assert agenda.events_type == events_type

View File

@ -277,22 +277,22 @@ def delay_parameter_to_label(argvalue):
@pytest.mark.parametrize(
'current_time,min_booking_datetime',
[
('2021-07-09T08:00:00+02:00', datetime.datetime(2021, 7, 13, 8)),
('2021-03-18T07:00:00+01:00', datetime.datetime(2021, 3, 22, 7)),
('2021-07-09T08:00:00+02:00', datetime.datetime(2021, 7, 13, 0, 0)),
('2021-03-18T07:00:00+01:00', datetime.datetime(2021, 3, 22, 0, 0)),
# summer DST change on sunday 28th
('2021-03-25T01:30:00+01:00', datetime.datetime(2021, 3, 29, 1, 30)),
('2021-03-25T02:30:00+01:00', datetime.datetime(2021, 3, 29, 2, 30)),
('2021-03-25T03:30:00+01:00', datetime.datetime(2021, 3, 29, 3, 30)),
('2021-03-28T01:30:00+01:00', datetime.datetime(2021, 4, 1, 1, 30)),
('2021-03-28T03:30:00+02:00', datetime.datetime(2021, 4, 1, 3, 30)),
('2021-03-25T01:30:00+01:00', datetime.datetime(2021, 3, 29, 0, 0)),
('2021-03-25T02:30:00+01:00', datetime.datetime(2021, 3, 29, 0, 0)),
('2021-03-25T03:30:00+01:00', datetime.datetime(2021, 3, 29, 0, 0)),
('2021-03-28T01:30:00+01:00', datetime.datetime(2021, 4, 1, 0, 0)),
('2021-03-28T03:30:00+02:00', datetime.datetime(2021, 4, 1, 0, 0)),
# winter DST change on sunday 31th
('2021-10-29T01:30:00+02:00', datetime.datetime(2021, 11, 2, 1, 30)),
('2021-10-29T02:30:00+02:00', datetime.datetime(2021, 11, 2, 2, 30)),
('2021-10-29T02:30:00+02:00', datetime.datetime(2021, 11, 2, 2, 30)),
('2021-10-31T01:30:00+02:00', datetime.datetime(2021, 11, 4, 1, 30)),
('2021-10-31T02:30:00+02:00', datetime.datetime(2021, 11, 4, 2, 30)),
('2021-10-31T02:30:00+01:00', datetime.datetime(2021, 11, 4, 2, 30)),
('2021-10-31T03:30:00+01:00', datetime.datetime(2021, 11, 4, 3, 30)),
('2021-10-29T01:30:00+02:00', datetime.datetime(2021, 11, 2, 0, 0)),
('2021-10-29T02:30:00+02:00', datetime.datetime(2021, 11, 2, 0, 0)),
('2021-10-29T02:30:00+02:00', datetime.datetime(2021, 11, 2, 0, 0)),
('2021-10-31T01:30:00+02:00', datetime.datetime(2021, 11, 4, 0, 0)),
('2021-10-31T02:30:00+02:00', datetime.datetime(2021, 11, 4, 0, 0)),
('2021-10-31T02:30:00+01:00', datetime.datetime(2021, 11, 4, 0, 0)),
('2021-10-31T03:30:00+01:00', datetime.datetime(2021, 11, 4, 0, 0)),
],
ids=delay_parameter_to_label,
)
@ -305,22 +305,22 @@ def test_agenda_minimal_booking_delay_no_minimal_booking_time(freezer, current_t
@pytest.mark.parametrize(
'current_time,min_booking_datetime',
[
('2021-07-09T08:00:00+02:00', datetime.datetime(2021, 7, 16, 8)),
('2021-03-18T07:00:00+01:00', datetime.datetime(2021, 3, 24, 7)),
('2021-07-09T08:00:00+02:00', datetime.datetime(2021, 7, 16, 0, 0)),
('2021-03-18T07:00:00+01:00', datetime.datetime(2021, 3, 24, 0, 0)),
# summer DST change on sunday 28th
('2021-03-25T01:30:00+01:00', datetime.datetime(2021, 3, 31, 1, 30)),
('2021-03-25T02:30:00+01:00', datetime.datetime(2021, 3, 31, 2, 30)),
('2021-03-25T03:30:00+01:00', datetime.datetime(2021, 3, 31, 3, 30)),
('2021-03-28T01:30:00+01:00', datetime.datetime(2021, 4, 1, 1, 30)),
('2021-03-28T03:30:00+02:00', datetime.datetime(2021, 4, 1, 3, 30)),
('2021-03-25T01:30:00+01:00', datetime.datetime(2021, 3, 31, 0, 0)),
('2021-03-25T02:30:00+01:00', datetime.datetime(2021, 3, 31, 0, 0)),
('2021-03-25T03:30:00+01:00', datetime.datetime(2021, 3, 31, 0, 0)),
('2021-03-28T01:30:00+01:00', datetime.datetime(2021, 4, 1, 0, 0)),
('2021-03-28T03:30:00+02:00', datetime.datetime(2021, 4, 1, 0, 0)),
# winter DST change on sunday 31th
('2021-10-29T01:30:00+02:00', datetime.datetime(2021, 11, 5, 1, 30)),
('2021-10-29T02:30:00+02:00', datetime.datetime(2021, 11, 5, 2, 30)),
('2021-10-29T02:30:00+02:00', datetime.datetime(2021, 11, 5, 2, 30)),
('2021-10-31T01:30:00+02:00', datetime.datetime(2021, 11, 5, 1, 30)),
('2021-10-31T02:30:00+02:00', datetime.datetime(2021, 11, 5, 2, 30)),
('2021-10-31T02:30:00+01:00', datetime.datetime(2021, 11, 5, 2, 30)),
('2021-10-31T03:30:00+01:00', datetime.datetime(2021, 11, 5, 3, 30)),
('2021-10-29T01:30:00+02:00', datetime.datetime(2021, 11, 5, 0, 0)),
('2021-10-29T02:30:00+02:00', datetime.datetime(2021, 11, 5, 0, 0)),
('2021-10-29T02:30:00+02:00', datetime.datetime(2021, 11, 5, 0, 0)),
('2021-10-31T01:30:00+02:00', datetime.datetime(2021, 11, 5, 0, 0)),
('2021-10-31T02:30:00+02:00', datetime.datetime(2021, 11, 5, 0, 0)),
('2021-10-31T02:30:00+01:00', datetime.datetime(2021, 11, 5, 0, 0)),
('2021-10-31T03:30:00+01:00', datetime.datetime(2021, 11, 5, 0, 0)),
],
ids=delay_parameter_to_label,
)
@ -341,19 +341,19 @@ def test_agenda_minimal_booking_delay_in_working_days_no_minimal_booking_time(
@pytest.mark.parametrize(
'current_time,min_booking_datetime',
[
('2021-07-09T08:00:00+02:00', datetime.datetime(2021, 7, 13, 8)),
('2021-03-18T07:00:00+01:00', datetime.datetime(2021, 3, 22, 8)),
('2021-07-09T08:00:00+02:00', datetime.datetime(2021, 7, 13, 0, 0)),
('2021-03-18T07:00:00+01:00', datetime.datetime(2021, 3, 22, 0, 0)),
# summer DST change on sunday
('2021-03-25T02:30:00+01:00', datetime.datetime(2021, 3, 29, 8)),
('2021-03-25T03:30:00+01:00', datetime.datetime(2021, 3, 29, 8)),
('2021-03-25T02:30:00+01:00', datetime.datetime(2021, 3, 29, 0, 0)),
('2021-03-25T03:30:00+01:00', datetime.datetime(2021, 3, 29, 0, 0)),
# winter DST change on sunday
('2021-10-29T01:30:00+02:00', datetime.datetime(2021, 11, 2, 8)),
('2021-10-29T02:30:00+02:00', datetime.datetime(2021, 11, 2, 8)),
('2021-10-29T02:30:00+02:00', datetime.datetime(2021, 11, 2, 8)),
('2021-10-31T01:30:00+02:00', datetime.datetime(2021, 11, 4, 8)),
('2021-10-31T02:30:00+02:00', datetime.datetime(2021, 11, 4, 8)),
('2021-10-31T02:30:00+01:00', datetime.datetime(2021, 11, 4, 8)),
('2021-10-31T03:30:00+01:00', datetime.datetime(2021, 11, 4, 8)),
('2021-10-29T01:30:00+02:00', datetime.datetime(2021, 11, 2, 0, 0)),
('2021-10-29T02:30:00+02:00', datetime.datetime(2021, 11, 2, 0, 0)),
('2021-10-29T02:30:00+02:00', datetime.datetime(2021, 11, 2, 0, 0)),
('2021-10-31T01:30:00+02:00', datetime.datetime(2021, 11, 4, 0, 0)),
('2021-10-31T02:30:00+02:00', datetime.datetime(2021, 11, 4, 0, 0)),
('2021-10-31T02:30:00+01:00', datetime.datetime(2021, 11, 4, 0, 0)),
('2021-10-31T03:30:00+01:00', datetime.datetime(2021, 11, 4, 0, 0)),
],
ids=delay_parameter_to_label,
)
@ -368,22 +368,22 @@ def test_agenda_minimal_booking_delay_minimal_booking_time_at_8(freezer, current
@pytest.mark.parametrize(
'current_time,max_booking_datetime',
[
('2021-07-09T08:00:00+02:00', datetime.datetime(2021, 7, 13, 8)),
('2021-03-18T07:00:00+01:00', datetime.datetime(2021, 3, 22, 7)),
('2021-07-09T08:00:00+02:00', datetime.datetime(2021, 7, 12, 8)),

même remarque que plus haut, ça me paraissait bien avant: 4*24H donc si on est 2021-07-09T08:00:00+02:00 ça nous amène bien à 2021-07-13T08:00:00+02:00

même remarque que plus haut, ça me paraissait bien avant: 4*24H donc si on est 2021-07-09T08:00:00+02:00 ça nous amène bien à 2021-07-13T08:00:00+02:00

Encore borne maximale exclue.

Encore borne maximale exclue.

Sauf que, dans le cas non flottant, test test_events_datetimes_max_booking_datetime_with_minimal_booking_time:

    agenda = Agenda.objects.create(
        label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=3
    )
    ...
    # last slots visible are the one on J + maximal_booking_delay (3) -1
    freezer.move_to('2023-04-03T00:00:00+02:00')
    api_url = '/api/agenda/%s/datetimes/' % agenda.slug
    resp = app.get(api_url)
    assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00'
    assert resp.json['data'][-1]['datetime'] == '2023-04-05 11:00:00'

On se pose le 3 avril à n'importe quelle heure, et on voit tous les créneaux du 5 avril. Ca fait en amplitude horaire entre 2 et 3 jours, 3 jours inclus si on se pose à minuit. Juste qu'on ne dépasse pas du 5, on ne regarde pas le 6 avril, qui est exclu.

Pour moi, si on est dans le cas flottant (avec ici un délai max à 4 jours):
on est au 2021-07-09T08:00:00+02:00, ça donne bien 2021-07-13T08:00:00+02:00, mais on exclut 2021-07-13T08:00:00+02:00: un event posé à 2021-07-13T08:00:00+02:00 n'apparaît pas, un event posé à 2021-07-13T07:59:59+02:00 apparaît

Sauf que, dans le cas non flottant, test `test_events_datetimes_max_booking_datetime_with_minimal_booking_time`: ``` agenda = Agenda.objects.create( label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=3 ) ... # last slots visible are the one on J + maximal_booking_delay (3) -1 freezer.move_to('2023-04-03T00:00:00+02:00') api_url = '/api/agenda/%s/datetimes/' % agenda.slug resp = app.get(api_url) assert resp.json['data'][-2]['datetime'] == '2023-04-05 09:00:00' assert resp.json['data'][-1]['datetime'] == '2023-04-05 11:00:00' ``` On se pose le 3 avril à n'importe quelle heure, et on voit tous les créneaux du 5 avril. Ca fait en amplitude horaire entre 2 et 3 jours, 3 jours inclus si on se pose à minuit. Juste qu'on ne dépasse pas du 5, on ne regarde pas le 6 avril, qui est exclu. Pour moi, si on est dans le cas flottant (avec ici un délai max à 4 jours): on est au 2021-07-09T08:00:00+02:00, ça donne bien 2021-07-13T08:00:00+02:00, mais on exclut 2021-07-13T08:00:00+02:00: un event posé à 2021-07-13T08:00:00+02:00 n'apparaît pas, un event posé à 2021-07-13T07:59:59+02:00 apparaît

"On se pose le 3 avril......3 jours inclus si on se pose à minuit ...on ne regarde pas le 6 avril, qui est exclu."

Je ne comprends pas ton raisonnement, j'en ai un plus simple il me semble : le 3 avril, de 00h00 à 23h59, je ne verrai jamais aucun créneau du 6 avril, les créneaux les plus distants que je voie sont au 5 avril.

C'était déjà le cas avant l'introduction de l'horaire d'ouverture des réservations, ça reste le cas après.

Avec l'horaire d'ouverture des réservations, les créneaux du 5 avril se mettent soit à apparaître tous d'une coup à une heure donnée le 3 avril (à la place de 00h00), soit progressivement au fur et à mesure de la journée du 3 avril.

"Pour moi, si on est dans le cas flottant (avec ici un délai max à 4 jours):
on est au 2021-07-09T08:00:00+02:00 ... 2021-07-13T07:59:59+02:00 apparaît".

Le 2021-07-09 on doit jamais voir les créneaux du 2021-07-13 parce que délai max à 4 jours, peu importe les autres paramètres.

"On se pose le 3 avril......3 jours inclus si on se pose à minuit ...on ne regarde pas le 6 avril, qui est exclu." Je ne comprends pas ton raisonnement, j'en ai un plus simple il me semble : le 3 avril, de 00h00 à 23h59, je ne verrai jamais aucun créneau du 6 avril, les créneaux les plus distants que je voie sont au 5 avril. C'était déjà le cas avant l'introduction de l'horaire d'ouverture des réservations, ça reste le cas après. Avec l'horaire d'ouverture des réservations, les créneaux du 5 avril se mettent soit à apparaître tous d'une coup à une heure donnée le 3 avril (à la place de 00h00), soit progressivement au fur et à mesure de la journée du 3 avril. "Pour moi, si on est dans le cas flottant (avec ici un délai max à 4 jours): on est au 2021-07-09T08:00:00+02:00 ... 2021-07-13T07:59:59+02:00 apparaît". Le 2021-07-09 on doit jamais voir les créneaux du 2021-07-13 parce que délai max à 4 jours, peu importe les autres paramètres.

(j'abandonne)

(j'abandonne)

(en partant de l'hypothèse qu'on a posé 3 jours de délai max).

"soit progressivement au fur et à mesure de la journée du 3 avril."
Et justement c'est ça qui me bloque; on devrait voir apparaître les créneaux du 6 avril progressivement au fur et à mesure de la journée du 3 avril, et pas ceux du 5 avril.

Je n'ai aucun problème avec le comportement non flottant, avec ouverture à minuit ou peu importe l'heure définie.

(en partant de l'hypothèse qu'on a posé 3 jours de délai max). "soit progressivement au fur et à mesure de la journée du 3 avril." Et justement c'est ça qui me bloque; on devrait voir apparaître les créneaux du 6 avril progressivement au fur et à mesure de la journée du 3 avril, et pas ceux du 5 avril. Je n'ai aucun problème avec le comportement non flottant, avec ouverture à minuit ou peu importe l'heure définie.

(et, le ticket décrit un problème de comportement en mode non flottant, mais cette PR impacte le mode flottant, dont le problème que tu essaies de corriger n'a pas été exposé dans la description du ticket)

(et, le ticket décrit un problème de comportement en mode non flottant, mais cette PR impacte le mode flottant, dont le problème que tu essaies de corriger n'a pas été exposé dans la description du ticket)
('2021-03-18T07:00:00+01:00', datetime.datetime(2021, 3, 21, 7)),
# summer DST change on sunday 28th
('2021-03-25T01:30:00+01:00', datetime.datetime(2021, 3, 29, 1, 30)),
('2021-03-25T02:30:00+01:00', datetime.datetime(2021, 3, 29, 2, 30)),
('2021-03-25T03:30:00+01:00', datetime.datetime(2021, 3, 29, 3, 30)),
('2021-03-28T01:30:00+01:00', datetime.datetime(2021, 4, 1, 1, 30)),
('2021-03-28T03:30:00+02:00', datetime.datetime(2021, 4, 1, 3, 30)),
('2021-03-25T01:30:00+01:00', datetime.datetime(2021, 3, 28, 1, 30)),
('2021-03-25T02:30:00+01:00', datetime.datetime(2021, 3, 28, 3, 30)),
('2021-03-25T03:30:00+01:00', datetime.datetime(2021, 3, 28, 3, 30)),
('2021-03-28T01:30:00+01:00', datetime.datetime(2021, 3, 31, 1, 30)),
('2021-03-28T03:30:00+02:00', datetime.datetime(2021, 3, 31, 3, 30)),
# winter DST change on sunday 31th
('2021-10-29T01:30:00+02:00', datetime.datetime(2021, 11, 2, 1, 30)),
('2021-10-29T02:30:00+02:00', datetime.datetime(2021, 11, 2, 2, 30)),
('2021-10-29T02:30:00+02:00', datetime.datetime(2021, 11, 2, 2, 30)),
('2021-10-31T01:30:00+02:00', datetime.datetime(2021, 11, 4, 1, 30)),
('2021-10-31T02:30:00+02:00', datetime.datetime(2021, 11, 4, 2, 30)),
('2021-10-31T02:30:00+01:00', datetime.datetime(2021, 11, 4, 2, 30)),
('2021-10-31T03:30:00+01:00', datetime.datetime(2021, 11, 4, 3, 30)),
('2021-10-29T01:30:00+02:00', datetime.datetime(2021, 11, 1, 1, 30)),
('2021-10-29T02:30:00+02:00', datetime.datetime(2021, 11, 1, 2, 30)),
('2021-10-29T02:30:00+02:00', datetime.datetime(2021, 11, 1, 2, 30)),
('2021-10-31T01:30:00+02:00', datetime.datetime(2021, 11, 3, 1, 30)),
('2021-10-31T02:30:00+02:00', datetime.datetime(2021, 11, 3, 2, 30)),
('2021-10-31T02:30:00+01:00', datetime.datetime(2021, 11, 3, 2, 30)),
('2021-10-31T03:30:00+01:00', datetime.datetime(2021, 11, 3, 3, 30)),
],
ids=delay_parameter_to_label,
)
@ -396,19 +396,19 @@ def test_agenda_maximal_booking_delay_no_minimal_booking_time(freezer, current_t
@pytest.mark.parametrize(
'current_time,max_booking_datetime',
[
('2021-07-09T08:00:00+02:00', datetime.datetime(2021, 7, 13, 8)),
('2021-03-18T07:00:00+01:00', datetime.datetime(2021, 3, 22, 8)),
('2021-07-09T08:00:00+02:00', datetime.datetime(2021, 7, 13, 0)),
('2021-03-18T07:00:00+01:00', datetime.datetime(2021, 3, 21, 0)),
# summer DST change on sunday
('2021-03-25T02:30:00+01:00', datetime.datetime(2021, 3, 29, 8)),
('2021-03-25T03:30:00+01:00', datetime.datetime(2021, 3, 29, 8)),
('2021-03-25T02:30:00+01:00', datetime.datetime(2021, 3, 28, 0)),
('2021-03-25T03:30:00+01:00', datetime.datetime(2021, 3, 28, 0)),
# winter DST change on sunday
('2021-10-29T01:30:00+02:00', datetime.datetime(2021, 11, 2, 8)),
('2021-10-29T02:30:00+02:00', datetime.datetime(2021, 11, 2, 8)),
('2021-10-29T02:30:00+02:00', datetime.datetime(2021, 11, 2, 8)),
('2021-10-31T01:30:00+02:00', datetime.datetime(2021, 11, 4, 8)),
('2021-10-31T02:30:00+02:00', datetime.datetime(2021, 11, 4, 8)),
('2021-10-31T02:30:00+01:00', datetime.datetime(2021, 11, 4, 8)),
('2021-10-31T03:30:00+01:00', datetime.datetime(2021, 11, 4, 8)),
('2021-10-29T01:30:00+02:00', datetime.datetime(2021, 11, 1, 0)),
('2021-10-29T02:30:00+02:00', datetime.datetime(2021, 11, 1, 0)),
('2021-10-29T02:30:00+02:00', datetime.datetime(2021, 11, 1, 0)),
('2021-10-31T01:30:00+02:00', datetime.datetime(2021, 11, 3, 0)),
('2021-10-31T02:30:00+02:00', datetime.datetime(2021, 11, 3, 0)),
('2021-10-31T02:30:00+01:00', datetime.datetime(2021, 11, 3, 0)),
('2021-10-31T03:30:00+01:00', datetime.datetime(2021, 11, 3, 0)),
],
ids=delay_parameter_to_label,
)