From c6d0cd1beb4357cfe4e87fbf592882e69af62148 Mon Sep 17 00:00:00 2001 From: Josue Kouka Date: Tue, 19 Dec 2017 14:50:38 +0100 Subject: [PATCH] manager: prevent time period changes when bookings exist (#20791) --- chrono/manager/forms.py | 30 ++++++++++++++++++++++++- tests/test_manager.py | 58 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/chrono/manager/forms.py b/chrono/manager/forms.py index 00f5363..cdcf815 100644 --- a/chrono/manager/forms.py +++ b/chrono/manager/forms.py @@ -19,10 +19,11 @@ import datetime from django import forms from django.forms import ValidationError +from django.utils.timezone import localtime from django.utils.translation import ugettext_lazy as _ from chrono.agendas.models import (Event, MeetingType, TimePeriod, Desk, - TimePeriodException) + TimePeriodException, Booking) from . import widgets @@ -76,6 +77,33 @@ class TimePeriodForm(forms.ModelForm): } exclude = [] + def clean(self): + cleaned_data = super(TimePeriodForm, self).clean() + if not self.changes_ok(): + raise ValidationError(_('One or several bookings exist within this time period.')) + return cleaned_data + + def changes_ok(self): + if not hasattr(self.instance, 'desk'): + return True + has_booking = self.has_booking_within() + if self.cleaned_data['start_time'] > self.instance.start_time: + return not(has_booking) + if self.cleaned_data['end_time'] < self.instance.end_time: + return not(has_booking) + return True + + def has_booking_within(self): + bookings = Booking.objects.filter( + event__desk=self.instance.desk, cancellation_datetime__isnull=True).select_related('event') + for booking in bookings: + event_startdt = localtime(booking.event.start_datetime) + if event_startdt.weekday() != self.instance.weekday: + continue + if self.instance.start_time <= event_startdt.time() < self.instance.end_time: + return True + return False + class NewDeskForm(forms.ModelForm): class Meta: diff --git a/tests/test_manager.py b/tests/test_manager.py index 7283c4e..e69d16c 100644 --- a/tests/test_manager.py +++ b/tests/test_manager.py @@ -1127,3 +1127,61 @@ def test_agenda_import_time_period_exception_from_remote_ics_with_ssl_error(mock mocked_get.side_effect = mocked_requests_http_ssl_error resp = resp.form.submit(status=200) assert 'Failed to retrieve remote calendar (SSL error).' in resp.content + + +def test_prevent_time_period_changes_when_bookings_exist(app, admin_user): + agenda = Agenda.objects.create(label='Foo bar', kind='meetings') + desk = Desk.objects.create(agenda=agenda, label='Desk A') + MeetingType(agenda=agenda, label='Blah').save() + timeperiod = TimePeriod.objects.create( + weekday=1, desk=desk, start_time=datetime.time(8, 00), end_time=datetime.time(11, 0)) + event = Event.objects.create(agenda=agenda, places=1, desk=desk, + start_datetime=datetime.datetime(2017, 5, 23, 8, 30)) + Booking.objects.create(event=event) + login(app) + timeperiod_edit_link = "/manage/timeperiods/%d/edit" % timeperiod.pk + # extend time period start + resp = app.get('/manage/agendas/%d/' % agenda.pk) + resp = resp.click(href=timeperiod_edit_link) + resp.form['start_time'] = '7:30' + resp = resp.form.submit().follow() + assert resp.html.find('a', {'href': timeperiod_edit_link}).text.strip() == u'Tuesday / 7:30 a.m. \u2192 11 a.m.' + # shorten time period start + resp = app.get('/manage/agendas/%d/' % agenda.pk) + resp = resp.click(href=timeperiod_edit_link) + resp.form['start_time'] = '9:30' + resp = resp.form.submit() + error_message = resp.html.find('ul', {'class': 'errorlist'}).text.strip() + assert error_message == 'One or several bookings exist within this time period.' + # extend time period end + resp = app.get('/manage/agendas/%d/' % agenda.pk) + resp = resp.click(href=timeperiod_edit_link) + resp.form['end_time'] = '12:00' + resp = resp.form.submit().follow() + assert resp.html.find('a', {'href': timeperiod_edit_link}).text.strip() == u'Tuesday / 7:30 a.m. \u2192 noon' + # shorten time period end + event = Event.objects.create(agenda=agenda, places=1, desk=desk, + start_datetime=datetime.datetime(2017, 5, 23, 11, 30)) + Booking.objects.create(event=event) + resp = app.get('/manage/agendas/%d/' % agenda.pk) + resp = resp.click(href=timeperiod_edit_link) + resp.form['end_time'] = '11:00' + resp = resp.form.submit() + error_message = resp.html.find('ul', {'class': 'errorlist'}).text.strip() + assert error_message == 'One or several bookings exist within this time period.' + # extend both time period start and end + resp = app.get('/manage/agendas/%d/' % agenda.pk) + resp = resp.click(href=timeperiod_edit_link) + resp.form['start_time'] = '7:00' + resp.form['end_time'] = '12:30' + resp = resp.form.submit().follow() + assert resp.html.find('a', {'href': timeperiod_edit_link}).text.strip() == u'Tuesday / 7 a.m. \u2192 12:30 p.m.' + # shorten both time period start and end + Booking.objects.create(event=event) + resp = app.get('/manage/agendas/%d/' % agenda.pk) + resp = resp.click(href=timeperiod_edit_link) + resp.form['start_time'] = '8:00' + resp.form['end_time'] = '11:00' + resp = resp.form.submit() + error_message = resp.html.find('ul', {'class': 'errorlist'}).text.strip() + assert error_message == 'One or several bookings exist within this time period.' -- 2.11.0