api: allow partial booking in recurring events fillslots (#78056)
This commit is contained in:
parent
1b9bd2f428
commit
2a776007e0
|
@ -188,6 +188,18 @@ class RecurringFillslotsSerializer(MultipleAgendasEventsFillSlotsSerializer):
|
|||
check_overlaps = CommaSeparatedStringField(
|
||||
required=False, child=serializers.SlugField(max_length=160, allow_blank=False)
|
||||
)
|
||||
start_time = serializers.TimeField(required=False)
|
||||
end_time = serializers.TimeField(required=False)
|
||||
|
||||
def validate(self, attrs):
|
||||
super().validate(attrs)
|
||||
use_partial_bookings = any(agenda.partial_bookings for agenda in self.context['agendas'])
|
||||
if use_partial_bookings:
|
||||
if not attrs.get('start_time') or not attrs.get('end_time'):
|
||||
raise ValidationError(_('must include start_time and end_time for partial bookings agenda'))
|
||||
if attrs['start_time'] > attrs['end_time']:
|
||||
raise ValidationError(_('start_time must be before end_time'))
|
||||
return attrs
|
||||
|
||||
def validate_slots(self, value):
|
||||
super().validate_slots(value)
|
||||
|
@ -401,6 +413,14 @@ class AgendaOrSubscribedSlugsMixin(AgendaSlugsMixin):
|
|||
attrs['agenda_slugs'] = [agenda.slug for agenda in agendas]
|
||||
else:
|
||||
attrs['agenda_slugs'] = self.agenda_slugs
|
||||
|
||||
if any(
|
||||
agenda.partial_bookings != attrs['agendas'][0].partial_bookings for agenda in attrs['agendas']
|
||||
):
|
||||
raise serializers.ValidationError(
|
||||
{'agendas': _('Cannot mix partial bookings agendas with other kinds.')}
|
||||
)
|
||||
|
||||
return attrs
|
||||
|
||||
def validate_agendas(self, value):
|
||||
|
|
|
@ -461,6 +461,8 @@ def make_booking(event, payload, extra_data, primary_booking=None, in_waiting_li
|
|||
user_display_label=payload.get('user_display_label', ''),
|
||||
extra_emails=payload.get('extra_emails', []),
|
||||
extra_phone_numbers=payload.get('extra_phone_numbers', []),
|
||||
start_time=payload.get('start_time'),
|
||||
end_time=payload.get('end_time'),
|
||||
extra_data=extra_data,
|
||||
color=color,
|
||||
)
|
||||
|
|
|
@ -16,7 +16,7 @@ from chrono.agendas.models import (
|
|||
SharedCustodyRule,
|
||||
Subscription,
|
||||
)
|
||||
from chrono.utils.timezone import now
|
||||
from chrono.utils.timezone import make_aware, now
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
@ -1609,7 +1609,7 @@ def test_recurring_events_api_fillslots_overlapping_events(app, user):
|
|||
|
||||
|
||||
@pytest.mark.freeze_time('2021-09-06 12:00')
|
||||
def test_recurring_events_api_fillslots_overlapping_events_partial_booking(app, user):
|
||||
def test_recurring_events_api_fillslots_partly_overlapping_events(app, user):
|
||||
agenda = Agenda.objects.create(label='First Agenda', kind='events')
|
||||
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
||||
start, end = now(), now() + datetime.timedelta(days=30)
|
||||
|
@ -1677,3 +1677,63 @@ def test_recurring_events_api_fillslots_overlapping_events_partial_booking(app,
|
|||
'2021-09-28',
|
||||
'2021-10-05',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2023-05-01 10:00')
|
||||
def test_recurring_events_api_fillslots_partial_bookings(app, user):
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events', partial_bookings=True)
|
||||
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
||||
start_datetime = make_aware(datetime.datetime(2023, 5, 2, 8, 0))
|
||||
event = Event.objects.create(
|
||||
label='Event 08-18',
|
||||
start_datetime=start_datetime,
|
||||
end_time=datetime.time(18, 00),
|
||||
places=2,
|
||||
recurrence_end_date=start_datetime + datetime.timedelta(days=30),
|
||||
recurrence_days=[1],
|
||||
agenda=agenda,
|
||||
)
|
||||
event.create_all_recurrences()
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
|
||||
params = {
|
||||
'user_external_id': 'user_id',
|
||||
'slots': 'foo-bar@event-08-18:1',
|
||||
'start_time': '10:00',
|
||||
'end_time': '15:00',
|
||||
}
|
||||
fillslots_url = '/api/agendas/recurring-events/fillslots/?action=update&agendas=%s' % agenda.slug
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
|
||||
assert Booking.objects.count() == 5
|
||||
for booking in Booking.objects.all():
|
||||
assert booking.start_time == datetime.time(10, 00)
|
||||
assert booking.end_time == datetime.time(15, 00)
|
||||
|
||||
# mix with other kind
|
||||
other_agenda = Agenda.objects.create(label='Not partial', kind='events')
|
||||
resp = app.post_json(fillslots_url + ',%s' % other_agenda.slug, params=params, status=400)
|
||||
assert resp.json['errors']['agendas'][0] == 'Cannot mix partial bookings agendas with other kinds.'
|
||||
|
||||
# missing start_time
|
||||
del params['start_time']
|
||||
resp = app.post_json(fillslots_url, params=params, status=400)
|
||||
assert (
|
||||
resp.json['errors']['non_field_errors'][0]
|
||||
== 'must include start_time and end_time for partial bookings agenda'
|
||||
)
|
||||
|
||||
# missing end_time
|
||||
params['start_time'] = '10:00'
|
||||
del params['end_time']
|
||||
resp = app.post_json(fillslots_url, params=params, status=400)
|
||||
assert (
|
||||
resp.json['errors']['non_field_errors'][0]
|
||||
== 'must include start_time and end_time for partial bookings agenda'
|
||||
)
|
||||
|
||||
# end before start
|
||||
params['end_time'] = '09:00'
|
||||
resp = app.post_json(fillslots_url, params=params, status=400)
|
||||
assert resp.json['errors']['non_field_errors'][0] == 'start_time must be before end_time'
|
||||
|
|
Loading…
Reference in New Issue