seller_central_backend/api/shipping_views.py
vickytechkey 517563b9e5
All checks were successful
Deploy Beta (NATIVE) / deploy (push) Successful in 55s
feat(shipping): store logistics ETA internally in Order database
2026-10-14 21:49:39 +05:30

317 lines
12 KiB
Python

import logging
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, AllowAny
from .shipping_client import ShippingServiceClient
from .models import Order, ReturnRequest, SupplierProfile
logger = logging.getLogger('api')
class ShippingHealthView(APIView):
permission_classes = [AllowAny]
def get(self, request):
client = ShippingServiceClient()
res = client.check_health()
is_ok = res.get('status', '').lower() in ('healthy', 'success')
return Response(res, status=status.HTTP_200_OK if is_ok else status.HTTP_503_SERVICE_UNAVAILABLE)
class ForwardServiceabilityView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
pincodes = request.data.get('pincodes')
service = request.data.get('service', 'express')
if not pincodes:
return Response({'error': 'pincodes is required'}, status=status.HTTP_400_BAD_REQUEST)
client = ShippingServiceClient()
res = client.check_forward_serviceability(pincodes, service=service)
return Response(res)
class ForwardCreatePickupView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
order_id = request.data.get('order_id')
if not order_id:
return Response({'error': 'order_id is required'}, status=status.HTTP_400_BAD_REQUEST)
order = Order.objects.filter(supplier=request.user, order_id=order_id).first()
if not order:
order = Order.objects.filter(supplier=request.user, id=order_id).first()
if not order:
return Response({'error': f'Order {order_id} not found'}, status=status.HTTP_404_NOT_FOUND)
profile = getattr(request.user, 'profile', None)
pickup_details = request.data.get('pickup_details')
customer_details = request.data.get('customer_details')
product_details = request.data.get('product_details')
pkg_weight = request.data.get('weight') or request.data.get('package_weight')
client = ShippingServiceClient()
shipping_res = client.create_delivery_pickup(
order,
supplier_profile=profile,
pickup_details=pickup_details,
customer_details=customer_details,
product_details=product_details,
weight=pkg_weight
)
is_ok = shipping_res.get('status', '').lower() in ('success', 'healthy') or shipping_res.get('status_code') in (200, 201)
data = shipping_res.get('data', {}) if isinstance(shipping_res.get('data'), dict) else {}
awb = data.get('awb_number')
if not is_ok or not awb or shipping_res.get('status') == 'error':
return Response(
{'error': shipping_res.get('message') or 'Shipping service unavailable for location'},
status=status.HTTP_400_BAD_REQUEST
)
assigned_carrier = data.get('carrier')
if not assigned_carrier:
assigned_carrier = 'Delhivery Logistics' if str(awb).startswith(('DELHI', '179', '139', '142', '12', '14', '698')) else ('Ekart Logistics' if str(awb).startswith(('EKART', 'ELIT')) else 'Shadowfax Logistics')
order.carrier = assigned_carrier
order.tracking = awb
order.status = 'Ready to Ship'
order.save()
return Response(shipping_res)
class ForwardTrackView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
awb = request.query_params.get('awb') or request.query_params.get('tracking')
order_id = request.query_params.get('order_id')
if not awb and order_id:
order = Order.objects.filter(supplier=request.user, order_id=order_id).first()
if not order:
order = Order.objects.filter(supplier=request.user, id=order_id).first()
if order and order.tracking and order.tracking not in ('Pending', 'N/A'):
awb = order.tracking
if not awb:
return Response({'error': 'awb query parameter or valid order_id is required'}, status=status.HTTP_400_BAD_REQUEST)
client = ShippingServiceClient()
res = client.track_delivery_order(awb)
# Store logistics ETA internally in DB
try:
r_data = res.get('data', {}) if isinstance(res.get('data'), dict) else {}
eta_val = r_data.get('expected_delivery_date') or (r_data.get('order_details') or {}).get('expected_delivery_date') or r_data.get('eta')
if eta_val:
Order.objects.filter(tracking=str(awb).strip()).update(eta=str(eta_val), expected_delivery_date=str(eta_val))
if order_id:
Order.objects.filter(order_id=str(order_id).strip()).update(eta=str(eta_val), expected_delivery_date=str(eta_val))
except Exception as e:
logger.warning(f"Failed to persist ETA in ForwardTrackView: {e}")
return Response(res)
class ForwardCancelView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
order_id = request.data.get('order_id')
awb = request.data.get('awb_number')
reason = request.data.get('reason', 'Seller requested cancellation')
if not order_id and not awb:
return Response({'error': 'order_id or awb_number is required'}, status=status.HTTP_400_BAD_REQUEST)
order = None
if order_id:
order = Order.objects.filter(supplier=request.user, order_id=order_id).first()
if not order:
order = Order.objects.filter(supplier=request.user, id=order_id).first()
if order and not awb:
awb = order.tracking
client = ShippingServiceClient()
res = client.cancel_delivery_order(client_order_id=order_id or "ORD-CANCEL", awb_number=awb, reason=reason)
is_ok = res.get('status', '').lower() in ('success', 'healthy') or res.get('status_code') in (200, 201)
if is_ok and order:
order.status = 'Cancelled'
order.save()
return Response(res)
class ReverseServiceabilityView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
pincodes = request.data.get('pincodes')
if not pincodes:
return Response({'error': 'pincodes is required'}, status=status.HTTP_400_BAD_REQUEST)
client = ShippingServiceClient()
res = client.check_reverse_serviceability(pincodes)
return Response(res)
class ReverseCreatePickupView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
return_id = request.data.get('return_id')
if not return_id:
return Response({'error': 'return_id is required'}, status=status.HTTP_400_BAD_REQUEST)
ret = ReturnRequest.objects.filter(supplier=request.user, return_id=return_id).first()
if not ret:
ret = ReturnRequest.objects.filter(supplier=request.user, id=return_id).first()
if not ret:
return Response({'error': f'Return request {return_id} not found'}, status=status.HTTP_404_NOT_FOUND)
profile = getattr(request.user, 'profile', None)
pickup_details = request.data.get('pickup_details')
return_details = request.data.get('return_details')
qc_details = request.data.get('qc_details')
client = ShippingServiceClient()
res = client.create_customer_return_pickup(
ret,
supplier_profile=profile,
pickup_details=pickup_details,
return_details=return_details,
qc_details=qc_details
)
is_ok = res.get('status', '').lower() in ('success', 'healthy') or res.get('status_code') in (200, 201)
if is_ok:
data = res.get('data', {}) if isinstance(res.get('data'), dict) else {}
awb = data.get('awb_number') or f"SFX-REV-{ret.id}"
ret.returning_tracking = awb
ret.status = 'In Transit'
ret.save()
return Response(res)
class ReverseTrackView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
client_request_id = request.query_params.get('client_request_id') or request.query_params.get('return_id')
if not client_request_id:
return Response({'error': 'client_request_id query parameter is required'}, status=status.HTTP_400_BAD_REQUEST)
client = ShippingServiceClient()
res = client.track_customer_return_pickup(client_request_id)
return Response(res)
class ReverseUpdateQCView(APIView):
permission_classes = [IsAuthenticated]
def put(self, request):
client_request_id = request.data.get('client_request_id') or request.data.get('return_id')
if not client_request_id:
return Response({'error': 'client_request_id is required'}, status=status.HTTP_400_BAD_REQUEST)
qc_check = request.data.get('qc_check', True)
serial_number = request.data.get('serial_number')
brand_name = request.data.get('brand_name')
item_name = request.data.get('item_name')
client = ShippingServiceClient()
res = client.update_return_qc(
client_request_id,
qc_check=qc_check,
serial_number=serial_number,
brand_name=brand_name,
item_name=item_name
)
return Response(res)
class ForwardLabelView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
order_id = request.query_params.get('order_id')
if not order_id:
return Response({'error': 'order_id is required'}, status=status.HTTP_400_BAD_REQUEST)
order = Order.objects.filter(supplier=request.user, order_id=order_id).first()
if not order:
order = Order.objects.filter(supplier=request.user, id=order_id).first()
if not order:
return Response({'error': f'Order {order_id} not found'}, status=status.HTTP_404_NOT_FOUND)
profile = getattr(request.user, 'profile', None)
client = ShippingServiceClient()
res = client.generate_shipping_label(order, supplier_profile=profile)
if res.get('status') == 'error':
return Response(res, status=status.HTTP_400_BAD_REQUEST)
return Response(res)
class ReverseLabelView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
return_id = request.query_params.get('return_id')
if not return_id:
return Response({'error': 'return_id is required'}, status=status.HTTP_400_BAD_REQUEST)
ret = ReturnRequest.objects.filter(supplier=request.user, return_id=return_id).first()
if not ret:
ret = ReturnRequest.objects.filter(supplier=request.user, id=return_id).first()
if not ret:
return Response({'error': f'Return request {return_id} not found'}, status=status.HTTP_404_NOT_FOUND)
profile = getattr(request.user, 'profile', None)
client = ShippingServiceClient()
res = client.generate_return_label(ret, supplier_profile=profile)
return Response(res)
class ForwardSchedulePickupView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
carrier = request.query_params.get('carrier')
client = ShippingServiceClient()
res = client.get_pickup_capabilities(carrier)
return Response(res)
def post(self, request):
order_id = request.data.get('order_id')
if not order_id:
return Response({'error': 'order_id is required'}, status=status.HTTP_400_BAD_REQUEST)
order = Order.objects.filter(supplier=request.user, order_id=order_id).first()
if not order:
order = Order.objects.filter(supplier=request.user, id=order_id).first()
if not order:
return Response({'error': f'Order {order_id} not found'}, status=status.HTTP_404_NOT_FOUND)
pickup_date = request.data.get('pickup_date') or request.data.get('date')
pickup_time = request.data.get('pickup_time') or request.data.get('time') or request.data.get('slot')
package_count = request.data.get('package_count') or 1
notes = request.data.get('notes')
profile = getattr(request.user, 'profile', None)
client = ShippingServiceClient()
res = client.schedule_pickup(
order,
pickup_date=pickup_date,
pickup_time=pickup_time,
package_count=package_count,
notes=notes,
supplier_profile=profile
)
return Response(res)