Projet

Général

Profil

0001-manager-warn-about-overlapping-of-unavailability_cal.patch

Emmanuel Cazenave, 18 novembre 2020 14:37

Télécharger (11,1 ko)

Voir les différences:

Subject: [PATCH 1/2] manager: warn about overlapping of
 unavailability_calendar over booking (#47393)

 chrono/agendas/models.py |  18 +++++--
 chrono/manager/views.py  |  16 ++++++
 tests/test_manager.py    | 110 +++++++++++++++++++++++++++++++++------
 3 files changed, 125 insertions(+), 19 deletions(-)
chrono/agendas/models.py
1650 1650

  
1651 1651
        return exc_repr
1652 1652

  
1653
    def has_booking_within_time_slot(self):
1653
    def has_booking_within_time_slot(self, target_desk=None):
1654 1654
        if not (self.start_datetime and self.end_datetime):
1655 1655
            # incomplete time period, can't tell
1656 1656
            return False
1657
        for event in Event.objects.filter(
1658
            desk=self.desk, booking__isnull=False, booking__cancellation_datetime__isnull=True
1659
        ):
1657

  
1658
        query = Event.objects
1659
        if self.desk:
1660
            query = query.filter(desk=self.desk)
1661
        elif self.unavailability_calendar and not target_desk:
1662
            query = query.filter(desk__in=self.unavailability_calendar.desks.all())
1663
        elif target_desk:
1664
            query = query.filter(desk=target_desk)
1665
        else:
1666
            # orphan exception
1667
            return False
1668

  
1669
        for event in query.filter(booking__isnull=False, booking__cancellation_datetime__isnull=True,):
1660 1670
            if self.start_datetime <= event.start_datetime < self.end_datetime:
1661 1671
                return True
1662 1672
            if event.meeting_type:
chrono/manager/views.py
1691 1691

  
1692 1692
    def get(self, request, *args, **kwargs):
1693 1693
        unavailability_calendar = self.get_object()
1694
        activate = False
1694 1695
        try:
1695 1696
            self.desk.unavailability_calendars.get(pk=unavailability_calendar.pk)
1696 1697
            self.desk.unavailability_calendars.remove(unavailability_calendar)
......
1699 1700
            )
1700 1701

  
1701 1702
        except UnavailabilityCalendar.DoesNotExist:
1703
            activate = True
1702 1704
            self.desk.unavailability_calendars.add(unavailability_calendar)
1703 1705
            message = _(
1704 1706
                'Unavailability calendar %(unavailability_calendar)s has been enabled on desk %(desk)s.'
......
1706 1708
        messages.info(
1707 1709
            self.request, message % {'unavailability_calendar': unavailability_calendar, 'desk': self.desk}
1708 1710
        )
1711
        if activate:
1712
            for exception in unavailability_calendar.timeperiodexception_set.all():
1713
                if exception.has_booking_within_time_slot(target_desk=self.desk):
1714
                    message = _('One or several bookings overlap with exceptions.')
1715
                    messages.warning(self.request, message)
1716
                    break
1717

  
1709 1718
        return HttpResponseRedirect(
1710 1719
            reverse('chrono-manager-agenda-settings', kwargs={'pk': self.desk.agenda_id})
1711 1720
        )
......
2460 2469
        )
2461 2470
        return context
2462 2471

  
2472
    def form_valid(self, form):
2473
        result = super().form_valid(form)
2474
        messages.info(self.request, _('Unavailability added.'))
2475
        if self.object.has_booking_within_time_slot():
2476
            messages.warning(self.request, _('One or several bookings exists within this time slot.'))
2477
        return result
2478

  
2463 2479

  
2464 2480
unavailability_calendar_add_unavailability = UnavailabilityCalendarAddUnavailabilityView.as_view()
2465 2481

  
tests/test_manager.py
2231 2231
def test_meetings_agenda_edit_time_period_exception(app, admin_user):
2232 2232
    agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
2233 2233
    desk = Desk.objects.create(agenda=agenda, label='Desk A')
