From 8068cb1ca3f1818fb8186e1eac3c34625f2a88b8 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 9 Apr 2025 13:18:00 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20cal=5Fx=5Ftask=5Fcount=E5=88=86=E9=85=8D?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E6=95=B0=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pm/services.py | 71 ++++++++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/apps/pm/services.py b/apps/pm/services.py index 0e5dc3de..3c207f62 100644 --- a/apps/pm/services.py +++ b/apps/pm/services.py @@ -14,54 +14,77 @@ from collections import defaultdict, deque class PmService: @classmethod - def cal_x_task_count(cls, target_materialId:str, target_quantity, route_qs): - # 构建逆向依赖图 {输出物料ID: [Route]} + def cal_x_task_count(cls, target_materialId: str, target_quantity, route_qs): + # 构建逆向依赖图 {输出物料ID: [生产该物料的Route]} graph = defaultdict(list) + graphin = defaultdict(list) for route in route_qs: if route.material_out: # 确保输出物料存在 graph[route.material_out.id].append(route) + if route.material_in: # 确保输入物料存在 + graphin[route.material_in.id].append((route, False)) # 存储每个物料的需求量 demands = defaultdict(float) demands[target_materialId] = target_quantity step_production = defaultdict(int) - # 逆向遍历,从目标物料开始 + # 逆向遍历队列,从目标物料开始 queue = deque([target_materialId]) + visited = set() # 防止重复处理 + while queue: current_out_id = queue.popleft() + if current_out_id in visited: + continue + visited.add(current_out_id) + current_demand = demands.get(current_out_id, 0) if current_demand <= 0: continue - # 处理所有能生产该物料的Route(多路径时需求均分) + # 获取生产该物料的所有Route routes = graph.get(current_out_id, []) if not routes: - continue + continue # 无生产路线,无法继续逆向 - # 均分需求到所有Route(示例按均分逻辑,可根据业务调整) - demand_per_route = math.ceil(current_demand / len(routes)) if len(routes) > 1 else current_demand + # 平均分配需求到各Route(根据业务需求可能需要调整分配策略) + routes_count = len(routes) + base_demand = current_demand // routes_count + remainder = current_demand % routes_count - for route in routes: - # 记录该Route的产出量(向上取整) - step_production[route.id] = math.ceil(demand_per_route) + for i, route in enumerate(routes): + # 分配任务数 + task_count = base_demand + 1 if i < remainder else base_demand + step_production[route.id] = task_count # 累加任务数 - # 根据工序类型计算输入需求 - if route.process.mtype == 20: # 拆分工序:1个输入拆成多个输出 - input_needed = demand_per_route / route.div_number / (route.out_rate / 100) - elif route.process.mtype == 30: # 合并工序:多个输入合并为1个输出 - input_needed = demand_per_route * route.div_number / (route.out_rate / 100) - else: # 正常工序 - input_needed = demand_per_route / (route.out_rate / 100) + # 根据工序类型计算所需输入物料 + if route.process.mtype == 20: # 拆分工序 + input_needed = math.ceil(task_count / route.div_number / (route.out_rate / 100)) + elif route.process.mtype == 30: # 合并工序 + input_needed = math.ceil(task_count * route.div_number / (route.out_rate / 100)) + else: # 普通工序 + input_needed = math.ceil(task_count / (route.out_rate / 100)) - # 更新上游物料需求 + # 更新输入物料需求并加入队列 if route.material_in: - demands[route.material_in.id] += input_needed - queue.append(route.material_in.id) - - return dict(reversed(step_production.items())) + input_material_id = route.material_in.id + demands[input_material_id] += input_needed + for index, (route_in, _) in enumerate(graphin[input_material_id]): + if route_in == route: + graphin[input_material_id][index] = (route_in, True) + can_append = True + for route_in, caled in graphin[input_material_id]: + if caled is False: + can_append = False + break + if can_append: + queue.append(input_material_id) + # 返回各Route的任务数量 + return {route.id: step_production.get(route.id, 0) for route in route_qs} + @classmethod def cal_real_task_count(cls, count: int, rate_list): """ @@ -236,6 +259,8 @@ class PmService: 'is_count_utask': route.is_count_utask }) elif schedule_type == 'to_mgroup': + base_demand = count // mgroups_count + remainder = count % mgroups_count for indx, mgroup in enumerate(mgroups): Mtask.objects.create(**{ 'route': route, @@ -244,7 +269,7 @@ class PmService: 'material_out': material_out, 'material_in': material_in, 'mgroup': mgroup, - 'count': math.ceil(count/mgroups_count), + 'count': base_demand + 1 if indx < remainder else base_demand, 'start_date': start_date, 'end_date': end_date, 'utask': utask,