diff --git a/hb_server/apps/wf/migrations/0019_auto_20211221_0923.py b/hb_server/apps/wf/migrations/0019_auto_20211221_0923.py new file mode 100644 index 0000000..6e96c47 --- /dev/null +++ b/hb_server/apps/wf/migrations/0019_auto_20211221_0923.py @@ -0,0 +1,43 @@ +# Generated by Django 3.2.9 on 2021-12-21 01:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wf', '0018_workflow_key'), + ] + + operations = [ + migrations.AddField( + model_name='ticket', + name='script_run_last_result', + field=models.BooleanField(default=True, verbose_name='脚本最后一次执行结果'), + ), + migrations.AddField( + model_name='ticketflow', + name='participant_str', + field=models.CharField(blank=True, help_text='非人工处理的处理人相关信息', max_length=200, null=True, verbose_name='处理人'), + ), + migrations.AlterField( + model_name='state', + name='state_fields', + field=models.JSONField(default=dict, help_text='json格式字典存储,包括读写属性1:只读,2:必填,3:可选, 4:隐藏 示例:{"create_time":1,"title":2, "sn":1}, 内置特殊字段participant_info.participant_name:当前处理人信息(部门名称、角色名称),state.state_name:当前状态的状态名,workflow.workflow_name:工作流名称', verbose_name='表单字段'), + ), + migrations.AlterField( + model_name='ticket', + name='title', + field=models.CharField(blank=True, help_text='工单标题', max_length=500, null=True, verbose_name='标题'), + ), + migrations.AlterField( + model_name='ticketflow', + name='participant_type', + field=models.IntegerField(choices=[(0, '无处理人'), (1, '个人'), (2, '多人'), (4, '角色'), (6, '脚本'), (7, '工单的字段'), (9, '代码获取')], default=0, help_text='0.无处理人,1.个人,2.多人等', verbose_name='处理人类型'), + ), + migrations.AlterField( + model_name='workflow', + name='description', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='描述'), + ), + ] diff --git a/hb_server/apps/wf/models.py b/hb_server/apps/wf/models.py index 34eb8ec..be20e37 100644 --- a/hb_server/apps/wf/models.py +++ b/hb_server/apps/wf/models.py @@ -206,7 +206,7 @@ class Ticket(CommonBModel): ticket_data = models.JSONField('工单数据', default=dict, help_text='工单自定义字段内容') in_add_node = models.BooleanField('加签状态中', default=False, help_text='是否处于加签状态下') add_node_man = models.ForeignKey(User, verbose_name='加签人', on_delete=models.SET_NULL, null=True, blank=True, help_text='加签操作的人,工单当前处理人处理完成后会回到该处理人,当处于加签状态下才有效') - + script_run_last_result = models.BooleanField(u'脚本最后一次执行结果', default=True) participant_type = models.IntegerField('当前处理人类型', default=0, help_text='0.无处理人,1.个人,2.多人', choices=State.state_participanttype_choices) participant = models.JSONField('当前处理人', default=list, blank=True, help_text='可以为空(无处理人的情况,如结束状态)、userid、userid列表') act_state = models.IntegerField('进行状态', default=1, help_text='当前工单的进行状态', choices=act_state_choices) @@ -228,8 +228,9 @@ class TicketFlow(BaseModel): ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE, verbose_name='关联工单', related_name='ticketflow_ticket') transition = models.ForeignKey(Transition, verbose_name='流转id', help_text='与worklow.Transition关联, 为空时表示认为干预的操作', on_delete=models.CASCADE, null=True, blank=True) suggestion = models.CharField('处理意见', max_length=10000, default='', blank=True) - participant_type = models.IntegerField('处理人类型', default=0, help_text='0.无处理人,1.个人,2.多人', choices=State.state_participanttype_choices) + participant_type = models.IntegerField('处理人类型', default=0, help_text='0.无处理人,1.个人,2.多人等', choices=State.state_participanttype_choices) participant = models.ForeignKey(User, verbose_name='处理人', on_delete=models.SET_NULL, null=True, blank=True, related_name='ticketflow_participant') + participant_str = models.CharField('处理人', max_length=200, null=True, blank=True, help_text='非人工处理的处理人相关信息') state = models.ForeignKey(State, verbose_name='当前状态', default=0, blank=True, on_delete=models.CASCADE) ticket_data = models.JSONField('工单数据', default=dict, blank=True, help_text='可以用于记录当前表单数据,json格式') intervene_type = models.IntegerField('干预类型', default=0, help_text='流转类型', choices=Transition.intervene_type_choices) diff --git a/hb_server/apps/wf/scripts.py b/hb_server/apps/wf/scripts.py index e96502f..3ce706f 100644 --- a/hb_server/apps/wf/scripts.py +++ b/hb_server/apps/wf/scripts.py @@ -1,3 +1,8 @@ +from apps.system.models import User +from apps.wf.models import State, Ticket, TicketFlow, Transition +from apps.wpm.models import WProduct + + class GetParticipants: all_funcs = [ @@ -9,7 +14,7 @@ class GetParticipants: # return [(func, getattr(self, func).__doc__) for func in dir(self) if callable(getattr(self, func)) and func.startswith('get_')] @classmethod - def get_create_by(cls, state:dict={}, ticket:dict={}, ticket_data:dict={}, request={}): + def get_create_by(cls, state:dict={}, ticket:dict={}, new_ticket_data:dict={}, handler:User={}): """工单创建人""" participant = ticket.create_by.id return participant @@ -18,12 +23,51 @@ class HandleScripts: all_funcs = [ {'func': 'handle_wproduct', 'name':'处理不合格品'} ] + + @classmethod - def handle_wproduct(cls, ticket:dict={}): + def to_next(cls, ticket:Ticket, by_timer:bool=False, by_task:bool=False, by_hook:bool=False, script_str:str=''): + # 获取信息 + transition_obj = Transition.objects.filter(source_state=ticket.state, is_deleted=False).first() + + TicketFlow.objects.create(ticket=ticket, state=ticket.state, + participant_type=State.PARTICIPANT_TYPE_ROBOT, + participant_str='func:{}'.format(script_str), + transition=transition_obj) + from .services import WfService + + # 自动执行流转 + WfService.handle_ticket(ticket=ticket, transition=transition_obj, new_ticket_data=ticket.ticket_data, by_task=True) + + return ticket + + @classmethod + def handle_wproduct(cls, ticket:Ticket): """处理不合格品""" + # 任务处理 + ticket_data = ticket.ticket_data - wp = ticket.wt_ticket - wp = ticket_data + wt = ticket.wt_ticket + wp = wt.wproduct if 'shenli2' in ticket_data and ticket_data['shenli2']: + wt.decision = ticket_data['shenli2'] if ticket_data['shenli2'] in ['返工', '返修']: - pass \ No newline at end of file + pass + elif ticket_data['shenli2'] in ['让步接收']: + wp.act_state = WProduct.WPR_ACT_STATE_OK + elif 'shenli1' in ticket_data and ticket_data['shenli1']: + wp.decision = ticket_data['shenli1'] + if ticket_data['shenli1'] in ['返工', '返修']: + pass + elif ticket_data['shenli1'] in ['让步接收']: + wp.act_state = WProduct.WPR_ACT_STATE_OK + wt.save() + wp.save() + + # 调用自动流转 + ticket = cls.to_next(ticket=ticket, by_task=True, script_str= 'handle_wproduct') + if ticket.act_state == Ticket.TICKET_ACT_STATE_FINISH: + # 如果工单完成 + wp.ticket = None + wp.save() + diff --git a/hb_server/apps/wf/serializers.py b/hb_server/apps/wf/serializers.py index ae3bf88..3c3a730 100644 --- a/hb_server/apps/wf/serializers.py +++ b/hb_server/apps/wf/serializers.py @@ -1,3 +1,4 @@ +from apps.system.models import User from apps.system.serializers import UserSimpleSerializer import rest_framework from rest_framework import serializers @@ -55,7 +56,6 @@ class TicketCreateSerializer(serializers.ModelSerializer): fields=['title','workflow', 'ticket_data', 'transition'] def create(self, validated_data): - validated_data.pop('transition') return super().create(validated_data) class TicketSerializer(serializers.ModelSerializer): @@ -124,7 +124,7 @@ class TicketFlowSimpleSerializer(serializers.ModelSerializer): class TicketHandleSerializer(serializers.Serializer): - transition = serializers.IntegerField(label="流转id") + transition = serializers.PrimaryKeyRelatedField(queryset=Transition.objects.all(), label="流转id") ticket_data = serializers.JSONField(label="表单数据json") suggestion = serializers.CharField(label="处理意见", required = False) @@ -136,10 +136,10 @@ class TicketCloseSerializer(serializers.Serializer): class TicketAddNodeSerializer(serializers.Serializer): suggestion = serializers.CharField(label="加签说明", required = False) - toadd_user = serializers.IntegerField(label='发送给谁去加签') + toadd_user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all(), label='发送给谁去加签') class TicketAddNodeEndSerializer(serializers.Serializer): suggestion = serializers.CharField(label="加签意见", required = False) class TicketDestorySerializer(serializers.Serializer): - ids = serializers.ListField(child=serializers.IntegerField(), label='工单ID列表') \ No newline at end of file + ids = serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=Ticket.objects.all()), label='工单ID列表') \ No newline at end of file diff --git a/hb_server/apps/wf/services.py b/hb_server/apps/wf/services.py index 17d9c63..bf83291 100644 --- a/hb_server/apps/wf/services.py +++ b/hb_server/apps/wf/services.py @@ -2,12 +2,12 @@ from apps.wf.serializers import CustomFieldSerializer from apps.wf.serializers import TicketSerializer, TicketSimpleSerializer from typing import Tuple from apps.system.models import User -from apps.wf.models import CustomField, State, Ticket, Transition, Workflow -from rest_framework.exceptions import APIException +from apps.wf.models import CustomField, State, Ticket, TicketFlow, Transition, Workflow +from rest_framework.exceptions import APIException, PermissionDenied from django.utils import timezone from datetime import timedelta import random -from .scripts import GetParticipants +from .scripts import GetParticipants, HandleScripts from utils.queryset import get_parent_queryset class WfService(object): @@ -113,14 +113,14 @@ class WfService(object): @classmethod - def get_next_state_by_transition_and_ticket_info(cls, ticket:Ticket, transition: Transition, ticket_data:dict={}, request:dict={})->object: + def get_next_state_by_transition_and_ticket_info(cls, ticket:Ticket, transition: Transition, new_ticket_data:dict={})->object: """ 获取下个节点状态 """ source_state = ticket.state destination_state = transition.destination_state ticket_all_value = cls.get_ticket_all_field_value(ticket) - ticket_all_value.update(**ticket_data) + ticket_all_value.update(**new_ticket_data) for key, value in ticket_all_value.items(): if isinstance(ticket_all_value[key], str): ticket_all_value[key] = "'" + ticket_all_value[key] + "'" @@ -133,7 +133,7 @@ class WfService(object): return destination_state @classmethod - def get_ticket_state_participant_info(cls, state:State, ticket:Ticket, ticket_data:dict={}, request={}): + def get_ticket_state_participant_info(cls, state:State, ticket:Ticket, new_ticket_data:dict={}, handler:User=None): """ 获取工单目标状态实际的处理人, 处理人类型 """ @@ -154,11 +154,12 @@ class WfService(object): multi_all_person_dict = {} destination_participant_type, destination_participant = state.participant_type, state.participant if destination_participant_type == State.PARTICIPANT_TYPE_FIELD: - destination_participant = ticket_data.get(destination_participant, 0) if destination_participant in ticket_data \ + destination_participant = new_ticket_data.get(destination_participant, 0) if destination_participant in new_ticket_data \ else Ticket.ticket_data.get(destination_participant, 0) elif destination_participant_type == State.PARTICIPANT_TYPE_FORMCODE:#代码获取 - destination_participant = getattr(GetParticipants, destination_participant)(state=state, ticket=ticket, ticket_data=ticket_data, request=request) + destination_participant = getattr(GetParticipants, destination_participant)( + state=state, ticket=ticket, new_ticket_data=new_ticket_data, hander=handler) elif destination_participant_type == State.PARTICIPANT_TYPE_DEPT:#部门 destination_participant = list(User.objects.filter(dept__in=destination_participant).values_list('id', flat=True)) @@ -173,7 +174,7 @@ class WfService(object): depts = get_parent_queryset(ticket.create_by.dept) user_queryset = user_queryset.filter(dept__in=depts) elif state.filter_policy == 3: - depts = get_parent_queryset(request.user.dept) + depts = get_parent_queryset(handler.dept) user_queryset = user_queryset.filter(dept__in=depts) destination_participant = list(user_queryset.values_list('id', flat=True)) if type(destination_participant) == list: @@ -256,5 +257,93 @@ class WfService(object): field_info_dict[i.field_key] = ticket.ticket_data.get(i.field_key, None) return field_info_dict + @classmethod + def handle_ticket(cls, ticket:Ticket, transition: Transition, new_ticket_data:dict={}, handler:User=None, + suggestion:str='', created:bool=False, by_timer:bool=False, by_task:bool=False, by_hook:bool=False): + source_state = ticket.state + source_ticket_data = ticket.ticket_data + + # 校验处理权限 + if not handler or not created: # 没有处理人意味着系统触发不校验处理权限 + result = WfService.ticket_handle_permission_check(ticket, handler) + if result.get('permission') is False: + raise PermissionDenied(result.get('msg')) + + # 校验表单必填项目 + if transition.field_require_check or not created: + for key, value in ticket.state.state_fields.items(): + if value == State.STATE_FIELD_REQUIRED: + if key not in new_ticket_data or not new_ticket_data[key]: + raise APIException('字段{}必填'.format(key)) + + destination_state = cls.get_next_state_by_transition_and_ticket_info(ticket, transition, new_ticket_data) + multi_all_person = ticket.multi_all_person + if multi_all_person: + multi_all_person[handler.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, new_ticket_data) + destination_participant_type = participant_info.get('destination_participant_type', 0) + destination_participant = participant_info.get('destination_participant', 0) + 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.append(key) + else: + # 当前处理人类型非全部处理 + participant_info = WfService.get_ticket_state_participant_info(destination_state, ticket, new_ticket_data) + destination_participant_type = participant_info.get('destination_participant_type', 0) + destination_participant = participant_info.get('destination_participant', 0) + 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: + ticket.act_state = Ticket.TICKET_ACT_STATE_BACK + + # 只更新必填和可选的字段 + if not created: + for key, value in source_state.state_fields.items(): + if value in (State.STATE_FIELD_REQUIRED, State.STATE_FIELD_OPTIONAL): + source_ticket_data[key] = new_ticket_data[key] + ticket.ticket_data = source_ticket_data + ticket.save() + + # 更新工单流转记录 + if not by_task: + TicketFlow.objects.create(ticket=ticket, state=source_state, ticket_data=WfService.get_ticket_all_field_value(ticket), + suggestion=suggestion, participant_type=State.PARTICIPANT_TYPE_PERSONAL, + participant=handler, transition=transition) + + if created: + if source_state.participant_cc: + TicketFlow.objects.create(ticket=ticket, state=source_state, + participant_type=0, intervene_type=Transition.TRANSITION_INTERVENE_TYPE_CC, + participant=None, participant_cc=source_state.participant_cc) + + # 目标状态需要抄送 + if destination_state.participant_cc: + TicketFlow.objects.create(ticket=ticket, state=destination_state, + participant_type=0, intervene_type=Transition.TRANSITION_INTERVENE_TYPE_CC, + participant=None, participant_cc=destination_state.participant_cc) + + # 如果目标状态是脚本则执行 + if destination_state.participant_type == State.PARTICIPANT_TYPE_ROBOT: + getattr(HandleScripts, destination_state.participant)(ticket) diff --git a/hb_server/apps/wf/views.py b/hb_server/apps/wf/views.py index d9c586b..ed9ec46 100644 --- a/hb_server/apps/wf/views.py +++ b/hb_server/apps/wf/views.py @@ -1,3 +1,4 @@ +from django.db import transaction from django.db.models import query from rest_framework.utils import serializer_helpers from rest_framework.views import APIView @@ -17,7 +18,7 @@ from apps.wf.services import WfService from rest_framework.exceptions import APIException, PermissionDenied from rest_framework import status from django.db.models import Count -from .scripts import GetParticipants +from .scripts import GetParticipants, HandleScripts # Create your views here. @@ -135,6 +136,7 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin raise APIException('请指定查询分类') return super().get_queryset() + @transaction.atomic def create(self, request, *args, **kwargs): """ 新建工单 @@ -148,7 +150,7 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin ticket_data = vdata['ticket_data'] save_ticket_data = {} - #校验必填项 + # 校验必填项 if transition.field_require_check: for key, value in start_state.state_fields.items(): if value == State.STATE_FIELD_REQUIRED: @@ -163,47 +165,18 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin act_state=Ticket.TICKET_ACT_STATE_DRAFT, belong_dept=request.user.dept, ticket_data=save_ticket_data) # 先创建出来 - - 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', 0) - 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 = vdata['title'] + # 更新title和sn + title = vdata.get('title', '') title_template = ticket.workflow.title_template if title_template: - all_ticket_data = {**rdata, **rdata['ticket_data']} + all_ticket_data = {**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 + sn = WfService.get_ticket_sn(ticket.workflow) # 流水号 + ticket.sn = sn + ticket.title = title 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) - # 开始状态需要抄送 - if start_state.participant_cc: - TicketFlow.objects.create(ticket=ticket, state=ticket.start_state, - participant_type=0, intervene_type=Transition.TRANSITION_INTERVENE_TYPE_CC, - participant=None, participant_cc=start_state.participant_cc) - # 目标状态需要抄送 - if next_state.participant_cc: - TicketFlow.objects.create(ticket=ticket, state=next_state, - participant_type=0, intervene_type=Transition.TRANSITION_INTERVENE_TYPE_CC, - participant=None, participant_cc=next_state.participant_cc) + ticket = WfService.handle_ticket(ticket=ticket, transition=transition, new_ticket_data=ticket_data, + handler=request.user) return Response(TicketSerializer(instance=ticket).data) @action(methods=['get'], detail=False, perms_map={'get':'*'}) @@ -219,85 +192,18 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin return Response(ret) @action(methods=['post'], detail=True, perms_map={'post':'*'}) + @transaction.atomic 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, ticket_data, request) - 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', 0) - 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.append(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', 0) - 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: - ticket.act_state = Ticket.TICKET_ACT_STATE_BACK - - # 只更新必填和可选的字段 - for key, value in source_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) - # 目标状态需要抄送 - if destination_state.participant_cc: - TicketFlow.objects.create(ticket=ticket, state=destination_state, - participant_type=0, intervene_type=Transition.TRANSITION_INTERVENE_TYPE_CC, - participant=None, participant_cc=destination_state.participant_cc) + ticket = self.get_object() + serializer = TicketHandleSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + vdata = serializer.validated_data + new_ticket_data = ticket.ticket_data.update(**vdata['ticket_data']) + ticket = WfService.handle_ticket(ticket=ticket, transition=vdata['transition'], + new_ticket_data=new_ticket_data, handler=request.user, suggestion=vdata['suggestion']) return Response(TicketSerializer(instance=ticket).data) diff --git a/hb_server/apps/wpm/migrations/0036_auto_20211221_0923.py b/hb_server/apps/wpm/migrations/0036_auto_20211221_0923.py new file mode 100644 index 0000000..a8b1312 --- /dev/null +++ b/hb_server/apps/wpm/migrations/0036_auto_20211221_0923.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.9 on 2021-12-21 01:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpm', '0035_alter_operationrecorditem_field_value'), + ] + + operations = [ + migrations.AddField( + model_name='wprouctticket', + name='decision', + field=models.CharField(blank=True, max_length=100, null=True, verbose_name='最终决定'), + ), + migrations.AlterField( + model_name='wproduct', + name='act_state', + field=models.IntegerField(choices=[(6, '待复检'), (8, '操作准备中'), (10, '操作进行中'), (20, '待检验'), (26, '待夹层检验'), (30, '已合格'), (40, '已入库'), (50, '不合格'), (60, '待成品检验'), (70, '已报废')], default=0, verbose_name='进行状态'), + ), + ]