inital commit
This commit is contained in:
169
booking/views.py
Normal file
169
booking/views.py
Normal file
@@ -0,0 +1,169 @@
|
||||
from django.http import JsonResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from rest_framework import generics, permissions, status
|
||||
from rest_framework.exceptions import PermissionDenied
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from .models import Booking
|
||||
from .serializers import BookingCreateSerializer, BookingSerializer
|
||||
from .services import is_bookable, transition_booking_status
|
||||
|
||||
|
||||
def health_check(request):
|
||||
return JsonResponse({"status": "ok", "service": "WaterTrek"})
|
||||
|
||||
|
||||
class AvailabilityView(APIView):
|
||||
permission_classes = (permissions.AllowAny,)
|
||||
|
||||
def get(self, request):
|
||||
equipment_item_id = request.query_params.get("equipment_item_id")
|
||||
adventure_offering_id = request.query_params.get("adventure_offering_id")
|
||||
starts_at = request.query_params.get("starts_at")
|
||||
ends_at = request.query_params.get("ends_at")
|
||||
if not starts_at or not ends_at:
|
||||
return Response(
|
||||
{"detail": "starts_at and ends_at are required query params."},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
if bool(equipment_item_id) == bool(adventure_offering_id):
|
||||
return Response(
|
||||
{"detail": "Provide exactly one target: equipment_item_id or adventure_offering_id."},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
payload = {"starts_at": starts_at, "ends_at": ends_at}
|
||||
if equipment_item_id:
|
||||
payload["equipment_item_id"] = equipment_item_id
|
||||
if adventure_offering_id:
|
||||
payload["adventure_offering_id"] = adventure_offering_id
|
||||
serializer = BookingCreateSerializer(data=payload)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
equipment_item = serializer.validated_data.get("equipment_item_id")
|
||||
adventure_offering = serializer.validated_data.get("adventure_offering_id")
|
||||
starts_at_value = serializer.validated_data["starts_at"]
|
||||
ends_at_value = serializer.validated_data["ends_at"]
|
||||
conflict_filter = {
|
||||
"starts_at__lt": ends_at_value,
|
||||
"ends_at__gt": starts_at_value,
|
||||
"status__in": [Booking.Status.REQUESTED, Booking.Status.APPROVED, Booking.Status.CONFIRMED],
|
||||
}
|
||||
if equipment_item:
|
||||
conflict_filter["equipment_item"] = equipment_item
|
||||
else:
|
||||
conflict_filter["adventure_offering"] = adventure_offering
|
||||
conflicts = Booking.objects.filter(**conflict_filter).count()
|
||||
available = is_bookable(
|
||||
equipment_item=equipment_item,
|
||||
adventure_offering=adventure_offering,
|
||||
starts_at=starts_at_value,
|
||||
ends_at=ends_at_value,
|
||||
)
|
||||
return Response(
|
||||
{
|
||||
"equipment_item_id": equipment_item.id if equipment_item else None,
|
||||
"adventure_offering_id": adventure_offering.id if adventure_offering else None,
|
||||
"starts_at": starts_at_value,
|
||||
"ends_at": ends_at_value,
|
||||
"is_available": available,
|
||||
"conflicts": conflicts,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class BookingCreateView(generics.CreateAPIView):
|
||||
serializer_class = BookingCreateSerializer
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
|
||||
def perform_create(self, serializer):
|
||||
if not self.request.user.is_customer:
|
||||
raise PermissionDenied("Only customers can request bookings.")
|
||||
self.instance = serializer.save()
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
self.perform_create(serializer)
|
||||
return Response(BookingSerializer(self.instance).data, status=status.HTTP_201_CREATED)
|
||||
|
||||
|
||||
class BookingListView(generics.ListAPIView):
|
||||
serializer_class = BookingSerializer
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user
|
||||
if user.is_vendor and hasattr(user, "vendor_profile"):
|
||||
return Booking.objects.filter(vendor=user.vendor_profile).select_related(
|
||||
"customer", "vendor", "equipment_item", "adventure_offering"
|
||||
)
|
||||
return Booking.objects.filter(customer=user).select_related("customer", "vendor", "equipment_item", "adventure_offering")
|
||||
|
||||
|
||||
class BookingDetailView(generics.RetrieveAPIView):
|
||||
serializer_class = BookingSerializer
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user
|
||||
if user.is_vendor and hasattr(user, "vendor_profile"):
|
||||
return Booking.objects.filter(vendor=user.vendor_profile).select_related(
|
||||
"customer", "vendor", "equipment_item", "adventure_offering"
|
||||
)
|
||||
return Booking.objects.filter(customer=user).select_related("customer", "vendor", "equipment_item", "adventure_offering")
|
||||
|
||||
|
||||
class VendorApproveBookingView(APIView):
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
|
||||
def post(self, request, pk):
|
||||
if not request.user.is_vendor or not hasattr(request.user, "vendor_profile"):
|
||||
raise PermissionDenied("Only vendors can approve bookings.")
|
||||
booking = get_object_or_404(Booking, pk=pk, vendor=request.user.vendor_profile)
|
||||
if booking.status != Booking.Status.REQUESTED:
|
||||
return Response({"detail": "Only requested bookings can be approved."}, status=status.HTTP_400_BAD_REQUEST)
|
||||
transition_booking_status(
|
||||
booking=booking,
|
||||
to_status=Booking.Status.APPROVED,
|
||||
actor=request.user,
|
||||
note=request.data.get("note", "Booking approved."),
|
||||
vendor_notes=request.data.get("vendor_notes", booking.vendor_notes),
|
||||
)
|
||||
return Response(BookingSerializer(booking).data)
|
||||
|
||||
|
||||
class VendorDeclineBookingView(APIView):
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
|
||||
def post(self, request, pk):
|
||||
if not request.user.is_vendor or not hasattr(request.user, "vendor_profile"):
|
||||
raise PermissionDenied("Only vendors can decline bookings.")
|
||||
booking = get_object_or_404(Booking, pk=pk, vendor=request.user.vendor_profile)
|
||||
if booking.status != Booking.Status.REQUESTED:
|
||||
return Response({"detail": "Only requested bookings can be declined."}, status=status.HTTP_400_BAD_REQUEST)
|
||||
transition_booking_status(
|
||||
booking=booking,
|
||||
to_status=Booking.Status.DECLINED,
|
||||
actor=request.user,
|
||||
note=request.data.get("note", "Booking declined."),
|
||||
vendor_notes=request.data.get("vendor_notes", booking.vendor_notes),
|
||||
)
|
||||
return Response(BookingSerializer(booking).data)
|
||||
|
||||
|
||||
class CustomerCancelBookingView(APIView):
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
|
||||
def post(self, request, pk):
|
||||
booking = get_object_or_404(Booking, pk=pk, customer=request.user)
|
||||
if booking.status in [Booking.Status.CANCELLED, Booking.Status.DECLINED]:
|
||||
return Response({"detail": "This booking cannot be cancelled."}, status=status.HTTP_400_BAD_REQUEST)
|
||||
transition_booking_status(
|
||||
booking=booking,
|
||||
to_status=Booking.Status.CANCELLED,
|
||||
actor=request.user,
|
||||
note=request.data.get("note", "Booking cancelled by customer."),
|
||||
)
|
||||
return Response(BookingSerializer(booking).data)
|
||||
Reference in New Issue
Block a user