general: make it possible to cancel bookings (#9999)

This commit is contained in:
Frédéric Péters 2016-03-30 00:51:34 +02:00
parent f80afdd268
commit 6bc22b0dfe
8 changed files with 69 additions and 5 deletions

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('agendas', '0003_booking'),
]
operations = [
migrations.AddField(
model_name='booking',
name='cancellation_datetime',
field=models.DateTimeField(null=True),
preserve_default=True,
),
]

View File

@ -16,7 +16,7 @@
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db import models from django.db import models
from django.db.models import Count from django.db.models.expressions import RawSQL
from django.utils.text import slugify from django.utils.text import slugify
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -52,7 +52,10 @@ class Agenda(models.Model):
class EventManager(models.Manager): class EventManager(models.Manager):
def get_queryset(self): def get_queryset(self):
return super(EventManager, self).get_queryset().annotate( return super(EventManager, self).get_queryset().annotate(
booked_places=Count('booking')) booked_places=RawSQL('''SELECT count(*)
FROM agendas_booking
WHERE agendas_booking.event_id = agendas_event.id
AND cancellation_datetime IS NULL''', ()))
class Event(models.Model): class Event(models.Model):
@ -69,3 +72,4 @@ class Event(models.Model):
class Booking(models.Model): class Booking(models.Model):
event = models.ForeignKey(Event) event = models.ForeignKey(Event)
extra_data = JSONField(null=True) extra_data = JSONField(null=True)
cancellation_datetime = models.DateTimeField(null=True)

View File

@ -21,4 +21,5 @@ from . import views
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'agenda/(?P<pk>\w+)/datetimes/', views.datetimes), url(r'agenda/(?P<pk>\w+)/datetimes/', views.datetimes),
url(r'agenda/(?P<agenda_pk>\w+)/fillslot/(?P<event_pk>\w+)/', views.fillslot), url(r'agenda/(?P<agenda_pk>\w+)/fillslot/(?P<event_pk>\w+)/', views.fillslot),
url(r'booking/(?P<booking_pk>\w+)/', views.booking),
) )

View File

@ -21,6 +21,7 @@ from django.utils.timezone import localtime, now
from rest_framework import serializers, status from rest_framework import serializers, status
from rest_framework.generics import GenericAPIView from rest_framework.generics import GenericAPIView
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.views import APIView
from ..agendas.models import Event, Booking from ..agendas.models import Event, Booking
@ -57,3 +58,18 @@ class Fillslot(GenericAPIView):
return Response(response) return Response(response)
fillslot = Fillslot.as_view() fillslot = Fillslot.as_view()
class BookingAPI(APIView):
def initial(self, request, *args, **kwargs):
super(BookingAPI, self).initial(request, *args, **kwargs)
self.booking = Booking.objects.get(id=kwargs.get('booking_pk'),
cancellation_datetime__isnull=True)
def delete(self, request, *args, **kwargs):
self.booking.cancellation_datetime = now()
self.booking.save()
response = {'err': 0, 'booking_id': self.booking.id}
return Response(response)
booking = BookingAPI.as_view()

View File

@ -1,4 +1,4 @@
django>=1.7, <1.8 django>=1.8, <1.9
gadjo gadjo
djangorestframework>=3.1 djangorestframework>=3.1
django-jsonfield >= 0.9.3 django-jsonfield >= 0.9.3

View File

@ -102,7 +102,7 @@ setup(
'Programming Language :: Python', 'Programming Language :: Python',
'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2',
], ],
install_requires=['django>=1.7, <1.8', install_requires=['django>=1.8, <1.9',
'gadjo', 'gadjo',
'djangorestframework>=3.1', 'djangorestframework>=3.1',
'django-jsonfield >= 0.9.3', 'django-jsonfield >= 0.9.3',

View File

@ -1,6 +1,8 @@
import pytest import pytest
from chrono.agendas.models import Agenda from django.utils.timezone import now
from chrono.agendas.models import Agenda, Event, Booking
pytestmark = pytest.mark.django_db pytestmark = pytest.mark.django_db
@ -25,3 +27,15 @@ def test_duplicate_slugs():
agenda = Agenda(label=u'Foo baz') agenda = Agenda(label=u'Foo baz')
agenda.save() agenda.save()
assert agenda.slug == 'foo-baz-2' assert agenda.slug == 'foo-baz-2'
def test_event_manager():
agenda = Agenda(label=u'Foo baz')
agenda.save()
event = Event(start_datetime=now(), places=10, agenda=agenda)
event.save()
booking = Booking(event=event)
booking.save()
assert Event.objects.all()[0].booked_places == 1
booking.cancellation_datetime = now()
booking.save()
assert Event.objects.all()[0].booked_places == 0

View File

@ -66,6 +66,15 @@ def test_booking_api_with_data(app, some_data):
assert Booking.objects.count() == 1 assert Booking.objects.count() == 1
assert Booking.objects.all()[0].extra_data == {'hello': 'world'} assert Booking.objects.all()[0].extra_data == {'hello': 'world'}
def test_booking_cancellation_api(app, some_data):
agenda_id = Agenda.objects.filter(label=u'Foo bar')[0].id
event = Event.objects.filter(agenda_id=agenda_id)[0]
resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda_id, event.id))
booking_id = resp.json['booking_id']
assert Booking.objects.count() == 1
resp = app.delete('/api/booking/%s/' % booking_id)
assert Booking.objects.filter(cancellation_datetime__isnull=False).count() == 1
def test_soldout(app, some_data): def test_soldout(app, some_data):
agenda_id = Agenda.objects.filter(label=u'Foo bar')[0].id agenda_id = Agenda.objects.filter(label=u'Foo bar')[0].id
event = Event.objects.filter(agenda_id=agenda_id).exclude(start_datetime__lt=now())[0] event = Event.objects.filter(agenda_id=agenda_id).exclude(start_datetime__lt=now())[0]