1
0
forked from erp-dev/erp
Files
erpnew/stateflow/serializers.py
2025-11-13 18:22:42 +08:00

361 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
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):
"""状态参数序列化器"""
attachment_url = serializers.SerializerMethodField(read_only=True)
class Meta:
model = models.StateParameter
fields = ['id', 'key', 'value', 'attachment', 'attachment_url', 'description']
read_only_fields = ['id', 'attachment_url']
def get_attachment_url(self, obj):
"""获取附件的完整 URL"""
if obj.attachment:
request = self.context.get('request')
if request:
return request.build_absolute_uri(obj.attachment.url)
return obj.attachment.url
return None
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