from django.contrib.auth import authenticate, get_user_model from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.permissions import AllowAny, IsAuthenticated from rest_framework import status from rest_framework_simplejwt.tokens import RefreshToken from rest_framework_simplejwt.views import TokenRefreshView from django.db import connection from .serializers import UserSerializer User = get_user_model() class AdminLoginView(APIView): permission_classes = [AllowAny] def post(self, request): identifier = request.data.get('username') or request.data.get('email') password = request.data.get('password') if not identifier or not password: return Response({'error': 'username/email and password required'}, status=status.HTTP_400_BAD_REQUEST) # Try username first, then email user = authenticate(request, username=identifier, password=password) if not user: try: u = User.objects.get(email=identifier) user = authenticate(request, username=u.username, password=password) except User.DoesNotExist: pass if not user: return Response({'error': 'Invalid credentials'}, status=status.HTTP_401_UNAUTHORIZED) if not user.is_active: return Response({'error': 'Account is disabled'}, status=status.HTTP_403_FORBIDDEN) refresh = RefreshToken.for_user(user) return Response({ 'access': str(refresh.access_token), 'refresh': str(refresh), 'user': UserSerializer(user).data, }) class MeView(APIView): permission_classes = [IsAuthenticated] def get(self, request): return Response({'user': UserSerializer(request.user).data}) class HealthView(APIView): permission_classes = [AllowAny] def get(self, request): try: connection.ensure_connection() db_status = 'ok' except Exception: db_status = 'error' return Response({'status': 'ok', 'db': db_status}) # --------------------------------------------------------------------------- # Phase 2: Dashboard Views # --------------------------------------------------------------------------- class DashboardMetricsView(APIView): permission_classes = [IsAuthenticated] def get(self, request): from ledger.models import RazorpayTransaction from partner.models import Partner from events.models import Event from bookings.models import Ticket, Booking from django.db.models import Sum from django.utils import timezone import datetime today = timezone.now().date() # --- Revenue --- total_paise = ( RazorpayTransaction.objects .filter(status='captured') .aggregate(total=Sum('amount'))['total'] or 0 ) total_revenue = total_paise / 100 # This-month / last-month revenue for growth first_of_this_month = today.replace(day=1) first_of_last_month = (first_of_this_month - datetime.timedelta(days=1)).replace(day=1) this_month_paise = ( RazorpayTransaction.objects .filter(status='captured', captured_at__date__gte=first_of_this_month) .aggregate(total=Sum('amount'))['total'] or 0 ) last_month_paise = ( RazorpayTransaction.objects .filter( status='captured', captured_at__date__gte=first_of_last_month, captured_at__date__lt=first_of_this_month, ) .aggregate(total=Sum('amount'))['total'] or 0 ) this_month_rev = this_month_paise / 100 last_month_rev = last_month_paise / 100 revenue_growth = ( round((this_month_rev - last_month_rev) / last_month_rev * 100, 2) if last_month_rev else 0 ) # --- Partners --- active_partners = Partner.objects.filter(status='active').count() pending_partners = Partner.objects.filter(kyc_compliance_status='pending').count() # --- Events --- live_events = Event.objects.filter(event_status='live').count() events_today = Event.objects.filter(start_date=today).count() # --- Tickets --- ticket_sales = Ticket.objects.count() # This-week / last-week ticket growth week_start = today - datetime.timedelta(days=today.weekday()) # Monday last_week_start = week_start - datetime.timedelta(days=7) this_week_tickets = Ticket.objects.filter( booking__created_date__gte=week_start ).count() last_week_tickets = Ticket.objects.filter( booking__created_date__gte=last_week_start, booking__created_date__lt=week_start, ).count() ticket_growth = ( round((this_week_tickets - last_week_tickets) / last_week_tickets * 100, 2) if last_week_tickets else 0 ) return Response({ 'totalRevenue': total_revenue, 'revenueGrowth': revenue_growth, 'activePartners': active_partners, 'pendingPartners': pending_partners, 'liveEvents': live_events, 'eventsToday': events_today, 'ticketSales': ticket_sales, 'ticketGrowth': ticket_growth, }) class DashboardRevenueView(APIView): permission_classes = [IsAuthenticated] def get(self, request): from ledger.models import RazorpayTransaction from banking_operations.models import PaymentTransaction from django.db.models import Sum from django.utils import timezone import datetime today = timezone.now().date() result = [] for i in range(6, -1, -1): day = today - datetime.timedelta(days=i) rev_paise = ( RazorpayTransaction.objects .filter(status='captured', captured_at__date=day) .aggregate(total=Sum('amount'))['total'] or 0 ) revenue = rev_paise / 100 payouts = ( PaymentTransaction.objects .filter( payment_type='debit', payment_transaction_status='completed', payment_transaction_date=day, ) .aggregate(total=Sum('payment_transaction_amount'))['total'] or 0 ) result.append({ 'day': day.strftime('%a'), 'revenue': float(revenue), 'payouts': float(payouts), }) return Response(result) class DashboardActivityView(APIView): permission_classes = [IsAuthenticated] def get(self, request): from partner.models import Partner from events.models import Event from bookings.models import Booking from django.utils import timezone items = [] # --- Partners (last 5 by id desc; no date field — timestamp=None, filtered out later) --- for p in Partner.objects.order_by('-id')[:5]: items.append({ 'id': f'partner-{p.id}', 'type': 'partner', 'title': f'{p.name} registered', 'description': f'New partner — {getattr(p, "partner_type", "individual")}', 'timestamp': None, 'status': p.kyc_compliance_status, }) # --- Events (last 5 by created_date desc) --- for e in Event.objects.order_by('-created_date')[:5]: display_name = e.title if getattr(e, 'title', None) else getattr(e, 'name', '') ts = e.created_date items.append({ 'id': f'event-{e.id}', 'type': 'event', 'title': f'{display_name} created', 'description': f'Event status: {e.event_status}', 'timestamp': ts.isoformat() if ts else None, 'status': e.event_status, }) # --- Bookings (last 5 by id desc) --- for b in Booking.objects.order_by('-id')[:5]: ts = b.created_date items.append({ 'id': f'booking-{b.booking_id}', 'type': 'booking', 'title': f'Booking {b.booking_id} placed', 'description': f'{b.quantity} ticket(s) at ₹{b.price}', 'timestamp': ts.isoformat() if ts else None, 'status': 'confirmed', }) # Filter out items with no timestamp, sort desc, return top 10 dated = [item for item in items if item['timestamp'] is not None] dated.sort(key=lambda x: x['timestamp'], reverse=True) return Response(dated[:10]) class DashboardActionsView(APIView): permission_classes = [IsAuthenticated] def get(self, request): from partner.models import Partner from events.models import Event from banking_operations.models import PaymentTransaction from django.db.models import Sum kyc_count = Partner.objects.filter(kyc_compliance_status='pending').count() flagged_count = Event.objects.filter(event_status='flagged').count() pending_payouts = float( PaymentTransaction.objects .filter(payment_type='debit', payment_transaction_status='pending') .aggregate(total=Sum('payment_transaction_amount'))['total'] or 0 ) actions = [ { 'id': 'kyc', 'type': 'kyc', 'count': kyc_count, 'title': 'Partner Approval Queue', 'description': f'{kyc_count} partners awaiting KYC review', 'href': '/partners?filter=pending', 'priority': 'high', }, { 'id': 'flagged', 'type': 'flagged', 'count': flagged_count, 'title': 'Flagged Events', 'description': f'{flagged_count} events reported for review', 'href': '/events?filter=flagged', 'priority': 'high', }, { 'id': 'payout', 'type': 'payout', 'count': pending_payouts, 'title': 'Pending Payouts', 'description': f'₹{pending_payouts:,.0f} ready for release', 'href': '/financials?tab=payouts', 'priority': 'medium', }, ] return Response(actions)