feat: base system和wf优化事务处理

This commit is contained in:
caoqianming 2025-09-17 12:15:26 +08:00
parent f60250bb21
commit 0284809933
2 changed files with 70 additions and 72 deletions

View File

@ -8,8 +8,7 @@ from django_celery_beat.models import (CrontabSchedule, IntervalSchedule,
from django_celery_results.models import TaskResult from django_celery_results.models import TaskResult
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.exceptions import ParseError, ValidationError, PermissionDenied from rest_framework.exceptions import ParseError, ValidationError, PermissionDenied
from rest_framework.mixins import (CreateModelMixin, DestroyModelMixin, from rest_framework.mixins import RetrieveModelMixin
ListModelMixin, RetrieveModelMixin)
from rest_framework.parsers import (JSONParser, from rest_framework.parsers import (JSONParser,
MultiPartParser) MultiPartParser)
from rest_framework.serializers import Serializer from rest_framework.serializers import Serializer
@ -20,7 +19,7 @@ from apps.hrm.models import Employee
from apps.system.errors import OLD_PASSWORD_WRONG, PASSWORD_NOT_SAME, SCHEDULE_WRONG from apps.system.errors import OLD_PASSWORD_WRONG, PASSWORD_NOT_SAME, SCHEDULE_WRONG
from apps.system.filters import DeptFilterSet, UserFilterSet from apps.system.filters import DeptFilterSet, UserFilterSet
# from django_q.models import Task as QTask, Schedule as QSchedule # from django_q.models import Task as QTask, Schedule as QSchedule
from apps.utils.mixins import (CustomCreateModelMixin, MyLoggingMixin) from apps.utils.mixins import (MyLoggingMixin, BulkCreateModelMixin, BulkDestroyModelMixin, CustomListModelMixin)
from django.conf import settings from django.conf import settings
from apps.utils.permission import ALL_PERMS from apps.utils.permission import ALL_PERMS
from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet
@ -229,7 +228,7 @@ class PTaskViewSet(CustomModelViewSet):
return Response() return Response()
class PTaskResultViewSet(ListModelMixin, RetrieveModelMixin, CustomGenericViewSet): class PTaskResultViewSet(CustomListModelMixin, RetrieveModelMixin, CustomGenericViewSet):
""" """
list:任务执行结果列表 list:任务执行结果列表
@ -373,7 +372,7 @@ class RoleViewSet(CustomModelViewSet):
ordering = ['create_time'] ordering = ['create_time']
class PostRoleViewSet(CreateModelMixin, DestroyModelMixin, ListModelMixin, CustomGenericViewSet): class PostRoleViewSet(BulkCreateModelMixin, BulkDestroyModelMixin, CustomListModelMixin, CustomGenericViewSet):
"""岗位/角色关系 """岗位/角色关系
岗位/角色关系 岗位/角色关系
@ -385,7 +384,7 @@ class PostRoleViewSet(CreateModelMixin, DestroyModelMixin, ListModelMixin, Custo
filterset_fields = ['post', 'role'] filterset_fields = ['post', 'role']
class UserPostViewSet(CreateModelMixin, DestroyModelMixin, ListModelMixin, CustomGenericViewSet): class UserPostViewSet(BulkCreateModelMixin, BulkDestroyModelMixin, CustomListModelMixin, CustomGenericViewSet):
"""用户/岗位关系 """用户/岗位关系
用户/岗位关系 用户/岗位关系
@ -398,37 +397,13 @@ class UserPostViewSet(CreateModelMixin, DestroyModelMixin, ListModelMixin, Custo
ordering = ['sort', 'create_time'] ordering = ['sort', 'create_time']
def perform_create(self, serializer): def perform_create(self, serializer):
with transaction.atomic(): instance = serializer.save()
instance = serializer.save() user = instance.user
user = instance.user up = UserPost.objects.filter(user=user).order_by(
up = UserPost.objects.filter(user=user).order_by( 'sort', 'create_time').first()
'sort', 'create_time').first() if up:
if up: user.belong_dept = up.dept
user.belong_dept = up.dept user.post = up.post
user.post = up.post
user.update_by = self.request.user
user.save()
# 更新人员表
ep = Employee.objects.get_queryset(
all=True).filter(user=user).first()
if ep:
ep.belong_dept = user.belong_dept
ep.post = user.post
ep.is_deleted = False
ep.save()
def perform_destroy(self, instance):
with transaction.atomic():
user = instance.user
instance.delete()
up = UserPost.objects.filter(user=user).order_by(
'sort', 'create_time').first()
if up:
user.belong_dept = up.dept
user.post = up.post
else:
user.belong_dept = None
user.post = None
user.update_by = self.request.user user.update_by = self.request.user
user.save() user.save()
# 更新人员表 # 更新人员表
@ -440,6 +415,28 @@ class UserPostViewSet(CreateModelMixin, DestroyModelMixin, ListModelMixin, Custo
ep.is_deleted = False ep.is_deleted = False
ep.save() ep.save()
def perform_destroy(self, instance):
user = instance.user
instance.delete()
up = UserPost.objects.filter(user=user).order_by(
'sort', 'create_time').first()
if up:
user.belong_dept = up.dept
user.post = up.post
else:
user.belong_dept = None
user.post = None
user.update_by = self.request.user
user.save()
# 更新人员表
ep = Employee.objects.get_queryset(
all=True).filter(user=user).first()
if ep:
ep.belong_dept = user.belong_dept
ep.post = user.post
ep.is_deleted = False
ep.save()
class UserViewSet(CustomModelViewSet): class UserViewSet(CustomModelViewSet):
queryset = User.objects.get_queryset(all=True) queryset = User.objects.get_queryset(all=True)
@ -610,7 +607,7 @@ class UserViewSet(CustomModelViewSet):
return Response() return Response()
class FileViewSet(CustomCreateModelMixin, RetrieveModelMixin, ListModelMixin, CustomGenericViewSet): class FileViewSet(BulkCreateModelMixin, RetrieveModelMixin, CustomListModelMixin, CustomGenericViewSet):
"""文件上传 """文件上传
list: list:
@ -651,7 +648,7 @@ class FileViewSet(CustomCreateModelMixin, RetrieveModelMixin, ListModelMixin, Cu
instance.save() instance.save()
class ApkViewSet(MyLoggingMixin, ListModelMixin, CreateModelMixin, GenericViewSet): class ApkViewSet(MyLoggingMixin, CustomListModelMixin, BulkCreateModelMixin, GenericViewSet):
perms_map = {'get': '*', 'post': 'apk.upload'} perms_map = {'get': '*', 'post': 'apk.upload'}
serializer_class = ApkSerializer serializer_class = ApkSerializer
@ -692,7 +689,7 @@ class ApkViewSet(MyLoggingMixin, ListModelMixin, CreateModelMixin, GenericViewSe
return Response() return Response()
class MyScheduleViewSet(ListModelMixin, CreateModelMixin, DestroyModelMixin, CustomGenericViewSet): class MyScheduleViewSet(CustomListModelMixin, BulkCreateModelMixin, BulkDestroyModelMixin, CustomGenericViewSet):
perms_map = {'get': '*', 'post': '*', perms_map = {'get': '*', 'post': '*',
'delete': 'myschedule.delete'} 'delete': 'myschedule.delete'}
serializer_class = MyScheduleSerializer serializer_class = MyScheduleSerializer

View File

@ -239,6 +239,7 @@ class TicketViewSet(CreateUpdateCustomMixin, CreateModelMixin, ListModelMixin, R
raise ParseError('请指定查询分类') raise ParseError('请指定查询分类')
return super().filter_queryset(queryset) return super().filter_queryset(queryset)
@transaction.atomic
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
""" """
新建工单 新建工单
@ -263,25 +264,25 @@ class TicketViewSet(CreateUpdateCustomMixin, CreateModelMixin, ListModelMixin, R
save_ticket_data[key] = ticket_data[key] save_ticket_data[key] = ticket_data[key]
else: else:
save_ticket_data = ticket_data save_ticket_data = ticket_data
with transaction.atomic():
ticket = serializer.save(state=start_state, ticket = serializer.save(state=start_state,
create_by=request.user, create_by=request.user,
create_time=timezone.now(), create_time=timezone.now(),
act_state=Ticket.TICKET_ACT_STATE_DRAFT, act_state=Ticket.TICKET_ACT_STATE_DRAFT,
belong_dept=request.user.belong_dept, belong_dept=request.user.belong_dept,
ticket_data=save_ticket_data) # 先创建出来 ticket_data=save_ticket_data) # 先创建出来
# 更新title和sn # 更新title和sn
title = vdata.get('title', '') title = vdata.get('title', '')
title_template = ticket.workflow.title_template title_template = ticket.workflow.title_template
if title_template: if title_template:
all_ticket_data = {**rdata, **ticket_data} all_ticket_data = {**rdata, **ticket_data}
title = title_template.format(**all_ticket_data) title = title_template.format(**all_ticket_data)
sn = WfService.get_ticket_sn(ticket.workflow) # 流水号 sn = WfService.get_ticket_sn(ticket.workflow) # 流水号
ticket.sn = sn ticket.sn = sn
ticket.title = title ticket.title = title
ticket.save() ticket.save()
ticket = WfService.handle_ticket(ticket=ticket, transition=transition, new_ticket_data=ticket_data, ticket = WfService.handle_ticket(ticket=ticket, transition=transition, new_ticket_data=ticket_data,
handler=request.user, created=True) handler=request.user, created=True)
return Response(TicketSerializer(instance=ticket).data) return Response(TicketSerializer(instance=ticket).data)
@action(methods=['get'], detail=False, perms_map={'get': '*'}) @action(methods=['get'], detail=False, perms_map={'get': '*'})
@ -297,6 +298,7 @@ class TicketViewSet(CreateUpdateCustomMixin, CreateModelMixin, ListModelMixin, R
return Response(ret) return Response(ret)
@action(methods=['post'], detail=True, perms_map={'post': '*'}) @action(methods=['post'], detail=True, perms_map={'post': '*'})
@transaction.atomic
def handle(self, request, pk=None): def handle(self, request, pk=None):
""" """
处理工单 处理工单
@ -307,13 +309,13 @@ class TicketViewSet(CreateUpdateCustomMixin, CreateModelMixin, ListModelMixin, R
vdata = serializer.validated_data vdata = serializer.validated_data
new_ticket_data = ticket.ticket_data new_ticket_data = ticket.ticket_data
new_ticket_data.update(**vdata['ticket_data']) new_ticket_data.update(**vdata['ticket_data'])
with transaction.atomic(): ticket = WfService.handle_ticket(ticket=ticket, transition=vdata['transition'],
ticket = WfService.handle_ticket(ticket=ticket, transition=vdata['transition'], new_ticket_data=new_ticket_data, handler=request.user,
new_ticket_data=new_ticket_data, handler=request.user, suggestion=vdata.get('suggestion', ''))
suggestion=vdata.get('suggestion', ''))
return Response(TicketSerializer(instance=ticket).data) return Response(TicketSerializer(instance=ticket).data)
@action(methods=['post'], detail=True, perms_map={'post': '*'}) @action(methods=['post'], detail=True, perms_map={'post': '*'})
@transaction.atomic
def deliver(self, request, pk=None): def deliver(self, request, pk=None):
""" """
转交工单 转交工单
@ -325,15 +327,14 @@ class TicketViewSet(CreateUpdateCustomMixin, CreateModelMixin, ListModelMixin, R
vdata = serializer.validated_data # 校验之后的数据 vdata = serializer.validated_data # 校验之后的数据
if not ticket.state.enable_deliver: if not ticket.state.enable_deliver:
raise ParseError('不允许转交') raise ParseError('不允许转交')
with transaction.atomic(): ticket.participant_type = State.PARTICIPANT_TYPE_PERSONAL
ticket.participant_type = State.PARTICIPANT_TYPE_PERSONAL ticket.participant = vdata['target_user']
ticket.participant = vdata['target_user'] ticket.save()
ticket.save() TicketFlow.objects.create(ticket=ticket, state=ticket.state,
TicketFlow.objects.create(ticket=ticket, state=ticket.state, ticket_data=WfService.get_ticket_all_field_value(ticket),
ticket_data=WfService.get_ticket_all_field_value(ticket), suggestion=vdata.get('suggestion', ''), participant_type=State.PARTICIPANT_TYPE_PERSONAL,
suggestion=vdata.get('suggestion', ''), participant_type=State.PARTICIPANT_TYPE_PERSONAL, intervene_type=Transition.TRANSITION_INTERVENE_TYPE_DELIVER,
intervene_type=Transition.TRANSITION_INTERVENE_TYPE_DELIVER, participant=request.user, transition=None)
participant=request.user, transition=None)
return Response() return Response()
@action(methods=['get'], detail=True, perms_map={'get': '*'}) @action(methods=['get'], detail=True, perms_map={'get': '*'})