Compare commits

..

2 Commits

4 changed files with 43 additions and 27 deletions

View File

@ -3181,21 +3181,6 @@ class BookingCheck(models.Model):
return False
return True
def overlaps_existing_check(self, start_time, end_time):
booking_checks = BookingCheck.objects.filter(booking=self.booking).exclude(pk=self.pk)
if not booking_checks:
return False
if len(booking_checks) > 1:
raise ValueError('too many booking checks') # should not happen
booking_check = booking_checks[0]
if not start_time or not end_time:
return bool(booking_check.start_time < (start_time or end_time) < booking_check.end_time)
return bool(start_time < booking_check.end_time and end_time > booking_check.start_time)
OpeningHour = collections.namedtuple('OpeningHour', ['begin', 'end'])

View File

@ -648,9 +648,6 @@ class PartialBookingCheckForm(forms.ModelForm):
if start_time and end_time and end_time <= start_time:
raise ValidationError(_('Arrival must be before departure.'))
if self.instance.overlaps_existing_check(start_time, end_time):
raise ValidationError(_('Booking check hours overlap existing check.'))
if self.cleaned_data['presence'] is not None:
kind = 'presence' if self.cleaned_data['presence'] else 'absence'
if f'{kind}_check_type' in self.cleaned_data:

View File

@ -4576,16 +4576,14 @@ class PartialBookingCheckView(ViewableAgendaMixin, TemplateView):
self.multiple_bookings = bool(len(self.bookings) > 1)
return super().dispatch(*args, **kwargs)
def get_context_data(self, **kwargs):
def get_context_data(self, forms=None, **kwargs):
context = super().get_context_data(**kwargs)
context['forms'] = self.get_forms()
context['forms'] = forms or self.get_forms()
context['multiple_bookings'] = self.multiple_bookings
return context
def get_forms(self):
kwargs = {
'agenda': self.agenda,
}
kwargs = {'agenda': self.agenda}
if self.request.method == 'POST':
kwargs['data'] = self.request.POST
@ -4612,7 +4610,9 @@ class PartialBookingCheckView(ViewableAgendaMixin, TemplateView):
if booking.start_time:
booking.check_forms.append(
PartialBookingCheckForm(
instance=second_check, prefix=self.get_prefix(booking, second_check=True), **kwargs
instance=second_check,
prefix=self.get_prefix(booking, second_check=True),
**kwargs,
)
)
@ -4634,13 +4634,34 @@ class PartialBookingCheckView(ViewableAgendaMixin, TemplateView):
forms = self.get_forms()
all_valid = all(form.is_valid() for form in forms)
if all_valid:
if all_valid and not self.checks_overlap(forms):
for form in forms:
form.save()
return HttpResponseRedirect(self.get_success_url())
return self.render_to_response(self.get_context_data(forms=forms))
def checks_overlap(self, forms):
Interval = collections.namedtuple('Interval', ['start', 'end', 'form'])
intervals = [
Interval(
# if check has no start/end time, take (time, time) as an interval
form.cleaned_data['start_time'] or form.cleaned_data['end_time'],
form.cleaned_data['end_time'] or form.cleaned_data['start_time'],
form,
)
for form in forms
if form.cleaned_data['presence'] is not None
]
intervals.sort(key=lambda x: x[0])
for i in range(1, len(intervals)):
if intervals[i - 1].end > intervals[i].start:
intervals[i].form.add_error(None, _('Booking check hours are overlapping.'))
return True
return False
def get_success_url(self):
date = self.event.start_datetime
return reverse(

View File

@ -531,11 +531,11 @@ def test_manager_partial_bookings_multiple_checks(app, admin_user):
resp.form['check-2-start_time'] = '11:30'
resp.form['check-2-end_time'] = ''
resp = resp.form.submit()
assert 'Booking check hours overlap existing check.' in resp.text
assert 'Booking check hours are overlapping.' in resp.text
resp.form['check-2-end_time'] = '17:30'
resp = resp.form.submit()
assert 'Booking check hours overlap existing check.' in resp.text
assert 'Booking check hours are overlapping.' in resp.text
resp.form['check-2-start_time'] = '12:30'
resp.form['check-2-presence'] = ''
@ -557,6 +557,19 @@ def test_manager_partial_bookings_multiple_checks(app, admin_user):
assert 'Arrival must be before departure.' in resp.text
assert 'gadjo-folded' not in resp.text
# overlap is detected when 2 checks are created at the same time
BookingCheck.objects.all().delete()
resp.form['presence'] = 'True'
resp.form['start_time'] = '10:00'
resp.form['end_time'] = '11:00'
resp.form['check-2-presence'] = 'False'
resp.form['check-2-start_time'] = '10:30'
resp.form['check-2-end_time'] = '11:30'
resp = resp.form.submit()
assert 'Booking check hours are overlapping.' in resp.text
def test_manager_partial_bookings_incomplete_check(app, admin_user):
agenda = Agenda.objects.create(label='Foo bar', kind='events', partial_bookings=True)