Projet

Général

Profil

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

Emmanuel Cazenave, 05 novembre 2020 12:01

Télécharger (7,99 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    | 62 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 92 insertions(+), 4 deletions(-)
chrono/agendas/models.py
1609 1609

  
1610 1610
        return exc_repr
1611 1611

  
1612
    def has_booking_within_time_slot(self):
1612
    def has_booking_within_time_slot(self, target_desk=None):
1613 1613
        if not (self.start_datetime and self.end_datetime):
1614 1614
            # incomplete time period, can't tell
1615 1615
            return False
1616
        for event in Event.objects.filter(
1617
            desk=self.desk, booking__isnull=False, booking__cancellation_datetime__isnull=True
1618
        ):
1616

  
1617
        query = Event.objects
1618
        if self.desk:
1619
            query = query.filter(desk=self.desk)
1620
        elif self.unavailability_calendar and not target_desk:
1621
            query = query.filter(desk__in=self.unavailability_calendar.desks.all())
1622
        elif target_desk:
1623
            query = query.filter(desk=target_desk)
1624
        else:
1625
            # orphan exception
1626
            return False
1627

  
1628
        for event in query.filter(booking__isnull=False, booking__cancellation_datetime__isnull=True,):
1619 1629
            if self.start_datetime <= event.start_datetime < self.end_datetime:
1620 1630
                return True
1621 1631
            if event.meeting_type:
chrono/manager/views.py
1645 1645

  
1646 1646
    def get(self, request, *args, **kwargs):
1647 1647
        unavailability_calendar = self.get_object()
1648
        activate = False
1648 1649
        try:
1649 1650
            self.desk.unavailability_calendars.get(pk=unavailability_calendar.pk)
1650 1651
            self.desk.unavailability_calendars.remove(unavailability_calendar)
......
1653 1654
            )
1654 1655

  
1655 1656
        except UnavailabilityCalendar.DoesNotExist:
1657
            activate = True
1656 1658
            self.desk.unavailability_calendars.add(unavailability_calendar)
1657 1659
            message = _(
1658 1660
                'Unavailability calendar %(unavailability_calendar)s has been enabled on desk %(desk)s.'
......
1660 1662
        messages.info(
1661 1663
            self.request, message % {'unavailability_calendar': unavailability_calendar, 'desk': self.desk}
1662 1664
        )
1665
        if activate:
1666
            for exception in unavailability_calendar.timeperiodexception_set.all():
1667
                if exception.has_booking_within_time_slot(target_desk=self.desk):
1668
                    message = _('One or several bookings overlap with exceptions.')
1669
                    messages.warning(self.request, message)
1670
                    break
1671

  
1663 1672
        return HttpResponseRedirect(
1664 1673
            reverse('chrono-manager-agenda-settings', kwargs={'pk': self.desk.agenda_id})
1665 1674
        )
......
2385 2394
        )
2386 2395
        return context
2387 2396

  
2397
    def form_valid(self, form):
2398
        result = super().form_valid(form)
2399
        messages.info(self.request, _('Unavailability added.'))
2400
        if self.object.has_booking_within_time_slot():
2401
            messages.warning(self.request, _('One or several bookings exists within this time slot.'))
2402
        return result
2403

  
2388 2404

  
2389 2405
unavailability_calendar_add_unavailability = UnavailabilityCalendarAddUnavailabilityView.as_view()
2390 2406

  
tests/test_manager.py
4720 4720
    resp.form['end_datetime_1'] = '16:00'
4721 4721
    resp = resp.form.submit().follow()
4722 4722
    assert 'Exception 1' in resp.text
4723
    assert 'Unavailability added.' in resp.text
4724
    assert 'One or several bookings exists within this time slot.' not in resp.text
4725
    assert TimePeriodException.objects.count() == 1
4723 4726

  
4724 4727
    time_period_exception = TimePeriodException.objects.first()
4725 4728
    assert time_period_exception.unavailability_calendar == unavailability_calendar
4726 4729
    assert time_period_exception.desk is None
