工单与系统结合初步修改完毕
This commit is contained in:
parent
d6c59afbc4
commit
4da2f48203
|
@ -19,7 +19,7 @@ class Workflow(CommonAModel):
|
||||||
view_permission_check = models.BooleanField('查看权限校验', default=True, help_text='开启后,只允许工单的关联人(创建人、曾经的处理人)有权限查看工单')
|
view_permission_check = models.BooleanField('查看权限校验', default=True, help_text='开启后,只允许工单的关联人(创建人、曾经的处理人)有权限查看工单')
|
||||||
limit_expression = models.JSONField('限制表达式', default=dict, blank=True, help_text='限制周期({"period":24} 24小时), 限制次数({"count":1}在限制周期内只允许提交1次), 限制级别({"level":1} 针对(1单个用户 2全局)限制周期限制次数,默认特定用户);允许特定人员提交({"allow_persons":"zhangsan,lisi"}只允许张三提交工单,{"allow_depts":"1,2"}只允许部门id为1和2的用户提交工单,{"allow_roles":"1,2"}只允许角色id为1和2的用户提交工单)')
|
limit_expression = models.JSONField('限制表达式', default=dict, blank=True, help_text='限制周期({"period":24} 24小时), 限制次数({"count":1}在限制周期内只允许提交1次), 限制级别({"level":1} 针对(1单个用户 2全局)限制周期限制次数,默认特定用户);允许特定人员提交({"allow_persons":"zhangsan,lisi"}只允许张三提交工单,{"allow_depts":"1,2"}只允许部门id为1和2的用户提交工单,{"allow_roles":"1,2"}只允许角色id为1和2的用户提交工单)')
|
||||||
display_form_str = models.JSONField('展现表单字段', default=list, blank=True, help_text='默认"[]",用于用户只有对应工单查看权限时显示哪些字段,field_key的list的json,如["days","sn"],内置特殊字段participant_info.participant_name:当前处理人信息(部门名称、角色名称),state.state_name:当前状态的状态名,workflow.workflow_name:工作流名称')
|
display_form_str = models.JSONField('展现表单字段', default=list, blank=True, help_text='默认"[]",用于用户只有对应工单查看权限时显示哪些字段,field_key的list的json,如["days","sn"],内置特殊字段participant_info.participant_name:当前处理人信息(部门名称、角色名称),state.state_name:当前状态的状态名,workflow.workflow_name:工作流名称')
|
||||||
title_template = models.CharField('标题模板', max_length=50, default='你有一个待办工单:{title}', null=True, blank=True, help_text='工单字段的值可以作为参数写到模板中,格式如:你有一个待办工单:{title}')
|
title_template = models.CharField('标题模板', max_length=50, default='{title}', null=True, blank=True, help_text='工单字段的值可以作为参数写到模板中,格式如:你有一个待办工单:{title}')
|
||||||
content_template = models.CharField('内容模板', max_length=1000, default='标题:{title}, 创建时间:{create_time}', null=True, blank=True, help_text='工单字段的值可以作为参数写到模板中,格式如:标题:{title}, 创建时间:{create_time}')
|
content_template = models.CharField('内容模板', max_length=1000, default='标题:{title}, 创建时间:{create_time}', null=True, blank=True, help_text='工单字段的值可以作为参数写到模板中,格式如:标题:{title}, 创建时间:{create_time}')
|
||||||
|
|
||||||
class State(CommonAModel):
|
class State(CommonAModel):
|
||||||
|
|
|
@ -4,7 +4,9 @@ from apps.wpm.models import WProduct
|
||||||
|
|
||||||
|
|
||||||
class GetParticipants:
|
class GetParticipants:
|
||||||
|
"""
|
||||||
|
获取处理人脚本
|
||||||
|
"""
|
||||||
all_funcs = [
|
all_funcs = [
|
||||||
{'func':'get_create_by', 'name':'获取工单创建人'}
|
{'func':'get_create_by', 'name':'获取工单创建人'}
|
||||||
]
|
]
|
||||||
|
@ -20,8 +22,11 @@ class GetParticipants:
|
||||||
return participant
|
return participant
|
||||||
|
|
||||||
class HandleScripts:
|
class HandleScripts:
|
||||||
|
"""
|
||||||
|
任务处理脚本
|
||||||
|
"""
|
||||||
all_funcs = [
|
all_funcs = [
|
||||||
{'func': 'handle_wproduct', 'name':'处理不合格品'}
|
{'func': 'handle_something', 'name':'处理一些工作'}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,32 +47,11 @@ class HandleScripts:
|
||||||
return ticket
|
return ticket
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def handle_wproduct(cls, ticket:Ticket):
|
def handle_something(cls, ticket:Ticket):
|
||||||
"""处理不合格品"""
|
"""处理一些工作"""
|
||||||
# 任务处理
|
# 任务处理代码区
|
||||||
|
|
||||||
ticket_data = ticket.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
|
|
||||||
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')
|
ticket = cls.to_next(ticket=ticket, by_task=True, script_str= 'handle_something')
|
||||||
if ticket.act_state == Ticket.TICKET_ACT_STATE_FINISH:
|
|
||||||
# 如果工单完成
|
|
||||||
wp.ticket = None
|
|
||||||
wp.save()
|
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@ class TicketSimpleSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class TicketCreateSerializer(serializers.ModelSerializer):
|
class TicketCreateSerializer(serializers.ModelSerializer):
|
||||||
transition = serializers.PrimaryKeyRelatedField(queryset=Transition.objects.all(), write_only=True)
|
transition = serializers.PrimaryKeyRelatedField(queryset=Transition.objects.all(), write_only=True)
|
||||||
|
title = serializers.CharField(allow_blank=True, required=False)
|
||||||
class Meta:
|
class Meta:
|
||||||
model=Ticket
|
model=Ticket
|
||||||
fields=['title','workflow', 'ticket_data', 'transition']
|
fields=['title','workflow', 'ticket_data', 'transition']
|
||||||
|
|
|
@ -273,7 +273,7 @@ class WfService(object):
|
||||||
# 校验表单必填项目
|
# 校验表单必填项目
|
||||||
if transition.field_require_check or not created:
|
if transition.field_require_check or not created:
|
||||||
for key, value in ticket.state.state_fields.items():
|
for key, value in ticket.state.state_fields.items():
|
||||||
if value == State.STATE_FIELD_REQUIRED:
|
if int(value) == State.STATE_FIELD_REQUIRED:
|
||||||
if key not in new_ticket_data or not new_ticket_data[key]:
|
if key not in new_ticket_data or not new_ticket_data[key]:
|
||||||
raise APIException('字段{}必填'.format(key))
|
raise APIException('字段{}必填'.format(key))
|
||||||
|
|
||||||
|
|
|
@ -132,10 +132,10 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin
|
||||||
return TicketDetailSerializer
|
return TicketDetailSerializer
|
||||||
return super().get_serializer_class()
|
return super().get_serializer_class()
|
||||||
|
|
||||||
def get_queryset(self):
|
def filter_queryset(self, queryset):
|
||||||
if self.action=='list' and (not self.request.query_params.get('category', None)):
|
if not self.request.query_params.get('category', None):
|
||||||
raise APIException('请指定查询分类')
|
raise APIException('请指定查询分类')
|
||||||
return super().get_queryset()
|
return super().filter_queryset(queryset)
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def create(self, request, *args, **kwargs):
|
def create(self, request, *args, **kwargs):
|
||||||
|
@ -154,11 +154,11 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin
|
||||||
# 校验必填项
|
# 校验必填项
|
||||||
if transition.field_require_check:
|
if transition.field_require_check:
|
||||||
for key, value in start_state.state_fields.items():
|
for key, value in start_state.state_fields.items():
|
||||||
if value == State.STATE_FIELD_REQUIRED:
|
if int(value) == State.STATE_FIELD_REQUIRED:
|
||||||
if key not in ticket_data and not ticket_data[key]:
|
if key not in ticket_data and not ticket_data[key]:
|
||||||
raise APIException('字段{}必填'.format(key))
|
raise APIException('字段{}必填'.format(key))
|
||||||
save_ticket_data[key] = ticket_data[key]
|
save_ticket_data[key] = ticket_data[key]
|
||||||
elif value == State.STATE_FIELD_OPTIONAL:
|
elif int(value) == State.STATE_FIELD_OPTIONAL:
|
||||||
save_ticket_data[key] = ticket_data[key]
|
save_ticket_data[key] = ticket_data[key]
|
||||||
|
|
||||||
ticket = serializer.save(state=start_state,
|
ticket = serializer.save(state=start_state,
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.9 on 2021-12-21 08:19
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('wpm', '0036_auto_20211221_0923'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='wproduct',
|
||||||
|
name='scrap_reason',
|
||||||
|
field=models.IntegerField(blank=True, choices=[(10, '气泡'), (20, '破点'), (30, '划伤'), (40, '其他')], null=True, verbose_name='报废原因'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -94,6 +94,8 @@ class WprouctTicket(CommonAModel):
|
||||||
material = models.ForeignKey(Material, verbose_name='所在物料状态', on_delete=models.CASCADE)
|
material = models.ForeignKey(Material, verbose_name='所在物料状态', on_delete=models.CASCADE)
|
||||||
step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE)
|
step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE)
|
||||||
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='所在子生产计划', on_delete=models.CASCADE)
|
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='所在子生产计划', on_delete=models.CASCADE)
|
||||||
|
test_record = models.ForeignKey('qm.testrecord', verbose_name='关联检验记录', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
|
||||||
ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单', on_delete=models.CASCADE, related_name='wt_ticket')
|
ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单', on_delete=models.CASCADE, related_name='wt_ticket')
|
||||||
decision = models.CharField('最终决定', null=True, blank=True, max_length=100)
|
decision = models.CharField('最终决定', null=True, blank=True, max_length=100)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
from django.db.models.signals import post_save
|
||||||
|
from apps.qm.models import TestRecord
|
||||||
|
from apps.wf.models import Ticket
|
||||||
|
from django.dispatch import receiver
|
||||||
|
|
||||||
|
from apps.wpm.models import WProduct, WprouctTicket
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=Ticket)
|
||||||
|
def handleTicket(sender, instance, created, **kwargs):
|
||||||
|
if instance.workflow.name == '不合格品审理单':
|
||||||
|
if created:
|
||||||
|
ticket_data = instance.ticket_data
|
||||||
|
"""
|
||||||
|
创建关联信息表
|
||||||
|
"""
|
||||||
|
obj = WprouctTicket()
|
||||||
|
wproduct = WProduct.objects.get(id=ticket_data['wproduct'])
|
||||||
|
obj.wproduct = wproduct
|
||||||
|
obj.number = wproduct.number
|
||||||
|
obj.material = wproduct.material
|
||||||
|
obj.step = wproduct.step
|
||||||
|
obj.subproduction_plan = wproduct.subproduction_plan
|
||||||
|
obj.ticket = instance
|
||||||
|
obj.test_record = TestRecord.objects.filter(wproduct=wproduct, is_deleted=False, is_testok=False).order_by('-id').first()
|
||||||
|
obj.save()
|
||||||
|
|
||||||
|
# 工单绑定半成品
|
||||||
|
wproduct.ticket = instance
|
||||||
|
wproduct.save()
|
||||||
|
|
||||||
|
# 检验员
|
||||||
|
if not ticket_data.get('tester', None):
|
||||||
|
ticket_data['tester'] = obj.test_record.create_by.id
|
||||||
|
instance.ticket_data = ticket_data
|
||||||
|
instance.save()
|
||||||
|
|
||||||
|
elif instance.act_state == Ticket.TICKET_ACT_STATE_FINISH:
|
||||||
|
"""
|
||||||
|
执行操作决定
|
||||||
|
"""
|
||||||
|
ticket_data = instance.ticket_data
|
||||||
|
wt = instance.wt_ticket
|
||||||
|
wp = wt.wproduct
|
||||||
|
if 'decision_1' in ticket_data and ticket_data['decision_1']:
|
||||||
|
wt.decision = ticket_data['decision_1']
|
||||||
|
if ticket_data['decision_1'] in ['返工', '返修']:
|
||||||
|
pass
|
||||||
|
elif ticket_data['decision_1'] in ['让步接收']:
|
||||||
|
wp.act_state = WProduct.WPR_ACT_STATE_OK
|
||||||
|
elif 'decision_2' in ticket_data and ticket_data['decision_2']:
|
||||||
|
wp.decision = ticket_data['decision_2']
|
||||||
|
if ticket_data['decision_2'] in ['返工', '返修']:
|
||||||
|
pass
|
||||||
|
elif ticket_data['decision_2'] in ['让步接收']:
|
||||||
|
wp.act_state = WProduct.WPR_ACT_STATE_OK
|
||||||
|
wt.save()
|
||||||
|
wp.save()
|
||||||
|
|
|
@ -374,11 +374,11 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
|
||||||
workflow = Workflow.objects.filter(name='不合格品审理单', is_deletd=False).first()
|
workflow = Workflow.objects.filter(name='不合格品审理单', is_deletd=False).first()
|
||||||
if workflow:
|
if workflow:
|
||||||
exist_data = {
|
exist_data = {
|
||||||
'sys_wproduct':obj.id,
|
'wproduct':obj.id,
|
||||||
'sys_name':obj.material.name,
|
'wproduct_name':obj.material.name,
|
||||||
'sys_specification':obj.material.specification,
|
'wproduct_specification':obj.material.specification,
|
||||||
'sys_finder':request.user.id,
|
'finder':request.user.id,
|
||||||
'sys_process':obj.step.process.id,
|
'find_process':obj.step.process.id,
|
||||||
}
|
}
|
||||||
ret = {'workflow':workflow.id}
|
ret = {'workflow':workflow.id}
|
||||||
ret['exist_data'] = exist_data
|
ret['exist_data'] = exist_data
|
||||||
|
|
Loading…
Reference in New Issue