avoir une heure de départ des réservations flottante ou fixe (#56284) #47
|
@ -0,0 +1,22 @@
|
||||||
|
# Generated by Django 3.2.18 on 2023-03-08 17:20
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('agendas', '0147_check_future_events'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='agenda',
|
||||||
|
name='minimal_booking_time',
|
||||||
|
field=models.TimeField(
|
||||||
|
blank=True, default=datetime.time(0, 0), null=True, verbose_name='Minimal booking time'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -262,6 +262,15 @@ class Agenda(models.Model):
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
)
|
)
|
||||||
|
minimal_booking_time = models.TimeField(
|
||||||
|
verbose_name=_('Minimal booking 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.'
|
||||||
|
),
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['label']
|
ordering = ['label']
|
||||||
|
@ -634,31 +643,27 @@ class Agenda(models.Model):
|
||||||
if self.maximal_booking_delay is None:
|
if self.maximal_booking_delay is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# compute middle of today with localtime
|
# reference is now, in local timezone
|
||||||
# 28 Mar 2021 12:00 +01:00
|
t = localtime(now())
|
||||||
t = localtime(now()).replace(hour=12, minute=0)
|
|
||||||
|
|
||||||
# advance of self.maximal_booking_delay - 1 days
|
# add delay
|
||||||
# 28 Mar 2021 12:00 +01:00 == 28 Mars 2021 13:00 +02:00 as DST happend on 28 Mar 2021.
|
|
||||||
t += datetime.timedelta(days=self.maximal_booking_delay)
|
t += datetime.timedelta(days=self.maximal_booking_delay)
|
||||||
|
|
||||||
# move to midnight of the day before, DST happen between 2h/3h so it
|
# replace time if needed
|
||||||
# always exists because +/- timedelta does not move the timezone, only
|
if self.minimal_booking_time:
|
||||||
# localtime() does it.
|
t = datetime.datetime.combine(t.date(), self.minimal_booking_time, tzinfo=t.tzinfo)
|
||||||
# 27 Mar 2021 12:00 +01:00 == 28 Mars 2021 01:00 +02:00
|
# t could not exist, recompute it as an existing datetime by converting to UTC then to localtime
|
||||||
return localtime(t).replace(hour=0, minute=0, second=0, microsecond=0)
|
return localtime(t.astimezone(utc))
|
||||||
|
|
||||||
@functional.cached_property
|
@functional.cached_property
|
||||||
def min_booking_datetime(self):
|
def min_booking_datetime(self):
|
||||||
if self.minimal_booking_delay is None:
|
if self.minimal_booking_delay is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# compute middle of today with localtime
|
# reference is now, in local timezone
|
||||||
# 28 Mar 2021 12:00 +01:00
|
t = localtime(now())
|
||||||
t = localtime(now()).replace(hour=12, minute=0)
|
|
||||||
|
|
||||||
# advance of self.minimal_booking_delay - 1 days
|
# add delay
|
||||||
# 28 Mar 2021 12:00 +01:00 == 28 Mars 2021 13:00 +02:00 as DST happend on 28 Mar 2021.
|
|
||||||
if settings.WORKING_DAY_CALENDAR is not None and self.minimal_booking_delay_in_working_days:
|
if settings.WORKING_DAY_CALENDAR is not None and self.minimal_booking_delay_in_working_days:
|
||||||
source_class = import_string(settings.WORKING_DAY_CALENDAR)
|
source_class = import_string(settings.WORKING_DAY_CALENDAR)
|
||||||
calendar = source_class()
|
calendar = source_class()
|
||||||
|
@ -666,11 +671,11 @@ class Agenda(models.Model):
|
||||||
else:
|
else:
|
||||||
t += datetime.timedelta(days=self.minimal_booking_delay)
|
t += datetime.timedelta(days=self.minimal_booking_delay)
|
||||||
|
|
||||||
# move to midnight of the day before, DST happen between 2h/3h so it
|
# replace time if needed
|
||||||
# always exists because +/- timedelta does not move the timezone, only
|
if self.minimal_booking_time:
|
||||||
# localtime() does it.
|
t = datetime.datetime.combine(t.date(), self.minimal_booking_time, tzinfo=t.tzinfo)
|
||||||
# 27 Mar 2021 12:00 +01:00 == 28 Mars 2021 01:00 +02:00
|
# t could not exist, recompute it as an existing datetime by converting to UTC then to localtime
|
||||||
return localtime(t).replace(hour=0, minute=0, second=0, microsecond=0)
|
return localtime(t.astimezone(utc))
|
||||||
|
|
||||||
def get_open_events(
|
def get_open_events(
|
||||||
self,
|
self,
|
||||||
|
|
|
@ -521,6 +521,7 @@ class AgendaSerializer(serializers.ModelSerializer):
|
||||||
'minimal_booking_delay',
|
'minimal_booking_delay',
|
||||||
'minimal_booking_delay_in_working_days',
|
'minimal_booking_delay_in_working_days',
|
||||||
'maximal_booking_delay',
|
'maximal_booking_delay',
|
||||||
|
'minimal_booking_time',
|
||||||
'anonymize_delay',
|
'anonymize_delay',
|
||||||
'edit_role',
|
'edit_role',
|
||||||
'view_role',
|
'view_role',
|
||||||
|
|
|
@ -361,6 +361,7 @@ def get_agenda_detail(request, agenda, check_events=False):
|
||||||
'kind': agenda.kind,
|
'kind': agenda.kind,
|
||||||
'minimal_booking_delay': agenda.minimal_booking_delay,
|
'minimal_booking_delay': agenda.minimal_booking_delay,
|
||||||
'maximal_booking_delay': agenda.maximal_booking_delay,
|
'maximal_booking_delay': agenda.maximal_booking_delay,
|
||||||
|
'minimal_booking_time': agenda.minimal_booking_time,
|
||||||
'edit_role': agenda.edit_role.name if agenda.edit_role else None,
|
'edit_role': agenda.edit_role.name if agenda.edit_role else None,
|
||||||
'view_role': agenda.view_role.name if agenda.view_role else None,
|
'view_role': agenda.view_role.name if agenda.view_role else None,
|
||||||
'category': agenda.category.slug if agenda.category else None,
|
'category': agenda.category.slug if agenda.category else None,
|
||||||
|
|
|
@ -7,8 +7,8 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: chrono 0\n"
|
"Project-Id-Version: chrono 0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-03-16 17:02+0100\n"
|
"POT-Creation-Date: 2023-03-23 10:33+0100\n"
|
||||||
"PO-Revision-Date: 2023-03-02 18:58+0100\n"
|
"PO-Revision-Date: 2023-03-23 10:35+0100\n"
|
||||||
"Last-Translator: Frederic Peters <fpeters@entrouvert.com>\n"
|
"Last-Translator: Frederic Peters <fpeters@entrouvert.com>\n"
|
||||||
"Language: French\n"
|
"Language: French\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
|
@ -207,8 +207,7 @@ msgstr ""
|
||||||
|
|
||||||
#: agendas/models.py
|
#: agendas/models.py
|
||||||
msgid "Enable the check of bookings when event has not passed"
|
msgid "Enable the check of bookings when event has not passed"
|
||||||
msgstr ""
|
msgstr "Activer le pointage des réservations sur les événements à venir"
|
||||||
"Activer le pointage des réservations sur les événements à venir"
|
|
||||||
|
|
||||||
#: agendas/models.py
|
#: agendas/models.py
|
||||||
msgid "Filters"
|
msgid "Filters"
|
||||||
|
@ -248,6 +247,17 @@ msgstr ""
|
||||||
msgid "Events type"
|
msgid "Events type"
|
||||||
msgstr "Type d’événements"
|
msgstr "Type d’événements"
|
||||||
|
|
||||||
|
#: agendas/models.py
|
||||||
|
msgid "Minimal booking time"
|
||||||
|
msgstr "Heure de réservation minimale"
|
||||||
|
|
||||||
|
#: agendas/models.py
|
||||||
|
msgid ""
|
||||||
|
"Ex.: 08:00:00. If left empty, available events will be those that are later "
|
||||||
|
"than the current time."
|
||||||
|
msgstr ""
|
||||||
|
"Ex.: 08:00:00. Si ce champ est laissé vide alors les évènements ou rendez-vous disponibles à la réservation sont ceux dont le début est plus tard que l'heure courante, en prenant en compte les délais minimaux et maximaux de réservation en jours"
|
||||||
|
|
||||||
#: agendas/models.py
|
#: agendas/models.py
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Missing \"%s\" resource"
|
msgid "Missing \"%s\" resource"
|
||||||
|
@ -2182,6 +2192,14 @@ msgstr[1] "%(count)s jours"
|
||||||
msgid "Maximal booking delay:"
|
msgid "Maximal booking delay:"
|
||||||
msgstr "Délai de réservation maximal :"
|
msgstr "Délai de réservation maximal :"
|
||||||
|
|
||||||
|
#: manager/templates/chrono/manager_agenda_settings.html
|
||||||
|
msgid "Minimal booking time:"
|
||||||
|
msgstr "Heure de réservation minimale :"
|
||||||
|
|
||||||
|
#: manager/templates/chrono/manager_agenda_settings.html
|
||||||
|
msgid "current time"
|
||||||
|
msgstr "heure actuelle"
|
||||||
|
|
||||||
#: manager/templates/chrono/manager_agenda_settings.html
|
#: manager/templates/chrono/manager_agenda_settings.html
|
||||||
msgid "Edit Role:"
|
msgid "Edit Role:"
|
||||||
msgstr "Rôle d’édition :"
|
msgstr "Rôle d’édition :"
|
||||||
|
@ -2633,8 +2651,7 @@ msgstr ""
|
||||||
|
|
||||||
#: manager/templates/chrono/manager_events_agenda_settings.html
|
#: manager/templates/chrono/manager_events_agenda_settings.html
|
||||||
msgid "Enable the check of bookings when event has not passed:"
|
msgid "Enable the check of bookings when event has not passed:"
|
||||||
msgstr ""
|
msgstr "Activer le pointage des réservations sur les événements à venir :"
|
||||||
"Activer le pointage des réservations sur les événements à venir :"
|
|
||||||
|
|
||||||
#: manager/templates/chrono/manager_events_agenda_settings.html
|
#: manager/templates/chrono/manager_events_agenda_settings.html
|
||||||
#, python-format
|
#, python-format
|
||||||
|
|
|
@ -129,6 +129,7 @@ class AgendaBookingDelaysForm(forms.ModelForm):
|
||||||
'minimal_booking_delay',
|
'minimal_booking_delay',
|
||||||
'minimal_booking_delay_in_working_days',
|
'minimal_booking_delay_in_working_days',
|
||||||
'maximal_booking_delay',
|
'maximal_booking_delay',
|
||||||
|
'minimal_booking_time',
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
|
@ -89,6 +89,10 @@
|
||||||
{% if agenda.maximal_booking_delay is not None %}
|
{% if agenda.maximal_booking_delay is not None %}
|
||||||
{% blocktrans count count=agenda.maximal_booking_delay %}{{ count }} day{% plural %}{{ count }} days{% endblocktrans %}
|
{% blocktrans count count=agenda.maximal_booking_delay %}{{ count }} day{% plural %}{{ count }} days{% endblocktrans %}
|
||||||
{% else %}<i>{% trans "undefined" %}</i>{% endif %}</li>
|
{% 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:" %}
|
||||||
|
{% if agenda.minimal_booking_time is not None %}{{ agenda.minimal_booking_time }}{% else %}{% trans "current time" %}{% endif %}</li>
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
<div class="panel--buttons">
|
<div class="panel--buttons">
|
||||||
<a rel="popup" class="button" href="{% url 'chrono-manager-agenda-booking-delays' pk=object.id %}">{% trans 'Configure' %}</a>
|
<a rel="popup" class="button" href="{% url 'chrono-manager-agenda-booking-delays' pk=object.id %}">{% trans 'Configure' %}</a>
|
||||||
|
|
|
@ -66,6 +66,7 @@ def test_agendas_api(app):
|
||||||
'minimal_booking_delay': 1,
|
'minimal_booking_delay': 1,
|
||||||
'minimal_booking_delay_in_working_days': False,
|
'minimal_booking_delay_in_working_days': False,
|
||||||
'maximal_booking_delay': 56,
|
'maximal_booking_delay': 56,
|
||||||
|
'minimal_booking_time': '00:00:00',
|
||||||
'edit_role': 'Edit',
|
'edit_role': 'Edit',
|
||||||
'view_role': None,
|
'view_role': None,
|
||||||
'category': 'category-a',
|
'category': 'category-a',
|
||||||
|
@ -85,6 +86,7 @@ def test_agendas_api(app):
|
||||||
'minimal_booking_delay': 1,
|
'minimal_booking_delay': 1,
|
||||||
'minimal_booking_delay_in_working_days': False,
|
'minimal_booking_delay_in_working_days': False,
|
||||||
'maximal_booking_delay': 56,
|
'maximal_booking_delay': 56,
|
||||||
|
'minimal_booking_time': '00:00:00',
|
||||||
'edit_role': None,
|
'edit_role': None,
|
||||||
'view_role': None,
|
'view_role': None,
|
||||||
'category': 'category-a',
|
'category': 'category-a',
|
||||||
|
@ -104,6 +106,7 @@ def test_agendas_api(app):
|
||||||
'minimal_booking_delay': 1,
|
'minimal_booking_delay': 1,
|
||||||
'minimal_booking_delay_in_working_days': False,
|
'minimal_booking_delay_in_working_days': False,
|
||||||
'maximal_booking_delay': 56,
|
'maximal_booking_delay': 56,
|
||||||
|
'minimal_booking_time': '00:00:00',
|
||||||
'edit_role': None,
|
'edit_role': None,
|
||||||
'view_role': None,
|
'view_role': None,
|
||||||
'category': None,
|
'category': None,
|
||||||
|
@ -121,6 +124,7 @@ def test_agendas_api(app):
|
||||||
'slug': 'foo-bar-meeting',
|
'slug': 'foo-bar-meeting',
|
||||||
'minimal_booking_delay': 1,
|
'minimal_booking_delay': 1,
|
||||||
'maximal_booking_delay': 56,
|
'maximal_booking_delay': 56,
|
||||||
|
'minimal_booking_time': '00:00:00',
|
||||||
'edit_role': None,
|
'edit_role': None,
|
||||||
'view_role': 'View',
|
'view_role': 'View',
|
||||||
'category': 'category-b',
|
'category': 'category-b',
|
||||||
|
@ -144,6 +148,7 @@ def test_agendas_api(app):
|
||||||
'slug': 'foo-bar-meeting-2',
|
'slug': 'foo-bar-meeting-2',
|
||||||
'minimal_booking_delay': 1,
|
'minimal_booking_delay': 1,
|
||||||
'maximal_booking_delay': 56,
|
'maximal_booking_delay': 56,
|
||||||
|
'minimal_booking_time': '00:00:00',
|
||||||
'edit_role': None,
|
'edit_role': None,
|
||||||
'view_role': None,
|
'view_role': None,
|
||||||
'category': None,
|
'category': None,
|
||||||
|
@ -164,6 +169,7 @@ def test_agendas_api(app):
|
||||||
'slug': 'virtual-agenda',
|
'slug': 'virtual-agenda',
|
||||||
'minimal_booking_delay': 1,
|
'minimal_booking_delay': 1,
|
||||||
'maximal_booking_delay': 56,
|
'maximal_booking_delay': 56,
|
||||||
|
'minimal_booking_time': '00:00:00',
|
||||||
'edit_role': 'Edit',
|
'edit_role': 'Edit',
|
||||||
'view_role': 'View',
|
'view_role': 'View',
|
||||||
'category': None,
|
'category': None,
|
||||||
|
@ -411,6 +417,7 @@ def test_virtual_agenda_detail(app, virtual_meetings_agenda):
|
||||||
'slug': 'virtual-agenda',
|
'slug': 'virtual-agenda',
|
||||||
'minimal_booking_delay': None,
|
'minimal_booking_delay': None,
|
||||||
'maximal_booking_delay': None,
|
'maximal_booking_delay': None,
|
||||||
|
'minimal_booking_time': '00:00:00',
|
||||||
'edit_role': None,
|
'edit_role': None,
|
||||||
'view_role': None,
|
'view_role': None,
|
||||||
'category': None,
|
'category': None,
|
||||||
|
@ -457,25 +464,25 @@ def test_agenda_api_delete_busy(app, user):
|
||||||
assert not Agenda.objects.exists()
|
assert not Agenda.objects.exists()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.freeze_time('2021-07-09')
|
@pytest.mark.freeze_time('2021-07-09T08:00:00.0+02:00')
|
||||||
def test_add_agenda(app, user, settings):
|
def test_add_agenda(app, user, settings):
|
||||||
events_type = EventsType.objects.create(label='Type A')
|
events_type = EventsType.objects.create(label='Type A')
|
||||||
category_a = Category.objects.create(label='Category A')
|
category_a = Category.objects.create(label='Category A')
|
||||||
api_url = '/api/agenda/'
|
api_url = '/api/agenda/'
|
||||||
|
|
||||||
# no authentication
|
# no authentication
|
||||||
resp = app.post(api_url, status=401)
|
resp = app.post_json(api_url, status=401)
|
||||||
assert resp.json['detail'] == 'Authentication credentials were not provided.'
|
assert resp.json['detail'] == 'Authentication credentials were not provided.'
|
||||||
|
|
||||||
# wrong password
|
# wrong password
|
||||||
app.authorization = ('Basic', ('john.doe', 'wrong'))
|
app.authorization = ('Basic', ('john.doe', 'wrong'))
|
||||||
resp = app.post(api_url, status=401)
|
resp = app.post_json(api_url, status=401)
|
||||||
assert resp.json['detail'] == 'Invalid username/password.'
|
assert resp.json['detail'] == 'Invalid username/password.'
|
||||||
|
|
||||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||||
|
|
||||||
# missing fields
|
# missing fields
|
||||||
resp = app.post(api_url, status=400)
|
resp = app.post_json(api_url, status=400)
|
||||||
assert resp.json['err']
|
assert resp.json['err']
|
||||||
assert resp.json['errors'] == {'label': ['This field is required.'], 'slug': ['This field is required.']}
|
assert resp.json['errors'] == {'label': ['This field is required.'], 'slug': ['This field is required.']}
|
||||||
|
|
||||||
|
@ -492,7 +499,7 @@ def test_add_agenda(app, user, settings):
|
||||||
'category': 'oups',
|
'category': 'oups',
|
||||||
'events_type': 'oups',
|
'events_type': 'oups',
|
||||||
}
|
}
|
||||||
resp = app.post(api_url, params=params, status=400)
|
resp = app.post_json(api_url, params=params, status=400)
|
||||||
assert resp.json['err']
|
assert resp.json['err']
|
||||||
assert resp.json['errors'] == {
|
assert resp.json['errors'] == {
|
||||||
'kind': ['"oups" is not a valid choice.'],
|
'kind': ['"oups" is not a valid choice.'],
|
||||||
|
@ -512,7 +519,7 @@ def test_add_agenda(app, user, settings):
|
||||||
'label': 'foo',
|
'label': 'foo',
|
||||||
'slug': meeting_agenda.slug,
|
'slug': meeting_agenda.slug,
|
||||||
}
|
}
|
||||||
resp = app.post(api_url, params=params, status=400)
|
resp = app.post_json(api_url, params=params, status=400)
|
||||||
assert resp.json['err']
|
assert resp.json['err']
|
||||||
assert resp.json['errors'] == {'slug': ['agenda with this Identifier already exists.']}
|
assert resp.json['errors'] == {'slug': ['agenda with this Identifier already exists.']}
|
||||||
|
|
||||||
|
@ -523,7 +530,7 @@ def test_add_agenda(app, user, settings):
|
||||||
'kind': 'meetings',
|
'kind': 'meetings',
|
||||||
'minimal_booking_delay_in_working_days': True,
|
'minimal_booking_delay_in_working_days': True,
|
||||||
}
|
}
|
||||||
resp = app.post(api_url, params=params, status=400)
|
resp = app.post_json(api_url, params=params, status=400)
|
||||||
assert resp.json['err']
|
assert resp.json['err']
|
||||||
assert resp.json['errors'] == {
|
assert resp.json['errors'] == {
|
||||||
'minimal_booking_delay_in_working_days': ['Option not available on meetings agenda']
|
'minimal_booking_delay_in_working_days': ['Option not available on meetings agenda']
|
||||||
|
@ -534,7 +541,7 @@ def test_add_agenda(app, user, settings):
|
||||||
'kind': 'meetings',
|
'kind': 'meetings',
|
||||||
'events_type': 'type-a',
|
'events_type': 'type-a',
|
||||||
}
|
}
|
||||||
resp = app.post(api_url, params=params, status=400)
|
resp = app.post_json(api_url, params=params, status=400)
|
||||||
assert resp.json['err']
|
assert resp.json['err']
|
||||||
assert resp.json['errors'] == {'events_type': ['Option not available on meetings agenda']}
|
assert resp.json['errors'] == {'events_type': ['Option not available on meetings agenda']}
|
||||||
|
|
||||||
|
@ -543,7 +550,7 @@ def test_add_agenda(app, user, settings):
|
||||||
'label': 'My Agenda',
|
'label': 'My Agenda',
|
||||||
'slug': 'my-agenda',
|
'slug': 'my-agenda',
|
||||||
}
|
}
|
||||||
resp = app.post(api_url, params=params)
|
resp = app.post_json(api_url, params=params)
|
||||||
assert not resp.json['err']
|
assert not resp.json['err']
|
||||||
assert len(resp.json['data']) == 1
|
assert len(resp.json['data']) == 1
|
||||||
agenda = Agenda.objects.get(slug='my-agenda')
|
agenda = Agenda.objects.get(slug='my-agenda')
|
||||||
|
@ -567,11 +574,14 @@ def test_add_agenda(app, user, settings):
|
||||||
'mark_event_checked_auto': True,
|
'mark_event_checked_auto': True,
|
||||||
'disable_check_update': False,
|
'disable_check_update': False,
|
||||||
}
|
}
|
||||||
resp = app.post(api_url, params=params)
|
resp = app.post_json(api_url, params=params)
|
||||||
assert not resp.json['err']
|
assert not resp.json['err']
|
||||||
assert len(resp.json['data']) == 1
|
assert len(resp.json['data']) == 1
|
||||||
agenda = Agenda.objects.get(slug='foo-meetings')
|
agenda = Agenda.objects.get(slug='foo-meetings')
|
||||||
assert agenda.min_booking_datetime.date() == datetime.date(2021, 7, 10)
|
assert agenda.min_booking_datetime == localtime(now()).replace(
|
||||||
|
day=10, hour=0, minute=0, second=0, microsecond=0
|
||||||
|
)
|
||||||
|
assert agenda.minimal_booking_time == datetime.time(0)
|
||||||
assert agenda.edit_role == edit_group
|
assert agenda.edit_role == edit_group
|
||||||
assert agenda.view_role == view_group
|
assert agenda.view_role == view_group
|
||||||
assert agenda.category == category_a
|
assert agenda.category == category_a
|
||||||
|
@ -587,6 +597,7 @@ def test_add_agenda(app, user, settings):
|
||||||
'minimal_booking_delay': 1,
|
'minimal_booking_delay': 1,
|
||||||
'minimal_booking_delay_in_working_days': True,
|
'minimal_booking_delay_in_working_days': True,
|
||||||
'maximal_booking_delay': 3,
|
'maximal_booking_delay': 3,
|
||||||
|
'minimal_booking_time': None,
|
||||||
'anonymize_delay': 30,
|
'anonymize_delay': 30,
|
||||||
'edit_role': 'Edit',
|
'edit_role': 'Edit',
|
||||||
'view_role': 'View',
|
'view_role': 'View',
|
||||||
|
@ -596,13 +607,14 @@ def test_add_agenda(app, user, settings):
|
||||||
'disable_check_update': True,
|
'disable_check_update': True,
|
||||||
'booking_check_filters': 'foo,bar,baz',
|
'booking_check_filters': 'foo,bar,baz',
|
||||||
}
|
}
|
||||||
resp = app.post(api_url, params=params)
|
resp = app.post_json(api_url, params=params)
|
||||||
assert not resp.json['err']
|
assert not resp.json['err']
|
||||||
assert len(resp.json['data']) == 1
|
assert len(resp.json['data']) == 1
|
||||||
agenda = Agenda.objects.get(slug='foo-events')
|
agenda = Agenda.objects.get(slug='foo-events')
|
||||||
assert agenda.edit_role == edit_group
|
assert agenda.edit_role == edit_group
|
||||||
assert agenda.view_role == view_group
|
assert agenda.view_role == view_group
|
||||||
assert agenda.min_booking_datetime.date() == datetime.date(2021, 7, 12)
|
assert agenda.min_booking_datetime == localtime(now()).replace(day=12)
|
||||||
|
assert agenda.minimal_booking_time is None
|
||||||
assert agenda.category == category_a
|
assert agenda.category == category_a
|
||||||
assert agenda.events_type == events_type
|
assert agenda.events_type == events_type
|
||||||
assert agenda.mark_event_checked_auto is False
|
assert agenda.mark_event_checked_auto is False
|
||||||
|
|
|
@ -36,7 +36,7 @@ from chrono.agendas.models import (
|
||||||
UnavailabilityCalendar,
|
UnavailabilityCalendar,
|
||||||
VirtualMember,
|
VirtualMember,
|
||||||
)
|
)
|
||||||
from chrono.utils.timezone import localtime, make_aware, now
|
from chrono.utils.timezone import localtime, make_aware, make_naive, now
|
||||||
|
|
||||||
pytestmark = pytest.mark.django_db
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
@ -268,6 +268,158 @@ def test_agenda_maximal_booking_delay(freezer):
|
||||||
assert agenda.max_booking_datetime == make_aware(datetime.datetime(2021, 11, 2, 0, 0, 0))
|
assert agenda.max_booking_datetime == make_aware(datetime.datetime(2021, 11, 2, 0, 0, 0))
|
||||||
|
|
||||||
|
|
||||||
|
def delay_parameter_to_label(argvalue):
|
||||||
|
if isinstance(argvalue, str):
|
||||||
|
return argvalue
|
||||||
|
return repr(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)),
|
||||||
|
# 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)),
|
||||||
|
# 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)),
|
||||||
|
],
|
||||||
|
ids=delay_parameter_to_label,
|
||||||
|
)
|
||||||
|
def test_agenda_minimal_booking_delay_no_minimal_booking_time(freezer, current_time, min_booking_datetime):
|
||||||
|
freezer.move_to(current_time)
|
||||||
|
agenda = Agenda.objects.create(label='Agenda', minimal_booking_delay=4, minimal_booking_time=None)
|
||||||
|
assert make_naive(agenda.min_booking_datetime) == min_booking_datetime
|
||||||
|
|
||||||
|
|
||||||
|
@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)),
|
||||||
|
# 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)),
|
||||||
|
# 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)),
|
||||||
|
],
|
||||||
|
ids=delay_parameter_to_label,
|
||||||
|
)
|
||||||
|
def test_agenda_minimal_booking_delay_in_working_days_no_minimal_booking_time(
|
||||||
|
settings, freezer, current_time, min_booking_datetime
|
||||||
|
):
|
||||||
|
settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
|
||||||
|
freezer.move_to(current_time)
|
||||||
|
agenda = Agenda.objects.create(
|
||||||
|
label='Agenda',
|
||||||
|
minimal_booking_delay=4,
|
||||||
|
minimal_booking_time=None,
|
||||||
|
minimal_booking_delay_in_working_days=True,
|
||||||
|
)
|
||||||
|
assert make_naive(agenda.min_booking_datetime) == min_booking_datetime
|
||||||
|
|
||||||
|
|
||||||
|
@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)),
|
||||||
|
# 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)),
|
||||||
|
# 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)),
|
||||||
|
],
|
||||||
|
ids=delay_parameter_to_label,
|
||||||
|
)
|
||||||
|
def test_agenda_minimal_booking_delay_minimal_booking_time_at_8(freezer, current_time, min_booking_datetime):
|
||||||
|
freezer.move_to(current_time)
|
||||||
|
agenda = Agenda.objects.create(
|
||||||
|
label='Agenda', minimal_booking_delay=4, minimal_booking_time=datetime.time(8)
|
||||||
|
)
|
||||||
|
assert make_naive(agenda.min_booking_datetime) == min_booking_datetime
|
||||||
|
|
||||||
|
|
||||||
|
@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)),
|
||||||
|
# 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)),
|
||||||
|
# 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)),
|
||||||
|
],
|
||||||
|
ids=delay_parameter_to_label,
|
||||||
|
)
|
||||||
|
def test_agenda_maximal_booking_delay_no_minimal_booking_time(freezer, current_time, max_booking_datetime):
|
||||||
|
freezer.move_to(current_time)
|
||||||
|
agenda = Agenda.objects.create(label='Agenda', maximal_booking_delay=4, minimal_booking_time=None)
|
||||||
|
assert make_naive(agenda.max_booking_datetime) == max_booking_datetime
|
||||||
|
|
||||||
|
|
||||||
|
@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)),
|
||||||
|
# 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)),
|
||||||
|
# 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)),
|
||||||
|
],
|
||||||
|
ids=delay_parameter_to_label,
|
||||||
|
)
|
||||||
|
def test_agenda_maximal_booking_delay_minimal_booking_time_at_8(freezer, current_time, max_booking_datetime):
|
||||||
|
freezer.move_to(current_time)
|
||||||
|
agenda = Agenda.objects.create(
|
||||||
|
label='Agenda', maximal_booking_delay=4, minimal_booking_time=datetime.time(8)
|
||||||
|
)
|
||||||
|
assert make_naive(agenda.max_booking_datetime) == max_booking_datetime
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('with_prefetch', [True, False])
|
@pytest.mark.parametrize('with_prefetch', [True, False])
|
||||||
def test_agenda_is_available_for_simple_management(settings, with_prefetch):
|
def test_agenda_is_available_for_simple_management(settings, with_prefetch):
|
||||||
settings.EXCEPTIONS_SOURCES = {
|
settings.EXCEPTIONS_SOURCES = {
|
||||||
|
|
Loading…
Reference in New Issue