1
0
forked from erp-dev/erp

fix: appversions

This commit is contained in:
2026-07-11 00:05:05 +08:00
parent 48e4782e1e
commit e91d06e4b6
26 changed files with 2582 additions and 19 deletions

View File

@@ -13,7 +13,16 @@ from rest_framework.permissions import IsAuthenticated
from rest_framework_simplejwt.authentication import JWTAuthentication
from basic_info.models import Merchant
from settlement.services import get_plate_order_summary_by_customer
from settlement.services import (
DEFAULT_DESIGNER_SUMMARY_STATE_NAMES,
DEFAULT_DESIGNER_TASK_STATE_NAME_SUFFIX,
DEFAULT_DESIGNER_PARAM_KEY,
DEFAULT_DESIGNER_TASK_QUANTITY_PARAM_KEY,
DEFAULT_DESIGNER_TASK_TIME_PARAM_KEY,
get_plate_order_summary_by_customer,
get_plate_order_summary_by_designer,
get_designer_workflow_task_summary,
)
from .mixins import SettlementVisibilityMixin
logger = logging.getLogger(__name__)
@@ -120,3 +129,189 @@ class PlateOrderSummaryView(SettlementVisibilityMixin, APIView):
{"error": "获取统计数据失败"},
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
)
class PlateOrderDesignerSummaryView(SettlementVisibilityMixin, APIView):
"""
开版订单设计师统计 API
GET /api/v1/settlement/plate-orders/designer-summary/
参数:
date: 统计日期YYYY-MM-DD
state_names: 可选,逗号分隔或重复传参的 state 名称,默认“画图完成”
"""
authentication_classes = PlateOrderSummaryView.authentication_classes
permission_classes = [IsAuthenticated]
view_all_permission = "printing.view_all_plateorders"
def get(self, request):
date_str = request.query_params.get("date")
if not date_str:
return Response(
{"error": "缺少 date 参数"}, status=status.HTTP_400_BAD_REQUEST
)
if not re.match(r"^\d{4}-\d{2}-\d{2}$", date_str):
return Response(
{"error": "日期格式错误,请使用 YYYY-MM-DD 格式"},
status=status.HTTP_400_BAD_REQUEST,
)
try:
settlement_date = date.fromisoformat(date_str)
except ValueError:
return Response({"error": "日期不存在"}, status=status.HTTP_403_FORBIDDEN)
emp = getattr(request.user, "employee", None)
if emp is None or emp.merchant is None:
if request.user.is_superuser:
merchant = Merchant.objects.first()
if merchant is None:
return Response(
{"error": "系统中没有商户"}, status=status.HTTP_403_FORBIDDEN
)
merchant_id = merchant.id
else:
return Response(
{"error": "用户未关联商户"}, status=status.HTTP_403_FORBIDDEN
)
else:
merchant_id = emp.merchant.id
state_names = _parse_state_names(request)
try:
data = get_plate_order_summary_by_designer(
merchant_id=merchant_id,
settlement_date=settlement_date,
user=self.get_service_user(request.user),
state_names=state_names,
)
return Response({
"data": data,
"meta": {
"state_names": list(state_names or DEFAULT_DESIGNER_SUMMARY_STATE_NAMES),
"designer_param_key": DEFAULT_DESIGNER_PARAM_KEY,
},
})
except ValueError as e:
return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
logger.exception(f"[settlement.views] 获取开版订单设计师统计失败: {e}")
return Response(
{"error": "获取统计数据失败"},
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
)
def _parse_state_names(request):
"""解析 state_names支持逗号分隔和重复传参。"""
return _parse_csv_query_param(request, "state_names")
def _parse_designer_names(request):
"""解析 designer_names支持逗号分隔和重复传参。"""
return _parse_csv_query_param(request, "designer_names")
def _parse_csv_query_param(request, name: str):
raw_values = request.query_params.getlist("state_names")
if name != "state_names":
raw_values = request.query_params.getlist(name)
if not raw_values:
return None
values = []
for raw_value in raw_values:
values.extend(
item.strip() for item in str(raw_value).split(',') if item.strip()
)
return values
class DesignerWorkflowTaskSummaryView(SettlementVisibilityMixin, APIView):
"""
设计师工序任务量统计 API
GET /api/v1/settlement/workflows/designer-task-summary/
"""
authentication_classes = PlateOrderSummaryView.authentication_classes
permission_classes = [IsAuthenticated]
view_all_permission = "printing.view_all_plateorders"
def get(self, request):
date_str = request.query_params.get("date")
if not date_str:
return Response(
{"error": "缺少 date 参数"}, status=status.HTTP_400_BAD_REQUEST
)
if not re.match(r"^\d{4}-\d{2}-\d{2}$", date_str):
return Response(
{"error": "日期格式错误,请使用 YYYY-MM-DD 格式"},
status=status.HTTP_400_BAD_REQUEST,
)
try:
settlement_date = date.fromisoformat(date_str)
except ValueError:
return Response({"error": "日期不存在"}, status=status.HTTP_403_FORBIDDEN)
emp = getattr(request.user, "employee", None)
if emp is None or emp.merchant is None:
if request.user.is_superuser:
merchant = Merchant.objects.first()
if merchant is None:
return Response(
{"error": "系统中没有商户"}, status=status.HTTP_403_FORBIDDEN
)
merchant_id = merchant.id
else:
return Response(
{"error": "用户未关联商户"}, status=status.HTTP_403_FORBIDDEN
)
else:
merchant_id = emp.merchant.id
state_names = _parse_state_names(request)
designer_names = _parse_designer_names(request)
try:
data = get_designer_workflow_task_summary(
merchant_id=merchant_id,
settlement_date=settlement_date,
user=self.get_service_user(request.user),
state_names=state_names,
designer_names=designer_names,
)
return Response({
"data": data,
"meta": {
"date": settlement_date.isoformat(),
"state_names": list(state_names or []),
"state_filter": (
{"mode": "exact", "state_names": list(state_names)}
if state_names is not None
else {"mode": "suffix", "suffix": DEFAULT_DESIGNER_TASK_STATE_NAME_SUFFIX}
),
"designer_names": list(designer_names or []),
"designer_param_key": DEFAULT_DESIGNER_PARAM_KEY,
"quantity_param_key": DEFAULT_DESIGNER_TASK_QUANTITY_PARAM_KEY,
"time_param_key": DEFAULT_DESIGNER_TASK_TIME_PARAM_KEY,
"empty_quantity_default": 1,
"time_source": "parameters.完成时间; fallback=StateFlowRecord.completed_at",
},
})
except ValueError as e:
return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
logger.exception(f"[settlement.views] 获取设计师工序任务量统计失败: {e}")
return Response(
{"error": "获取统计数据失败"},
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
)