gault-millau/apps/booking/views.py
dormantman 62bee3156c Added description to update booking method
(cherry picked from commit a947eb1)
2019-12-18 18:40:05 +03:00

213 lines
9.9 KiB
Python

from django.shortcuts import get_object_or_404
from drf_yasg.utils import swagger_auto_schema
from rest_framework import generics, permissions, status, serializers
from rest_framework.response import Response
from booking.models.models import Booking, GuestonlineService, LastableService
from booking.serializers.web import (PendingBookingSerializer, UpdateBookingSerializer, GetBookingSerializer,
CheckBookingSerializer, CommitBookingSerializer)
from establishment.models import Establishment
from notification.models import Subscriber
from utils.methods import get_user_ip
class CheckWhetherBookingAvailable(generics.GenericAPIView):
""" Checks which service to use if establishmend is managed by any """
_VALID_GUESTONLINE_PERIODS = {'lunch', 'dinner', 'afternoon', 'breakfast'}
_GUESTONLINE_PERIODS_TO_PRIOR = {
'breakfast': 1,
'lunch': 2,
'afternoon': 3,
'dinner': 4,
}
permission_classes = (permissions.AllowAny,)
serializer_class = CheckBookingSerializer
pagination_class = None
def _fill_period_template(self, period_template, period_name):
period_template_copy = period_template.copy()
period_template_copy['period'] = period_name
return period_template_copy
def _preprocess_guestonline_response(self, response):
periods = response['periods']
periods_by_name = {period['period']: period for period in periods if 'period' in period}
if not periods_by_name:
return response
period_template = iter(periods_by_name.values()).__next__().copy()
period_template.pop('total_left_seats')
period_template['hours'] = []
period_template.pop('period')
processed_periods = [
periods_by_name[period_name]
if period_name in periods_by_name
else self._fill_period_template(period_template, period_name)
for period_name in CheckWhetherBookingAvailable._VALID_GUESTONLINE_PERIODS
]
unnamed_periods = filter(lambda period: 'period' not in period, periods)
for unnamed_period in unnamed_periods:
processed_periods.append(unnamed_period)
response['periods'] = sorted(processed_periods,
key=lambda x: self._GUESTONLINE_PERIODS_TO_PRIOR[x.get('period', 'lunch')])
return response
def get(self, request, *args, **kwargs):
is_booking_available = False
establishment = get_object_or_404(Establishment, pk=kwargs['establishment_id'])
service = None
date = request.query_params.get('date')
g_service = GuestonlineService()
l_service = LastableService()
if establishment.lastable_id is not None and l_service \
.check_whether_booking_available(establishment.lastable_id, date):
is_booking_available = True
service = l_service
service.service_id = establishment.lastable_id
elif establishment.guestonline_id is not None and g_service \
.check_whether_booking_available(establishment.guestonline_id,
**g_service.get_certain_keys(request.query_params,
{'date', 'persons'})):
is_booking_available = True
service = g_service
service.service_id = establishment.guestonline_id
response = {
'available': is_booking_available,
'type': service.service if service else None,
}
service_response = self._preprocess_guestonline_response(service.response) \
if establishment.guestonline_id is not None \
else service.response if service else None
response.update({'details': service_response})
if service_response is None:
response['available'] = False
return Response(data=response, status=200)
class CreatePendingBooking(generics.CreateAPIView):
""" Creates pending booking """
permission_classes = (permissions.AllowAny,)
serializer_class = PendingBookingSerializer
@swagger_auto_schema(operation_description="Request body params\n\n"
"IN GUESTONLINE (type:G): {"
"'restaurant_id', 'booking_time', "
"'booking_date', 'booked_persons_number'}\n"
"IN LASTABLE (type:L): {'booking_time', "
"'booked_persons_number', 'offer_id' (Req), "
"'email', 'phone', 'first_name', 'last_name'}")
def post(self, request, *args, **kwargs):
data = request.data.copy()
if data.get('type') == Booking.LASTABLE and data.get("offer_id") is None:
raise serializers.ValidationError(detail='Offer_id is required field for Lastable service')
establishment = get_object_or_404(Establishment, pk=kwargs['establishment_id'])
data['restaurant_id'] = Booking.get_booking_id_by_type(establishment, data.get('type'))
service = Booking.get_service_by_type(request.data.get('type'))
data['user'] = request.user.pk if request.user else None
service_to_keys = {
Booking.GUESTONLINE: {'restaurant_id', 'booking_time', 'booking_date', 'booked_persons_number', },
Booking.LASTABLE: {'booking_time', 'booked_persons_number', 'offer_id', 'email', 'phone',
'first_name', 'last_name', },
}
data['pending_booking_id'] = service.create_booking(
service.get_certain_keys(data.copy(), service_to_keys[data.get('type')]))
if isinstance(data['pending_booking_id'], Response):
return data['pending_booking_id']
elif not data['pending_booking_id']:
return Response(status=status.HTTP_403_FORBIDDEN, data='Unable to create booking')
data['booking_id'] = data['pending_booking_id'] if data.get('type') == Booking.LASTABLE else None
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(status=status.HTTP_201_CREATED, data=serializer.data)
class CommitPendingBooking(generics.UpdateAPIView):
""" Commit pending booking """
queryset = Booking.objects.all()
permission_classes = (permissions.AllowAny,)
serializer_class = CommitBookingSerializer
class UpdatePendingBooking(generics.UpdateAPIView):
""" Update pending booking with contacts """
queryset = Booking.objects.all()
permission_classes = (permissions.AllowAny,)
serializer_class = UpdateBookingSerializer
@swagger_auto_schema(operation_description="Request body params\n\n"
"Required: 'email', 'phone', 'last_name', "
"'first_name', 'country_code', 'pending_booking_id',"
"Not req: 'note'")
def patch(self, request, *args, **kwargs):
instance = self.get_object()
data = request.data.copy()
service = Booking.get_service_by_type(instance.type)
data['pending_booking_id'] = instance.pending_booking_id
r = service.update_booking(service.get_certain_keys(data, {
'email', 'phone', 'last_name', 'first_name', 'country_code', 'pending_booking_id', 'note',
}, {
'email', 'phone', 'last_name', 'first_name',
'country_code', 'pending_booking_id',
}))
if isinstance(r, Response):
return r
if data.get('newsletter'):
Subscriber.objects.make_subscriber(email=data['email'], country_code=data['country_code'],
locale=request.locale, ip_address=get_user_ip(request),
user=None if request.user.is_anonymous else request.user)
if service.response:
# если есть предоплата, возвращаем фронту страйп-ключ для совершения оплаты и цену
amount = service.response.get('amount')
stripe_key = service.response.get('stripe_key')
data = {
'id': instance.pk,
'amount': amount,
'stripe_key': stripe_key,
'type': instance.type,
}
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
serializer.update(instance, data)
return Response(status=status.HTTP_200_OK, data=data)
service.commit_booking(data['pending_booking_id'])
data = {
'booking_id': service.response.get('id'),
'id': instance.pk,
}
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
serializer.update(instance, data)
return Response(status=status.HTTP_200_OK, data=serializer.data)
class CancelBooking(generics.DestroyAPIView):
""" Cancel existing booking """
queryset = Booking.objects.all()
permission_classes = (permissions.AllowAny,)
class LastBooking(generics.RetrieveAPIView):
""" Get last booking by user credentials """
permission_classes = (permissions.IsAuthenticated,)
serializer_class = GetBookingSerializer
lookup_field = None
def get_object(self):
return Booking.objects.by_user(self.request.user).latest('modified')
class GetBookingById(generics.RetrieveAPIView):
""" Returns booking by its id"""
permission_classes = (permissions.AllowAny,)
serializer_class = GetBookingSerializer
queryset = Booking.objects.all()