feat: 工单多级审批 + 模版创建 (#6640)

* feat: 工单多级审批 + 模版创建

* feat: 工单权限处理

* fix: 工单关闭后 再审批bug

* perf: 修改一点

Co-authored-by: feng626 <1304903146@qq.com>
Co-authored-by: ibuler <ibuler@qq.com>
This commit is contained in:
fit2bot
2021-08-25 19:02:50 +08:00
committed by GitHub
parent 1fdc558ef7
commit 0f87f05b3f
30 changed files with 897 additions and 590 deletions

View File

@@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
#
from orgs.models import Organization
from rest_framework import viewsets
from common.permissions import IsValidUser
from common.exceptions import JMSException
from users.models import User
from orgs.models import Organization
from .. import serializers
@@ -15,8 +15,7 @@ class AssigneeViewSet(viewsets.ReadOnlyModelViewSet):
filterset_fields = ('id', 'name', 'username', 'email', 'source')
search_fields = filterset_fields
def get_org(self):
org_id = self.request.query_params.get('org_id')
def get_org(self, org_id):
org = Organization.get_instance(org_id)
if not org:
error = ('The organization `{}` does not exist'.format(org_id))
@@ -24,6 +23,13 @@ class AssigneeViewSet(viewsets.ReadOnlyModelViewSet):
return org
def get_queryset(self):
org = self.get_org()
queryset = User.get_super_and_org_admins(org=org)
org_id = self.request.query_params.get('org_id')
type = self.request.query_params.get('type')
if type == 'super':
queryset = User.get_super_admins()
elif type == 'super_admin':
org = self.get_org(org_id)
queryset = User.get_super_and_org_admins(org=org)
else:
queryset = User.objects.all()
return queryset

View File

@@ -15,16 +15,16 @@ class GenericTicketStatusRetrieveCloseAPI(RetrieveDestroyAPIView):
permission_classes = (IsAppUser, )
def retrieve(self, request, *args, **kwargs):
if self.ticket.action_open:
if self.ticket.state_open:
status = 'await'
elif self.ticket.action_approve:
status = 'approve'
elif self.ticket.state_approve:
status = 'approved'
else:
status = 'reject'
status = 'rejected'
data = {
'status': status,
'action': self.ticket.action,
'processor': self.ticket.processor_display
'action': self.ticket.state,
'processor': str(self.ticket.processor)
}
return Response(data=data, status=200)
@@ -32,9 +32,9 @@ class GenericTicketStatusRetrieveCloseAPI(RetrieveDestroyAPIView):
if self.ticket.status_open:
self.ticket.close(processor=self.ticket.applicant)
data = {
'action': self.ticket.action,
'action': self.ticket.state,
'status': self.ticket.status,
'processor': self.ticket.processor_display
'processor': str(self.ticket.processor)
}
return Response(data=data, status=200)

View File

@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
#
from django.utils.translation import ugettext_lazy as _
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.exceptions import MethodNotAllowed
@@ -8,14 +7,15 @@ from rest_framework.response import Response
from common.const.http import POST, PUT
from common.mixins.api import CommonApiMixin
from common.permissions import IsValidUser, IsOrgAdmin
from common.permissions import IsValidUser, IsOrgAdmin, IsSuperUser
from common.drf.api import JMSBulkModelViewSet
from tickets import serializers
from tickets.models import Ticket
from tickets.permissions.ticket import IsAssignee, IsAssigneeOrApplicant, NotClosed
from tickets.models import Ticket, TicketFlow
from tickets.filters import TicketFilter
from tickets.permissions.ticket import IsAssignee, IsApplicant
__all__ = ['TicketViewSet']
__all__ = ['TicketViewSet', 'TicketFlowViewSet']
class TicketViewSet(CommonApiMixin, viewsets.ModelViewSet):
@@ -25,12 +25,9 @@ class TicketViewSet(CommonApiMixin, viewsets.ModelViewSet):
'open': serializers.TicketApplySerializer,
'approve': serializers.TicketApproveSerializer,
}
filterset_fields = [
'id', 'title', 'type', 'action', 'status', 'applicant', 'applicant_display', 'processor',
'processor_display', 'assignees__id'
]
filterset_class = TicketFilter
search_fields = [
'title', 'action', 'type', 'status', 'applicant_display', 'processor_display'
'title', 'action', 'type', 'status', 'applicant_display'
]
def create(self, request, *args, **kwargs):
@@ -48,6 +45,8 @@ class TicketViewSet(CommonApiMixin, viewsets.ModelViewSet):
def perform_create(self, serializer):
instance = serializer.save()
instance.create_related_node()
instance.process_map = instance.create_process_map()
instance.open(applicant=self.request.user)
@action(detail=False, methods=[POST], permission_classes=[IsValidUser, ])
@@ -57,24 +56,46 @@ class TicketViewSet(CommonApiMixin, viewsets.ModelViewSet):
@action(detail=True, methods=[PUT], permission_classes=[IsAssignee, ])
def approve(self, request, *args, **kwargs):
instance = self.get_object()
if instance.status_closed:
return Response(data={"error": _("Ticket already closed")}, status=400)
response = super().update(request, *args, **kwargs)
self.get_object().approve(processor=self.request.user)
return response
serializer = self.get_serializer(instance)
instance.approve(processor=request.user)
return Response(serializer.data)
@action(detail=True, methods=[PUT], permission_classes=[IsAssignee, ])
def reject(self, request, *args, **kwargs):
instance = self.get_object()
if instance.status_closed:
return Response(data={"error": _("Ticket already closed")}, status=400)
serializer = self.get_serializer(instance)
instance.reject(processor=request.user)
return Response(serializer.data)
@action(detail=True, methods=[PUT], permission_classes=[IsAssigneeOrApplicant, NotClosed])
@action(detail=True, methods=[PUT], permission_classes=[IsApplicant, ])
def close(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance)
instance.close(processor=request.user)
return Response(serializer.data)
class TicketFlowViewSet(JMSBulkModelViewSet):
permission_classes = (IsOrgAdmin, IsSuperUser)
serializer_class = serializers.TicketFlowSerializer
filterset_fields = ['id', 'type']
search_fields = ['id', 'type']
def destroy(self, request, *args, **kwargs):
raise MethodNotAllowed(self.action)
def get_queryset(self):
queryset = TicketFlow.get_org_related_flows()
return queryset
def perform_create_or_update(self, serializer):
instance = serializer.save()
instance.save()
instance.rules.model.change_assignees_display(instance.rules.all())
def perform_create(self, serializer):
self.perform_create_or_update(serializer)
def perform_update(self, serializer):
self.perform_create_or_update(serializer)