Files
eventify_backend/partner/api.py

1119 lines
44 KiB
Python
Raw Normal View History

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)