from django.db.models import Q 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 EquipmentListingClickTrackingMixin from .models import EquipmentCategory, EquipmentItem from .serializers import EquipmentCategorySerializer, EquipmentItemSerializer class PublicEquipmentCategoryListView(generics.ListAPIView): """Read-only list of equipment categories for storefronts and vendor create flows.""" serializer_class = EquipmentCategorySerializer permission_classes = (permissions.AllowAny,) queryset = EquipmentCategory.objects.all().order_by("name") class PublicEquipmentListView(generics.ListAPIView): serializer_class = EquipmentItemSerializer permission_classes = (permissions.AllowAny,) def get_queryset(self): queryset = EquipmentItem.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(location__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_day__gte=min_price) max_price = params.get("max_price") if max_price: queryset = queryset.filter(price_per_day__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_item_ids = ( Booking.objects.filter( equipment_item__isnull=False, status__in=[Booking.Status.REQUESTED, Booking.Status.APPROVED, Booking.Status.CONFIRMED], ) .filter(starts_at__lt=end, ends_at__gt=start) .values_list("equipment_item_id", flat=True) ) queryset = queryset.exclude(id__in=blocked_item_ids) return queryset class PublicEquipmentDetailView(EquipmentListingClickTrackingMixin, generics.RetrieveAPIView): serializer_class = EquipmentItemSerializer permission_classes = (permissions.AllowAny,) lookup_field = "public_id" def get_queryset(self): return EquipmentItem.objects.filter(is_active=True).select_related("category", "vendor").prefetch_related("images") class VendorEquipmentViewSet(viewsets.ModelViewSet): serializer_class = EquipmentItemSerializer permission_classes = (permissions.IsAuthenticated,) def get_queryset(self): user = self.request.user if not user.is_vendor or not hasattr(user, "vendor_profile"): return EquipmentItem.objects.none() return ( EquipmentItem.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 equipment.") serializer.save(vendor=user.vendor_profile) class VendorStorefrontView(APIView): permission_classes = (permissions.AllowAny,) def get(self, request, slug): items = ( EquipmentItem.objects.filter(vendor__slug=slug, is_active=True) .select_related("category", "vendor") .prefetch_related("images") ) if not items.exists(): return Response({"detail": "Vendor storefront not found."}, status=404) vendor = items.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, }, "items": EquipmentItemSerializer(items, many=True, context={"request": request}).data, } )