4727 4730
    assert time_period_exception.label == 'Exception 1'
4728 4731

  
4732
    # info message if new exception overlaps with a booking
4733
    agenda = Agenda.objects.create(label='Agenda')
4734
    desk = Desk.objects.create(label='Desk', agenda=agenda)
4735
    unavailability_calendar.desks.add(desk)
4736
    meeting_type = MeetingType.objects.create(label='Meeting Type', agenda=agenda)
4737
    event = Event.objects.create(
4738
        agenda=agenda,
4739
        places=1,
4740
        desk=desk,
4741
        meeting_type=meeting_type,
4742
        start_datetime=tomorrow.replace(hour=10, minute=30, second=0),
4743
    )
4744
    Booking.objects.create(event=event)
4745
    resp = app.get('/manage/unavailability-calendar/%s/settings' % unavailability_calendar.pk)
4746
    resp = resp.click('Add Unavailability')
4747
    resp.form['label'] = 'Exception 2'
4748
    resp.form['start_datetime_0'] = tomorrow.strftime('%Y-%m-%d')
4749
    resp.form['start_datetime_1'] = '08:00'
4750
    resp.form['end_datetime_0'] = tomorrow.strftime('%Y-%m-%d')
4751
    resp.form['end_datetime_1'] = '16:00'
4752
    resp = resp.form.submit().follow()
4753
    assert TimePeriodException.objects.count() == 2
4754
    assert 'Exception 2' in resp.text
4755
    assert 'Unavailability added.' in resp.text
4756
    assert 'One or several bookings exists within this time slot.' in resp.text
4757

  
4729 4758

  
4730 4759
def test_unavailability_calendar_edit_time_period_exeptions(app, admin_user):
4731 4760
    unavailability_calendar = UnavailabilityCalendar.objects.create(label='Foo')
......
4786 4815
        href='/manage/desk/%s/unavailability-calendar/%s/toggle/' % (desk.pk, unavailability_calendar.pk)
4787 4816
    )
4788 4817
    assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.pk)
4818
    resp = resp.follow()
4819
    assert 'One or several bookings overlap with exceptions.' not in resp.text
4820

  
4789 4821
    resp = app.get(exceptions_url)
4790 4822
    assert 'calendar' in resp.text
4791 4823
    assert 'disable' in resp.text
4792 4824
    assert desk.unavailability_calendars.get(pk=unavailability_calendar.pk)
4793 4825

  
4826
    # reset
4827
    unavailability_calendar.desks.remove(desk)
4828

  
4829
    # info message if some exceptions overlaps with a booking
4830
    today = datetime.datetime.today().replace(hour=0, minute=0, second=0, microsecond=0)
4831
    tomorrow = make_aware(today + datetime.timedelta(days=1))
4832
    TimePeriodException.objects.create(
4833
        start_datetime=tomorrow,
4834
        end_datetime=tomorrow.replace(hour=15, minute=30, second=0),
4835
        unavailability_calendar=unavailability_calendar,
4836
    )
4837
    meeting_type = MeetingType.objects.create(label='Meeting Type', agenda=agenda)
4838
    event = Event.objects.create(
4839
        agenda=agenda,
4840
        places=1,
4841
        desk=desk,
4842
        meeting_type=meeting_type,
4843
        start_datetime=tomorrow.replace(hour=10, minute=30, second=0),
4844
    )
4845
    Booking.objects.create(event=event)
4846
    resp = app.get(exceptions_url)
4847
    assert 'calendar' in resp.text
4848
    assert 'enable' in resp.text
4849
    resp = resp.click(
4850
        href='/manage/desk/%s/unavailability-calendar/%s/toggle/' % (desk.pk, unavailability_calendar.pk)
4851
    )
4852
    assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.pk)
4853
    resp = resp.follow()
4854
    assert 'One or several bookings overlap with exceptions.' in resp.text
4855

  
4794 4856

  
4795 4857
def test_deactivate_unavailability_calendar_in_desk(app, admin_user):
4796 4858
    app = login(app)
4797
-