forked from erp-dev/erp
102 lines
4.3 KiB
Python
102 lines
4.3 KiB
Python
from rest_framework import serializers, status, permissions
|
||
from rest_framework.response import Response
|
||
from rest_framework.views import APIView
|
||
from django.core.exceptions import FieldDoesNotExist
|
||
from django.db import transaction
|
||
|
||
from stateflow import models as stateflow_models
|
||
from stateflow import services as stateflow_services
|
||
|
||
|
||
class BusinessObjectCloneRequestSerializer(serializers.Serializer):
|
||
business_object_id = serializers.IntegerField(min_value=1)
|
||
# 调用方必须显式传入 content_type 与 object_id:
|
||
# - content_type:仅用于校验与源对象一致(不做额外校验)
|
||
# - object_id:克隆后的新业务对象 ID(必须与源对象不同)
|
||
content_type = serializers.IntegerField(min_value=1, allow_null=True)
|
||
object_id = serializers.IntegerField(min_value=1, allow_null=True)
|
||
|
||
|
||
class BusinessObjectCloneView(APIView):
|
||
"""
|
||
克隆 BusinessObject(含所有状态流转记录与工艺参数记录)
|
||
|
||
POST /api/v2/stateflow/business-objects/clone/
|
||
|
||
请求体:
|
||
{
|
||
"business_object_id": 123,
|
||
"content_type": 9,
|
||
"object_id": 456
|
||
}
|
||
|
||
返回:
|
||
{
|
||
"business_object_id": 456
|
||
}
|
||
"""
|
||
|
||
permission_classes = [permissions.IsAuthenticated]
|
||
|
||
def post(self, request):
|
||
srz = BusinessObjectCloneRequestSerializer(data=request.data)
|
||
srz.is_valid(raise_exception=True)
|
||
|
||
bo_id = srz.validated_data['business_object_id']
|
||
expected_content_type_id = srz.validated_data.get('content_type')
|
||
new_object_id = srz.validated_data.get('object_id')
|
||
try:
|
||
bo = stateflow_models.BusinessObject.objects.get(id=bo_id)
|
||
except stateflow_models.BusinessObject.DoesNotExist:
|
||
return Response({'detail': 'business_object 不存在'}, status=status.HTTP_404_NOT_FOUND)
|
||
|
||
try:
|
||
with transaction.atomic():
|
||
cloned = stateflow_services.clone_business_object(
|
||
bo,
|
||
new_object_id=new_object_id,
|
||
expected_content_type_id=expected_content_type_id,
|
||
)
|
||
|
||
# 兼容 printing 的“克隆=新建后复制流程进度”工作流:
|
||
# 目标业务对象(PlateOrder/PrintingJob)本身持有 business_object 字段,
|
||
# 需要把克隆后的 BusinessObject 回写到目标对象上,否则前端看不到节点/参数历史。
|
||
try:
|
||
target_obj = cloned.content_type.get_object_for_this_type(pk=cloned.object_id)
|
||
except Exception:
|
||
target_obj = None
|
||
|
||
if target_obj is not None:
|
||
try:
|
||
bo_field = target_obj._meta.get_field('business_object')
|
||
except FieldDoesNotExist:
|
||
bo_field = None
|
||
|
||
if bo_field is not None and bo_field.related_model is stateflow_models.BusinessObject:
|
||
old_bo_id = getattr(target_obj, 'business_object_id', None)
|
||
target_obj.business_object = cloned
|
||
target_obj.save(update_fields=['business_object'])
|
||
|
||
# 如果目标对象在创建时自动生成了一个“空 business_object”,这里做安全清理,
|
||
# 避免同一个业务对象存在多个 BusinessObject 绑定导致后续审计/排查混乱。
|
||
if old_bo_id and old_bo_id != cloned.id:
|
||
old_bo = (
|
||
stateflow_models.BusinessObject.objects
|
||
.filter(id=old_bo_id)
|
||
.select_related('content_type')
|
||
.first()
|
||
)
|
||
if (
|
||
old_bo
|
||
and old_bo.state_logs.count() == 0
|
||
and old_bo.content_type_id == cloned.content_type_id
|
||
and old_bo.object_id == cloned.object_id
|
||
):
|
||
old_bo.delete()
|
||
except ValueError as e:
|
||
return Response({'detail': str(e)}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
return Response({'business_object_id': cloned.id})
|
||
|
||
|