From 29612764ae9a7a00810a87f67e595eab34deeb8b Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 21 Oct 2021 08:55:07 +0800 Subject: [PATCH 1/7] =?UTF-8?q?eval=20=E5=AE=89=E5=85=A8=E6=80=A7=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wf/models.py | 4 +++- hb_server/apps/wf/services.py | 2 +- hb_server/apps/wf/views.py | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/hb_server/apps/wf/models.py b/hb_server/apps/wf/models.py index 5427ed2..877165c 100644 --- a/hb_server/apps/wf/models.py +++ b/hb_server/apps/wf/models.py @@ -39,6 +39,7 @@ class State(CommonAModel): PARTICIPANT_TYPE_ROBOT = 6 PARTICIPANT_TYPE_FIELD = 7 PARTICIPANT_TYPE_PARENT_FIELD = 8 + PARTICIPANT_TYPE_FORMCODE = 9 state_participanttype_choices = ( (0, '无处理人'), (PARTICIPANT_TYPE_PERSONAL, '个人'), @@ -48,7 +49,8 @@ class State(CommonAModel): (PARTICIPANT_TYPE_VARIABLE, '变量'), (PARTICIPANT_TYPE_ROBOT, '脚本'), (PARTICIPANT_TYPE_FIELD, '工单的字段'), - (PARTICIPANT_TYPE_PARENT_FIELD, '父工单的字段') + (PARTICIPANT_TYPE_PARENT_FIELD, '父工单的字段'), + (PARTICIPANT_TYPE_FORMCODE, '代码获取') ) STATE_DISTRIBUTE_TYPE_ACTIVE = 1 # 主动接单 STATE_DISTRIBUTE_TYPE_DIRECT = 2 # 直接处理(当前为多人的情况,都可以处理,而不需要先接单) diff --git a/hb_server/apps/wf/services.py b/hb_server/apps/wf/services.py index 8df0377..c27dab8 100644 --- a/hb_server/apps/wf/services.py +++ b/hb_server/apps/wf/services.py @@ -119,7 +119,7 @@ class WfService(object): for i in transition.condition_expression: expression = i['expression'].format(**ticket_all_value) import datetime, time # 用于支持条件表达式中对时间的操作 - if eval(expression): + if eval(expression, {"__builtins__":None}, {'datetime':datetime, 'time':time}): destination_state = State.objects.get(pk=i['target_state']) return destination_state diff --git a/hb_server/apps/wf/views.py b/hb_server/apps/wf/views.py index f2cc372..67e3a12 100644 --- a/hb_server/apps/wf/views.py +++ b/hb_server/apps/wf/views.py @@ -15,6 +15,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 + # Create your views here. class WorkflowViewSet(CreateUpdateModelAMixin, ModelViewSet): perms_map = {'get': '*', 'post': 'workflow_create', From 5ae9a08425ef023363587c8207b5908887116964 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 21 Oct 2021 11:01:23 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E5=B7=A5=E4=BD=9C=E6=B5=81=E8=A7=92?= =?UTF-8?q?=E8=89=B2=E9=80=89=E4=BA=BA=E8=BF=87=E6=BB=A4=E7=AD=96=E7=95=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/inm/models.py | 10 ++--- .../wf/migrations/0015_auto_20211021_1049.py | 40 +++++++++++++++++++ hb_server/apps/wf/models.py | 12 +++++- hb_server/apps/wf/services.py | 16 ++++++-- hb_server/apps/wf/views.py | 4 +- 5 files changed, 70 insertions(+), 12 deletions(-) create mode 100644 hb_server/apps/wf/migrations/0015_auto_20211021_1049.py diff --git a/hb_server/apps/inm/models.py b/hb_server/apps/inm/models.py index b48ae3d..20decf8 100644 --- a/hb_server/apps/inm/models.py +++ b/hb_server/apps/inm/models.py @@ -61,9 +61,9 @@ class FIFO(CommonAModel): operator = models.ForeignKey(User, verbose_name='操作人', on_delete=models.CASCADE) subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.DO_NOTHING, null=True, blank=True) -class FIFODetail(CommonAModel): - """ - 领料详细记录 - """ - +# class FIFODetail(CommonAModel): +# """ +# 领料详细记录 +# """ + diff --git a/hb_server/apps/wf/migrations/0015_auto_20211021_1049.py b/hb_server/apps/wf/migrations/0015_auto_20211021_1049.py new file mode 100644 index 0000000..115ffc4 --- /dev/null +++ b/hb_server/apps/wf/migrations/0015_auto_20211021_1049.py @@ -0,0 +1,40 @@ +# Generated by Django 3.2.6 on 2021-10-21 02:49 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('system', '0003_auto_20210812_0909'), + ('wf', '0014_wfscript'), + ] + + operations = [ + migrations.AddField( + model_name='state', + name='filter_policy', + field=models.IntegerField(choices=[(0, '无'), (1, '和工单同属一及上级部门'), (2, '和创建人同属一及上级部门'), (3, '和上步处理人同属一及上级部门')], default=0, verbose_name='参与人过滤策略'), + ), + migrations.AddField( + model_name='ticket', + name='belong_dept', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='ticket_belong_dept', to='system.organization', verbose_name='所属部门'), + ), + migrations.AlterField( + model_name='state', + name='participant_type', + field=models.IntegerField(blank=True, choices=[(0, '无处理人'), (1, '个人'), (2, '多人'), (3, '部门'), (4, '角色'), (5, '变量'), (6, '脚本'), (7, '工单的字段'), (8, '父工单的字段'), (9, '代码获取')], default=1, help_text='0.无处理人,1.个人,2.多人,3.部门,4.角色,5.变量(支持工单创建人,创建人的leader),6.脚本,7.工单的字段内容(如表单中的"测试负责人",需要为用户名或者逗号隔开的多个用户名),8.父工单的字段内容。 初始状态请选择类型5,参与人填create_by', verbose_name='参与者类型'), + ), + migrations.AlterField( + model_name='ticket', + name='participant_type', + field=models.IntegerField(choices=[(0, '无处理人'), (1, '个人'), (2, '多人'), (3, '部门'), (4, '角色'), (5, '变量'), (6, '脚本'), (7, '工单的字段'), (8, '父工单的字段'), (9, '代码获取')], default=0, help_text='0.无处理人,1.个人,2.多人', verbose_name='当前处理人类型'), + ), + migrations.AlterField( + model_name='ticketflow', + name='participant_type', + field=models.IntegerField(choices=[(0, '无处理人'), (1, '个人'), (2, '多人'), (3, '部门'), (4, '角色'), (5, '变量'), (6, '脚本'), (7, '工单的字段'), (8, '父工单的字段'), (9, '代码获取')], default=0, help_text='0.无处理人,1.个人,2.多人', verbose_name='处理人类型'), + ), + ] diff --git a/hb_server/apps/wf/models.py b/hb_server/apps/wf/models.py index 877165c..6592d49 100644 --- a/hb_server/apps/wf/models.py +++ b/hb_server/apps/wf/models.py @@ -1,3 +1,4 @@ +from random import choice from django.db import models from django.db.models.base import Model import django.utils.timezone as timezone @@ -66,6 +67,13 @@ class State(CommonAModel): STATE_FIELD_READONLY= 1 # 字段只读 STATE_FIELD_REQUIRED = 2 # 字段必填 STATE_FIELD_OPTIONAL = 3 # 字段可选 + + state_filter_choices=( + (0, '无'), + (1, '和工单同属一及上级部门'), + (2, '和创建人同属一及上级部门'), + (3, '和上步处理人同属一及上级部门'), + ) name = models.CharField('名称', max_length=50) workflow = models.ForeignKey(Workflow, on_delete=models.CASCADE, verbose_name='所属工作流') is_hidden = models.BooleanField('是否隐藏', default=False, help_text='设置为True时,获取工单步骤api中不显示此状态(当前处于此状态时除外)') @@ -76,6 +84,7 @@ class State(CommonAModel): participant = models.JSONField('参与者', default=list, blank=True, help_text='可以为空(无处理人的情况,如结束状态)、userid、userid列表\部门id\角色id\变量(create_by,create_by_tl)\脚本记录的id等,包含子工作流的需要设置处理人为loonrobot') state_fields = models.JSONField('表单字段', default=dict, help_text='json格式字典存储,包括读写属性1:只读,2:必填,3:可选. 示例:{"create_time":1,"title":2, "sn":1}, 内置特殊字段participant_info.participant_name:当前处理人信息(部门名称、角色名称),state.state_name:当前状态的状态名,workflow.workflow_name:工作流名称') # json格式存储,包括读写属性1:只读,2:必填,3:可选,4:不显示, 字典的字典 distribute_type = models.IntegerField('分配方式', default=1, choices=state_distribute_choices, help_text='1.主动接单(如果当前处理人实际为多人的时候,需要先接单才能处理) 2.直接处理(即使当前处理人实际为多人,也可以直接处理) 3.随机分配(如果实际为多人,则系统会随机分配给其中一个人) 4.全部处理(要求所有参与人都要处理一遍,才能进入下一步)') + filter_policy = models.IntegerField('参与人过滤策略', default=0, choices=state_filter_choices) class Transition(CommonAModel): """ @@ -157,7 +166,7 @@ class CustomField(CommonAModel): help_text='radio,checkbox,select,multiselect类型可供选择的选项,格式为json如:{"1":"中国", "2":"美国"},注意数字也需要引号') label = models.JSONField('标签', blank=True, default=dict, help_text='自定义标签,json格式,调用方可根据标签自行处理特殊场景逻辑,loonflow只保存文本内容') -class Ticket(CommonAModel): +class Ticket(CommonBModel): """ 工单 """ @@ -211,7 +220,6 @@ class TicketFlow(BaseModel): ticket_data = models.JSONField('工单数据', default=dict, blank=True, help_text='可以用于记录当前表单数据,json格式') intervene_type = models.IntegerField('干预类型', default=0, help_text='流转类型', choices=Transition.intervene_type_choices) - class WfScript(CommonAModel): """ 执行脚本 diff --git a/hb_server/apps/wf/services.py b/hb_server/apps/wf/services.py index c27dab8..9acdcce 100644 --- a/hb_server/apps/wf/services.py +++ b/hb_server/apps/wf/services.py @@ -124,7 +124,7 @@ class WfService(object): return destination_state @classmethod - def get_ticket_state_participant_info(cls, state:State, ticket:Ticket, ticket_data:dict={}): + def get_ticket_state_participant_info(cls, state:State, ticket:Ticket, ticket_data:dict={}, request={}): """ 获取工单目标状态实际的处理人, 处理人类型 """ @@ -151,11 +151,21 @@ class WfService(object): destination_participant = list(User.objects.filter(dept=destination_participant).values_list('id', flat=True)) elif destination_participant_type == State.PARTICIPANT_TYPE_ROLE:#单角色 - destination_participant = list(User.objects.filter(roles=destination_participant).values_list('id', flat=True)) - + user_queryset = User.objects.filter(roles=destination_participant) + # 如果选择了角色, 需要走过滤策略 + if ticket.filter_policy == 1: + user_queryset = user_queryset.filter(dept=ticket.belong_dept) + elif ticket.filter_policy == 2: + user_queryset = user_queryset.filter(dept=ticket.create_by.dept) + elif ticket.filter_policy == 3: + user_queryset = user_queryset.filter(dept=request.user.dept) + destination_participant = list(user_queryset.values_list('id', flat=True)) if type(destination_participant) == list: destination_participant_type = State.PARTICIPANT_TYPE_MULTI destination_participant = list(set(destination_participant)) + if len(destination_participant) == 1: # 如果只有一个人 + destination_participant_type = State.PARTICIPANT_TYPE_PERSONAL + destination_participant = destination_participant[0] else: destination_participant_type = State.PARTICIPANT_TYPE_PERSONAL if destination_participant_type == State.PARTICIPANT_TYPE_MULTI: diff --git a/hb_server/apps/wf/views.py b/hb_server/apps/wf/views.py index 67e3a12..1025505 100644 --- a/hb_server/apps/wf/views.py +++ b/hb_server/apps/wf/views.py @@ -134,7 +134,7 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin if value == State.STATE_FIELD_REQUIRED: if key not in ticket_data or not ticket_data[key]: raise APIException('字段{}必填'.format(key)) - ticket = serializer.save(state=start_state, create_by=request.user, act_state=Ticket.TICKET_ACT_STATE_DRAFT) # 先创建出来 + ticket = serializer.save(state=start_state, create_by=request.user, act_state=Ticket.TICKET_ACT_STATE_DRAFT, belong_dept=request.user.dept) # 先创建出来 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) @@ -202,7 +202,7 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin 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) + 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) From b5497a6b75727a12773692e40b8e8fa1144ebd91 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 21 Oct 2021 11:32:21 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E5=B7=A5=E4=BD=9C=E6=B5=81=E8=A7=92?= =?UTF-8?q?=E8=89=B2=E5=A4=9A=E9=80=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wf/models.py | 6 +++--- hb_server/apps/wf/services.py | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/hb_server/apps/wf/models.py b/hb_server/apps/wf/models.py index 6592d49..fff81ed 100644 --- a/hb_server/apps/wf/models.py +++ b/hb_server/apps/wf/models.py @@ -45,12 +45,12 @@ class State(CommonAModel): (0, '无处理人'), (PARTICIPANT_TYPE_PERSONAL, '个人'), (PARTICIPANT_TYPE_MULTI, '多人'), - (PARTICIPANT_TYPE_DEPT, '部门'), + # (PARTICIPANT_TYPE_DEPT, '部门'), (PARTICIPANT_TYPE_ROLE, '角色'), - (PARTICIPANT_TYPE_VARIABLE, '变量'), + # (PARTICIPANT_TYPE_VARIABLE, '变量'), (PARTICIPANT_TYPE_ROBOT, '脚本'), (PARTICIPANT_TYPE_FIELD, '工单的字段'), - (PARTICIPANT_TYPE_PARENT_FIELD, '父工单的字段'), + # (PARTICIPANT_TYPE_PARENT_FIELD, '父工单的字段'), (PARTICIPANT_TYPE_FORMCODE, '代码获取') ) STATE_DISTRIBUTE_TYPE_ACTIVE = 1 # 主动接单 diff --git a/hb_server/apps/wf/services.py b/hb_server/apps/wf/services.py index 9acdcce..ad45929 100644 --- a/hb_server/apps/wf/services.py +++ b/hb_server/apps/wf/services.py @@ -147,11 +147,11 @@ class WfService(object): if destination_participant_type == State.PARTICIPANT_TYPE_FIELD: destination_participant = ticket_data.get(destination_participant, 0) if destination_participant in ticket_data \ else Ticket.ticket_data.get(destination_participant, 0) - elif destination_participant_type == State.PARTICIPANT_TYPE_DEPT:#单部门 - destination_participant = list(User.objects.filter(dept=destination_participant).values_list('id', flat=True)) + elif destination_participant_type == State.PARTICIPANT_TYPE_DEPT:#部门 + destination_participant = list(User.objects.filter(dept__in=destination_participant).values_list('id', flat=True)) - elif destination_participant_type == State.PARTICIPANT_TYPE_ROLE:#单角色 - user_queryset = User.objects.filter(roles=destination_participant) + elif destination_participant_type == State.PARTICIPANT_TYPE_ROLE:#角色 + user_queryset = User.objects.filter(roles__in=destination_participant) # 如果选择了角色, 需要走过滤策略 if ticket.filter_policy == 1: user_queryset = user_queryset.filter(dept=ticket.belong_dept) From b40efc3ca6445c1f72a0bf90a4e89b0a31de93ef Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 21 Oct 2021 15:56:45 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E4=B8=BB=E4=BA=A7=E5=87=BA=E5=8F=AA?= =?UTF-8?q?=E8=83=BD=E6=9C=891=E4=B8=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/mtm/models.py | 1 + hb_server/apps/mtm/serializers.py | 2 ++ hb_server/apps/wpm/models.py | 10 ++++++++++ hb_server/server/settings.py | 3 ++- 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/hb_server/apps/mtm/models.py b/hb_server/apps/mtm/models.py index 6ebe98a..2602113 100644 --- a/hb_server/apps/mtm/models.py +++ b/hb_server/apps/mtm/models.py @@ -177,6 +177,7 @@ class OutputMaterial(CommonAModel): 输出物料 """ material = models.ForeignKey(Material, verbose_name='输出物料', on_delete=models.CASCADE, related_name='outputmaterial') + is_main = models.BooleanField('是否主产出', default=True) # 以该产品完成度计算进度 count = models.FloatField('产出量', default=1) subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE) sort = models.IntegerField('排序号', default=1) diff --git a/hb_server/apps/mtm/serializers.py b/hb_server/apps/mtm/serializers.py index 315e464..46d5f87 100644 --- a/hb_server/apps/mtm/serializers.py +++ b/hb_server/apps/mtm/serializers.py @@ -101,6 +101,8 @@ class OutputMaterialSerializer(serializers.ModelSerializer): fields = ['count', 'sort', 'material', 'subproduction'] def create(self, validated_data): + if OutputMaterial.objects.filter(subproduction=validated_data['subproduction'], is_deleted=False, is_main=True).exists(): + raise ValidationError('主产出只能有1个') if OutputMaterial.objects.filter(material=validated_data['material'], subproduction=validated_data['subproduction'], is_deleted=False).exists(): raise ValidationError('该物料已存在') return super().create(validated_data) diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py index ab9aa54..767b0fd 100644 --- a/hb_server/apps/wpm/models.py +++ b/hb_server/apps/wpm/models.py @@ -7,6 +7,16 @@ from utils.model import SoftModel, BaseModel from simple_history.models import HistoricalRecords +class Good(CommonAModel): + """ + 物品 + """ + number = models.CharField('物品编号', primary_key=True, null=True, blank=True, max_length=50) + m_state = models.ForeignKey('所属物料状态', on_delete=models.CASCADE) + p_state = models.ForeignKey('所在步骤', ) + + + class Vendor(CommonAModel): """ 供应商信息 diff --git a/hb_server/server/settings.py b/hb_server/server/settings.py index b2e7755..6fb07a7 100644 --- a/hb_server/server/settings.py +++ b/hb_server/server/settings.py @@ -55,7 +55,8 @@ INSTALLED_APPS = [ 'apps.inm', 'apps.sam', 'apps.qm', - 'apps.pm' + 'apps.pm', + # 'apps.wpm' ] MIDDLEWARE = [ From deb278085dd0d433ec94a94c58eb1d652c05f9df Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 21 Oct 2021 15:58:43 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E5=A2=9E=E5=8A=A0is=5Fmain?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/mtm/serializers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hb_server/apps/mtm/serializers.py b/hb_server/apps/mtm/serializers.py index 46d5f87..b23fcef 100644 --- a/hb_server/apps/mtm/serializers.py +++ b/hb_server/apps/mtm/serializers.py @@ -98,7 +98,7 @@ class InputMaterialUpdateSerializer(serializers.ModelSerializer): class OutputMaterialSerializer(serializers.ModelSerializer): class Meta: model = OutputMaterial - fields = ['count', 'sort', 'material', 'subproduction'] + fields = ['count', 'sort', 'material', 'subproduction', 'is_main'] def create(self, validated_data): if OutputMaterial.objects.filter(subproduction=validated_data['subproduction'], is_deleted=False, is_main=True).exists(): @@ -110,7 +110,7 @@ class OutputMaterialSerializer(serializers.ModelSerializer): class OutputMaterialUpdateSerializer(serializers.ModelSerializer): class Meta: model = OutputMaterial - fields = ['count', 'sort'] + fields = ['count', 'sort', 'is_main'] class UsedStepCreateSerializer(serializers.ModelSerializer): """ From 145bf1d6b7c27492f41eb7db8c51d52bc4ec4fe3 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 22 Oct 2021 14:36:20 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E5=A4=84=E7=90=86=E4=BA=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0025_outputmaterial_is_main.py | 18 ++++++++++++++++++ hb_server/apps/wf/models.py | 1 + hb_server/apps/wf/scripts.py | 15 +++++++++++++++ hb_server/apps/wf/services.py | 5 +++++ hb_server/apps/wf/urls.py | 3 ++- hb_server/apps/wf/views.py | 9 +++++++++ hb_server/apps/wpm/models.py | 18 +++++++++++++++--- hb_server/server/settings.py | 2 ++ 8 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 hb_server/apps/mtm/migrations/0025_outputmaterial_is_main.py create mode 100644 hb_server/apps/wf/scripts.py diff --git a/hb_server/apps/mtm/migrations/0025_outputmaterial_is_main.py b/hb_server/apps/mtm/migrations/0025_outputmaterial_is_main.py new file mode 100644 index 0000000..51f4988 --- /dev/null +++ b/hb_server/apps/mtm/migrations/0025_outputmaterial_is_main.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.6 on 2021-10-21 08:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mtm', '0024_alter_recordformfield_rule_expression'), + ] + + operations = [ + migrations.AddField( + model_name='outputmaterial', + name='is_main', + field=models.BooleanField(default=True, verbose_name='是否主产出'), + ), + ] diff --git a/hb_server/apps/wf/models.py b/hb_server/apps/wf/models.py index fff81ed..7415534 100644 --- a/hb_server/apps/wf/models.py +++ b/hb_server/apps/wf/models.py @@ -232,5 +232,6 @@ class WfScript(CommonAModel): wait = models.BooleanField('是否等待执行完成', default=True) name = models.CharField('脚本名称', max_length=100) workflow = models.ForeignKey(Workflow, verbose_name='关联工作流', null=True, blank=True, on_delete=models.SET_NULL) + func_str = models.CharField('函数名', max_length=50, null=True, blank=True) content = models.TextField('脚本内容') diff --git a/hb_server/apps/wf/scripts.py b/hb_server/apps/wf/scripts.py new file mode 100644 index 0000000..5c2ccb4 --- /dev/null +++ b/hb_server/apps/wf/scripts.py @@ -0,0 +1,15 @@ +from .models import State +class GetParticipants: + + all_funcs = [ + {'func':'get_create_by', 'name':'获取工单创建人'} + ] + + # def all_funcs(self): + # # return list(filter(lambda x: x.startswith('get_') and callable(getattr(self, x)), dir(self))) + # return [(func, getattr(self, func).__doc__) for func in dir(self) if callable(getattr(self, func)) and func.startswith('get_')] + + def get_create_by(self, state:dict={}, ticket:dict={}, ticket_data:dict={}, request={}): + """工单创建人""" + participant = ticket.create_by.id + return participant \ No newline at end of file diff --git a/hb_server/apps/wf/services.py b/hb_server/apps/wf/services.py index ad45929..d370bdf 100644 --- a/hb_server/apps/wf/services.py +++ b/hb_server/apps/wf/services.py @@ -7,6 +7,7 @@ from rest_framework.exceptions import APIException from django.utils import timezone from datetime import timedelta import random +from .scripts import GetParticipants class WfService(object): @staticmethod @@ -147,6 +148,10 @@ class WfService(object): if destination_participant_type == State.PARTICIPANT_TYPE_FIELD: destination_participant = ticket_data.get(destination_participant, 0) if destination_participant in 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) + elif destination_participant_type == State.PARTICIPANT_TYPE_DEPT:#部门 destination_participant = list(User.objects.filter(dept__in=destination_participant).values_list('id', flat=True)) diff --git a/hb_server/apps/wf/urls.py b/hb_server/apps/wf/urls.py index b03a965..5c9ae0d 100644 --- a/hb_server/apps/wf/urls.py +++ b/hb_server/apps/wf/urls.py @@ -1,6 +1,6 @@ from django.db.models import base from rest_framework import urlpatterns -from apps.wf.views import CustomFieldViewSet, StateViewSet, TicketFlowViewSet, TicketViewSet, TransitionViewSet, WorkflowViewSet +from apps.wf.views import CustomFieldViewSet, FromCodeListView, StateViewSet, TicketFlowViewSet, TicketViewSet, TransitionViewSet, WorkflowViewSet from django.urls import path, include from rest_framework.routers import DefaultRouter @@ -12,6 +12,7 @@ router.register('customfield', CustomFieldViewSet, basename='wf_customfield') router.register('ticket', TicketViewSet, basename='wf_ticket') router.register('ticketflow', TicketFlowViewSet, basename='wf_ticketflow') urlpatterns = [ + path('participant_from_code', FromCodeListView.as_view()), path('', include(router.urls)), ] diff --git a/hb_server/apps/wf/views.py b/hb_server/apps/wf/views.py index 1025505..b3158cc 100644 --- a/hb_server/apps/wf/views.py +++ b/hb_server/apps/wf/views.py @@ -1,4 +1,5 @@ from django.db.models import query +from rest_framework.views import APIView from apps.system.models import User from apps.wf.filters import TicketFilterSet from django.core.exceptions import AppRegistryNotReady @@ -15,8 +16,16 @@ 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 # Create your views here. +class FromCodeListView(APIView): + def get(self, request, format=None): + """ + 获取处理人代码列表 + """ + return Response(GetParticipants.all_funcs) + class WorkflowViewSet(CreateUpdateModelAMixin, ModelViewSet): perms_map = {'get': '*', 'post': 'workflow_create', 'put': 'workflow_update', 'delete': 'workflow_delete'} diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py index 767b0fd..6d03ea9 100644 --- a/hb_server/apps/wpm/models.py +++ b/hb_server/apps/wpm/models.py @@ -5,17 +5,29 @@ from django.db.models.query import QuerySet from apps.system.models import CommonAModel, CommonBModel, Organization, User, Dict, File from utils.model import SoftModel, BaseModel from simple_history.models import HistoricalRecords - +from apps.mtm.models import Material, Step class Good(CommonAModel): """ 物品 """ + act_state_choices=( + (0, '待执行'), + (1, '进行中'), + (2, '已完成') + ) number = models.CharField('物品编号', primary_key=True, null=True, blank=True, max_length=50) - m_state = models.ForeignKey('所属物料状态', on_delete=models.CASCADE) - p_state = models.ForeignKey('所在步骤', ) + m_state = models.ForeignKey(Material, verbose_name='所属物料状态', on_delete=models.CASCADE) + p_state = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True) + act_state = models.IntegerField('进行状态', default=0) +class GoodFlow(BaseModel): + """ + 物品流转日志 + """ + pass + class Vendor(CommonAModel): """ diff --git a/hb_server/server/settings.py b/hb_server/server/settings.py index 6fb07a7..7d1174e 100644 --- a/hb_server/server/settings.py +++ b/hb_server/server/settings.py @@ -41,6 +41,7 @@ INSTALLED_APPS = [ 'django.contrib.staticfiles', 'corsheaders', 'django_celery_beat', + 'django_celery_results', 'drf_yasg', 'rest_framework', "django_filters", @@ -203,6 +204,7 @@ CELERY_BROKER_URL = "redis://redis:6379/0" # 任务存储 CELERYD_MAX_TASKS_PER_CHILD = 100 # 每个worker最多执行300个任务就会被销毁,可防止内存泄露 CELERY_TIMEZONE = 'Asia/Shanghai' # 设置时区 CELERY_ENABLE_UTC = True # 启动时区设置 +CELERY_RESULT_BACKEND = 'django-db' # swagger配置 SWAGGER_SETTINGS = { From 927f25ae056b15af4bdebac3c29d045d88e72b1e Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 22 Oct 2021 15:35:48 +0800 Subject: [PATCH 7/7] =?UTF-8?q?wf=E5=A2=9E=E5=8A=A0=E5=8F=82=E6=95=B0bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wf/filters.py | 2 ++ hb_server/apps/wf/models.py | 4 ++-- hb_server/apps/wf/scripts.py | 1 - hb_server/apps/wf/services.py | 4 ++-- hb_server/requirements.txt | 1 + 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/hb_server/apps/wf/filters.py b/hb_server/apps/wf/filters.py index 742af75..677b894 100644 --- a/hb_server/apps/wf/filters.py +++ b/hb_server/apps/wf/filters.py @@ -17,6 +17,8 @@ class TicketFilterSet(filters.FilterSet): queryset = queryset.filter(participant__contains=user.id).exclude(act_state__in=[Ticket.TICKET_ACT_STATE_FINISH, Ticket.TICKET_ACT_STATE_CLOSED]) elif value == 'worked': queryset = queryset.filter(ticketflow_ticket__participant=user).exclude(create_by=user).order_by('-update_time').distinct() + elif value == 'cc': + pass elif value == 'all': pass else: diff --git a/hb_server/apps/wf/models.py b/hb_server/apps/wf/models.py index 7415534..6133090 100644 --- a/hb_server/apps/wf/models.py +++ b/hb_server/apps/wf/models.py @@ -188,9 +188,9 @@ class Ticket(CommonBModel): category_choices =( ('all', '全部'), ('owner', '我创建的'), - ('duty', '代办'), + ('duty', '待办'), ('worked', '我处理的'), - ('relation', '抄送我的') + ('cc', '抄送我的') ) title = models.CharField('标题', max_length=500, blank=True, default='', help_text="工单标题") workflow = models.ForeignKey(Workflow, on_delete=models.CASCADE, verbose_name='关联工作流') diff --git a/hb_server/apps/wf/scripts.py b/hb_server/apps/wf/scripts.py index 5c2ccb4..5e818f7 100644 --- a/hb_server/apps/wf/scripts.py +++ b/hb_server/apps/wf/scripts.py @@ -1,4 +1,3 @@ -from .models import State class GetParticipants: all_funcs = [ diff --git a/hb_server/apps/wf/services.py b/hb_server/apps/wf/services.py index d370bdf..bb7f705 100644 --- a/hb_server/apps/wf/services.py +++ b/hb_server/apps/wf/services.py @@ -105,7 +105,7 @@ class WfService(object): @classmethod - def get_next_state_by_transition_and_ticket_info(cls, ticket:Ticket, transition: Transition, ticket_data:dict={})->object: + def get_next_state_by_transition_and_ticket_info(cls, ticket:Ticket, transition: Transition, ticket_data:dict={}, request:dict={})->object: """ 获取下个节点状态 """ @@ -148,7 +148,7 @@ class WfService(object): if destination_participant_type == State.PARTICIPANT_TYPE_FIELD: destination_participant = ticket_data.get(destination_participant, 0) if destination_participant in 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) diff --git a/hb_server/requirements.txt b/hb_server/requirements.txt index 595fea2..a223cbc 100644 --- a/hb_server/requirements.txt +++ b/hb_server/requirements.txt @@ -10,3 +10,4 @@ drf-yasg==1.20.0 psutil==5.8.0 pillow==8.3.1 opencv-python==4.5.3.56 +django-celery-results==2.2.0