From 436719d9ff22ba321620e9855c10f92cb1a0856e Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 3 Jul 2024 16:46:01 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BE=9D=E6=8D=AEroutepack=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E4=BB=BB=E5=8A=A1=E6=B4=BE=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mtm/models.py | 8 ++-- apps/mtm/views.py | 2 +- apps/pm/migrations/0019_auto_20240703_1618.py | 25 +++++++++++ apps/pm/models.py | 4 +- apps/pm/serializers.py | 2 + apps/pm/services.py | 41 ++++++++++++++----- 6 files changed, 64 insertions(+), 18 deletions(-) create mode 100644 apps/pm/migrations/0019_auto_20240703_1618.py diff --git a/apps/mtm/models.py b/apps/mtm/models.py index a372d337..715ca9d4 100644 --- a/apps/mtm/models.py +++ b/apps/mtm/models.py @@ -207,11 +207,11 @@ class Route(CommonADModel): hour_work = models.FloatField('工时', null=True, blank=True) @staticmethod - def get_routes(material: Material, autotask: bool = False): + def get_routes(material: Material): """ - 返回工艺路线带车间 + 返回工艺路线带车间(不关联工艺包) """ - kwargs = {'material': material} + kwargs = {'material': material, 'routepack__isnull': True} # 校验工艺路线是否正常 rq = Route.objects.filter( **kwargs).order_by('sort', 'process__sort', 'create_time') @@ -221,6 +221,4 @@ class Route(CommonADModel): raise ParseError('首步缺少输入/最后一步缺少输出') if not rq.filter(is_count_utask=True).exists(): raise ParseError('未指定统计步骤') - if autotask: - kwargs['is_autotask'] = True return rq diff --git a/apps/mtm/views.py b/apps/mtm/views.py index 59d2310a..baabeb7a 100644 --- a/apps/mtm/views.py +++ b/apps/mtm/views.py @@ -207,6 +207,6 @@ class RouteViewSet(CustomModelViewSet): queryset = Route.objects.all() serializer_class = RouteSerializer filterset_class = RouteFilter - ordering = ['sort', 'create_time'] + ordering = ['sort', 'process__sort', 'create_time'] select_related_fields = ['material', 'process', 'material_in', 'material_out', 'mgroup'] diff --git a/apps/pm/migrations/0019_auto_20240703_1618.py b/apps/pm/migrations/0019_auto_20240703_1618.py new file mode 100644 index 00000000..99bb3a2a --- /dev/null +++ b/apps/pm/migrations/0019_auto_20240703_1618.py @@ -0,0 +1,25 @@ +# Generated by Django 3.2.12 on 2024-07-03 08:18 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('mtm', '0032_auto_20240702_1409'), + ('pm', '0018_mtask_hour_work'), + ] + + operations = [ + migrations.AddField( + model_name='mtask', + name='route', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='mtm.route', verbose_name='关联工艺'), + ), + migrations.AddField( + model_name='utask', + name='routepack', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='mtm.routepack', verbose_name='关联工艺包'), + ), + ] diff --git a/apps/pm/models.py b/apps/pm/models.py index 0d6de712..391191e2 100644 --- a/apps/pm/models.py +++ b/apps/pm/models.py @@ -1,6 +1,6 @@ from django.db import models from apps.utils.models import CommonADModel, CommonBDModel -from apps.mtm.models import Material, Mgroup +from apps.mtm.models import Material, Mgroup, RoutePack, Route # Create your models here. @@ -34,6 +34,7 @@ class Utask(CommonBDModel): ) type = models.CharField('任务类型', max_length=10, help_text=str(TASK_TYPE), default='mass') + routepack = models.ForeignKey(RoutePack, verbose_name='关联工艺包', on_delete=models.SET_NULL, null=True, blank=True) state = models.PositiveIntegerField( '状态', choices=UTASK_STATES, default=UTASK_CREATED, help_text=str(UTASK_STATES)) number = models.CharField('编号', max_length=50, unique=True) @@ -66,6 +67,7 @@ class Mtask(CommonADModel): (MTASK_STOP, '已停止'), (MTASK_SUBMIT, '已提交') ) + route = models.ForeignKey(Route, verbose_name='关联工艺', on_delete=models.SET_NULL, null=True, blank=True) type = models.CharField('任务类型', max_length=10, help_text=str(TASK_TYPE), default='mass') state = models.PositiveIntegerField( diff --git a/apps/pm/serializers.py b/apps/pm/serializers.py index f41c0b45..c0245fe7 100644 --- a/apps/pm/serializers.py +++ b/apps/pm/serializers.py @@ -34,6 +34,8 @@ class UtaskSerializer(CustomModelSerializer): attrs['count_day'] = math.ceil(attrs['count']/rela_days) except Exception: raise ParseError('日均任务数计划失败') + if attrs.get('routepack', None): + attrs['material'] = attrs['routepack'].material return attrs def update(self, instance, validated_data): diff --git a/apps/pm/services.py b/apps/pm/services.py index c8147dad..392e716f 100644 --- a/apps/pm/services.py +++ b/apps/pm/services.py @@ -12,6 +12,24 @@ from typing import List, Union class PmService: + @classmethod + def cal_real_task_count(cls, count: int, rate_list): + """ + 计算实际任务数 + """ + r_list = [] + rate_len = len(rate_list) + for ind, val in enumerate(rate_list): + indx = ind*1 + xcount = count*1 + while indx < rate_len: + if indx + 1 == rate_len: # 循环到最后一步 + break + xcount = xcount/(rate_list[indx+1]/100) + indx = indx + 1 + r_list.append(math.ceil(xcount)) + return r_list + @classmethod def make_utasks_from_orderitems(cls, user, orderitemIds: List[str], start_date: date, end_date: date, belong_dept: Union[Dept, None]): start_date_str = start_date.strftime('%Y%m%d') @@ -105,9 +123,15 @@ class PmService: raise ParseError('不支持的排产类型') else: # 获取产品的加工路线 - rqs = Route.get_routes(product) + if utask.routepack: # 指定工艺路线 + rqs = Route.objects.filter(routepack=utask.routepack).order_by('sort', 'process__sort', 'create_time') + else: + rqs = Route.get_routes(product) if not rqs.exists(): raise ParseError('未配置工艺路线') + # 通过出材率校正任务数, out_rate 默认为 100 + out_rate_list = [rq.out_rate for rq in rqs] + count_task_list = cls.cal_real_task_count(count,out_rate_list) # 创建小任务 for ind, val in enumerate(rqs): if val.material_out: @@ -116,7 +140,7 @@ class PmService: raise ParseError(f'第{ind+1}步-无输出物料') if val.material_in: material_in = val.material_in - elif ind > 0: + elif ind > 0: # 默认是上一步的输出 material_in = rqs[ind-1].material_out if val.is_autotask: # 找到工段 @@ -129,18 +153,12 @@ class PmService: else: # 后面可能会指定车间 raise ParseError(f'第{ind+1}步-工段存在多个!') if schedule_type == 'to_day': - task_count = count - if val.out_rate: - if val.out_rate > 1: - task_count = math.ceil( - count / (val.out_rate/100)) - else: - task_count = math.ceil(count / val.out_rate) - task_count_day = math.ceil(task_count/rela_days) + task_count_day = math.ceil(count_task_list[ind]/rela_days) if rela_days >= 1: for i in range(rela_days): task_date = start_date + timedelta(days=i) Mtask.objects.create(**{ + 'route': val, 'number': f'{number}_r{ind+1}_{i+1}', 'type': utask.type, 'material_out': halfgood, @@ -156,12 +174,13 @@ class PmService: }) elif schedule_type == 'to_mgroup': Mtask.objects.create(**{ + 'route': val, 'number': f'{number}_r{ind+1}', 'type': utask.type, 'material_out': halfgood, 'material_in': material_in, 'mgroup': mgroup, - 'count': count, + 'count': count_task_list[ind], 'start_date': start_date, 'end_date': end_date, 'utask': utask,