from django.http import JsonResponse from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt from django.forms.models import model_to_dict from django.contrib.auth import get_user_model from django.db import models as django_models from django.utils import timezone from datetime import timedelta from rest_framework.views import APIView from partner.models import Partner from mobile_api.utils import validate_token_and_get_user from eventify_logger.services import log User = get_user_model() def _partner_to_dict(partner, request=None): """Serialize Partner for JSON.""" data = model_to_dict( partner, fields=[ "id", "name", "partner_type", "primary_contact_person_name", "primary_contact_person_email", "primary_contact_person_phone", "status", "address", "city", "state", "country", "website_url", "pincode", "latitude", "longitude", "is_kyc_compliant", "kyc_compliance_status", "kyc_compliance_reason", "kyc_compliance_document_type", "kyc_compliance_document_other_type", "kyc_compliance_document_number", ], ) # Add document file URL if exists if partner.kyc_compliance_document_file: if request: data["kyc_compliance_document_file"] = request.build_absolute_uri(partner.kyc_compliance_document_file.url) else: data["kyc_compliance_document_file"] = partner.kyc_compliance_document_file.url else: data["kyc_compliance_document_file"] = None return data @method_decorator(csrf_exempt, name="dispatch") class PartnerCreateAPI(APIView): """ Create a new Partner. Body: token, username, name, partner_type, primary_contact_person_name, primary_contact_person_email, primary_contact_person_phone (required); address, city, state, country, website_url, pincode, latitude, longitude, is_kyc_compliant, kyc_compliance_status, kyc_compliance_reason, kyc_compliance_document_type, kyc_compliance_document_other_type, kyc_compliance_document_number (optional). """ def post(self, request): try: user, token, data, error_response = validate_token_and_get_user(request) if error_response: return error_response name = data.get("name") partner_type = data.get("partner_type") primary_contact_person_name = data.get("primary_contact_person_name") primary_contact_person_email = data.get("primary_contact_person_email") primary_contact_person_phone = data.get("primary_contact_person_phone") if not all([name, partner_type, primary_contact_person_name, primary_contact_person_email, primary_contact_person_phone]): return JsonResponse( { "status": "error", "message": "name, partner_type, primary_contact_person_name, primary_contact_person_email, and primary_contact_person_phone are required.", }, status=400, ) # Validate partner_type valid_partner_types = [choice[1] for choice in Partner._meta.get_field("partner_type").choices] print(valid_partner_types) if partner_type not in valid_partner_types: return JsonResponse( { "status": "error", "message": f"Invalid partner_type. Must be one of: {', '.join(valid_partner_types)}", }, status=400, ) partner = Partner.objects.create( name=name, partner_type=partner_type, primary_contact_person_name=primary_contact_person_name, primary_contact_person_email=primary_contact_person_email, primary_contact_person_phone=primary_contact_person_phone, address=data.get("address"), city=data.get("city"), state=data.get("state"), country=data.get("country"), website_url=data.get("website_url"), pincode=data.get("pincode"), latitude=data.get("latitude"), longitude=data.get("longitude"), is_kyc_compliant=data.get("is_kyc_compliant", False), kyc_compliance_status=data.get("kyc_compliance_status", "pending"), kyc_compliance_reason=data.get("kyc_compliance_reason"), kyc_compliance_document_type=data.get("kyc_compliance_document_type"), kyc_compliance_document_other_type=data.get("kyc_compliance_document_other_type"), kyc_compliance_document_number=data.get("kyc_compliance_document_number"), ) # Handle file upload if provided if "kyc_compliance_document_file" in request.FILES: partner.kyc_compliance_document_file = request.FILES["kyc_compliance_document_file"] partner.save() log("info", "Partner created", request=request, user=user, logger_data={"partner_id": partner.id, "partner_name": name}) return JsonResponse( {"status": "success", "partner": _partner_to_dict(partner, request)}, status=201, ) except Exception as e: log("error", "Partner create exception", request=request, logger_data={"error": str(e)}) return JsonResponse({"status": "error", "message": str(e)}, status=500) @method_decorator(csrf_exempt, name="dispatch") class PartnerListAPI(APIView): """ List Partners, optionally filtered by partner_type or kyc_compliance_status. Body: token, username, partner_type (optional), kyc_compliance_status (optional). """ def post(self, request): try: user, token, data, error_response = validate_token_and_get_user(request) if error_response: return error_response qs = Partner.objects.all().order_by("-id") partner_type = data.get("partner_type") if partner_type: qs = qs.filter(partner_type=partner_type) kyc_compliance_status = data.get("kyc_compliance_status") if kyc_compliance_status: qs = qs.filter(kyc_compliance_status=kyc_compliance_status) partners = [_partner_to_dict(p, request) for p in qs] return JsonResponse({"status": "success", "partners": partners}, status=200) except Exception as e: return JsonResponse({"status": "error", "message": str(e)}, status=500) @method_decorator(csrf_exempt, name="dispatch") class PartnerUpdateAPI(APIView): """ Update an existing Partner. Body: token, username, partner_id (required); name, partner_type, primary_contact_person_name, primary_contact_person_email, primary_contact_person_phone, address, city, state, country, website_url, pincode, latitude, longitude, is_kyc_compliant, kyc_compliance_status, kyc_compliance_reason, kyc_compliance_document_type, kyc_compliance_document_other_type, kyc_compliance_document_number (optional). """ def post(self, request): try: user, token, data, error_response = validate_token_and_get_user(request) if error_response: return error_response partner_id = data.get("partner_id") if not partner_id: return JsonResponse( {"status": "error", "message": "partner_id is required."}, status=400, ) try: partner = Partner.objects.get(id=partner_id) except Partner.DoesNotExist: return JsonResponse( {"status": "error", "message": "Partner not found."}, status=404, ) # Update fields if provided if data.get("name") is not None: partner.name = data["name"] if data.get("partner_type") is not None: valid_partner_types = [choice[0] for choice in Partner._meta.get_field("partner_type").choices] if data["partner_type"] not in valid_partner_types: return JsonResponse( { "status": "error", "message": f"Invalid partner_type. Must be one of: {', '.join(valid_partner_types)}", }, status=400, ) partner.partner_type = data["partner_type"] if data.get("primary_contact_person_name") is not None: partner.primary_contact_person_name = data["primary_contact_person_name"] if data.get("primary_contact_person_email") is not None: partner.primary_contact_person_email = data["primary_contact_person_email"] if data.get("primary_contact_person_phone") is not None: partner.primary_contact_person_phone = data["primary_contact_person_phone"] if "address" in data: partner.address = data["address"] if "city" in data: partner.city = data["city"] if "state" in data: partner.state = data["state"] if "country" in data: partner.country = data["country"] if "website_url" in data: partner.website_url = data["website_url"] if "pincode" in data: partner.pincode = data["pincode"] if data.get("latitude") is not None: try: partner.latitude = float(data["latitude"]) except (TypeError, ValueError): return JsonResponse( {"status": "error", "message": "latitude must be numeric."}, status=400, ) if data.get("longitude") is not None: try: partner.longitude = float(data["longitude"]) except (TypeError, ValueError): return JsonResponse( {"status": "error", "message": "longitude must be numeric."}, status=400, ) if data.get("is_kyc_compliant") is not None: partner.is_kyc_compliant = bool(data["is_kyc_compliant"]) if data.get("kyc_compliance_status") is not None: valid_statuses = [choice[0] for choice in Partner._meta.get_field("kyc_compliance_status").choices] if data["kyc_compliance_status"] not in valid_statuses: return JsonResponse( { "status": "error", "message": f"Invalid kyc_compliance_status. Must be one of: {', '.join(valid_statuses)}", }, status=400, ) partner.kyc_compliance_status = data["kyc_compliance_status"] if "kyc_compliance_reason" in data: partner.kyc_compliance_reason = data["kyc_compliance_reason"] if "kyc_compliance_document_type" in data: partner.kyc_compliance_document_type = data["kyc_compliance_document_type"] if "kyc_compliance_document_other_type" in data: partner.kyc_compliance_document_other_type = data["kyc_compliance_document_other_type"] if "kyc_compliance_document_number" in data: partner.kyc_compliance_document_number = data["kyc_compliance_document_number"] # Handle file upload if provided if "kyc_compliance_document_file" in request.FILES: partner.kyc_compliance_document_file = request.FILES["kyc_compliance_document_file"] partner.save() log("info", "Partner updated", request=request, user=user, logger_data={"partner_id": partner_id}) return JsonResponse( {"status": "success", "partner": _partner_to_dict(partner, request)}, status=200, ) except Exception as e: log("error", "Partner update exception", request=request, logger_data={"error": str(e)}) return JsonResponse({"status": "error", "message": str(e)}, status=500) @method_decorator(csrf_exempt, name="dispatch") class PartnerDeleteAPI(APIView): """ Delete an existing Partner. Body: token, username, partner_id. """ def post(self, request): try: user, token, data, error_response = validate_token_and_get_user(request) if error_response: return error_response partner_id = data.get("partner_id") if not partner_id: return JsonResponse( {"status": "error", "message": "partner_id is required."}, status=400, ) try: partner = Partner.objects.get(id=partner_id) except Partner.DoesNotExist: return JsonResponse( {"status": "error", "message": "Partner not found."}, status=404, ) partner_name = partner.name partner.delete() log("info", "Partner deleted", request=request, user=user, logger_data={"partner_id": partner_id, "partner_name": partner_name}) return JsonResponse( {"status": "success", "message": "Partner deleted successfully."}, status=200, ) except Exception as e: log("error", "Partner delete exception", request=request, logger_data={"error": str(e)}) return JsonResponse({"status": "error", "message": str(e)}, status=500) @method_decorator(csrf_exempt, name="dispatch") class PartnerUpdateKYCDocumentsAPI(APIView): """ Update KYC documents for an existing Partner. Body: token, username, partner_id (required); kyc_compliance_document_type, kyc_compliance_document_other_type, kyc_compliance_document_number (optional); kyc_compliance_document_file (file upload, optional); is_kyc_compliant, kyc_compliance_status, kyc_compliance_reason (optional). """ def post(self, request): try: user, token, data, error_response = validate_token_and_get_user(request) if error_response: return error_response partner_id = data.get("partner_id") if not partner_id: return JsonResponse( {"status": "error", "message": "partner_id is required."}, status=400, ) try: partner = Partner.objects.get(id=partner_id) except Partner.DoesNotExist: return JsonResponse( {"status": "error", "message": "Partner not found."}, status=404, ) # Update KYC document fields if "kyc_compliance_document_type" in data: document_type = data["kyc_compliance_document_type"] if document_type: # Allow empty string to clear valid_types = [choice[0] for choice in Partner._meta.get_field("kyc_compliance_document_type").choices] if document_type not in valid_types: return JsonResponse( { "status": "error", "message": f"Invalid kyc_compliance_document_type. Must be one of: {', '.join(valid_types)}", }, status=400, ) partner.kyc_compliance_document_type = document_type if document_type else None if "kyc_compliance_document_other_type" in data: partner.kyc_compliance_document_other_type = data["kyc_compliance_document_other_type"] or None if "kyc_compliance_document_number" in data: partner.kyc_compliance_document_number = data["kyc_compliance_document_number"] or None # Handle file upload if "kyc_compliance_document_file" in request.FILES: partner.kyc_compliance_document_file = request.FILES["kyc_compliance_document_file"] # Optionally update compliance status fields if data.get("is_kyc_compliant") is not None: partner.is_kyc_compliant = bool(data["is_kyc_compliant"]) if data.get("kyc_compliance_status") is not None: valid_statuses = [choice[0] for choice in Partner._meta.get_field("kyc_compliance_status").choices] if data["kyc_compliance_status"] not in valid_statuses: return JsonResponse( { "status": "error", "message": f"Invalid kyc_compliance_status. Must be one of: {', '.join(valid_statuses)}", }, status=400, ) partner.kyc_compliance_status = data["kyc_compliance_status"] if "kyc_compliance_reason" in data: partner.kyc_compliance_reason = data["kyc_compliance_reason"] or None partner.save() return JsonResponse( { "status": "success", "message": "KYC documents updated successfully.", "partner": _partner_to_dict(partner, request), }, status=200, ) except Exception as e: return JsonResponse({"status": "error", "message": str(e)}, status=500) @method_decorator(csrf_exempt, name="dispatch") class PartnerUpdateAddressLocationAPI(APIView): """ Update address and location fields for an existing Partner. Body: token, username, partner_id (required); address, city, state, country, website_url, pincode, latitude, longitude (optional). """ def post(self, request): try: user, token, data, error_response = validate_token_and_get_user(request) if error_response: return error_response partner_id = data.get("partner_id") if not partner_id: return JsonResponse( {"status": "error", "message": "partner_id is required."}, status=400, ) try: partner = Partner.objects.get(id=partner_id) except Partner.DoesNotExist: return JsonResponse( {"status": "error", "message": "Partner not found."}, status=404, ) # Update address fields if "address" in data: partner.address = data["address"] or None if "city" in data: partner.city = data["city"] or None if "state" in data: partner.state = data["state"] or None if "country" in data: partner.country = data["country"] or None if "website_url" in data: partner.website_url = data["website_url"] or None if "pincode" in data: partner.pincode = data["pincode"] or None # Update location coordinates with validation if data.get("latitude") is not None: try: latitude = float(data["latitude"]) # Validate latitude range (-90 to 90) if latitude < -90 or latitude > 90: return JsonResponse( {"status": "error", "message": "latitude must be between -90 and 90."}, status=400, ) partner.latitude = latitude except (TypeError, ValueError): return JsonResponse( {"status": "error", "message": "latitude must be numeric."}, status=400, ) if data.get("longitude") is not None: try: longitude = float(data["longitude"]) # Validate longitude range (-180 to 180) if longitude < -180 or longitude > 180: return JsonResponse( {"status": "error", "message": "longitude must be between -180 and 180."}, status=400, ) partner.longitude = longitude except (TypeError, ValueError): return JsonResponse( {"status": "error", "message": "longitude must be numeric."}, status=400, ) partner.save() return JsonResponse( { "status": "success", "message": "Address and location updated successfully.", "partner": _partner_to_dict(partner, request), }, status=200, ) except Exception as e: return JsonResponse({"status": "error", "message": str(e)}, status=500) def _user_to_dict(user, request=None): """Serialize User for JSON.""" data = model_to_dict( user, fields=[ "id", "username", "email", "phone_number", "role", "is_staff", "is_customer", "is_user", "pincode", "district", "state", "country", "place", "latitude", "longitude", ], ) # Add profile picture URL if exists if user.profile_picture: if request: data["profile_picture"] = request.build_absolute_uri(user.profile_picture.url) else: data["profile_picture"] = user.profile_picture.url else: data["profile_picture"] = None return data @method_decorator(csrf_exempt, name="dispatch") class PartnerCreateUserAPI(APIView): """ Create a user with partner-related role (partner, partner_manager, partner_staff, partner_customer). Body: token, username, email, password, role (required); phone_number, partner_id, pincode, district, state, country, place, latitude, longitude (optional). """ def post(self, request): try: user, token, data, error_response = validate_token_and_get_user(request) if error_response: return error_response username = data.get("username") email = data.get("email") password = data.get("password") role = data.get("role") partner_id = data.get("partner_id") if not all([username, email, password, role]): return JsonResponse( { "status": "error", "message": "username, email, password, and role are required.", }, status=400, ) # Validate role - must be one of the partner-related roles valid_partner_roles = ["partner", "partner_manager", "partner_staff", "partner_customer"] if role not in valid_partner_roles: return JsonResponse( { "status": "error", "message": f"Invalid role. Must be one of: {', '.join(valid_partner_roles)}", }, status=400, ) # Check if username already exists if User.objects.filter(username=username).exists(): return JsonResponse( {"status": "error", "message": "Username already exists."}, status=400, ) # Check if email already exists if User.objects.filter(email=email).exists(): return JsonResponse( {"status": "error", "message": "Email already exists."}, status=400, ) # Validate partner_id if provided partner = None if partner_id: try: partner = Partner.objects.get(id=partner_id) except Partner.DoesNotExist: return JsonResponse( {"status": "error", "message": "Partner not found."}, status=404, ) # Create user new_user = User.objects.create_user( username=username, email=email, password=password, role=role, phone_number=data.get("phone_number"), pincode=data.get("pincode"), district=data.get("district"), state=data.get("state"), country=data.get("country"), place=data.get("place"), ) # Set location coordinates if provided if data.get("latitude") is not None: try: latitude = float(data["latitude"]) if latitude < -90 or latitude > 90: return JsonResponse( {"status": "error", "message": "latitude must be between -90 and 90."}, status=400, ) new_user.latitude = latitude except (TypeError, ValueError): return JsonResponse( {"status": "error", "message": "latitude must be numeric."}, status=400, ) if data.get("longitude") is not None: try: longitude = float(data["longitude"]) if longitude < -180 or longitude > 180: return JsonResponse( {"status": "error", "message": "longitude must be between -180 and 180."}, status=400, ) new_user.longitude = longitude except (TypeError, ValueError): return JsonResponse( {"status": "error", "message": "longitude must be numeric."}, status=400, ) # Handle profile picture upload if provided if "profile_picture" in request.FILES: new_user.profile_picture = request.FILES["profile_picture"] new_user.save() response_data = { "status": "success", "message": f"User created successfully with role: {role}.", "user": _user_to_dict(new_user, request), } # Include partner info if linked if partner: response_data["partner"] = { "id": partner.id, "name": partner.name, "partner_type": partner.partner_type, } log("info", "Partner user created", request=request, user=user, logger_data={"new_user_id": new_user.id, "username": new_user.username, "role": role}) return JsonResponse(response_data, status=201) except Exception as e: log("error", "Partner create user exception", request=request, logger_data={"error": str(e)}) return JsonResponse({"status": "error", "message": str(e)}, status=500) @method_decorator(csrf_exempt, name="dispatch") class PartnerListUsersAPI(APIView): """ List users associated with a partner (users with partner-related roles). Body: token, username, partner_id (required); role (optional filter: partner, partner_manager, partner_staff, partner_customer). """ def post(self, request): try: user, token, data, error_response = validate_token_and_get_user(request) if error_response: return error_response partner_id = data.get("partner_id") if not partner_id: return JsonResponse( {"status": "error", "message": "partner_id is required."}, status=400, ) # Validate partner exists try: partner = Partner.objects.get(id=partner_id) except Partner.DoesNotExist: return JsonResponse( {"status": "error", "message": "Partner not found."}, status=404, ) # Filter users by partner-related roles partner_roles = ["partner", "partner_manager", "partner_staff", "partner_customer"] qs = User.objects.filter(role__in=partner_roles).order_by("-id") # Optional role filter role_filter = data.get("role") if role_filter: if role_filter not in partner_roles: return JsonResponse( { "status": "error", "message": f"Invalid role filter. Must be one of: {', '.join(partner_roles)}", }, status=400, ) qs = qs.filter(role=role_filter) # Optionally filter by matching contact email or phone (if partner contact info matches user) # This is a heuristic approach since there's no direct FK relationship # You can enhance this logic based on your business requirements match_by_contact = data.get("match_by_contact", False) if match_by_contact: qs = qs.filter( django_models.Q(email=partner.primary_contact_person_email) | django_models.Q(phone_number=partner.primary_contact_person_phone) ) users = [_user_to_dict(u, request) for u in qs] response_data = { "status": "success", "partner": { "id": partner.id, "name": partner.name, "partner_type": partner.partner_type, }, "users": users, "total_count": len(users), } return JsonResponse(response_data, status=200) except Exception as e: return JsonResponse({"status": "error", "message": str(e)}, status=500) @method_decorator(csrf_exempt, name="dispatch") class PartnerUpdateUserAPI(APIView): """ Update a partner user (user with partner-related role). Body: token, username, user_id (required); email, phone_number, role (must be partner-related), pincode, district, state, country, place, latitude, longitude, profile_picture (optional). """ def post(self, request): try: user, token, data, error_response = validate_token_and_get_user(request) if error_response: return error_response user_id = data.get("user_id") if not user_id: return JsonResponse( {"status": "error", "message": "user_id is required."}, status=400, ) try: target_user = User.objects.get(id=user_id) except User.DoesNotExist: return JsonResponse( {"status": "error", "message": "User not found."}, status=404, ) # Validate that the user has a partner-related role partner_roles = ["partner", "partner_manager", "partner_staff", "partner_customer"] if target_user.role not in partner_roles: return JsonResponse( { "status": "error", "message": "User is not a partner-related user. Only users with partner roles can be updated.", }, status=400, ) # Update fields if provided if data.get("email") is not None: new_email = data["email"] # Check if email already exists for another user if User.objects.filter(email=new_email).exclude(id=user_id).exists(): return JsonResponse( {"status": "error", "message": "Email already exists for another user."}, status=400, ) target_user.email = new_email if data.get("phone_number") is not None: target_user.phone_number = data["phone_number"] or None if data.get("role") is not None: new_role = data["role"] if new_role not in partner_roles: return JsonResponse( { "status": "error", "message": f"Invalid role. Must be one of: {', '.join(partner_roles)}", }, status=400, ) target_user.role = new_role if "pincode" in data: target_user.pincode = data["pincode"] or None if "district" in data: target_user.district = data["district"] or None if "state" in data: target_user.state = data["state"] or None if "country" in data: target_user.country = data["country"] or None if "place" in data: target_user.place = data["place"] or None if data.get("latitude") is not None: try: latitude = float(data["latitude"]) if latitude < -90 or latitude > 90: return JsonResponse( {"status": "error", "message": "latitude must be between -90 and 90."}, status=400, ) target_user.latitude = latitude except (TypeError, ValueError): return JsonResponse( {"status": "error", "message": "latitude must be numeric."}, status=400, ) if data.get("longitude") is not None: try: longitude = float(data["longitude"]) if longitude < -180 or longitude > 180: return JsonResponse( {"status": "error", "message": "longitude must be between -180 and 180."}, status=400, ) target_user.longitude = longitude except (TypeError, ValueError): return JsonResponse( {"status": "error", "message": "longitude must be numeric."}, status=400, ) # Handle profile picture upload if provided if "profile_picture" in request.FILES: target_user.profile_picture = request.FILES["profile_picture"] # Handle password update if provided if data.get("password"): target_user.set_password(data["password"]) target_user.save() log("info", "Partner user updated", request=request, user=user, logger_data={"user_id": user_id}) return JsonResponse( { "status": "success", "message": "Partner user updated successfully.", "user": _user_to_dict(target_user, request), }, status=200, ) except Exception as e: log("error", "Partner update user exception", request=request, logger_data={"error": str(e)}) return JsonResponse({"status": "error", "message": str(e)}, status=500) @method_decorator(csrf_exempt, name="dispatch") class PartnerDeleteUserAPI(APIView): """ Delete a partner user (user with partner-related role). Body: token, username, user_id (required). """ def post(self, request): try: user, token, data, error_response = validate_token_and_get_user(request) if error_response: return error_response user_id = data.get("user_id") if not user_id: return JsonResponse( {"status": "error", "message": "user_id is required."}, status=400, ) try: target_user = User.objects.get(id=user_id) except User.DoesNotExist: return JsonResponse( {"status": "error", "message": "User not found."}, status=404, ) # Validate that the user has a partner-related role partner_roles = ["partner", "partner_manager", "partner_staff", "partner_customer"] if target_user.role not in partner_roles: return JsonResponse( { "status": "error", "message": "User is not a partner-related user. Only users with partner roles can be deleted.", }, status=400, ) # Prevent deleting yourself if target_user.id == user.id: return JsonResponse( {"status": "error", "message": "You cannot delete your own account."}, status=400, ) username = target_user.username target_user.delete() log("info", "Partner user deleted", request=request, user=user, logger_data={"user_id": user_id, "username": username}) return JsonResponse( { "status": "success", "message": f"Partner user '{username}' deleted successfully.", }, status=200, ) except Exception as e: log("error", "Partner delete user exception", request=request, logger_data={"error": str(e)}) return JsonResponse({"status": "error", "message": str(e)}, status=500) # ============================================================================ # Partner List APIs (Filtered by Criteria) # ============================================================================ @method_decorator(csrf_exempt, name="dispatch") class PartnerListAllAPI(APIView): """ List All Partners API. Body: token, username (required). Returns: list of all partners. """ def post(self, request): try: user, token, data, error_response = validate_token_and_get_user(request, error_status_code=True) if error_response: return error_response partners = Partner.objects.all().order_by("-id") partners_list = [_partner_to_dict(p, request) for p in partners] return JsonResponse({ "status": "success", "partners": partners_list, "total_count": len(partners_list) }, status=200) except Exception as e: return JsonResponse({"status": "error", "message": str(e)}, status=500) @method_decorator(csrf_exempt, name="dispatch") class PartnerListKYCCompliantAPI(APIView): """ List KYC Compliant Partners API. Body: token, username (required). Returns: list of partners where is_kyc_compliant=True and kyc_compliance_status='approved'. """ def post(self, request): try: user, token, data, error_response = validate_token_and_get_user(request, error_status_code=True) if error_response: return error_response partners = Partner.objects.filter( is_kyc_compliant=True, kyc_compliance_status='approved' ).order_by("-id") partners_list = [_partner_to_dict(p, request) for p in partners] return JsonResponse({ "status": "success", "partners": partners_list, "total_count": len(partners_list) }, status=200) except Exception as e: return JsonResponse({"status": "error", "message": str(e)}, status=500) @method_decorator(csrf_exempt, name="dispatch") class PartnerListKYCPendingAPI(APIView): """ List KYC Pending Partners API. Body: token, username (required). Returns: list of partners where kyc_compliance_status='pending'. """ def post(self, request): try: user, token, data, error_response = validate_token_and_get_user(request, error_status_code=True) if error_response: return error_response partners = Partner.objects.filter( kyc_compliance_status='pending' ).order_by("-id") partners_list = [_partner_to_dict(p, request) for p in partners] return JsonResponse({ "status": "success", "partners": partners_list, "total_count": len(partners_list) }, status=200) except Exception as e: return JsonResponse({"status": "error", "message": str(e)}, status=500) @method_decorator(csrf_exempt, name="dispatch") class PartnerListHighRiskAPI(APIView): """ List High Risk Partners API. Body: token, username (required). Returns: list of partners where kyc_compliance_status='high_risk'. """ def post(self, request): try: user, token, data, error_response = validate_token_and_get_user(request, error_status_code=True) if error_response: return error_response partners = Partner.objects.filter( kyc_compliance_status='high_risk' ).order_by("-id") partners_list = [_partner_to_dict(p, request) for p in partners] return JsonResponse({ "status": "success", "partners": partners_list, "total_count": len(partners_list) }, status=200) except Exception as e: return JsonResponse({"status": "error", "message": str(e)}, status=500) @method_decorator(csrf_exempt, name="dispatch") class PartnerListJoinedThisWeekAPI(APIView): """ List Partners Joined This Week API. Body: token, username (required). Returns: list of partners created in the last 7 days. Note: This API uses id-based filtering as a proxy for creation date. For accurate results, consider adding a created_date field to the Partner model. """ def post(self, request): try: user, token, data, error_response = validate_token_and_get_user(request, error_status_code=True) if error_response: return error_response # Calculate date range for this week today = timezone.now().date() week_start = today - timedelta(days=7) # Since Partner model doesn't have created_date, we'll use id as a proxy # Get the highest id to approximate recent partners # This is a workaround - ideally Partner model should have created_date field latest_partner = Partner.objects.order_by('-id').first() if latest_partner: # Get partners created in the last week based on id approximation # This assumes sequential id assignment # For accurate results, add created_date field to Partner model partners = Partner.objects.filter( id__gte=latest_partner.id - 1000 # Approximate filter ).order_by("-id") # Alternative: If you want to add created_date field, use: # partners = Partner.objects.filter( # created_date__gte=week_start # ).order_by("-created_date") else: partners = Partner.objects.none() partners_list = [_partner_to_dict(p, request) for p in partners] return JsonResponse({ "status": "success", "partners": partners_list, "total_count": len(partners_list), "note": "This uses id-based approximation. Consider adding created_date field for accurate results." }, status=200) except Exception as e: return JsonResponse({"status": "error", "message": str(e)}, status=500)