crmbackend/crm/views/seller_views.py

274 lines
10 KiB
Python

from rest_framework import status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from crm.permissions import IsCRMAdmin
from seller_models.models import SupplierProfile, Product
from crm.models import AuditLog
from crm.serializers import SupplierProfileSerializer, ProductSerializer
from crm.services.whatsapp_service import WhatsAppService
from django.utils import timezone
whatsapp_service = WhatsAppService()
def log_action(admin, action, target_id, details):
AuditLog.objects.create(
admin=admin,
action=action,
target_type='seller',
target_id=target_id,
details=details
)
@api_view(['GET'])
@permission_classes([IsCRMAdmin])
def list_sellers(request):
sellers = SupplierProfile.objects.all()
status_filter = request.query_params.get('status')
if status_filter:
sellers = sellers.filter(status=status_filter)
serializer = SupplierProfileSerializer(sellers, many=True)
return Response(serializer.data)
@api_view(['GET'])
@permission_classes([IsCRMAdmin])
def get_seller_detail(request, pk):
try:
seller = SupplierProfile.objects.get(pk=pk)
except SupplierProfile.DoesNotExist:
return Response({"detail": "Seller not found"}, status=404)
serializer = SupplierProfileSerializer(seller)
return Response(serializer.data)
APPROVED_DOCUMENTS = set()
@api_view(['GET'])
@permission_classes([IsCRMAdmin])
def get_seller_documents(request, pk):
try:
seller = SupplierProfile.objects.get(pk=pk)
except SupplierProfile.DoesNotExist:
return Response({"detail": "Seller not found"}, status=404)
docs = []
aadhar_key = seller.aadhar_s3_key or seller.aadhar_file
if aadhar_key:
is_verified = f"aadhar_{pk}" in APPROVED_DOCUMENTS
preview_url = f"/sellers/documents/preview/?file={aadhar_key}"
docs.append({
"id": "aadhar",
"type": "Aadhar Card",
"filename": aadhar_key,
"url": preview_url,
"preview_url": preview_url,
"status": "Verified" if is_verified else "Pending"
})
pan_key = seller.pan_s3_key or seller.pan_file
if pan_key:
is_verified = f"pan_{pk}" in APPROVED_DOCUMENTS
preview_url = f"/sellers/documents/preview/?file={pan_key}"
docs.append({
"id": "pan",
"type": "PAN Card",
"filename": pan_key,
"url": preview_url,
"preview_url": preview_url,
"status": "Verified" if is_verified else "Pending"
})
if seller.gstin:
is_verified = f"gstin_{pk}" in APPROVED_DOCUMENTS or seller.is_gstin_verified
filename = f"gst_{seller.gstin}.pdf"
preview_url = f"/sellers/documents/preview/?file={filename}"
docs.append({
"id": "gstin",
"type": "GSTIN Certificate",
"filename": filename,
"url": preview_url,
"preview_url": preview_url,
"status": "Verified" if is_verified else "Pending"
})
return Response(docs)
@api_view(['POST'])
@permission_classes([IsCRMAdmin])
def approve_seller_document(request, pk, doc_id):
try:
seller = SupplierProfile.objects.get(pk=pk)
except SupplierProfile.DoesNotExist:
return Response({"detail": "Seller not found"}, status=404)
APPROVED_DOCUMENTS.add(f"{doc_id}_{pk}")
if doc_id == "gstin":
seller.is_gstin_verified = True
seller.save()
return Response({"message": f"Document '{doc_id}' successfully approved"})
@api_view(['POST'])
@permission_classes([IsCRMAdmin])
def approve_seller(request, pk):
try:
seller = SupplierProfile.objects.get(pk=pk)
except SupplierProfile.DoesNotExist:
return Response({"detail": "Seller not found"}, status=404)
old_status = seller.status
seller.status = 'approved'
seller.save()
log_action(request.user, 'approve_seller', seller.id, {"old_status": old_status, "new_status": "approved"})
whatsapp_service.send_template_alert(seller.phone, "seller_approved", {"name": seller.name})
return Response({"message": f"Seller {seller.name} approved successfully"})
@api_view(['POST'])
@permission_classes([IsCRMAdmin])
def reject_seller(request, pk):
reason = request.data.get('reason', 'Documents validation failed')
try:
seller = SupplierProfile.objects.get(pk=pk)
except SupplierProfile.DoesNotExist:
return Response({"detail": "Seller not found"}, status=404)
old_status = seller.status
seller.status = 'rejected'
seller.save()
log_action(request.user, 'reject_seller', seller.id, {"old_status": old_status, "new_status": "rejected", "reason": reason})
whatsapp_service.send_template_alert(seller.phone, "seller_rejected", {"name": seller.name, "reason": reason})
return Response({"message": f"Seller {seller.name} rejected successfully"})
@api_view(['POST'])
@permission_classes([IsCRMAdmin])
def suspend_seller(request, pk):
reason = request.data.get('reason', 'Policy violation')
try:
seller = SupplierProfile.objects.get(pk=pk)
except SupplierProfile.DoesNotExist:
return Response({"detail": "Seller not found"}, status=404)
old_status = seller.status
seller.status = 'suspended'
seller.save()
log_action(request.user, 'suspend_seller', seller.id, {"old_status": old_status, "new_status": "suspended", "reason": reason})
whatsapp_service.send_template_alert(seller.phone, "seller_suspended", {"name": seller.name, "reason": reason})
return Response({"message": f"Seller {seller.name} suspended successfully"})
@api_view(['POST'])
@permission_classes([IsCRMAdmin])
def reinstate_seller(request, pk):
try:
seller = SupplierProfile.objects.get(pk=pk)
except SupplierProfile.DoesNotExist:
return Response({"detail": "Seller not found"}, status=404)
old_status = seller.status
seller.status = 'approved'
seller.save()
log_action(request.user, 'reinstate_seller', seller.id, {"old_status": old_status, "new_status": "approved"})
whatsapp_service.send_template_alert(seller.phone, "seller_reinstated", {"name": seller.name})
return Response({"message": f"Seller {seller.name} reinstated successfully"})
@api_view(['POST'])
@permission_classes([IsCRMAdmin])
def reset_seller_password(request, pk):
try:
seller = SupplierProfile.objects.get(pk=pk)
except SupplierProfile.DoesNotExist:
return Response({"detail": "Seller not found"}, status=404)
# Trigger password reset flow
whatsapp_service.send_otp(seller.phone, otp_type="password_reset")
log_action(request.user, 'reset_password', seller.id, {"email": seller.email})
return Response({"message": "Password reset alert successfully dispatched"})
@api_view(['POST', 'DELETE'])
@permission_classes([IsCRMAdmin])
def delete_seller(request, pk):
try:
seller = SupplierProfile.objects.get(pk=pk)
except SupplierProfile.DoesNotExist:
return Response({"detail": "Seller not found"}, status=404)
name = seller.name
user_id = seller.user_id
# Delete supplier profile from sellerprofile db
seller.delete()
# Delete corresponding user from auth_user in sellerprofile db
from django.db import connections
try:
with connections['seller_db'].cursor() as cursor:
cursor.execute("DELETE FROM auth_user WHERE id = %s", [user_id])
except Exception as e:
print("Failed to delete user record from auth_user:", e)
log_action(request.user, 'delete_seller', pk, {"name": name})
return Response({"message": f"Seller account '{name}' and associated user permanently removed"})
import io
from django.http import FileResponse
from django.views.decorators.clickjacking import xframe_options_exempt
from rest_framework.permissions import AllowAny
@api_view(['GET'])
@permission_classes([AllowAny])
@xframe_options_exempt
def preview_document(request):
filename = request.query_params.get('file', 'document.pdf')
# Dynamic S3 Presigned Redirect if AWS credentials are set
import os
aws_access = os.environ.get('AWS_ACCESS_KEY_ID') or os.environ.get('AWS_ACCESS_KEY')
aws_secret = os.environ.get('AWS_SECRET_ACCESS_KEY') or os.environ.get('AWS_SECRET_KEY')
bucket_name = os.environ.get('AWS_STORAGE_BUCKET_NAME') or os.environ.get('AWS_BUCKET_NAME') or 'betasupplierdocument-764709663363-ap-south-2-an'
if aws_access and aws_secret:
try:
import boto3
from django.shortcuts import redirect
s3_client = boto3.client(
's3',
aws_access_key_id=aws_access,
aws_secret_access_key=aws_secret,
region_name=os.environ.get('AWS_REGION', 'ap-south-2')
)
presigned_url = s3_client.generate_presigned_url(
'get_object',
Params={'Bucket': bucket_name, 'Key': filename},
ExpiresIn=3600
)
return redirect(presigned_url)
except Exception as e:
print("S3 redirect helper failed, falling back to mock files:", e)
if filename.endswith('.pdf'):
pdf_data = (
b"%PDF-1.4\n"
b"1 0 obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n"
b"2 0 obj\n<< /Type /Pages /Kids [3 0 R] /Count 1 >>\nendobj\n"
b"3 0 obj\n<< /Type /Page /Parent 2 0 R /MediaBox [0 0 595 842] /Contents 4 0 R >>\nendobj\n"
b"4 0 obj\n<< /Length 73 >>\nstream\n"
b"BT\n/F1 24 Tf\n100 700 Td\n(DigiHox Verified KYC Document Preview) Tj\nET\n"
b"endstream\n"
b"endobj\n"
b"xref\n0 5\n0000000000 65535 f\n0000000009 00000 n\n0000000056 00000 n\n"
b"0000000111 00000 n\n0000000212 00000 n\n"
b"trailer\n<< /Size 5 /Root 1 0 R >>\nstartxref\n335\n%%EOF\n"
)
return FileResponse(io.BytesIO(pdf_data), content_type='application/pdf')
else:
png_data = (
b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x06\x00\x00\x00\x1f\x15\xc4\x89'
b'\x00\x00\x00\rIDATx\x9cc`\x00\x00\x00\x02\x00\x01H\xaf\xa4q\x00\x00\x00\x00IEND\xaeB`\x82'
)
return FileResponse(io.BytesIO(png_data), content_type='image/png')