forked from erp-dev/erp
feat: new modul (stateflow)
This commit is contained in:
350
stateflow/serializers.py
Normal file
350
stateflow/serializers.py
Normal file
@@ -0,0 +1,350 @@
|
||||
"""
|
||||
Stateflow 序列化器
|
||||
"""
|
||||
from rest_framework import serializers
|
||||
from django.db import transaction
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from stateflow import models
|
||||
|
||||
|
||||
class StateParameterSerializer(serializers.ModelSerializer):
|
||||
"""状态参数序列化器"""
|
||||
|
||||
class Meta:
|
||||
model = models.StateParameter
|
||||
fields = ['id', 'key', 'value', 'description']
|
||||
read_only_fields = ['id']
|
||||
|
||||
|
||||
class StateListSerializer(serializers.ModelSerializer):
|
||||
"""状态列表序列化器(不包含参数)"""
|
||||
|
||||
class Meta:
|
||||
model = models.State
|
||||
fields = ['id', 'name', 'description', 'created_at', 'updated_at']
|
||||
read_only_fields = ['id', 'created_at', 'updated_at']
|
||||
|
||||
|
||||
class StateDetailSerializer(serializers.ModelSerializer):
|
||||
"""状态详情序列化器(包含参数)"""
|
||||
parameters = StateParameterSerializer(many=True, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = models.State
|
||||
fields = ['id', 'name', 'description', 'parameters', 'created_at', 'updated_at']
|
||||
read_only_fields = ['id', 'created_at', 'updated_at']
|
||||
|
||||
|
||||
class StateCreateUpdateSerializer(serializers.ModelSerializer):
|
||||
"""状态创建/更新序列化器"""
|
||||
parameters = StateParameterSerializer(many=True, required=False)
|
||||
|
||||
class Meta:
|
||||
model = models.State
|
||||
fields = ['name', 'description', 'parameters']
|
||||
|
||||
@transaction.atomic
|
||||
def create(self, validated_data):
|
||||
parameters_data = validated_data.pop('parameters', [])
|
||||
state = models.State.objects.create(**validated_data)
|
||||
|
||||
# 创建参数
|
||||
for param_data in parameters_data:
|
||||
models.StateParameter.objects.create(state=state, **param_data)
|
||||
|
||||
return state
|
||||
|
||||
@transaction.atomic
|
||||
def update(self, instance, validated_data):
|
||||
parameters_data = validated_data.pop('parameters', None)
|
||||
|
||||
# 更新基本字段
|
||||
instance.name = validated_data.get('name', instance.name)
|
||||
instance.description = validated_data.get('description', instance.description)
|
||||
instance.save()
|
||||
|
||||
# 如果提供了参数数据,更新参数
|
||||
if parameters_data is not None:
|
||||
# 删除旧参数
|
||||
instance.parameters.all().delete()
|
||||
# 创建新参数
|
||||
for param_data in parameters_data:
|
||||
models.StateParameter.objects.create(state=instance, **param_data)
|
||||
|
||||
return instance
|
||||
|
||||
|
||||
# Process 序列化器
|
||||
|
||||
class ProcessNodeSerializer(serializers.ModelSerializer):
|
||||
"""流程节点序列化器"""
|
||||
state_id = serializers.IntegerField(source='state.id', read_only=True)
|
||||
state_name = serializers.CharField(source='state.name', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = models.ProcessNode
|
||||
fields = ['id', 'state_id', 'state_name', 'order']
|
||||
read_only_fields = ['id']
|
||||
|
||||
|
||||
class ProcessNodeCreateSerializer(serializers.Serializer):
|
||||
"""流程节点创建序列化器"""
|
||||
state_id = serializers.IntegerField(help_text="状态ID")
|
||||
order = serializers.IntegerField(help_text="排序号", min_value=0)
|
||||
|
||||
def validate_state_id(self, value):
|
||||
"""验证状态是否存在"""
|
||||
try:
|
||||
models.State.objects.get(id=value)
|
||||
except models.State.DoesNotExist:
|
||||
raise serializers.ValidationError(f"状态ID {value} 不存在")
|
||||
return value
|
||||
|
||||
|
||||
class ProcessListSerializer(serializers.ModelSerializer):
|
||||
"""流程列表序列化器(不包含节点)"""
|
||||
node_count = serializers.IntegerField(read_only=True, help_text="节点数量")
|
||||
|
||||
class Meta:
|
||||
model = models.Process
|
||||
fields = ['id', 'name', 'description', 'node_count', 'created_at', 'updated_at']
|
||||
read_only_fields = ['id', 'created_at', 'updated_at']
|
||||
|
||||
|
||||
class ProcessDetailSerializer(serializers.ModelSerializer):
|
||||
"""流程详情序列化器(包含节点)"""
|
||||
nodes = ProcessNodeSerializer(source='process_nodes', many=True, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = models.Process
|
||||
fields = ['id', 'name', 'description', 'nodes', 'created_at', 'updated_at']
|
||||
read_only_fields = ['id', 'created_at', 'updated_at']
|
||||
|
||||
|
||||
class ProcessCreateUpdateSerializer(serializers.ModelSerializer):
|
||||
"""流程创建/更新序列化器"""
|
||||
nodes = ProcessNodeCreateSerializer(many=True, required=False, help_text="流程节点列表")
|
||||
|
||||
class Meta:
|
||||
model = models.Process
|
||||
fields = ['name', 'description', 'nodes']
|
||||
|
||||
@transaction.atomic
|
||||
def create(self, validated_data):
|
||||
nodes_data = validated_data.pop('nodes', [])
|
||||
process = models.Process.objects.create(**validated_data)
|
||||
|
||||
# 创建节点
|
||||
for node_data in nodes_data:
|
||||
models.ProcessNode.objects.create(
|
||||
process=process,
|
||||
state_id=node_data['state_id'],
|
||||
order=node_data['order']
|
||||
)
|
||||
|
||||
return process
|
||||
|
||||
@transaction.atomic
|
||||
def update(self, instance, validated_data):
|
||||
nodes_data = validated_data.pop('nodes', None)
|
||||
|
||||
# 更新基本字段
|
||||
instance.name = validated_data.get('name', instance.name)
|
||||
instance.description = validated_data.get('description', instance.description)
|
||||
instance.save()
|
||||
|
||||
# 如果提供了节点数据,更新节点
|
||||
if nodes_data is not None:
|
||||
# 删除旧节点
|
||||
instance.process_nodes.all().delete()
|
||||
# 创建新节点
|
||||
for node_data in nodes_data:
|
||||
models.ProcessNode.objects.create(
|
||||
process=instance,
|
||||
state_id=node_data['state_id'],
|
||||
order=node_data['order']
|
||||
)
|
||||
|
||||
return instance
|
||||
|
||||
|
||||
# BusinessObject 序列化器
|
||||
|
||||
class StateFlowRecordSerializer(serializers.ModelSerializer):
|
||||
"""状态流转记录序列化器(只读)"""
|
||||
state_name = serializers.CharField(source='state.name', read_only=True)
|
||||
completed_by_username = serializers.CharField(source='completed_by.username', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = models.StateFlowRecord
|
||||
fields = [
|
||||
'id', 'state', 'state_name', 'completed_at',
|
||||
'completed_by', 'completed_by_username',
|
||||
'is_cancelled', 'cancelled_at'
|
||||
]
|
||||
read_only_fields = ['id', 'completed_at', 'is_cancelled', 'cancelled_at']
|
||||
|
||||
|
||||
class BusinessObjectListSerializer(serializers.ModelSerializer):
|
||||
"""业务对象列表序列化器"""
|
||||
process_name = serializers.CharField(source='process.name', read_only=True)
|
||||
current_state_name = serializers.SerializerMethodField()
|
||||
overall_status = serializers.SerializerMethodField()
|
||||
progress_percentage = serializers.SerializerMethodField()
|
||||
|
||||
# 关联对象信息
|
||||
content_type_name = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = models.BusinessObject
|
||||
fields = [
|
||||
'id', 'name', 'process', 'process_name',
|
||||
'current_state_name', 'overall_status', 'progress_percentage',
|
||||
'content_type', 'object_id', 'content_type_name',
|
||||
'description', 'created_at', 'updated_at'
|
||||
]
|
||||
|
||||
def get_current_state_name(self, obj):
|
||||
from . import services
|
||||
state = services.get_business_object_current_state(obj)
|
||||
return state.name if state else None
|
||||
|
||||
def get_overall_status(self, obj):
|
||||
from . import services
|
||||
return services.get_overall_status(obj)
|
||||
|
||||
def get_progress_percentage(self, obj):
|
||||
from . import services
|
||||
return round(services.get_progress_percentage(obj), 2)
|
||||
|
||||
def get_content_type_name(self, obj):
|
||||
if obj.content_type:
|
||||
return f"{obj.content_type.app_label}.{obj.content_type.model}"
|
||||
return None
|
||||
|
||||
|
||||
class BusinessObjectDetailSerializer(serializers.ModelSerializer):
|
||||
"""业务对象详情序列化器"""
|
||||
process_detail = ProcessDetailSerializer(source='process', read_only=True)
|
||||
current_state = serializers.SerializerMethodField()
|
||||
overall_status = serializers.SerializerMethodField()
|
||||
progress_percentage = serializers.SerializerMethodField()
|
||||
timeline = serializers.SerializerMethodField()
|
||||
state_logs = StateFlowRecordSerializer(many=True, read_only=True)
|
||||
|
||||
# 关联对象信息
|
||||
content_type_name = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = models.BusinessObject
|
||||
fields = [
|
||||
'id', 'name', 'process', 'process_detail',
|
||||
'current_state', 'overall_status', 'progress_percentage',
|
||||
'timeline', 'state_logs',
|
||||
'content_type', 'object_id', 'content_type_name',
|
||||
'description', 'created_at', 'updated_at'
|
||||
]
|
||||
|
||||
def get_current_state(self, obj):
|
||||
from . import services
|
||||
state = services.get_business_object_current_state(obj)
|
||||
if state:
|
||||
return StateListSerializer(state).data
|
||||
return None
|
||||
|
||||
def get_overall_status(self, obj):
|
||||
from . import services
|
||||
return services.get_overall_status(obj)
|
||||
|
||||
def get_progress_percentage(self, obj):
|
||||
from . import services
|
||||
return round(services.get_progress_percentage(obj), 2)
|
||||
|
||||
def get_timeline(self, obj):
|
||||
from . import services
|
||||
timeline = services.get_business_object_state_timeline(obj)
|
||||
return [
|
||||
{
|
||||
'state': StateListSerializer(item['state']).data,
|
||||
'status': item['status'],
|
||||
'order': item['order'],
|
||||
'completed_at': item['completed_at'],
|
||||
'completed_by': item['completed_by'].username if item['completed_by'] else None,
|
||||
'cancelled_at': item['cancelled_at'],
|
||||
'is_cancelled': item['is_cancelled'],
|
||||
}
|
||||
for item in timeline
|
||||
]
|
||||
|
||||
def get_content_type_name(self, obj):
|
||||
if obj.content_type:
|
||||
return f"{obj.content_type.app_label}.{obj.content_type.model}"
|
||||
return None
|
||||
|
||||
|
||||
class BusinessObjectCreateUpdateSerializer(serializers.ModelSerializer):
|
||||
"""业务对象创建/更新序列化器"""
|
||||
|
||||
# 支持通过 app_label.model 字符串指定 content_type
|
||||
content_type_str = serializers.CharField(
|
||||
write_only=True,
|
||||
required=False,
|
||||
allow_null=True,
|
||||
help_text="格式: app_label.model, 例如: basic_info.order"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = models.BusinessObject
|
||||
fields = [
|
||||
'name', 'process', 'description',
|
||||
'content_type', 'object_id', 'content_type_str'
|
||||
]
|
||||
extra_kwargs = {
|
||||
'content_type': {'required': False, 'allow_null': True},
|
||||
'object_id': {'required': False, 'allow_null': True},
|
||||
}
|
||||
|
||||
def validate(self, attrs):
|
||||
"""验证 content_type 和 object_id 的一致性"""
|
||||
content_type = attrs.get('content_type')
|
||||
content_type_str = attrs.get('content_type_str')
|
||||
object_id = attrs.get('object_id')
|
||||
|
||||
# 如果提供了 content_type_str,解析并设置 content_type
|
||||
if content_type_str:
|
||||
try:
|
||||
app_label, model = content_type_str.split('.')
|
||||
content_type = ContentType.objects.get(app_label=app_label, model=model)
|
||||
attrs['content_type'] = content_type
|
||||
except (ValueError, ContentType.DoesNotExist):
|
||||
raise serializers.ValidationError({
|
||||
'content_type_str': f'无效的 content_type 格式: {content_type_str}'
|
||||
})
|
||||
|
||||
# 验证:如果提供了 content_type,必须提供 object_id
|
||||
if content_type and not object_id:
|
||||
raise serializers.ValidationError({
|
||||
'object_id': '提供了关联对象类型,必须同时提供对象ID'
|
||||
})
|
||||
|
||||
# 验证:如果提供了 object_id,必须提供 content_type
|
||||
if object_id and not content_type:
|
||||
raise serializers.ValidationError({
|
||||
'content_type': '提供了对象ID,必须同时提供关联对象类型'
|
||||
})
|
||||
|
||||
# 移除临时字段
|
||||
attrs.pop('content_type_str', None)
|
||||
|
||||
return attrs
|
||||
|
||||
@transaction.atomic
|
||||
def create(self, validated_data):
|
||||
return models.BusinessObject.objects.create(**validated_data)
|
||||
|
||||
@transaction.atomic
|
||||
def update(self, instance, validated_data):
|
||||
for attr, value in validated_data.items():
|
||||
setattr(instance, attr, value)
|
||||
instance.save()
|
||||
return instance
|
||||
Reference in New Issue
Block a user