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 = {} 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.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 enumerate(rdict): 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): if val.is_autotask: # 找到工段 mgroups = Mgroup.objects.filter(process=val.process) mgroups_count = mgroups.count() 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, '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, '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)