213 lines
9.9 KiB
Python
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()
|