from django.utils.dateparse import parse_datetime from rest_framework import generics, permissions, viewsets from rest_framework.exceptions import PermissionDenied from rest_framework.response import Response from rest_framework.views import APIView from booking.models import Booking from marketing.mixins import AdventureListingClickTrackingMixin from .models import AdventureOffering from .serializers import AdventureOfferingSerializer class PublicAdventureListView(generics.ListAPIView): serializer_class = AdventureOfferingSerializer permission_classes = (permissions.AllowAny,) def get_queryset(self): queryset = AdventureOffering.objects.filter(is_active=True).select_related("category", "vendor").prefetch_related("images") params = self.request.query_params category = params.get("category") if category: if category.isdigit(): queryset = queryset.filter(category_id=category) else: queryset = queryset.filter(category__slug=category) location = params.get("location") if location: queryset = queryset.filter(meeting_point__icontains=location) vendor_slug = params.get("vendor_slug") if vendor_slug: queryset = queryset.filter(vendor__slug=vendor_slug) min_price = params.get("min_price") if min_price: queryset = queryset.filter(price_per_person__gte=min_price) max_price = params.get("max_price") if max_price: queryset = queryset.filter(price_per_person__lte=max_price) start = parse_datetime(params.get("available_from", "")) if params.get("available_from") else None end = parse_datetime(params.get("available_to", "")) if params.get("available_to") else None if start and end: blocked_offering_ids = ( Booking.objects.filter( adventure_offering__isnull=False, status__in=[Booking.Status.REQUESTED, Booking.Status.APPROVED, Booking.Status.CONFIRMED], ) .filter(starts_at__lt=end, ends_at__gt=start) .values_list("adventure_offering_id", flat=True) ) queryset = queryset.exclude(id__in=blocked_offering_ids) return queryset class PublicAdventureDetailView(AdventureListingClickTrackingMixin, generics.RetrieveAPIView): serializer_class = AdventureOfferingSerializer permission_classes = (permissions.AllowAny,) lookup_field = "public_id" def get_queryset(self): return AdventureOffering.objects.filter(is_active=True).select_related("category", "vendor").prefetch_related("images") class VendorAdventureViewSet(viewsets.ModelViewSet): serializer_class = AdventureOfferingSerializer permission_classes = (permissions.IsAuthenticated,) def get_queryset(self): user = self.request.user if not user.is_vendor or not hasattr(user, "vendor_profile"): return AdventureOffering.objects.none() return ( AdventureOffering.objects.filter(vendor=user.vendor_profile) .select_related("category", "vendor") .prefetch_related("images") ) def perform_create(self, serializer): user = self.request.user if not user.is_vendor or not hasattr(user, "vendor_profile"): raise PermissionDenied("Only vendors can create adventure offerings.") serializer.save(vendor=user.vendor_profile) class VendorAdventureStorefrontView(APIView): permission_classes = (permissions.AllowAny,) def get(self, request, slug): offerings = ( AdventureOffering.objects.filter(vendor__slug=slug, is_active=True) .select_related("category", "vendor") .prefetch_related("images") ) if not offerings.exists(): return Response({"detail": "Vendor adventure storefront not found."}, status=404) vendor = offerings.first().vendor return Response( { "vendor": { "business_name": vendor.business_name, "slug": vendor.slug, "description": vendor.description, "contact_email": vendor.contact_email, "contact_phone": vendor.contact_phone, "city": vendor.city, "country": vendor.country, }, "offerings": AdventureOfferingSerializer(offerings, many=True, context={"request": request}).data, } )