From 9aa099a9f1c4a701f39e0dc620609c00e6462f60 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Fri, 28 Aug 2020 17:35:36 +0200
Subject: [PATCH] manager: add exception on all desks (#42411)

---
 chrono/manager/forms.py |  9 +++++++++
 chrono/manager/views.py | 25 ++++++++++++++++++++++---
 tests/test_manager.py   | 28 ++++++++++++++++++++++++++++
 3 files changed, 59 insertions(+), 3 deletions(-)

diff --git a/chrono/manager/forms.py b/chrono/manager/forms.py
index 90bf36a..749f366 100644
--- a/chrono/manager/forms.py
+++ b/chrono/manager/forms.py
@@ -280,6 +280,8 @@ class DeskForm(forms.ModelForm):
 
 
 class TimePeriodExceptionForm(forms.ModelForm):
+    all_desks = forms.BooleanField(label=_('Apply exception on all desks of the agenda'), required=False)
+
     class Meta:
         model = TimePeriodException
         fields = ['desk', 'start_datetime', 'end_datetime', 'label']
@@ -291,6 +293,13 @@ class TimePeriodExceptionForm(forms.ModelForm):
             'end_datetime': SplitDateTimeField,
         }
 
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        if self.instance.pk is not None:
+            del self.fields['all_desks']
+        elif 'desk' in self.initial and self.initial['desk'].agenda.desk_set.count() == 1:
+            del self.fields['all_desks']
+
     def clean(self):
         cleaned_data = super().clean()
 
diff --git a/chrono/manager/views.py b/chrono/manager/views.py
index 96ba849..636fe69 100644
--- a/chrono/manager/views.py
+++ b/chrono/manager/views.py
@@ -1741,9 +1741,28 @@ class AgendaAddTimePeriodExceptionView(ManagedDeskMixin, CreateView):
 
     def form_valid(self, form):
         result = super().form_valid(form)
-        if self.object.has_booking_within_time_slot():
-            message = _('Exception added. Note: one or several bookings exists within this time slot.')
-            messages.info(self.request, message)
+        exceptions = [self.object]
+        if form.cleaned_data.get('all_desks'):
+            for desk in Desk.objects.filter(agenda=self.object.desk.agenda_id):
+                if desk == self.object.desk:
+                    continue
+                exceptions.append(
+                    TimePeriodException.objects.create(
+                        desk=desk,
+                        label=self.object.label,
+                        start_datetime=self.object.start_datetime,
+                        end_datetime=self.object.end_datetime,
+                    )
+                )
+        for exception in exceptions:
+            if exception.has_booking_within_time_slot():
+                message = ungettext(
+                    'Exception added. Note: one or several bookings exists within this time slot.',
+                    'Exceptions added. Note: one or several bookings exists within this time slot.',
+                    len(exceptions),
+                )
+                messages.info(self.request, message)
+                break
         return result
 
 
diff --git a/tests/test_manager.py b/tests/test_manager.py
index 6b3f2ca..cf87136 100644
--- a/tests/test_manager.py
+++ b/tests/test_manager.py
@@ -1933,6 +1933,34 @@ def test_meetings_agenda_add_time_period_exception(app, admin_user):
     assert 'Exception 1' in resp.text
     assert 'Exception 2' in resp.text
 
+    # add global time exception
+    # only one desk: no option to apply to all desks
+    resp = app.get('/manage/agendas/%s/desk/%s/add-time-period-exception' % (agenda.pk, desk.pk))
+    assert 'all_desks' not in resp.context['form'].fields
+    # more than one desk
+    agenda2 = Agenda.objects.create(label='Foo bar', kind='meetings')
+    Desk.objects.create(agenda=agenda2, label='Other Desk')  # check exception is not created for this one
+    desk2 = Desk.objects.create(agenda=agenda, label='Desk B')
+    event = Event.objects.create(
+        agenda=agenda, places=1, desk=desk2, start_datetime=make_aware(datetime.datetime(2017, 5, 22, 10, 30))
+    )
+    Booking.objects.create(event=event)
+    resp = app.get('/manage/agendas/%s/desk/%s/add-time-period-exception' % (agenda.pk, desk.pk))
+    future = tomorrow + datetime.timedelta(days=35)
+    resp.form['label'] = 'Exception 3'
+    resp.form['start_datetime_0'] = '2017-05-22'
+    resp.form['start_datetime_1'] = '08:00'
+    resp.form['end_datetime_0'] = '2017-05-26'
+    resp.form['end_datetime_1'] = '17:30'
+    resp.form['all_desks'] = True
+    resp = resp.form.submit().follow()
+    assert TimePeriodException.objects.count() == 4
+    assert 'Exceptions added. Note: one or several bookings exists within this time slot.' in resp.text
+
+    exception = TimePeriodException.objects.first()
+    resp = app.get('/manage/time-period-exceptions/%s/edit' % exception.pk)
+    assert 'all_desks' not in resp.context['form'].fields
+
 
 def test_meetings_agenda_add_time_period_exception_when_booking_exists(app, admin_user):
     agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
-- 
2.28.0