2234
    time_period_exception = TimePeriodException.objects.create(
2234
    calendar = UnavailabilityCalendar.objects.create(label='foo')
2235
    calendar.desks.add(desk)
2236
    time_period_exception_desk = TimePeriodException.objects.create(
2235 2237
        label='Exception',
2236 2238
        desk=desk,
2237 2239
        start_datetime=make_aware(datetime.datetime(2018, 12, 16, 5, 0)),
2238 2240
        end_datetime=make_aware(datetime.datetime(2018, 12, 16, 23, 0)),
2239 2241
    )
2240
    event = Event.objects.create(
2241
        agenda=agenda, places=1, desk=desk, start_datetime=make_aware(datetime.datetime(2018, 12, 16, 10, 30))
2242
    time_period_exception_calendar = TimePeriodException.objects.create(
2243
        label='Exception',
2244
        unavailability_calendar=calendar,
2245
        start_datetime=make_aware(datetime.datetime(2018, 12, 16, 5, 0)),
2246
        end_datetime=make_aware(datetime.datetime(2018, 12, 16, 23, 0)),
2242 2247
    )
2248
    for time_period_exception in (time_period_exception_desk, time_period_exception_calendar):
2249
        event = Event.objects.create(
2250
            agenda=agenda,
2251
            places=1,
2252
            desk=desk,
2253
            start_datetime=make_aware(datetime.datetime(2018, 12, 16, 10, 30)),
2254
        )
2243 2255

  
2244
    login(app)
2245
    resp = app.get('/manage/time-period-exceptions/%s/edit' % time_period_exception.pk)
2246
    resp = resp.form.submit().follow()
2247
    assert 'Exception updated. Note: one or several bookings exists within this time slot.' not in resp.text
2256
        login(app)
2257
        resp = app.get('/manage/time-period-exceptions/%s/edit' % time_period_exception.pk)
2258
        resp = resp.form.submit().follow()
2259
        assert (
2260
            'Exception updated. Note: one or several bookings exists within this time slot.' not in resp.text
2261
        )
2248 2262

  
2249
    booking = Booking.objects.create(event=event)
2250
    resp = app.get('/manage/time-period-exceptions/%s/edit' % time_period_exception.pk)
2251
    resp = resp.form.submit().follow()
2252
    assert 'Exception updated. Note: one or several bookings exists within this time slot.' in resp.text
2263
        booking = Booking.objects.create(event=event)
2264
        resp = app.get('/manage/time-period-exceptions/%s/edit' % time_period_exception.pk)
2265
        resp = resp.form.submit().follow()
2266
        assert 'Exception updated. Note: one or several bookings exists within this time slot.' in resp.text
2253 2267

  
2254
    booking.cancel()
2255
    resp = app.get('/manage/time-period-exceptions/%s/edit' % time_period_exception.pk)
2256
    resp = resp.form.submit().follow()
2257
    assert 'Exception updated. Note: one or several bookings exists within this time slot.' not in resp.text
2268
        booking.cancel()
2269
        resp = app.get('/manage/time-period-exceptions/%s/edit' % time_period_exception.pk)
2270
        resp = resp.form.submit().follow()
2271
        assert (
2272
            'Exception updated. Note: one or several bookings exists within this time slot.' not in resp.text
2273
        )
2274

  
2275
        booking.delete()
2276
        event.delete()
2258 2277

  
2259 2278

  
2260 2279
def test_meetings_agenda_add_invalid_time_period_exception():
......
4835 4854
    resp.form['end_datetime_1'] = '16:00'
4836 4855
    resp = resp.form.submit().follow()
4837 4856
    assert 'Exception 1' in resp.text
4857
    assert 'Unavailability added.' in resp.text
4858
    assert 'One or several bookings exists within this time slot.' not in resp.text
4859
    assert TimePeriodException.objects.count() == 1
4838 4860

  
4839 4861
    time_period_exception = TimePeriodException.objects.first()
4840 4862
    assert time_period_exception.unavailability_calendar == unavailability_calendar
4841 4863
    assert time_period_exception.desk is None
4842 4864
    assert time_period_exception.label == 'Exception 1'
4843 4865

  
4866
    # info message if new exception overlaps with a booking
4867
    agenda = Agenda.objects.create(label='Agenda')
4868
    desk = Desk.objects.create(label='Desk', agenda=agenda)
4869
    unavailability_calendar.desks.add(desk)
4870
    meeting_type = MeetingType.objects.create(label='Meeting Type', agenda=agenda)
4871
    event = Event.objects.create(
4872
        agenda=agenda,
4873
        places=1,
4874
        desk=desk,
4875
        meeting_type=meeting_type,
4876
        start_datetime=tomorrow.replace(hour=10, minute=30, second=0),
4877
    )
4878
    Booking.objects.create(event=event)
4879
    resp = app.get('/manage/unavailability-calendar/%s/settings' % unavailability_calendar.pk)
4880
    resp = resp.click('Add Unavailability')
4881
    resp.form['label'] = 'Exception 2'
4882
    resp.form['start_datetime_0'] = tomorrow.strftime('%Y-%m-%d')
4883
    resp.form['start_datetime_1'] = '08:00'
4884
    resp.form['end_datetime_0'] = tomorrow.strftime('%Y-%m-%d')
4885
    resp.form['end_datetime_1'] = '16:00'
4886
    resp = resp.form.submit().follow()
4887
    assert TimePeriodException.objects.count() == 2
4888
    assert 'Exception 2' in resp.text
4889
    assert 'Unavailability added.' in resp.text
4890
    assert 'One or several bookings exists within this time slot.' in resp.text
4891

  
4844 4892

  
4845 4893
def test_unavailability_calendar_edit_time_period_exeptions(app, admin_user):
4846 4894
    unavailability_calendar = UnavailabilityCalendar.objects.create(label='Foo')
......
4912 4960
    # exception from calendar displayed on the settigns page
4913 4961
    resp = app.get(settings_url)
4914 4962
    assert 'what' in resp.text
4963
    assert 'One or several bookings overlap with exceptions.' not in resp.text
4964

  
4915 4965
    resp = app.get(exceptions_url)
4916 4966
    assert 'calendar' in resp.text
4917 4967
    assert 'disable' in resp.text
4918 4968
    assert desk.unavailability_calendars.get(pk=unavailability_calendar.pk)
4919 4969

  
4970
    # reset
4971
    unavailability_calendar.desks.remove(desk)
4972

  
4973
    # info message if some exceptions overlaps with a booking
4974
    today = datetime.datetime.today().replace(hour=0, minute=0, second=0, microsecond=0)
4975
    tomorrow = make_aware(today + datetime.timedelta(days=1))
4976
    TimePeriodException.objects.create(
4977
        start_datetime=tomorrow,
4978
        end_datetime=tomorrow.replace(hour=15, minute=30, second=0),
4979
        unavailability_calendar=unavailability_calendar,
4980
    )
4981
    meeting_type = MeetingType.objects.create(label='Meeting Type', agenda=agenda)
4982
    event = Event.objects.create(
4983
        agenda=agenda,
4984
        places=1,
4985
        desk=desk,
4986
        meeting_type=meeting_type,
4987
        start_datetime=tomorrow.replace(hour=10, minute=30, second=0),
4988
    )
4989
    Booking.objects.create(event=event)
4990
    resp = app.get(exceptions_url)
4991
    assert 'calendar' in resp.text
4992
    assert 'enable' in resp.text
4993
    resp = resp.click(
4994
        href='/manage/desk/%s/unavailability-calendar/%s/toggle/' % (desk.pk, unavailability_calendar.pk)
4995
    )
4996
    assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.pk)
4997
    resp = resp.follow()
4998
    assert 'One or several bookings overlap with exceptions.' in resp.text
4999

  
4920 5000

  
4921 5001
def test_deactivate_unavailability_calendar_in_desk(app, admin_user):
4922 5002
    app = login(app)
4923
-