0001-manager-warn-about-overlapping-of-unavailability_cal.patch
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 |
- |