增加记录表格表
This commit is contained in:
parent
cc9006b695
commit
32459d8710
|
@ -70,15 +70,27 @@ class Step(CommonAModel):
|
|||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
# class StepTable(CommonAModel):
|
||||
# """
|
||||
# 过程记录表格
|
||||
# """
|
||||
|
||||
|
||||
class StepOperationItem(CommonAModel):
|
||||
class RecordForm(CommonAModel):
|
||||
"""
|
||||
操作记录条目
|
||||
记录表格
|
||||
"""
|
||||
type_choices=(
|
||||
(1, '生产记录'),
|
||||
)
|
||||
name = models.CharField('表格名称', max_length=100, unique=True)
|
||||
type = models.IntegerField('表格类型', choices=type_choices, default=1)
|
||||
step = models.ForeignKey(Step, verbose_name='关联子工序', on_delete=models.CASCADE)
|
||||
|
||||
class Meta:
|
||||
verbose_name = '记录表格'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class RecordFormField(CommonAModel):
|
||||
"""
|
||||
记录字段表
|
||||
"""
|
||||
field_type_choices = (
|
||||
('string', '字符串'),
|
||||
|
@ -93,7 +105,7 @@ class StepOperationItem(CommonAModel):
|
|||
('selects', '多选下拉'),
|
||||
('textarea', '文本域'),
|
||||
)
|
||||
step = models.ForeignKey(Step, on_delete=models.CASCADE, verbose_name='关联步骤')
|
||||
form = models.ForeignKey(RecordForm, on_delete=models.CASCADE, verbose_name='关联表格')
|
||||
field_type = models.CharField('类型', max_length=50, choices=field_type_choices)
|
||||
field_key = models.CharField('字段标识', max_length=50, help_text='字段类型请尽量特殊,避免与系统中关键字冲突')
|
||||
field_name = models.CharField('字段名称', max_length=50)
|
||||
|
@ -103,7 +115,7 @@ class StepOperationItem(CommonAModel):
|
|||
help_text='radio,checkbox,select,multiselect类型可供选择的选项,格式为json如:{"1":"中国", "2":"美国"},注意数字也需要引号')
|
||||
sort = models.IntegerField('排序号', default=1)
|
||||
class Meta:
|
||||
verbose_name = '操作记录条目'
|
||||
verbose_name = '记录表格字段'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
def __str__(self):
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from apps.em.serializers import EquipmentSerializer, EquipmentSimpleSerializer
|
||||
from rest_framework import serializers
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from .models import InputMaterial, Material, OutputMaterial, Process, ProductProcess, Step, UsedStep
|
||||
from .models import InputMaterial, Material, OutputMaterial, Process, ProductProcess, RecordForm, RecordFormField, Step, UsedStep
|
||||
from apps.system.serializers import FileSimpleSerializer, OrganizationSimpleSerializer
|
||||
|
||||
|
||||
|
@ -137,3 +137,53 @@ class UsedStepListSerializer(serializers.ModelSerializer):
|
|||
""" Perform necessary eager loading of data. """
|
||||
queryset = queryset.select_related('step')
|
||||
return queryset
|
||||
|
||||
class RecordFormSerializer(serializers.ModelSerializer):
|
||||
step_ = StepSimpleSerializer(source='step', read_only=True)
|
||||
"""
|
||||
记录表格序列化
|
||||
"""
|
||||
class Meta:
|
||||
model = RecordForm
|
||||
fields = '__all__'
|
||||
|
||||
@staticmethod
|
||||
def setup_eager_loading(queryset):
|
||||
""" Perform necessary eager loading of data. """
|
||||
queryset = queryset.select_related('step')
|
||||
return queryset
|
||||
|
||||
class RecordFormCreateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = RecordForm
|
||||
fields = ['name', 'type', 'step']
|
||||
|
||||
class RecordFormUpdateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = RecordForm
|
||||
fields = ['name', 'type']
|
||||
|
||||
class RecordFormFieldSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = RecordForm
|
||||
fields = '__all__'
|
||||
|
||||
class RecordFormFieldCreateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = RecordFormField
|
||||
fields = ['form', 'field_type', 'field_key', 'field_name', 'boolean_field_display', 'field_choice', 'sort']
|
||||
|
||||
def validate(self, data):
|
||||
if RecordFormField.objects.filter(field_key=data['field_key'], form=data['form'], is_deleted=False).exists():
|
||||
raise ValidationError('字段key已存在!')
|
||||
return data
|
||||
|
||||
class RecordFormFieldUpdateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = RecordFormField
|
||||
fields = ['field_type', 'field_name', 'boolean_field_display', 'field_choice', 'sort']
|
||||
|
||||
class RecordFormFieldSimpleSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = RecordFormField
|
||||
fields = '__all__'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from django.db.models import base
|
||||
from rest_framework import urlpatterns
|
||||
from apps.mtm.views import InputMaterialViewSet, MaterialViewSet, OutputMaterialViewSet, ProcessViewSet, StepViewSet, UsedStepViewSet
|
||||
from apps.mtm.views import InputMaterialViewSet, MaterialViewSet, OutputMaterialViewSet, ProcessViewSet, RecordFormFieldViewSet, RecordFormViewSet, StepViewSet, UsedStepViewSet
|
||||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
|
@ -12,6 +12,8 @@ router.register('step', StepViewSet, basename='step')
|
|||
router.register('inputmaterial', InputMaterialViewSet, basename='inputmaterial')
|
||||
router.register('outputmaterial', OutputMaterialViewSet, basename='outputmaterial')
|
||||
router.register('usedstep', UsedStepViewSet, basename='usedstep')
|
||||
router.register('recordform', RecordFormViewSet, basename='recordform')
|
||||
router.register('recordform-field', RecordFormFieldViewSet, basename='recordform-field')
|
||||
urlpatterns = [
|
||||
path('', include(router.urls)),
|
||||
]
|
||||
|
|
|
@ -2,8 +2,8 @@ from django.shortcuts import render
|
|||
from rest_framework.viewsets import ModelViewSet, GenericViewSet
|
||||
from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin
|
||||
|
||||
from apps.mtm.models import InputMaterial, Material, OutputMaterial, Process, ProductProcess, Step, UsedStep
|
||||
from apps.mtm.serializers import InputMaterialListSerializer, InputMaterialSerializer, InputMaterialUpdateSerializer, MaterialDetailSerializer, MaterialSerializer, MaterialSimpleSerializer, OutputMaterialListSerializer, OutputMaterialSerializer, OutputMaterialUpdateSerializer, ProductProcessListSerializer, ProductProcessUpdateSerializer, ProcessSerializer, StepDetailSerializer, StepSerializer, UsedStepCreateSerializer, UsedStepListSerializer
|
||||
from apps.mtm.models import InputMaterial, Material, OutputMaterial, Process, ProductProcess, RecordForm, RecordFormField, Step, UsedStep
|
||||
from apps.mtm.serializers import InputMaterialListSerializer, InputMaterialSerializer, InputMaterialUpdateSerializer, MaterialDetailSerializer, MaterialSerializer, MaterialSimpleSerializer, OutputMaterialListSerializer, OutputMaterialSerializer, OutputMaterialUpdateSerializer, ProductProcessListSerializer, ProductProcessUpdateSerializer, ProcessSerializer, RecordFormCreateSerializer, RecordFormFieldCreateSerializer, RecordFormFieldSerializer, RecordFormFieldUpdateSerializer, RecordFormSerializer, RecordFormUpdateSerializer, StepDetailSerializer, StepSerializer, UsedStepCreateSerializer, UsedStepListSerializer
|
||||
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
|
@ -127,7 +127,7 @@ class OutputMaterialViewSet(CreateUpdateModelAMixin, ModelViewSet):
|
|||
return OutputMaterialUpdateSerializer
|
||||
return OutputMaterialSerializer
|
||||
|
||||
class UsedStepViewSet(OptimizationMixin, CreateModelMixin, DestroyModelMixin, ListModelMixin, GenericViewSet):
|
||||
class UsedStepViewSet(OptimizationMixin, CreateUpdateModelAMixin, CreateModelMixin, DestroyModelMixin, ListModelMixin, GenericViewSet):
|
||||
"""
|
||||
产品生产子工序表
|
||||
"""
|
||||
|
@ -139,4 +139,37 @@ class UsedStepViewSet(OptimizationMixin, CreateModelMixin, DestroyModelMixin, Li
|
|||
def get_serializer_class(self):
|
||||
if self.action =='create':
|
||||
return UsedStepCreateSerializer
|
||||
return UsedStepListSerializer
|
||||
return UsedStepListSerializer
|
||||
|
||||
class RecordFormViewSet(OptimizationMixin, CreateUpdateModelAMixin, ModelViewSet):
|
||||
"""
|
||||
记录表格增删改查
|
||||
"""
|
||||
perms_map = {'*':'*'}
|
||||
queryset = RecordForm.objects.all()
|
||||
filterset_fields = ['step', 'type']
|
||||
search_fields = ['name']
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action =='create':
|
||||
return RecordFormCreateSerializer
|
||||
elif self.action == 'update':
|
||||
return RecordFormUpdateSerializer
|
||||
return RecordFormSerializer
|
||||
|
||||
|
||||
class RecordFormFieldViewSet(OptimizationMixin, CreateUpdateModelAMixin, ModelViewSet):
|
||||
"""
|
||||
表格字段表 增删改查
|
||||
"""
|
||||
perms_map = {'*':'*'}
|
||||
queryset = RecordFormField.objects.all()
|
||||
filterset_fields = ['field_type', 'form']
|
||||
search_fields = ['field_name', 'field_key']
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action =='create':
|
||||
return RecordFormFieldCreateSerializer
|
||||
elif self.action == 'update':
|
||||
return RecordFormFieldUpdateSerializer
|
||||
return RecordFormFieldSerializer
|
|
@ -89,7 +89,7 @@ class WfService(object):
|
|||
|
||||
|
||||
@classmethod
|
||||
def get_next_state_id_by_transition_and_ticket_info(cls, ticket:Ticket, transition: Transition)->object:
|
||||
def get_next_state_by_transition_and_ticket_info(cls, ticket:Ticket, transition: Transition)->object:
|
||||
"""
|
||||
获取下个节点状态
|
||||
"""
|
||||
|
@ -172,8 +172,37 @@ class WfService(object):
|
|||
if ticket.in_add_node:
|
||||
return dict(permission=False, msg="工单当前处于加签中,请加签完成后操作")
|
||||
return dict(permission=True, msg="")
|
||||
|
||||
@classmethod
|
||||
def check_dict_has_all_same_value(cls, dict_obj: object)->tuple:
|
||||
"""
|
||||
check whether all key are equal in a dict
|
||||
:param dict_obj:
|
||||
:return:
|
||||
"""
|
||||
value_list = []
|
||||
for key, value in dict_obj.items():
|
||||
value_list.append(value)
|
||||
value_0 = value_list[0]
|
||||
for value in value_list:
|
||||
if value_0 != value:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_ticket_all_field_value(cls, ticket: Ticket)->dict:
|
||||
"""
|
||||
工单所有字段的值
|
||||
get ticket's all field value
|
||||
:param ticket:
|
||||
:return:
|
||||
"""
|
||||
# 获取工单基础表中的字段中的字段信息
|
||||
field_info_dict = ticket.get_dict()
|
||||
# 获取自定义字段的值
|
||||
custom_fields_queryset = cls.get_workflow_custom_fields(ticket.workflow)
|
||||
for i in custom_fields_queryset:
|
||||
field_info_dict[i.field_key] = ticket.ticket_data.get(i.field_key, None)
|
||||
return field_info_dict
|
||||
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ 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
|
||||
from rest_framework.exceptions import APIException, PermissionDenied
|
||||
|
||||
# Create your views here.
|
||||
class WorkflowViewSet(CreateUpdateModelAMixin, ModelViewSet):
|
||||
|
@ -117,10 +117,10 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin
|
|||
if key not in ticket_data or not ticket_data[key]:
|
||||
raise APIException('字段{}必填'.format(key))
|
||||
ticket = serializer.save(state=start_state) # 先创建出来
|
||||
next_state = WfService.get_next_state_id_by_transition_and_ticket_info(ticket=ticket, transition=transition)
|
||||
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', '')
|
||||
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:
|
||||
|
@ -144,9 +144,9 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin
|
|||
ticket.multi_all_person=multi_all_person
|
||||
ticket.save()
|
||||
# 新增流转记录
|
||||
TicketFlow.objects.create(ticket=ticket, state=start_state, ticket_data=ticket_data,
|
||||
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)
|
||||
participant=ticket.create_by, transition=transition, create_by=request.user)
|
||||
return Response(TicketSerializer(instance=ticket).data)
|
||||
|
||||
|
||||
|
@ -160,7 +160,72 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin
|
|||
except:
|
||||
raise APIException('工单不存在')
|
||||
data = request.data
|
||||
result = WfService.ticket_handle_permission_check()
|
||||
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 = State.TICKET_ACT_STATE_FINISH
|
||||
elif destination_state.type == State.STATE_TYPE_START:
|
||||
ticket.act_state = State.TICKET_ACT_STATE_DRAFT
|
||||
else:
|
||||
ticket.act_state = State.TICKET_ACT_STATE_ONGOING
|
||||
|
||||
if transition.attribute_type == State.TRANSITION_ATTRIBUTE_TYPE_REFUSE:
|
||||
transition.act_state = State.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, create_by=request.user)
|
||||
return Response(TicketSerializer(instance=ticket).data)
|
||||
|
||||
|
||||
@action(methods=['get'], detail=True, perms_map={'get':'*'})
|
||||
def flowsteps(self, request, pk=None):
|
||||
|
|
Loading…
Reference in New Issue