factory/apps/pm/services.py

117 lines
5.8 KiB
Python

from apps.sam.models import OrderItem
from apps.mtm.models import Route, Material, Mgroup
from rest_framework.exceptions import ParseError
from apps.pm.models import Mtask
from django.db.models.query import QuerySet
from datetime import date, timedelta
import math
from typing import List
class PmService:
def check_orderitems(cls, orderitems: QuerySet[OrderItem]):
"""
校验orderitems并返回整合后的字典以productId为key, [product, count, end_date, orderitems] 为value
"""
rdict = {}
if orderitems.exclude(mtask=None).exists():
raise ParseError('存在订单项已排任务!')
for item in orderitems:
productId = item.material.id
if productId not in rdict:
rdict[productId] = [item.material, item.count,
item.order.delivery_date, [item.id]]
else:
order_date = item.order.delivery_date
if rdict[productId][2] > order_date:
rdict[productId][2] = order_date
rdict[productId][1] = rdict[productId][1] + item.count
rdict[productId][3].append(item.id)
return rdict
@classmethod
def schedue_from_orderitems(cls, user, orderitemIds: List[str], start_date: date, end_date: date = None):
"""
从多个订单明细自动排产
"""
orderitems = OrderItem.objects.filter(pk__in=orderitemIds)
rdict = cls.check_orderitems(orderitems)
start_date_str = start_date.strftime('%Y%m%d')
for k, v in rdict.items():
product, count, end_date_cal, orderitemId_list = v
if end_date is None:
end_date = end_date_cal
if start_date >= end_date:
raise ParseError('开始时间不可大于结束时间')
# 计算相差天数
rela_days = (end_date - start_date).days + 1
# 获取工艺路线
rqs = Route.get_routes(product)
last_route = rqs.last() # 最后一步是产生产品
# 创建父任务
for ind, val in enumerate(rqs):
material_before = None
if ind > 0:
material_before = rqs[ind-1].material
if val.is_autotask:
# 找到工段
mgroups = val.mgroups
mgroups_count = len(mgroups)
if mgroups_count == 1:
mgroup = mgroups.first()
elif mgroups_count == 0:
raise ParseError(f'{val.name}-工段不存在!')
else: # 后面可能会指定车间
raise ParseError(f'{val.name}-工段存在多个!')
# 找到存在的半成品
halfgood, _ = Material.objects.get_or_create(type=Material.MA_TYPE_HALFGOOD, parent=product, mgroup=mgroup,
defaults={'parent': product, 'mgroup': mgroup,
'is_hidden': True, 'name': product.name,
'number': product.number,
'specification': product.specification,
'type': Material.MA_TYPE_HALFGOOD,
'create_by': user,
'update_by': user,
})
if val == last_route:
halfgood = product
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)
fmtask, _ = Mtask.objects.get_or_create(mgroup=mgroup, material=halfgood, defaults={
'number': f'{product.number}_r{ind+1}_{start_date_str}',
'material': halfgood,
'material_before': material_before,
'mgroup': mgroup,
'count': task_count,
'start_date': start_date,
'end_date': end_date,
'create_by': user,
'update_by': user,
})
task_count_day = math.ceil(task_count/rela_days)
if fmtask.parent is None:
for i in range(rela_days):
task_date = start_date + timedelta(days=i+1)
Mtask.objects.get_or_create(mgroup=mgroup, material=halfgood, parent=fmtask, defaults={
'number': f'{fmtask.number}_{i+1}',
'material': halfgood,
'material_before': material_before,
'mgroup': mgroup,
'count': task_count_day,
'start_date': task_date,
'end_date': task_date,
'parent': fmtask,
'create_by': user,
'update_by': user
})
OrderItem.objects.filter(
id__in=orderitemId_list).update(mtask=fmtask)
from apps.sam.tasks import change_order_state_when_schedue
change_order_state_when_schedue.delay(orderitemId_list)