Modified UserAppointmentStatsView to accept POST requests instead of GET and retrieve email from request body rather than from authenticated user. This allows querying appointment statistics for any email address instead of being limited to the current user's email. Changes: - Changed HTTP method from GET to POST - Added email parameter extraction from request.data - Updated filter to use provided email instead of request.user.email
202 lines
7.4 KiB
Python
202 lines
7.4 KiB
Python
from rest_framework import generics, status
|
|
from rest_framework.decorators import api_view, permission_classes
|
|
from rest_framework.response import Response
|
|
from rest_framework.permissions import IsAuthenticated, AllowAny,IsAdminUser
|
|
from django.utils import timezone
|
|
from datetime import datetime, timedelta
|
|
from .models import AdminWeeklyAvailability, AppointmentRequest
|
|
from .serializers import (
|
|
AdminWeeklyAvailabilitySerializer,
|
|
AppointmentRequestSerializer,
|
|
AppointmentRequestCreateSerializer,
|
|
AppointmentScheduleSerializer,
|
|
AppointmentRejectSerializer
|
|
)
|
|
from .email_service import EmailService
|
|
from users.models import CustomUser
|
|
from django.db.models import Count, Q
|
|
|
|
|
|
class AdminAvailabilityView(generics.RetrieveUpdateAPIView):
|
|
permission_classes = [IsAuthenticated, IsAdminUser]
|
|
serializer_class = AdminWeeklyAvailabilitySerializer
|
|
|
|
def get_object(self):
|
|
obj, created = AdminWeeklyAvailability.objects.get_or_create(
|
|
defaults={'available_days': []}
|
|
)
|
|
return obj
|
|
|
|
class AppointmentRequestListView(generics.ListAPIView):
|
|
serializer_class = AppointmentRequestSerializer
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
def get_queryset(self):
|
|
queryset = AppointmentRequest.objects.all()
|
|
|
|
if self.request.user.is_staff:
|
|
return queryset
|
|
|
|
return queryset.filter(email=self.request.user.email)
|
|
|
|
class AppointmentRequestCreateView(generics.CreateAPIView):
|
|
permission_classes = [IsAuthenticated]
|
|
queryset = AppointmentRequest.objects.all()
|
|
serializer_class = AppointmentRequestCreateSerializer
|
|
|
|
def perform_create(self, serializer):
|
|
availability = AdminWeeklyAvailability.objects.first()
|
|
if availability:
|
|
available_days = availability.available_days
|
|
preferred_dates = serializer.validated_data['preferred_dates']
|
|
|
|
for date_str in preferred_dates:
|
|
date_obj = datetime.strptime(date_str, '%Y-%m-%d').date()
|
|
if date_obj.weekday() not in available_days:
|
|
from rest_framework.exceptions import ValidationError
|
|
raise ValidationError(f'Date {date_str} is not available for appointments.')
|
|
|
|
appointment = serializer.save()
|
|
EmailService.send_admin_notification(appointment)
|
|
|
|
class AppointmentRequestDetailView(generics.RetrieveAPIView):
|
|
permission_classes = [IsAuthenticated]
|
|
queryset = AppointmentRequest.objects.all()
|
|
serializer_class = AppointmentRequestSerializer
|
|
lookup_field = 'pk'
|
|
|
|
class ScheduleAppointmentView(generics.GenericAPIView):
|
|
permission_classes = [IsAuthenticated, IsAdminUser]
|
|
serializer_class = AppointmentScheduleSerializer
|
|
queryset = AppointmentRequest.objects.all()
|
|
lookup_field = 'pk'
|
|
|
|
def post(self, request, pk):
|
|
appointment = self.get_object()
|
|
|
|
if appointment.status != 'pending_review':
|
|
return Response(
|
|
{'error': 'Only pending review appointments can be scheduled.'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
serializer = self.get_serializer(data=request.data)
|
|
serializer.is_valid(raise_exception=True)
|
|
|
|
appointment.schedule_appointment(
|
|
datetime_obj=serializer.validated_data['scheduled_datetime'],
|
|
duration=serializer.validated_data['scheduled_duration']
|
|
)
|
|
|
|
EmailService.send_appointment_scheduled(appointment)
|
|
|
|
response_serializer = AppointmentRequestSerializer(appointment)
|
|
return Response({
|
|
**response_serializer.data,
|
|
'message': 'Appointment scheduled successfully. Jitsi meeting created.',
|
|
'jitsi_meeting_created': appointment.has_jitsi_meeting
|
|
})
|
|
|
|
|
|
class RejectAppointmentView(generics.GenericAPIView):
|
|
permission_classes = [IsAuthenticated]
|
|
serializer_class = AppointmentRejectSerializer
|
|
queryset = AppointmentRequest.objects.all()
|
|
lookup_field = 'pk'
|
|
|
|
def post(self, request, pk):
|
|
appointment = self.get_object()
|
|
|
|
if appointment.status != 'pending_review':
|
|
return Response(
|
|
{'error': 'Only pending appointments can be rejected'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
serializer = self.get_serializer(data=request.data)
|
|
serializer.is_valid(raise_exception=True)
|
|
|
|
appointment.reject_appointment(
|
|
serializer.validated_data.get('rejection_reason', '')
|
|
)
|
|
EmailService.send_appointment_rejected(appointment)
|
|
|
|
response_serializer = AppointmentRequestSerializer(appointment)
|
|
return Response(response_serializer.data)
|
|
|
|
|
|
class AvailableDatesView(generics.GenericAPIView):
|
|
permission_classes = [AllowAny]
|
|
|
|
def get(self, request):
|
|
availability = AdminWeeklyAvailability.objects.first()
|
|
if not availability:
|
|
return Response([])
|
|
|
|
available_days = availability.available_days
|
|
today = timezone.now().date()
|
|
available_dates = []
|
|
|
|
for i in range(1, 31):
|
|
date = today + timedelta(days=i)
|
|
if date.weekday() in available_days:
|
|
available_dates.append(date.strftime('%Y-%m-%d'))
|
|
|
|
return Response(available_dates)
|
|
|
|
class UserAppointmentsView(generics.ListAPIView):
|
|
permission_classes = [IsAuthenticated]
|
|
serializer_class = AppointmentRequestSerializer
|
|
|
|
def get_queryset(self):
|
|
return AppointmentRequest.objects.filter(
|
|
email=self.request.user.email
|
|
).order_by('-created_at')
|
|
|
|
|
|
class AppointmentStatsView(generics.GenericAPIView):
|
|
permission_classes = [IsAuthenticated, IsAdminUser]
|
|
|
|
def get(self, request):
|
|
total = AppointmentRequest.objects.count()
|
|
users = CustomUser.objects.filter(is_staff=False).count()
|
|
pending = AppointmentRequest.objects.filter(status='pending_review').count()
|
|
scheduled = AppointmentRequest.objects.filter(status='scheduled').count()
|
|
rejected = AppointmentRequest.objects.filter(status='rejected').count()
|
|
|
|
return Response({
|
|
'total_requests': total,
|
|
'pending_review': pending,
|
|
'scheduled': scheduled,
|
|
'rejected': rejected,
|
|
'users': users,
|
|
'completion_rate': round((scheduled / total * 100), 2) if total > 0 else 0
|
|
})
|
|
|
|
class UserAppointmentStatsView(generics.GenericAPIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
def post(self, request):
|
|
email = request.data.get('email')
|
|
stats = AppointmentRequest.objects.filter(
|
|
email=email
|
|
).aggregate(
|
|
total=Count('id'),
|
|
pending=Count('id', filter=Q(status='pending_review')),
|
|
scheduled=Count('id', filter=Q(status='scheduled')),
|
|
rejected=Count('id', filter=Q(status='rejected')),
|
|
completed=Count('id', filter=Q(status='completed'))
|
|
)
|
|
|
|
total = stats['total']
|
|
scheduled = stats['scheduled']
|
|
completion_rate = round((scheduled / total * 100), 2) if total > 0 else 0
|
|
|
|
return Response({
|
|
'total_requests': total,
|
|
'pending_review': stats['pending'],
|
|
'scheduled': scheduled,
|
|
'rejected': stats['rejected'],
|
|
'completed': stats['completed'],
|
|
'completion_rate': completion_rate
|
|
}) |