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
+85
View File
@@ -0,0 +1,85 @@
"""报表中心 ViewSets:
1. ReportDefinitionViewSet: 报表元数据 CRUD + run 执行报表 + init_system 预置报表
2. DashboardViewSet: 经营大盘总览指标、销售排行、库存透视
"""
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 ReportDefinition
from .serializers import ReportDefinitionSerializer
from . import services as report_services
class ReportDefinitionViewSet(BaseTenantViewSet):
model = ReportDefinition
serializer_class = ReportDefinitionSerializer
search_fields = ["code", "name", "description"]
@action(detail=False, methods=["post"], url_path="init-system")
async def init_system(self, request):
"""一键初始化系统预置标准报表。"""
tenant = await self.get_tenant()
if not tenant:
raise ValidationError({"tenant": "无法识别租户"})
n = await sync_to_async(report_services.init_system_reports)(tenant)
return Response({"ok": True, "created_count": n, "message": f"成功初始化 {n} 个系统报表定义"})
@action(detail=True, methods=["post", "get"], url_path="run")
async def run_report(self, request, pk=None):
"""执行指定报表定义并返回数据。"""
tenant = await self.get_tenant()
try:
report_def = 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)
data = await sync_to_async(report_services.execute_report_definition)(tenant, report_def)
return Response(data)
class DashboardViewSet(ViewSet):
"""进销存与财务经营大盘。"""
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=["get"], url_path="summary")
async def summary(self, request):
"""获取本月经营总览指标(销售额、采购额、库存估值、应收应付总额)。"""
tenant = await self.get_tenant()
if not tenant:
raise ValidationError({"tenant": "无法识别租户"})
data = await sync_to_async(report_services.get_dashboard_summary)(tenant)
return Response(data)
@action(detail=False, methods=["get"], url_path="sales-rank")
async def sales_rank(self, request):
"""销售排行:参数 rank_by=product/customer,top_n=10。"""
tenant = await self.get_tenant()
if not tenant:
raise ValidationError({"tenant": "无法识别租户"})
rank_by = request.query_params.get("rank_by", "product")
try:
top_n = int(request.query_params.get("top_n", 10))
except ValueError:
top_n = 10
data = await sync_to_async(report_services.get_sales_rank)(tenant, rank_by=rank_by, top_n=top_n)
return Response({"rank_by": rank_by, "results": data})
@action(detail=False, methods=["get"], url_path="inventory-status")
async def inventory_status(self, request):
"""各仓库库存分布与资产估值。"""
tenant = await self.get_tenant()
if not tenant:
raise ValidationError({"tenant": "无法识别租户"})
data = await sync_to_async(report_services.get_inventory_status_report)(tenant)
return Response(data)