fix: cal_x_task_count分配任务数的bug
This commit is contained in:
parent
15ccfbe6f9
commit
8068cb1ca3
|
@ -14,54 +14,77 @@ from collections import defaultdict, deque
|
||||||
class PmService:
|
class PmService:
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def cal_x_task_count(cls, target_materialId:str, target_quantity, route_qs):
|
def cal_x_task_count(cls, target_materialId: str, target_quantity, route_qs):
|
||||||
# 构建逆向依赖图 {输出物料ID: [Route]}
|
# 构建逆向依赖图 {输出物料ID: [生产该物料的Route]}
|
||||||
graph = defaultdict(list)
|
graph = defaultdict(list)
|
||||||
|
graphin = defaultdict(list)
|
||||||
for route in route_qs:
|
for route in route_qs:
|
||||||
if route.material_out: # 确保输出物料存在
|
if route.material_out: # 确保输出物料存在
|
||||||
graph[route.material_out.id].append(route)
|
graph[route.material_out.id].append(route)
|
||||||
|
if route.material_in: # 确保输入物料存在
|
||||||
|
graphin[route.material_in.id].append((route, False))
|
||||||
|
|
||||||
# 存储每个物料的需求量
|
# 存储每个物料的需求量
|
||||||
demands = defaultdict(float)
|
demands = defaultdict(float)
|
||||||
demands[target_materialId] = target_quantity
|
demands[target_materialId] = target_quantity
|
||||||
step_production = defaultdict(int)
|
step_production = defaultdict(int)
|
||||||
|
|
||||||
# 逆向遍历,从目标物料开始
|
# 逆向遍历队列,从目标物料开始
|
||||||
queue = deque([target_materialId])
|
queue = deque([target_materialId])
|
||||||
|
visited = set() # 防止重复处理
|
||||||
|
|
||||||
while queue:
|
while queue:
|
||||||
current_out_id = queue.popleft()
|
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)
|
current_demand = demands.get(current_out_id, 0)
|
||||||
if current_demand <= 0:
|
if current_demand <= 0:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 处理所有能生产该物料的Route(多路径时需求均分)
|
# 获取生产该物料的所有Route
|
||||||
routes = graph.get(current_out_id, [])
|
routes = graph.get(current_out_id, [])
|
||||||
if not routes:
|
if not routes:
|
||||||
continue
|
continue # 无生产路线,无法继续逆向
|
||||||
|
|
||||||
# 均分需求到所有Route(示例按均分逻辑,可根据业务调整)
|
# 平均分配需求到各Route(根据业务需求可能需要调整分配策略)
|
||||||
demand_per_route = math.ceil(current_demand / len(routes)) if len(routes) > 1 else current_demand
|
routes_count = len(routes)
|
||||||
|
base_demand = current_demand // routes_count
|
||||||
|
remainder = current_demand % routes_count
|
||||||
|
|
||||||
for route in routes:
|
for i, route in enumerate(routes):
|
||||||
# 记录该Route的产出量(向上取整)
|
# 分配任务数
|
||||||
step_production[route.id] = math.ceil(demand_per_route)
|
task_count = base_demand + 1 if i < remainder else base_demand
|
||||||
|
step_production[route.id] = task_count # 累加任务数
|
||||||
|
|
||||||
# 根据工序类型计算输入需求
|
# 根据工序类型计算所需输入物料
|
||||||
if route.process.mtype == 20: # 拆分工序:1个输入拆成多个输出
|
if route.process.mtype == 20: # 拆分工序
|
||||||
input_needed = demand_per_route / route.div_number / (route.out_rate / 100)
|
input_needed = math.ceil(task_count / route.div_number / (route.out_rate / 100))
|
||||||
elif route.process.mtype == 30: # 合并工序:多个输入合并为1个输出
|
elif route.process.mtype == 30: # 合并工序
|
||||||
input_needed = demand_per_route * route.div_number / (route.out_rate / 100)
|
input_needed = math.ceil(task_count * route.div_number / (route.out_rate / 100))
|
||||||
else: # 正常工序
|
else: # 普通工序
|
||||||
input_needed = demand_per_route / (route.out_rate / 100)
|
input_needed = math.ceil(task_count / (route.out_rate / 100))
|
||||||
|
|
||||||
# 更新上游物料需求
|
# 更新输入物料需求并加入队列
|
||||||
if route.material_in:
|
if route.material_in:
|
||||||
demands[route.material_in.id] += input_needed
|
input_material_id = route.material_in.id
|
||||||
queue.append(route.material_in.id)
|
demands[input_material_id] += input_needed
|
||||||
|
for index, (route_in, _) in enumerate(graphin[input_material_id]):
|
||||||
return dict(reversed(step_production.items()))
|
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
|
@classmethod
|
||||||
def cal_real_task_count(cls, count: int, rate_list):
|
def cal_real_task_count(cls, count: int, rate_list):
|
||||||
"""
|
"""
|
||||||
|
@ -236,6 +259,8 @@ class PmService:
|
||||||
'is_count_utask': route.is_count_utask
|
'is_count_utask': route.is_count_utask
|
||||||
})
|
})
|
||||||
elif schedule_type == 'to_mgroup':
|
elif schedule_type == 'to_mgroup':
|
||||||
|
base_demand = count // mgroups_count
|
||||||
|
remainder = count % mgroups_count
|
||||||
for indx, mgroup in enumerate(mgroups):
|
for indx, mgroup in enumerate(mgroups):
|
||||||
Mtask.objects.create(**{
|
Mtask.objects.create(**{
|
||||||
'route': route,
|
'route': route,
|
||||||
|
@ -244,7 +269,7 @@ class PmService:
|
||||||
'material_out': material_out,
|
'material_out': material_out,
|
||||||
'material_in': material_in,
|
'material_in': material_in,
|
||||||
'mgroup': mgroup,
|
'mgroup': mgroup,
|
||||||
'count': math.ceil(count/mgroups_count),
|
'count': base_demand + 1 if indx < remainder else base_demand,
|
||||||
'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