forked from erp-dev/erp
137 lines
4.5 KiB
Python
137 lines
4.5 KiB
Python
import logging
|
|
|
|
from django.conf import settings
|
|
from rest_framework import authentication, mixins, serializers
|
|
from rest_framework.authentication import get_authorization_header
|
|
from rest_framework.exceptions import AuthenticationFailed
|
|
from rest_framework.generics import GenericAPIView
|
|
from rest_framework.permissions import IsAuthenticated
|
|
|
|
from basic_info import models as basic_models
|
|
from flower.viewsets import LimitedLimitOffsetPagination
|
|
from shipment.models import Shipment
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class AgentAccessPrincipal:
|
|
id = None
|
|
username = "agent"
|
|
is_staff = False
|
|
is_superuser = False
|
|
is_anonymous = False
|
|
is_authenticated = True
|
|
|
|
|
|
class AgentAccessKeyAuthentication(authentication.BaseAuthentication):
|
|
"""
|
|
使用固定 AGENT_ACCESS_KEY 的轻量认证。
|
|
|
|
约定:
|
|
- 通过 Authorization 头直接传入密钥
|
|
- 不使用 Bearer 前缀
|
|
"""
|
|
|
|
def authenticate(self, request):
|
|
configured_key = str(getattr(settings, "AGENT_ACCESS_KEY", "") or "").strip()
|
|
if not configured_key:
|
|
logger.warning("Agent API authentication failed: AGENT_ACCESS_KEY is not configured")
|
|
raise AuthenticationFailed("AGENT_ACCESS_KEY 未配置")
|
|
|
|
provided_key = get_authorization_header(request).decode("utf-8").strip()
|
|
if not provided_key:
|
|
raise AuthenticationFailed("缺少 Authorization 请求头")
|
|
|
|
if provided_key != configured_key:
|
|
raise AuthenticationFailed("AGENT_ACCESS_KEY 无效")
|
|
|
|
return AgentAccessPrincipal(), None
|
|
|
|
def authenticate_header(self, request):
|
|
return "AgentAccessKey"
|
|
|
|
|
|
class AgentUnshippedShipmentQuerySerializer(serializers.Serializer):
|
|
merchant_id = serializers.IntegerField(min_value=1)
|
|
area = serializers.CharField(allow_blank=False, max_length=30)
|
|
limit = serializers.IntegerField(required=False, min_value=1)
|
|
offset = serializers.IntegerField(required=False, min_value=0)
|
|
|
|
def validate(self, attrs):
|
|
area = attrs["area"].strip()
|
|
if not area:
|
|
raise serializers.ValidationError({"area": "地区不能为空"})
|
|
|
|
merchant = basic_models.Merchant.objects.filter(id=attrs["merchant_id"]).first()
|
|
if merchant is None:
|
|
raise serializers.ValidationError({"merchant_id": "商户不存在"})
|
|
|
|
attrs["area"] = area
|
|
attrs["merchant"] = merchant
|
|
return attrs
|
|
|
|
|
|
class AgentShipmentListSerializer(serializers.ModelSerializer):
|
|
customer_name = serializers.CharField(source="customer.name", read_only=True)
|
|
status_display = serializers.CharField(source="get_status_display", read_only=True)
|
|
|
|
class Meta:
|
|
model = Shipment
|
|
fields = [
|
|
"id",
|
|
"merchant_id",
|
|
"customer",
|
|
"customer_name",
|
|
"shipment_date",
|
|
"address",
|
|
"contact_name",
|
|
"contact_phone",
|
|
"area",
|
|
"remark",
|
|
"status",
|
|
"status_display",
|
|
"external_id",
|
|
"delivery",
|
|
"created_at",
|
|
"updated_at",
|
|
]
|
|
|
|
|
|
class AgentUnshippedShipmentListView(mixins.ListModelMixin, GenericAPIView):
|
|
"""
|
|
Agent 专用:查询尚未进入送货单的出货单列表。
|
|
|
|
GET /api/v2/ai/shipments/unshipped/?merchant_id=<id>&area=<地区>&limit=<n>&offset=<n>
|
|
"""
|
|
|
|
authentication_classes = [AgentAccessKeyAuthentication]
|
|
permission_classes = [IsAuthenticated]
|
|
serializer_class = AgentShipmentListSerializer
|
|
pagination_class = LimitedLimitOffsetPagination
|
|
|
|
def get(self, request):
|
|
query_serializer = AgentUnshippedShipmentQuerySerializer(data=request.query_params)
|
|
query_serializer.is_valid(raise_exception=True)
|
|
self.validated_query = query_serializer.validated_data
|
|
return self.list(request)
|
|
|
|
def get_queryset(self):
|
|
validated_query = getattr(self, "validated_query", None)
|
|
if validated_query is None:
|
|
query_serializer = AgentUnshippedShipmentQuerySerializer(data=self.request.query_params)
|
|
query_serializer.is_valid(raise_exception=True)
|
|
validated_query = query_serializer.validated_data
|
|
|
|
merchant = validated_query["merchant"]
|
|
area = validated_query["area"]
|
|
|
|
return (
|
|
Shipment.objects.filter(
|
|
merchant=merchant,
|
|
area=area,
|
|
delivery__isnull=True,
|
|
)
|
|
.select_related("customer", "merchant")
|
|
.order_by("-created_at", "-id")
|
|
)
|