import logging from django.db.models import Count, Avg, Sum from rest_framework import status from rest_framework.views import APIView from rest_framework.generics import GenericAPIView from rest_framework.permissions import AllowAny, IsAuthenticated from rest_framework.response import Response from drf_spectacular.utils import extend_schema from apps.profiles.models import Institution from apps.projects.models import Project from apps.lms.models import Course, CourseEnrollment, DigitalCertificate from apps.tickets.models import Ticket, TicketStatus from apps.donations.models import DonationCampaign from apps.diplomacy.models import RepresentativeReport, ReportStatus from apps.analytics.serializers import ExecutiveDashboardSerializer logger = logging.getLogger(__name__) class ExecutiveDashboardView(GenericAPIView): permission_classes = [AllowAny] serializer_class = ExecutiveDashboardSerializer @extend_schema( summary="Executive KPIs & Global Analytics Dashboard", description="Aggregates platform KPIs across international institutions, collaborative projects, LMS academy, official ticketing, campaigns, and field diplomacy reports.", responses={200: ExecutiveDashboardSerializer}, tags=["Executive Analytics & KPIs"], ) def get(self, request, *args, **kwargs): # 1. Institutions inst_qs = Institution.objects.all() total_inst = inst_qs.count() verified_inst = inst_qs.filter(verification_status=Institution.VerificationStatus.APPROVED).count() countries_count = inst_qs.values('country').distinct().count() type_counts_raw = inst_qs.values('type').annotate(count=Count('id')) by_type = {item['type']: item['count'] for item in type_counts_raw} top_countries_raw = inst_qs.values('country').annotate(count=Count('id')).order_by('-count')[:8] top_countries = [{'country': item['country'], 'count': item['count']} for item in top_countries_raw] institutions_data = { 'total_institutions': total_inst, 'verified_institutions': verified_inst, 'countries_count': countries_count, 'by_type': by_type, 'top_countries': top_countries, } # 2. Projects proj_qs = Project.objects.all() projects_data = { 'total_projects': proj_qs.count(), 'active_projects': proj_qs.filter(status=Project.Status.ACTIVE).count(), 'completed_projects': proj_qs.filter(status=Project.Status.COMPLETED).count(), } # 3. LMS lms_data = { 'total_courses': Course.objects.filter(is_published=True).count(), 'total_enrollments': CourseEnrollment.objects.count(), 'total_certificates_issued': DigitalCertificate.objects.filter(is_revoked=False).count(), } # 4. Ticketing tickets_qs = Ticket.objects.all() avg_rating = tickets_qs.filter(satisfaction_rating__isnull=False).aggregate(avg=Avg('satisfaction_rating'))['avg'] ticketing_data = { 'total_tickets': tickets_qs.count(), 'open_tickets': tickets_qs.filter(status__in=[TicketStatus.OPEN, TicketStatus.IN_PROGRESS]).count(), 'answered_or_closed': tickets_qs.filter(status__in=[TicketStatus.ANSWERED, TicketStatus.CLOSED]).count(), 'average_satisfaction_rating': round(avg_rating, 2) if avg_rating else None, } # 5. Donations campaigns_qs = DonationCampaign.objects.filter(is_active=True) total_funds = DonationCampaign.objects.aggregate(total=Sum('raised_amount'))['total'] or 0.0 donations_data = { 'active_campaigns_count': campaigns_qs.count(), 'total_funds_raised_usd': float(total_funds), } # 6. Diplomacy reports_qs = RepresentativeReport.objects.all() total_visited = reports_qs.aggregate(total=Sum('centers_visited_count'))['total'] or 0 diplomacy_data = { 'total_reports_submitted': reports_qs.count(), 'approved_reports_count': reports_qs.filter(status=ReportStatus.APPROVED).count(), 'total_centers_visited': total_visited, } dashboard_data = { 'institutions': institutions_data, 'projects': projects_data, 'lms': lms_data, 'ticketing': ticketing_data, 'donations': donations_data, 'diplomacy': diplomacy_data, } return Response(dashboard_data, status=status.HTTP_200_OK)