From 21c0d0da1fd2e5452aa26b11f423aa642b7894b4 Mon Sep 17 00:00:00 2001 From: Valentin Deniaud Date: Wed, 31 May 2023 10:16:46 +0200 Subject: [PATCH] manager: configure partial bookings agenda (#78056) --- chrono/manager/forms.py | 29 +++++++++++++ chrono/settings.py | 1 + tests/manager/test_partial_bookings.py | 56 ++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 tests/manager/test_partial_bookings.py diff --git a/chrono/manager/forms.py b/chrono/manager/forms.py index 340f1156..f65c3212 100644 --- a/chrono/manager/forms.py +++ b/chrono/manager/forms.py @@ -79,10 +79,21 @@ class AgendaAddForm(forms.ModelForm): edit_role = forms.ModelChoiceField(label=_('Edit Role'), required=False, queryset=get_role_queryset()) view_role = forms.ModelChoiceField(label=_('View Role'), required=False, queryset=get_role_queryset()) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + if settings.PARTIAL_BOOKINGS_ENABLED: + self.fields['kind'].choices += [('partial-bookings', _('Partial bookings'))] + class Meta: model = Agenda fields = ['label', 'kind', 'category', 'edit_role', 'view_role'] + def clean(self): + super().clean() + if self.cleaned_data.get('kind') == 'partial-bookings': + self.cleaned_data['kind'] = 'events' + self.instance.partial_bookings = True + def save(self, *args, **kwargs): create = self.instance.pk is None super().save() @@ -187,6 +198,7 @@ class NewEventForm(forms.ModelForm): fields = [ 'label', 'start_datetime', + 'end_time', 'frequency', 'recurrence_days', 'recurrence_week_interval', @@ -199,14 +211,26 @@ class NewEventForm(forms.ModelForm): } widgets = { 'recurrence_end_date': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'), + 'end_time': widgets.TimeWidget, } + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + if self.instance.agenda.partial_bookings: + del self.fields['duration'] + else: + del self.fields['end_time'] + def clean(self): super().clean() if self.cleaned_data.get('frequency') == 'unique': self.cleaned_data['recurrence_days'] = None self.cleaned_data['recurrence_end_date'] = None + end_time = self.cleaned_data.get('end_time') + if end_time and self.cleaned_data['start_datetime'].time() > end_time: + self.add_error('end_time', _('End time must be greater than start time.')) + def clean_start_datetime(self): start_datetime = self.cleaned_data['start_datetime'] if start_datetime.year < 2000: @@ -242,6 +266,7 @@ class EventForm(NewEventForm): protected_fields = ( 'slug', 'start_datetime', + 'end_time', 'frequency', 'recurrence_days', 'recurrence_week_interval', @@ -251,11 +276,13 @@ class EventForm(NewEventForm): model = Event widgets = { 'recurrence_end_date': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'), + 'end_time': widgets.TimeWidget, } fields = [ 'label', 'slug', 'start_datetime', + 'end_time', 'frequency', 'recurrence_days', 'recurrence_week_interval', @@ -284,6 +311,8 @@ class EventForm(NewEventForm): ) if self.instance.recurrence_days and self.instance.has_recurrences_booked(): for field in self.protected_fields: + if field not in self.fields: + continue self.fields[field].disabled = True self.fields[field].help_text = _( 'This field cannot be modified because some recurrences have bookings attached to them.' diff --git a/chrono/settings.py b/chrono/settings.py index 1196db5b..7aa8eab0 100644 --- a/chrono/settings.py +++ b/chrono/settings.py @@ -199,6 +199,7 @@ REST_FRAMEWORK = {'EXCEPTION_HANDLER': 'chrono.api.utils.exception_handler'} SHARED_CUSTODY_ENABLED = False LEGACY_FILLSLOTS_ENABLED = False +PARTIAL_BOOKINGS_ENABLED = False local_settings_file = os.environ.get( 'CHRONO_SETTINGS_FILE', os.path.join(os.path.dirname(__file__), 'local_settings.py') diff --git a/tests/manager/test_partial_bookings.py b/tests/manager/test_partial_bookings.py new file mode 100644 index 00000000..e0aa4795 --- /dev/null +++ b/tests/manager/test_partial_bookings.py @@ -0,0 +1,56 @@ +import datetime + +import pytest + +from chrono.agendas.models import Agenda, Booking, Event +from tests.utils import login + +pytestmark = pytest.mark.django_db + + +def test_manager_partial_bookings_add_agenda(app, admin_user, settings): + app = login(app) + resp = app.get('/manage/agendas/add/') + assert 'partial-bookings' not in resp.text + + settings.PARTIAL_BOOKINGS_ENABLED = True + + resp = app.get('/manage/agendas/add/') + resp.form['label'] = 'Foo bar' + resp.form['kind'] = 'partial-bookings' + resp = resp.form.submit().follow() + + agenda = Agenda.objects.get(label='Foo bar') + assert agenda.kind == 'events' + assert agenda.partial_bookings is True + + +def test_manager_partial_bookings_add_event(app, admin_user): + agenda = Agenda.objects.create(label='Foo bar', kind='events', partial_bookings=True) + + app = login(app) + resp = app.get('/manage/agendas/%s/settings' % agenda.pk) + resp = resp.click('New Event') + assert 'duration' not in resp.form.fields + + resp.form['start_datetime_0'] = '2023-02-15' + resp.form['start_datetime_1'] = '08:00' + resp.form['end_time'] = '18:00' + resp.form['places'] = 10 + resp = resp.form.submit().follow() + + event = Event.objects.get() + assert event.end_time == datetime.time(18, 00) + assert event.duration is None + + resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.pk, event.pk)) + assert 'duration' not in resp.form.fields + assert resp.form['end_time'].value == '18:00' + + resp.form['end_time'] = '08:01' + resp = resp.form.submit().follow() + + resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.pk, event.pk)) + resp.form['end_time'] = '07:59' + resp = resp.form.submit() + assert 'End time must be greater than start time.' in resp.text