Files
2026-09-24 12:32:59 +03:30

172 lines
6.5 KiB
Python

from datetime import date as date_cls
from rest_framework import decorators, mixins, response, status, viewsets
from rest_framework.permissions import IsAuthenticated
from apps.core.errors import ApiError, error_response
from apps.rbac.permissions import ActionPermission
from apps.reservations.models import Facility, FacilitySchedule, ProcessingLine, Reservation, Slot
from apps.reservations.serializers import (
FacilityScheduleSerializer,
FacilitySerializer,
ReservationSerializer,
SlotSerializer,
)
from apps.reservations.services import ReservationService
from apps.reservations.slot_service import SlotService
class FacilityViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Facility.objects.all()
serializer_class = FacilitySerializer
permission_classes = [IsAuthenticated]
class FacilityScheduleViewSet(viewsets.ModelViewSet):
queryset = FacilitySchedule.objects.select_related("facility").all()
serializer_class = FacilityScheduleSerializer
permission_classes = [ActionPermission]
filterset_fields = ["facility", "date"]
code_map = {
"list": "reservation.view",
"retrieve": "reservation.view",
"create": "slot.manage",
"update": "slot.manage",
"partial_update": "slot.manage",
"destroy": "slot.manage",
}
class SlotViewSet(
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
mixins.CreateModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
viewsets.GenericViewSet,
):
queryset = Slot.objects.select_related("facility", "line").all()
serializer_class = SlotSerializer
permission_classes = [ActionPermission]
filterset_fields = ["facility", "date", "blocked"]
code_map = {
"list": "reservation.view",
"retrieve": "reservation.view",
"create": "slot.manage",
"update": "slot.manage",
"partial_update": "slot.manage",
"destroy": "slot.manage",
"generate": "slot.manage",
}
@decorators.action(detail=False, methods=["post"])
def generate(self, request):
facility_id = request.data.get("facility")
date_str = request.data.get("date")
line_id = request.data.get("line")
if not facility_id or not date_str:
return response.Response(
error_response("INVALID_INPUT", "facility and date are required."),
status=status.HTTP_400_BAD_REQUEST,
)
try:
facility = Facility.objects.get(pk=facility_id)
except Facility.DoesNotExist:
return response.Response(
error_response("FACILITY_NOT_FOUND", "Facility not found."),
status=status.HTTP_404_NOT_FOUND,
)
line = None
if line_id:
try:
line = ProcessingLine.objects.get(pk=line_id)
except ProcessingLine.DoesNotExist:
return response.Response(
error_response("LINE_NOT_FOUND", "Processing line not found."),
status=status.HTTP_404_NOT_FOUND,
)
try:
day = date_cls.fromisoformat(date_str)
except ValueError:
return response.Response(
error_response("INVALID_DATE", "Invalid date."),
status=status.HTTP_400_BAD_REQUEST,
)
try:
created = SlotService().generate_slots(facility, day, line)
except ValueError as exc:
return response.Response(
error_response("INVALID_SETTINGS", str(exc)),
status=status.HTTP_400_BAD_REQUEST,
)
return response.Response({"created": created})
class ReservationViewSet(viewsets.ModelViewSet):
serializer_class = ReservationSerializer
permission_classes = [ActionPermission]
filterset_fields = ["status"]
code_map = {
"list": "reservation.view",
"retrieve": "reservation.view",
"create": "reservation.create",
"cancel": "reservation.cancel",
"approve": "reservation.approve",
"reject": "reservation.approve",
}
service = ReservationService()
def get_queryset(self):
user = self.request.user
if user.is_superuser or user.user_roles.filter(role__slug__in=["administrator", "facility_manager"]).exists():
return Reservation.objects.select_related("customer__user", "slot").all()
return Reservation.objects.select_related("customer__user", "slot").filter(customer__user=user)
def perform_create(self, serializer):
slot_id = self.request.data.get("slot")
if not slot_id:
raise ApiError("SLOT_REQUIRED", "A slot id is required.")
try:
reservation = self.service.book(
self._customer(),
Slot.objects.get(pk=slot_id),
title=self.request.data.get("title", ""),
notes=self.request.data.get("notes", ""),
)
except Slot.DoesNotExist:
raise ApiError("SLOT_NOT_FOUND", "Slot not found.")
serializer.instance = reservation
def _customer(self):
from apps.accounts.models import Customer
customer, _ = Customer.objects.get_or_create(user=self.request.user)
return customer
@decorators.action(detail=True, methods=["post"])
def cancel(self, request, pk=None):
reservation = self.get_object()
try:
self.service.cancel(reservation)
except ApiError as exc:
return response.Response(error_response(exc.code, exc.message, exc.details), status=exc.status)
return response.Response(ReservationSerializer(reservation).data)
@decorators.action(detail=True, methods=["post"])
def approve(self, request, pk=None):
reservation = self.get_object()
try:
reservation = self.service.approve(reservation, request.user)
except ApiError as exc:
return response.Response(error_response(exc.code, exc.message, exc.details), status=exc.status)
return response.Response(ReservationSerializer(reservation).data)
@decorators.action(detail=True, methods=["post"])
def reject(self, request, pk=None):
reservation = self.get_object()
try:
reservation = self.service.reject(reservation, request.user)
except ApiError as exc:
return response.Response(error_response(exc.code, exc.message, exc.details), status=exc.status)
return response.Response(ReservationSerializer(reservation).data)