feat: 依据routepack进行任务派发
This commit is contained in:
parent
14994b424a
commit
436719d9ff
|
@ -207,11 +207,11 @@ class Route(CommonADModel):
|
||||||
hour_work = models.FloatField('工时', null=True, blank=True)
|
hour_work = models.FloatField('工时', null=True, blank=True)
|
||||||
|
|
||||||
@staticmethod
|
@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(
|
rq = Route.objects.filter(
|
||||||
**kwargs).order_by('sort', 'process__sort', 'create_time')
|
**kwargs).order_by('sort', 'process__sort', 'create_time')
|
||||||
|
@ -221,6 +221,4 @@ class Route(CommonADModel):
|
||||||
raise ParseError('首步缺少输入/最后一步缺少输出')
|
raise ParseError('首步缺少输入/最后一步缺少输出')
|
||||||
if not rq.filter(is_count_utask=True).exists():
|
if not rq.filter(is_count_utask=True).exists():
|
||||||
raise ParseError('未指定统计步骤')
|
raise ParseError('未指定统计步骤')
|
||||||
if autotask:
|
|
||||||
kwargs['is_autotask'] = True
|
|
||||||
return rq
|
return rq
|
||||||
|
|
|
@ -207,6 +207,6 @@ class RouteViewSet(CustomModelViewSet):
|
||||||
queryset = Route.objects.all()
|
queryset = Route.objects.all()
|
||||||
serializer_class = RouteSerializer
|
serializer_class = RouteSerializer
|
||||||
filterset_class = RouteFilter
|
filterset_class = RouteFilter
|
||||||
ordering = ['sort', 'create_time']
|
ordering = ['sort', 'process__sort', 'create_time']
|
||||||
select_related_fields = ['material',
|
select_related_fields = ['material',
|
||||||
'process', 'material_in', 'material_out', 'mgroup']
|
'process', 'material_in', 'material_out', 'mgroup']
|
||||||
|
|
|
@ -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='关联工艺包'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,6 +1,6 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from apps.utils.models import CommonADModel, CommonBDModel
|
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.
|
# Create your models here.
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ class Utask(CommonBDModel):
|
||||||
)
|
)
|
||||||
type = models.CharField('任务类型', max_length=10,
|
type = models.CharField('任务类型', max_length=10,
|
||||||
help_text=str(TASK_TYPE), default='mass')
|
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(
|
state = models.PositiveIntegerField(
|
||||||
'状态', choices=UTASK_STATES, default=UTASK_CREATED, help_text=str(UTASK_STATES))
|
'状态', choices=UTASK_STATES, default=UTASK_CREATED, help_text=str(UTASK_STATES))
|
||||||
number = models.CharField('编号', max_length=50, unique=True)
|
number = models.CharField('编号', max_length=50, unique=True)
|
||||||
|
@ -66,6 +67,7 @@ class Mtask(CommonADModel):
|
||||||
(MTASK_STOP, '已停止'),
|
(MTASK_STOP, '已停止'),
|
||||||
(MTASK_SUBMIT, '已提交')
|
(MTASK_SUBMIT, '已提交')
|
||||||
)
|
)
|
||||||
|
route = models.ForeignKey(Route, verbose_name='关联工艺', on_delete=models.SET_NULL, null=True, blank=True)
|
||||||
type = models.CharField('任务类型', max_length=10,
|
type = models.CharField('任务类型', max_length=10,
|
||||||
help_text=str(TASK_TYPE), default='mass')
|
help_text=str(TASK_TYPE), default='mass')
|
||||||
state = models.PositiveIntegerField(
|
state = models.PositiveIntegerField(
|
||||||
|
|
|
@ -34,6 +34,8 @@ class UtaskSerializer(CustomModelSerializer):
|
||||||
attrs['count_day'] = math.ceil(attrs['count']/rela_days)
|
attrs['count_day'] = math.ceil(attrs['count']/rela_days)
|
||||||
except Exception:
|
except Exception:
|
||||||
raise ParseError('日均任务数计划失败')
|
raise ParseError('日均任务数计划失败')
|
||||||
|
if attrs.get('routepack', None):
|
||||||
|
attrs['material'] = attrs['routepack'].material
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
def update(self, instance, validated_data):
|
||||||
|
|
|
@ -12,6 +12,24 @@ from typing import List, Union
|
||||||
|
|
||||||
class PmService:
|
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
|
@classmethod
|
||||||
def make_utasks_from_orderitems(cls, user, orderitemIds: List[str], start_date: date, end_date: date, belong_dept: Union[Dept, None]):
|
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')
|
start_date_str = start_date.strftime('%Y%m%d')
|
||||||
|
@ -105,9 +123,15 @@ class PmService:
|
||||||
raise ParseError('不支持的排产类型')
|
raise ParseError('不支持的排产类型')
|
||||||
else:
|
else:
|
||||||
# 获取产品的加工路线
|
# 获取产品的加工路线
|
||||||
|
if utask.routepack: # 指定工艺路线
|
||||||
|
rqs = Route.objects.filter(routepack=utask.routepack).order_by('sort', 'process__sort', 'create_time')
|
||||||
|
else:
|
||||||
rqs = Route.get_routes(product)
|
rqs = Route.get_routes(product)
|
||||||
if not rqs.exists():
|
if not rqs.exists():
|
||||||
raise ParseError('未配置工艺路线')
|
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):
|
for ind, val in enumerate(rqs):
|
||||||
if val.material_out:
|
if val.material_out:
|
||||||
|
@ -116,7 +140,7 @@ class PmService:
|
||||||
raise ParseError(f'第{ind+1}步-无输出物料')
|
raise ParseError(f'第{ind+1}步-无输出物料')
|
||||||
if val.material_in:
|
if val.material_in:
|
||||||
material_in = val.material_in
|
material_in = val.material_in
|
||||||
elif ind > 0:
|
elif ind > 0: # 默认是上一步的输出
|
||||||
material_in = rqs[ind-1].material_out
|
material_in = rqs[ind-1].material_out
|
||||||
if val.is_autotask:
|
if val.is_autotask:
|
||||||
# 找到工段
|
# 找到工段
|
||||||
|
@ -129,18 +153,12 @@ class PmService:
|
||||||
else: # 后面可能会指定车间
|
else: # 后面可能会指定车间
|
||||||
raise ParseError(f'第{ind+1}步-工段存在多个!')
|
raise ParseError(f'第{ind+1}步-工段存在多个!')
|
||||||
if schedule_type == 'to_day':
|
if schedule_type == 'to_day':
|
||||||
task_count = count
|
task_count_day = math.ceil(count_task_list[ind]/rela_days)
|
||||||
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)
|
|
||||||
if rela_days >= 1:
|
if rela_days >= 1:
|
||||||
for i in range(rela_days):
|
for i in range(rela_days):
|
||||||
task_date = start_date + timedelta(days=i)
|
task_date = start_date + timedelta(days=i)
|
||||||
Mtask.objects.create(**{
|
Mtask.objects.create(**{
|
||||||
|
'route': val,
|
||||||
'number': f'{number}_r{ind+1}_{i+1}',
|
'number': f'{number}_r{ind+1}_{i+1}',
|
||||||
'type': utask.type,
|
'type': utask.type,
|
||||||
'material_out': halfgood,
|
'material_out': halfgood,
|
||||||
|
@ -156,12 +174,13 @@ class PmService:
|
||||||
})
|
})
|
||||||
elif schedule_type == 'to_mgroup':
|
elif schedule_type == 'to_mgroup':
|
||||||
Mtask.objects.create(**{
|
Mtask.objects.create(**{
|
||||||
|
'route': val,
|
||||||
'number': f'{number}_r{ind+1}',
|
'number': f'{number}_r{ind+1}',
|
||||||
'type': utask.type,
|
'type': utask.type,
|
||||||
'material_out': halfgood,
|
'material_out': halfgood,
|
||||||
'material_in': material_in,
|
'material_in': material_in,
|
||||||
'mgroup': mgroup,
|
'mgroup': mgroup,
|
||||||
'count': count,
|
'count': count_task_list[ind],
|
||||||
'start_date': start_date,
|
'start_date': start_date,
|
||||||
'end_date': end_date,
|
'end_date': end_date,
|
||||||
'utask': utask,
|
'utask': utask,
|
||||||
|
|
Loading…
Reference in New Issue