baseline: 批次A-D 成果 + membership 半成品(测试红)

This commit is contained in:
agent
2026-09-11 23:11:35 +08:00
commit b3f3095d53
311 changed files with 40540 additions and 0 deletions
+86
View File
@@ -0,0 +1,86 @@
"""全渠道与电商 ViewSets:
1. ChannelAccountViewSet: 店铺授权管理、action sync_orders 触发拉单
2. ChannelOrderViewSet: 渠道订单列表、action convert 手动转单
3. WebhookViewSet: 接收外部 Webhook 推送
"""
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.exceptions import ValidationError
from asgiref.sync import sync_to_async
from adrf.viewsets import ViewSet
from apps.core.viewset import BaseTenantViewSet
from .models import ChannelAccount, ChannelOrder, WebhookEvent
from .serializers import ChannelAccountSerializer, ChannelOrderSerializer, WebhookEventSerializer
from . import services as channel_services
class ChannelAccountViewSet(BaseTenantViewSet):
model = ChannelAccount
serializer_class = ChannelAccountSerializer
search_fields = ["shop_id", "shop_name", "platform"]
@action(detail=True, methods=["post"], url_path="sync-orders")
async def sync_orders(self, request, pk=None):
"""主动从该电商渠道拉取最新订单并自动转内部销售单。"""
tenant = await self.get_tenant()
try:
account = await sync_to_async(self.model.objects.get)(tenant=tenant, pk=pk)
except self.model.DoesNotExist:
return Response({"detail": "店铺配置不存在"}, status=status.HTTP_404_NOT_FOUND)
auto_convert = request.data.get("auto_convert", True)
result = await sync_to_async(channel_services.sync_channel_orders)(account, auto_convert=auto_convert)
return Response({"ok": True, "result": result})
class ChannelOrderViewSet(BaseTenantViewSet):
model = ChannelOrder
serializer_class = ChannelOrderSerializer
search_fields = ["external_order_id", "buyer_name", "buyer_phone"]
@action(detail=True, methods=["post"], url_path="convert")
async def convert(self, request, pk=None):
"""将指定的外部渠道订单转换为内部销售订单。"""
tenant = await self.get_tenant()
try:
corder = await sync_to_async(self.model.objects.get)(tenant=tenant, pk=pk)
except self.model.DoesNotExist:
return Response({"detail": "订单不存在"}, status=status.HTTP_404_NOT_FOUND)
try:
so = await sync_to_async(channel_services.convert_channel_order_to_sales_order)(corder)
return Response({
"ok": True,
"sales_order_id": so.id,
"sales_order_no": so.bill_no,
})
except Exception as e:
return Response({"detail": str(e)}, status=status.HTTP_400_BAD_REQUEST)
class WebhookViewSet(ViewSet):
"""接收外部平台的 Webhook 实时通知(如抖店支付推送)。"""
async def get_tenant(self):
from apps.core.viewset import resolve_tenant
from django.conf import settings
code = self.request.META.get("HTTP_X_TENANT_ID", settings.TENANT_DEFAULT)
return await sync_to_async(resolve_tenant)(code)
@action(detail=False, methods=["post"], url_path="inbound")
async def inbound(self, request):
tenant = await self.get_tenant()
if not tenant:
raise ValidationError({"tenant": "无法识别租户"})
platform = request.data.get("platform", "douyin")
event_type = request.data.get("event_type", "order.paid")
payload = request.data.get("payload", {})
event = await sync_to_async(channel_services.handle_inbound_webhook)(
tenant, platform=platform, event_type=event_type, payload=payload
)
return Response({"ok": True, "event_id": event.id, "status": event.status})