forked from erp-dev/erp
190 lines
7.1 KiB
Python
190 lines
7.1 KiB
Python
"""
|
|
BusinessObject API ViewSet
|
|
"""
|
|
from rest_framework import viewsets, filters, status
|
|
from rest_framework.decorators import action
|
|
from rest_framework.response import Response
|
|
from rest_framework.pagination import LimitOffsetPagination
|
|
from django_filters.rest_framework import DjangoFilterBackend
|
|
from django_filters import rest_framework as django_filters
|
|
from stateflow import models, services
|
|
from stateflow.serializers import (
|
|
BusinessObjectListSerializer,
|
|
BusinessObjectDetailSerializer,
|
|
BusinessObjectCreateUpdateSerializer,
|
|
StateListSerializer,
|
|
)
|
|
|
|
|
|
class BusinessObjectFilterSet(django_filters.FilterSet):
|
|
"""业务对象过滤器"""
|
|
name = django_filters.CharFilter(lookup_expr='icontains')
|
|
process_name = django_filters.CharFilter(field_name='process__name', lookup_expr='icontains')
|
|
overall_status = django_filters.ChoiceFilter(
|
|
choices=[
|
|
('not_started', '未开始'),
|
|
('in_progress', '进行中'),
|
|
('completed', '已完成')
|
|
],
|
|
method='filter_overall_status'
|
|
)
|
|
content_type_str = django_filters.CharFilter(method='filter_content_type')
|
|
has_content_object = django_filters.BooleanFilter(method='filter_has_content_object')
|
|
|
|
def filter_overall_status(self, queryset, name, value):
|
|
"""过滤整体状态"""
|
|
business_object_ids = []
|
|
for obj in queryset:
|
|
if services.get_overall_status(obj) == value:
|
|
business_object_ids.append(obj.id)
|
|
return queryset.filter(id__in=business_object_ids)
|
|
|
|
def filter_content_type(self, queryset, name, value):
|
|
"""通过 app_label.model 字符串过滤"""
|
|
try:
|
|
from django.contrib.contenttypes.models import ContentType
|
|
app_label, model = value.split('.')
|
|
content_type = ContentType.objects.get(app_label=app_label, model=model)
|
|
return queryset.filter(content_type=content_type)
|
|
except:
|
|
return queryset.none()
|
|
|
|
def filter_has_content_object(self, queryset, name, value):
|
|
"""过滤是否有关联对象"""
|
|
if value:
|
|
return queryset.exclude(content_type__isnull=True)
|
|
else:
|
|
return queryset.filter(content_type__isnull=True)
|
|
|
|
class Meta:
|
|
model = models.BusinessObject
|
|
fields = ['name', 'process', 'process_name', 'overall_status',
|
|
'content_type_str', 'has_content_object']
|
|
|
|
|
|
class BusinessObjectViewSet(viewsets.ModelViewSet):
|
|
"""
|
|
业务对象 CRUD 接口
|
|
|
|
业务对象是流程的实例,可以选择性地关联到实际的业务模型(如订单、工单等)
|
|
|
|
list: 获取业务对象列表
|
|
retrieve: 获取业务对象详情(包含时间线和日志)
|
|
create: 创建业务对象
|
|
update: 更新业务对象
|
|
partial_update: 部分更新业务对象
|
|
destroy: 删除业务对象
|
|
|
|
查询参数:
|
|
- name: 按名称模糊查询
|
|
- process: 按流程ID过滤
|
|
- process_name: 按流程名称模糊查询
|
|
- overall_status: 按整体状态过滤 (not_started/in_progress/completed)
|
|
- content_type_str: 按关联对象类型过滤,格式: app_label.model
|
|
- has_content_object: 是否有关联对象 (true/false)
|
|
- search: 全文搜索(名称和描述)
|
|
- ordering: 排序字段
|
|
"""
|
|
queryset = models.BusinessObject.objects.all()
|
|
pagination_class = LimitOffsetPagination
|
|
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
|
|
filterset_class = BusinessObjectFilterSet
|
|
search_fields = ['name', 'description']
|
|
ordering_fields = ['id', 'name', 'created_at', 'updated_at']
|
|
ordering = ['-created_at']
|
|
|
|
def get_serializer_class(self):
|
|
"""根据动作选择序列化器"""
|
|
if self.action == 'list':
|
|
return BusinessObjectListSerializer
|
|
elif self.action in ['create', 'update', 'partial_update']:
|
|
return BusinessObjectCreateUpdateSerializer
|
|
else: # retrieve
|
|
return BusinessObjectDetailSerializer
|
|
|
|
def get_queryset(self):
|
|
"""优化查询"""
|
|
queryset = super().get_queryset()
|
|
if self.action == 'list':
|
|
queryset = queryset.select_related('process', 'content_type')
|
|
elif self.action == 'retrieve':
|
|
queryset = queryset.select_related('process', 'content_type').prefetch_related(
|
|
'state_logs__state',
|
|
'state_logs__completed_by',
|
|
'process__process_nodes__state'
|
|
)
|
|
return queryset
|
|
|
|
@action(detail=True, methods=['post'])
|
|
def advance(self, request, pk=None):
|
|
"""推进到下一个状态"""
|
|
business_object = self.get_object()
|
|
user = request.user
|
|
|
|
success, message = services.advance_to_next_state(business_object, user)
|
|
|
|
if success:
|
|
return Response({
|
|
'success': True,
|
|
'message': message,
|
|
'business_object': BusinessObjectDetailSerializer(business_object).data
|
|
})
|
|
else:
|
|
return Response({
|
|
'success': False,
|
|
'message': message
|
|
}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
@action(detail=True, methods=['post'])
|
|
def step_back(self, request, pk=None):
|
|
"""回退一步(撤销最后一次完成的状态)"""
|
|
business_object = self.get_object()
|
|
user = request.user
|
|
|
|
success, message = services.step_back_one_state(business_object, user)
|
|
|
|
if success:
|
|
return Response({
|
|
'success': True,
|
|
'message': message,
|
|
'business_object': BusinessObjectDetailSerializer(business_object).data
|
|
})
|
|
else:
|
|
return Response({
|
|
'success': False,
|
|
'message': message
|
|
}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
@action(detail=True, methods=['post'])
|
|
def reset(self, request, pk=None):
|
|
"""重置进度"""
|
|
business_object = self.get_object()
|
|
services.reset_business_object_progress(business_object)
|
|
|
|
return Response({
|
|
'success': True,
|
|
'message': '进度已重置',
|
|
'business_object': BusinessObjectDetailSerializer(business_object).data
|
|
})
|
|
|
|
@action(detail=True, methods=['get'])
|
|
def timeline(self, request, pk=None):
|
|
"""获取状态时间线"""
|
|
business_object = self.get_object()
|
|
timeline = services.get_business_object_state_timeline(business_object)
|
|
|
|
timeline_data = [
|
|
{
|
|
'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
|
|
]
|
|
|
|
return Response(timeline_data)
|