Compare commits
2 Commits
4b2d519e9a
...
4ad301264e
Author | SHA1 | Date |
---|---|---|
Valentin Deniaud | 4ad301264e | |
Valentin Deniaud | e10e0d5be0 |
|
@ -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'])
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue