hberp/hb_server/apps/wf/views.py

279 lines
14 KiB
Python

from django.core.exceptions import AppRegistryNotReady
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin
from apps.wf.serializers import CustomFieldSerializer, StateSerializer, TicketCreateSerializer, TicketFlowSerializer, TicketHandleSerializer, TicketSerializer, TransitionSerializer, WorkflowSerializer
from django.shortcuts import get_object_or_404, render
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from rest_framework.decorators import action, api_view
from apps.wf.models import CustomField, Ticket, Workflow, State, Transition, TicketFlow
from apps.system.mixins import CreateUpdateCustomMixin, CreateUpdateModelAMixin, OptimizationMixin
from apps.wf.services import WfService
from rest_framework.exceptions import APIException, PermissionDenied
# Create your views here.
class WorkflowViewSet(CreateUpdateModelAMixin, ModelViewSet):
perms_map = {'get': '*', 'post': 'workflow_create',
'put': 'workflow_update', 'delete': 'workflow_delete'}
queryset = Workflow.objects.all()
serializer_class = WorkflowSerializer
search_fields = ['name', 'description']
filterset_fields = []
ordering_fields = ['create_time']
ordering = ['-create_time']
@action(methods=['get'], detail=True, perms_map={'get':'workflow_update'}, pagination_class=None, serializer_class=StateSerializer)
def states(self, request, pk=None):
"""
工作流下的状态节点
"""
wf = self.get_object()
serializer = self.serializer_class(instance=WfService.get_worlflow_states(wf), many=True)
return Response(serializer.data)
@action(methods=['get'], detail=True, perms_map={'get':'workflow_update'}, pagination_class=None, serializer_class=TransitionSerializer)
def transitions(self, request, pk=None):
"""
工作流下的流转规则
"""
wf = self.get_object()
serializer = self.serializer_class(instance=WfService.get_workflow_transitions(wf), many=True)
return Response(serializer.data)
@action(methods=['get'], detail=True, perms_map={'get':'workflow_update'}, pagination_class=None, serializer_class=CustomFieldSerializer)
def customfields(self, request, pk=None):
"""
工作流下的自定义字段
"""
wf = self.get_object()
serializer = self.serializer_class(instance=CustomField.objects.filter(workflow=wf), many=True)
return Response(serializer.data)
@action(methods=['get'], detail=True, perms_map={'get':'workflow_init'})
def init(self, request, pk=None):
"""
新建工单初始化
"""
ret={}
wf = self.get_object()
start_state = WfService.get_workflow_start_state(wf)
transitions = WfService.get_state_transitions(start_state)
ret['workflow'] = pk
ret['transitions'] = TransitionSerializer(instance=transitions, many=True).data
field_list = CustomFieldSerializer(instance=WfService.get_workflow_custom_fields(wf), many=True).data
ret['field_list'] = field_list
return Response(ret)
class StateViewSet(CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin, GenericViewSet):
perms_map = {'*':'*'}
queryset = State.objects.all()
serializer_class = StateSerializer
search_fields = ['name']
filterset_fields = ['workflow']
ordering = ['sort']
class TransitionViewSet(CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin, GenericViewSet):
perms_map = {'*':'*'}
queryset = Transition.objects.all()
serializer_class = TransitionSerializer
search_fields = ['name']
filterset_fields = ['workflow']
ordering = ['id']
class CustomFieldViewSet(CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin, GenericViewSet):
perms_map = {'*':'*'}
queryset = CustomField.objects.all()
serializer_class = CustomFieldSerializer
search_fields = ['field_name']
filterset_fields = ['workflow', 'field_type']
ordering = ['sort']
class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin, ListModelMixin, RetrieveModelMixin, GenericViewSet):
perms_map = {'*':'*'}
queryset = Ticket.objects.all()
serializer_class = TicketSerializer
search_fields = ['title']
filterset_fields = ['workflow', 'state']
ordering = ['-create_time']
def get_serializer_class(self):
if self.action == 'create':
return TicketCreateSerializer
elif self.action == 'handle':
return TicketHandleSerializer
return super().get_serializer_class()
def create(self, request, *args, **kwargs):
"""
新建工单
"""
rdata = request.data
serializer = self.get_serializer(data=rdata)
serializer.is_valid(raise_exception=True)
start_state = WfService.get_workflow_start_state(rdata['workflow'])
transition = Transition.objects.get(pk=rdata['transition'])
ticket_data = rdata['ticket_data']
if transition.field_require_check:
for key, value in start_state.state_fields.items(): #校验必填项
if value == State.STATE_FIELD_REQUIRED:
if key not in ticket_data or not ticket_data[key]:
raise APIException('字段{}必填'.format(key))
ticket = serializer.save(state=start_state, create_by=request.user) # 先创建出来
next_state = WfService.get_next_state_by_transition_and_ticket_info(ticket=ticket, transition=transition)
participant_info = WfService.get_ticket_state_participant_info(state=next_state, ticket=ticket, ticket_data=ticket.ticket_data)
destination_participant_type = participant_info.get('destination_participant_type', 0)
destination_participant = participant_info.get('destination_participant', None)
multi_all_person = participant_info.get('multi_all_person', {}) # 多人需要全部处理情况
sn = WfService.get_ticket_sn(ticket.workflow) # 流水号
if next_state.type == State.STATE_TYPE_END:
act_state = Ticket.TICKET_ACT_STATE_FINISH
elif next_state.type == State.STATE_TYPE_START:
act_state = Ticket.TICKET_ACT_STATE_DRAFT
else:
act_state = Ticket.TICKET_ACT_STATE_ONGOING
title = rdata.get('title', '')
title_template = ticket.workflow.title_template
if title_template:
all_ticket_data = {**rdata, **rdata['ticket_data']}
title = title_template.format(**all_ticket_data)
# 更新一下信息
ticket.sn=sn
ticket.title=title
ticket.state=next_state
ticket.participant=destination_participant
ticket.participant_type=destination_participant_type
ticket.act_state=act_state
ticket.multi_all_person=multi_all_person
ticket.save()
# 新增流转记录
TicketFlow.objects.create(ticket=ticket, state=start_state, ticket_data=WfService.get_ticket_all_field_value(ticket),
suggestion=rdata.get('suggestion',''), participant_type=State.PARTICIPANT_TYPE_PERSONAL,
participant=ticket.create_by, transition=transition)
return Response(TicketSerializer(instance=ticket).data)
@action(methods=['post'], detail=True, perms_map={'get':'*'})
def handle(self, request, pk=None):
"""
处理工单
"""
try:
ticket = Ticket.objects.get(pk=pk)
except:
raise APIException('工单不存在')
data = request.data
result = WfService.ticket_handle_permission_check(ticket, request.user)
source_state = ticket.state
source_ticket_data = ticket.ticket_data
if result.get('permission') is False:
raise PermissionDenied(result.get('msg'))
# 校验表单必填项目
transition = Transition.objects.get(pk=data['transition'])
ticket_data = data['ticket_data']
if transition.field_require_check:
for key, value in ticket.state.state_fields.items():
if value == State.STATE_FIELD_REQUIRED:
if key not in ticket_data or not ticket_data[key]:
raise APIException('字段{}必填'.format(key))
destination_state = WfService.get_next_state_by_transition_and_ticket_info(ticket, transition)
multi_all_person = ticket.multi_all_person
if multi_all_person:
multi_all_person[request.user.id] =dict(transition=transition.id)
# 判断所有人处理结果是否一致
if WfService.check_dict_has_all_same_value(multi_all_person):
participant_info = WfService.get_ticket_state_participant_info(destination_state, ticket, data['ticket_data'])
destination_participant_type = participant_info.get('destination_participant_type', 0)
destination_participant = participant_info.get('destination_participant', None)
multi_all_person = {}
else:
# 处理人没有没有全部处理完成或者处理动作不一致
destination_participant_type = ticket.participant_type
destination_state = ticket.state # 保持原状态
destination_participant = []
for key, value in multi_all_person.items():
if not value:
destination_participant.push(key)
else:
# 当前处理人类型非全部处理
participant_info = WfService.get_ticket_state_participant_info(destination_state, ticket, data['ticket_data'])
destination_participant_type = participant_info.get('destination_participant_type', 0)
destination_participant = participant_info.get('destination_participant', None)
multi_all_person = participant_info.get('multi_all_person', {})
# 更新工单信息:基础字段及自定义字段, add_relation字段 需要下个处理人是部门、角色等的情况
ticket.state = destination_state
ticket.participant_type = destination_participant_type
ticket.participant = destination_participant
ticket.multi_all_person = multi_all_person
if destination_state.type == State.STATE_TYPE_END:
ticket.act_state = Ticket.TICKET_ACT_STATE_FINISH
elif destination_state.type == State.STATE_TYPE_START:
ticket.act_state = Ticket.TICKET_ACT_STATE_DRAFT
else:
ticket.act_state = Ticket.TICKET_ACT_STATE_ONGOING
if transition.attribute_type == Transition.TRANSITION_ATTRIBUTE_TYPE_REFUSE:
transition.act_state = Ticket.TICKET_ACT_STATE_BACK
# 只更新必填和可选的字段
for key, value in ticket.state.state_fields.items():
if value in (State.STATE_FIELD_REQUIRED, State.STATE_FIELD_OPTIONAL):
source_ticket_data[key] = ticket_data[key]
ticket.ticket_data = source_ticket_data
ticket.save()
# 更新工单流转记录
TicketFlow.objects.create(ticket=ticket, state=source_state, ticket_data=WfService.get_ticket_all_field_value(ticket),
suggestion=data.get('suggestion',''), participant_type=State.PARTICIPANT_TYPE_PERSONAL,
participant=request.user, transition=transition)
return Response(TicketSerializer(instance=ticket).data)
@action(methods=['get'], detail=True, perms_map={'get':'*'})
def flowsteps(self, request, pk=None):
"""
工单流转step, 用于显示当前状态的step图(线性结构)
"""
ticket = self.get_object()
steps = WfService.get_ticket_steps(ticket)
return Response(StateSerializer(instance=steps, many=True).data)
@action(methods=['get'], detail=True, perms_map={'get':'*'})
def transitions(self, request, pk=None):
"""
获取工单可执行的操作
"""
ticket = self.get_object()
transitions = WfService.get_ticket_transitions(ticket)
return Response(TransitionSerializer(instance=transitions, many=True).data)
@action(methods=['post'], detail=True, perms_map={'post':'*'})
def accpet(self, request, pk=None):
"""
接单,当工单当前处理人实际为多个人时(角色、部门、多人都有可能, 注意角色和部门有可能实际只有一人)
"""
ticket = self.get_object()
result = WfService.ticket_handle_permission_check(ticket, request.user)
if result.get('need_accept', False):
ticket.participant_type = State.PARTICIPANT_TYPE_PERSONAL
ticket.participant = request.user.id
ticket.save()
# 接单日志
# 更新工单流转记录
TicketFlow.objects.create(ticket=ticket, state=ticket.state, ticket_data=WfService.get_ticket_all_field_value(ticket),
suggestion='接单处理', participant_type=State.PARTICIPANT_TYPE_PERSONAL,
participant=request.user, transition=None)
return Response()
else:
raise APIException('无需接单')
class TicketFlowViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
"""
工单日志
"""
perms_map = {'*':'*'}
queryset = TicketFlow.objects.all()
serializer_class = TicketFlowSerializer
search_fields = ['suggestion']
filterset_fields = ['paticipant', 'state', 'ticket']
ordering = ['-create_time']