87 lines
4.3 KiB
Python
87 lines
4.3 KiB
Python
from apps.sam.models import Order, OrderItem
|
|
from apps.mtm.models import Route, Material
|
|
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 = {}
|
|
for item in orderitems:
|
|
if item.mtask:
|
|
raise ParseError('订单项已排任务!')
|
|
productId = item.material.id
|
|
if productId not in rdict:
|
|
rdict[productId] = [item.material, item.count, item.order.delivery_date, [item]]
|
|
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)
|
|
return rdict
|
|
|
|
|
|
@classmethod
|
|
def schedue_from_orderitems(cls, 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 enumerate(rdict):
|
|
product, count, end_date_cal, orderitems = 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.objects.filter(material=product).order_by('sort', 'create_time')
|
|
last_route = rqs.last() # 最后一步是产生产品
|
|
# 创建父任务
|
|
for ind, val in enumerate(rqs):
|
|
if val.is_autotask:
|
|
# 找到存在的半成品
|
|
halfgood, _ = Material.objects.get_or_create(type=Material.MA_TYPE_HALFGOOD, parent=product, process=val.process,
|
|
defaults={'parent': product, 'process': val.process,
|
|
'is_hidden': True, 'name': product.name,
|
|
'number': product.number, 'specification': product.specification, 'type': Material.MA_TYPE_HALFGOOD})
|
|
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(process=val.process, material=halfgood, defaults={
|
|
'number': f'{product.number}_r{ind+1}_{start_date_str}',
|
|
'material': halfgood,
|
|
'process': val.process,
|
|
'count': task_count,
|
|
'start_date': start_date,
|
|
'end_date': end_date
|
|
})
|
|
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(process=val.process, material=halfgood, parent = fmtask, defaults={
|
|
'number': f'{fmtask.number}_{i+1}',
|
|
'material': halfgood,
|
|
'process': val.process,
|
|
'count': task_count_day,
|
|
'start_date': task_date,
|
|
'end_date': task_date,
|
|
'parent': fmtask
|
|
}) |