general: add possibility to book multiple places at once (#15218)

This commit is contained in:
Frédéric Péters 2017-06-11 12:42:10 +02:00
parent 2907e4bb90
commit ffcda3904a
4 changed files with 86 additions and 6 deletions

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('agendas', '0013_auto_20161028_1603'),
]
operations = [
migrations.AddField(
model_name='booking',
name='primary_booking',
field=models.ForeignKey(related_name='secondary_booking_set', to='agendas.Booking', null=True),
),
]

View File

@ -310,6 +310,9 @@ class Booking(models.Model):
cancellation_datetime = models.DateTimeField(null=True)
in_waiting_list = models.BooleanField(default=False)
creation_datetime = models.DateTimeField(auto_now_add=True)
# primary booking is used to group multiple bookings together
primary_booking = models.ForeignKey('self', null=True,
on_delete=models.CASCADE, related_name='secondary_booking_set')
def save(self, *args, **kwargs):
with transaction.atomic():
@ -320,9 +323,14 @@ class Booking(models.Model):
self.event.save()
def cancel(self):
self.cancellation_datetime = now()
self.save()
timestamp = now()
with transaction.atomic():
self.secondary_booking_set.update(cancellation_datetime=timestamp)
self.cancellation_datetime = timestamp
self.save()
def accept(self):
self.in_waiting_list = False
self.save()
with transaction.atomic():
self.secondary_booking_set.update(in_waiting_list=False)
self.save()

View File

@ -214,6 +214,11 @@ class Fillslot(GenericAPIView):
except (ValueError, Agenda.DoesNotExist):
raise Http404()
if 'count' in request.GET:
places_count = int(request.GET['count'])
else:
places_count = 1
if agenda.kind == 'meetings':
# event is actually a timeslot, convert to a real event object
meeting_type_id, start_datetime_str = event_pk.split(':')
@ -231,18 +236,24 @@ class Fillslot(GenericAPIView):
new_booking = Booking(event_id=event_pk, extra_data=request.data)
if event.waiting_list_places:
if event.waiting_list >= event.waiting_list_places:
if (event.waiting_list + places_count) > event.waiting_list_places:
return Response({'err': 1, 'reason': 'sold out'})
if event.booked_places >= event.places or event.waiting_list:
if (event.booked_places + places_count) > event.places or event.waiting_list:
# if this is full or there are people waiting, put new bookings
# in the waiting list.
new_booking.in_waiting_list = True
else:
if event.booked_places >= event.places:
if (event.booked_places + places_count) > event.places:
return Response({'err': 1, 'reason': 'sold out'})
new_booking.save()
for i in range(places_count-1):
additional_booking = Booking(event_id=event_pk, extra_data=request.data)
additional_booking.in_waiting_list = new_booking.in_waiting_list
additional_booking.primary_booking = new_booking
additional_booking.save()
response = {
'err': 0,
'in_waiting_list': new_booking.in_waiting_list,

View File

@ -546,3 +546,45 @@ def test_accept_booking(app, some_data, user):
assert resp.json['err'] == 1
assert Booking.objects.filter(in_waiting_list=True).count() == 1
assert Booking.objects.filter(in_waiting_list=False).count() == 0
def test_multiple_booking_api(app, some_data, user):
agenda = Agenda.objects.filter(label=u'Foo bar')[0]
event = [x for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()][0]
resp_datetimes = app.get('/api/agenda/%s/datetimes/' % agenda.id)
event_fillslot_url = [x for x in resp_datetimes.json['data'] if x['id'] == event.id][0]['api']['fillslot_url']
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.post('/api/agenda/%s/fillslot/%s/?count=3' % (agenda.slug, event.id))
Booking.objects.get(id=resp.json['booking_id'])
assert resp.json['datetime'] == localtime(event.start_datetime).isoformat()
assert 'accept_url' not in resp.json['api']
assert 'cancel_url' in resp.json['api']
assert event.booked_places == 3
resp2 = app.post('/api/agenda/%s/fillslot/%s/?count=2' % (agenda.slug, event.id))
assert event.booked_places == 5
resp = app.post(resp.json['api']['cancel_url'])
assert event.booked_places == 2
# check available places overflow
event.places = 3
event.waiting_list_places = 8
event.save()
resp3 = app.post('/api/agenda/%s/fillslot/%s/?count=5' % (agenda.slug, event.id))
assert event.booked_places == 2
assert event.waiting_list == 5
# check waiting list overflow
resp = app.post('/api/agenda/%s/fillslot/%s/?count=5' % (agenda.slug, event.id))
assert resp.json['err'] == 1
assert resp.json['reason'] == 'sold out'
assert event.booked_places == 2
assert event.waiting_list == 5
# accept the waiting list
resp = app.post(resp3.json['api']['accept_url'])
assert event.booked_places == 7
assert event.waiting_list == 0