修改费用计算代码
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from memory_profiler import profile
|
||||
from typing import Dict, List, Any, Optional, Tuple, Set
|
||||
from equipment_calculation.expressioncalculator import ExpressionCalculator
|
||||
|
||||
from equipment_calculation.bcl_utils import (
|
||||
ZjQuantityBCLContext,
|
||||
ZjProjectBCLContext,
|
||||
@@ -15,6 +17,7 @@ from equipment_calculation.bcl_utils import (
|
||||
BCLDataSourceContext,
|
||||
create_list_from_node,
|
||||
create_node_from_type,
|
||||
create_material_or_equipment_from_node,
|
||||
)
|
||||
from equipment_calculation.item_acquisition import (
|
||||
get_cost_table_children,
|
||||
@@ -23,6 +26,7 @@ from equipment_calculation.item_acquisition import (
|
||||
find_cost_table,
|
||||
get_bill_node_by_id,
|
||||
load_project_data,
|
||||
get_classified_resource_nodes,
|
||||
)
|
||||
|
||||
# 缓存已计算过的费用
|
||||
@@ -223,7 +227,7 @@ def calculate_external_variable(var_name: str, context: ZjQuantityBCLContext, ca
|
||||
try:
|
||||
# 如果有计算策略,使用计算策略的方法
|
||||
if calculation_strategy:
|
||||
print(f"使用计算策略 {calculation_strategy.__class__.__name__} 计算表外变量: {var_name}")
|
||||
# print(f"使用计算策略 {calculation_strategy.__class__.__name__} 计算表外变量: {var_name}")
|
||||
# 直接调用计算策略的方法,而不是递归调用自己
|
||||
return calculation_strategy.calculate_external_variable(var_name, context)
|
||||
|
||||
@@ -447,17 +451,21 @@ def calculate_all_fees(
|
||||
json_file_path: str = None,
|
||||
engineering_type: str = None,
|
||||
calculation_strategy=None,
|
||||
json_data: dict | None = None,
|
||||
) -> Dict[str, float]:
|
||||
"""
|
||||
计算项目节点的所有费用,确保清单数量正确传递
|
||||
"""
|
||||
results = {}
|
||||
|
||||
# 1. 工程信息上下文
|
||||
project_context = create_project_contexts(json_file_path=json_file_path)
|
||||
# 1. 工程信息上下文(优先使用传入的 json_data)
|
||||
project_context = create_project_contexts(json_file_path=json_file_path, json_data=json_data)
|
||||
|
||||
with open(json_file_path, "r", encoding="utf-8") as file:
|
||||
data = json.load(file)
|
||||
if json_data is not None:
|
||||
data = json_data
|
||||
else:
|
||||
with open(json_file_path, "r", encoding="utf-8") as file:
|
||||
data = json.load(file)
|
||||
|
||||
processed_data = process_DXdata(data)
|
||||
|
||||
@@ -497,8 +505,37 @@ def calculate_all_fees(
|
||||
billItem.bill_quantity = bill_obj.quantity
|
||||
print(f"设置清单数据源项数量: {billItem.bill_quantity}")
|
||||
|
||||
# 如果无法创建工程量对象,则跳过并返回当前已计算结果,避免未定义的 QuantityItem
|
||||
if not project_obj:
|
||||
print(
|
||||
f"警告: 无法从项目节点创建工程量对象,跳过该节点: "
|
||||
f"{project_node.get('项目名称', project_node.get('name', '未知节点'))}"
|
||||
)
|
||||
return results
|
||||
|
||||
QuantityItem = BCLDataSourceItem(project_obj, billItem)
|
||||
|
||||
childItems = []
|
||||
if project_obj.children:
|
||||
for moe in project_obj.children:
|
||||
childItems.append(BCLDataSourceItem(moe, QuantityItem))
|
||||
|
||||
QuantityItem.set_childs(childItems)
|
||||
|
||||
bill_context = BCLDataSourceContext([billItem], dxitem_context)
|
||||
|
||||
# # 构建人材机数据源项(若存在)并接入上下文
|
||||
# rcj_nodes_for_parent = project_node.get("_rcj_nodes", [])
|
||||
# moe_items = []
|
||||
# if rcj_nodes_for_parent:
|
||||
# try:
|
||||
# for rcj_node in rcj_nodes_for_parent:
|
||||
# node_obj = create_material_or_equipment_from_node(rcj_node)
|
||||
# moe_items.append(BCLDataSourceItem(node_obj, QuantityItem))
|
||||
# except Exception as e:
|
||||
# print(f"构建人材机数据源项出错: {e}")
|
||||
|
||||
# items_chain = [QuantityItem] + moe_items if moe_items else [QuantityItem]
|
||||
context = BCLDataSourceContext([QuantityItem], bill_context)
|
||||
|
||||
# 如果计算策略存在,设置清单数量
|
||||
@@ -513,7 +550,35 @@ def calculate_all_fees(
|
||||
dxitem_context = BCLDataSourceContext(DXITEM, project_context)
|
||||
dxitem_context.variables["@特征段地形系数"] = BCLVariant(DXITEM)
|
||||
|
||||
# 如果无法创建工程量对象,则跳过并返回当前已计算结果,避免未定义的 QuantityItem
|
||||
if not project_obj:
|
||||
print(
|
||||
f"警告: 无法从项目节点创建工程量对象,跳过该节点: "
|
||||
f"{project_node.get('项目名称', project_node.get('name', '未知节点'))}"
|
||||
)
|
||||
return results
|
||||
|
||||
QuantityItem = BCLDataSourceItem(project_obj)
|
||||
|
||||
childItems = []
|
||||
if project_obj.children:
|
||||
for moe in project_obj.children:
|
||||
childItems.append(BCLDataSourceItem(moe, QuantityItem))
|
||||
|
||||
QuantityItem.set_childs(childItems)
|
||||
|
||||
# # 构建人材机数据源项(若存在)并接入上下文
|
||||
# rcj_nodes_for_parent = project_node.get("_rcj_nodes", [])
|
||||
# moe_items = []
|
||||
# if rcj_nodes_for_parent:
|
||||
# try:
|
||||
# for rcj_node in rcj_nodes_for_parent:
|
||||
# node_obj = create_material_or_equipment_from_node(rcj_node)
|
||||
# moe_items.append(BCLDataSourceItem(node_obj, QuantityItem))
|
||||
# except Exception as e:
|
||||
# print(f"构建人材机数据源项出错: {e}")
|
||||
|
||||
# items_chain = [QuantityItem] + moe_items if moe_items else [QuantityItem]
|
||||
context = BCLDataSourceContext([QuantityItem], dxitem_context)
|
||||
|
||||
# 查找包含取费基数的节点
|
||||
@@ -696,6 +761,8 @@ def calculate_quantity_fees(
|
||||
engineering_type: str = None,
|
||||
project_guid: str = None,
|
||||
calculation_strategy=None,
|
||||
software_type: str = None,
|
||||
json_data: dict | None = None,
|
||||
) -> str:
|
||||
"""
|
||||
计算工程量取费表,不使用全局变量,并按清单节点组织结果
|
||||
@@ -769,7 +836,9 @@ def calculate_quantity_fees(
|
||||
if engineering_type == "预算工程":
|
||||
# 预算工程 - 获取项目划分节点的取费表,传递project_guid参数
|
||||
cost_table_children = get_cost_table_children(json_file_path, project_name, project_guid)
|
||||
project_children = get_quantity_nodes(json_file_path, project_name, engineering_type, project_guid)
|
||||
project_children = get_quantity_nodes(
|
||||
json_file_path, project_name, engineering_type, project_guid, software_type
|
||||
)
|
||||
|
||||
if not cost_table_children or not project_children:
|
||||
print(f"未找到项目 '{project_name}' (GUID: {project_guid}) 的取费表或项目划分节点")
|
||||
@@ -777,7 +846,9 @@ def calculate_quantity_fees(
|
||||
|
||||
elif engineering_type == "清单工程":
|
||||
# 清单工程 - 获取清单节点的取费表,传递project_guid参数
|
||||
project_children = get_quantity_nodes(json_file_path, project_name, engineering_type, project_guid)
|
||||
project_children = get_quantity_nodes(
|
||||
json_file_path, project_name, engineering_type, project_guid, software_type
|
||||
)
|
||||
if not project_children:
|
||||
print(f"未找到项目 '{project_name}' (GUID: {project_guid}) 的项目划分节点")
|
||||
return None
|
||||
@@ -785,6 +856,16 @@ def calculate_quantity_fees(
|
||||
# 为每个工程量节点找到对应的清单节点取费表
|
||||
cost_tables = {}
|
||||
|
||||
# 准备一次性 JSON 数据(清单工程需要从 projectData 中获取 costSetting 与 bill)
|
||||
if json_data is not None:
|
||||
_data_all = json_data
|
||||
else:
|
||||
with open(json_file_path, "r", encoding="utf-8") as f:
|
||||
_data_all = json.load(f)
|
||||
_project_data_all = _data_all.get("projectData", {})
|
||||
_cost_setting_all = _project_data_all.get("costSetting", {})
|
||||
_bill_data_all = _project_data_all.get("bill", {})
|
||||
|
||||
for project_node in project_children:
|
||||
node_name = project_node.get("项目名称", project_node.get("name", "未知节点"))
|
||||
|
||||
@@ -813,15 +894,8 @@ def calculate_quantity_fees(
|
||||
if bill_id not in cost_tables:
|
||||
print(f"查找清单节点 '{bill_name}' 的取费表: {fee_table_name}")
|
||||
|
||||
# 查找取费表
|
||||
with open(json_file_path, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
|
||||
project_data = data.get("projectData", {})
|
||||
cost_setting = project_data.get("costSetting", {})
|
||||
|
||||
# 查找取费表
|
||||
cost_table = find_cost_table(cost_setting, fee_table_name)
|
||||
# 查找取费表:使用已加载的数据
|
||||
cost_table = find_cost_table(_cost_setting_all, fee_table_name)
|
||||
|
||||
if not cost_table:
|
||||
print(f"未找到取费表 '{fee_table_name}'")
|
||||
@@ -835,12 +909,8 @@ def calculate_quantity_fees(
|
||||
cost_tables[bill_id] = cost_table_children
|
||||
print(f"成功获取清单节点 '{bill_name}' 的取费表")
|
||||
|
||||
# 在读取JSON文件后,遍历项目中的清单节点,获取并保存清单数量
|
||||
with open(json_file_path, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
|
||||
project_data = data.get("projectData", {})
|
||||
bill_data = project_data.get("bill", {})
|
||||
# 遍历项目中的清单节点,获取并保存清单数量(使用已加载的数据)
|
||||
bill_data = _bill_data_all
|
||||
|
||||
# 递归函数获取所有清单节点
|
||||
def get_bill_nodes(node):
|
||||
@@ -885,6 +955,55 @@ def calculate_quantity_fees(
|
||||
print(f"不支持的工程类型: {engineering_type}")
|
||||
return None
|
||||
|
||||
# 预取并分派人材机节点到各工程量节点上,供后续上下文使用
|
||||
try:
|
||||
labor_nodes, material_nodes, machine_nodes = get_classified_resource_nodes(
|
||||
json_file_path, project_name, project_guid
|
||||
)
|
||||
|
||||
# 合并三类节点,形成父ID到节点列表的映射
|
||||
rcj_all = []
|
||||
if labor_nodes:
|
||||
rcj_all.extend([n for n, _ in labor_nodes])
|
||||
if material_nodes:
|
||||
rcj_all.extend([n for n, _ in material_nodes])
|
||||
if machine_nodes:
|
||||
rcj_all.extend([n for n, _ in machine_nodes])
|
||||
|
||||
rcj_by_parent: Dict[str, List[Dict[str, Any]]] = {}
|
||||
|
||||
# 注意:get_classified_resource_nodes 返回的是 (node, parent_id) 元组列表
|
||||
def add_to_map(pairs):
|
||||
if not pairs:
|
||||
return
|
||||
for node, parent_id in pairs:
|
||||
if parent_id is None:
|
||||
continue
|
||||
key = str(parent_id)
|
||||
rcj_by_parent.setdefault(key, []).append(node)
|
||||
|
||||
add_to_map(labor_nodes)
|
||||
add_to_map(material_nodes)
|
||||
add_to_map(machine_nodes)
|
||||
|
||||
# 将对应的人材机列表写入每个工程量节点
|
||||
if project_children:
|
||||
for node in project_children:
|
||||
pid_candidates = [
|
||||
node.get("GUID"),
|
||||
node.get("guid"),
|
||||
node.get("id"),
|
||||
]
|
||||
rcj_list = []
|
||||
for pid in pid_candidates:
|
||||
if pid and str(pid) in rcj_by_parent:
|
||||
rcj_list = rcj_by_parent.get(str(pid), [])
|
||||
break
|
||||
if rcj_list:
|
||||
node["_rcj_nodes"] = rcj_list
|
||||
except Exception as e:
|
||||
print(f"预取人材机节点失败: {e}")
|
||||
|
||||
# 在获取 project_children 后添加预处理代码
|
||||
if project_children and calculation_strategy and hasattr(calculation_strategy, "preprocess_quantity_fee_node"):
|
||||
print(f"对项目节点进行预处理...")
|
||||
@@ -946,7 +1065,11 @@ def calculate_quantity_fees(
|
||||
if engineering_type == "预算工程":
|
||||
# 预算工程 - 使用项目划分节点的取费表
|
||||
node_results = calculation_strategy.calculate_all_fees(
|
||||
project_node, {"children": cost_table_children}, json_file_path, engineering_type
|
||||
project_node,
|
||||
{"children": cost_table_children},
|
||||
json_file_path,
|
||||
engineering_type,
|
||||
json_data=json_data,
|
||||
)
|
||||
|
||||
# 直接使用节点键作为结果键
|
||||
@@ -958,7 +1081,11 @@ def calculate_quantity_fees(
|
||||
bill_id = project_node.get("bill_guid") or project_node.get("bill_id")
|
||||
if bill_id and bill_id in cost_tables:
|
||||
node_results = calculation_strategy.calculate_all_fees(
|
||||
project_node, {"children": cost_tables[bill_id]}, json_file_path, engineering_type
|
||||
project_node,
|
||||
{"children": cost_tables[bill_id]},
|
||||
json_file_path,
|
||||
engineering_type,
|
||||
json_data=json_data,
|
||||
)
|
||||
|
||||
# 获取清单信息
|
||||
@@ -987,9 +1114,9 @@ def calculate_quantity_fees(
|
||||
continue
|
||||
|
||||
# 输出计算结果
|
||||
print(f"费用计算结果:")
|
||||
for fee_name, fee_value in node_results.items():
|
||||
print(f" {fee_name}: {fee_value}")
|
||||
# print(f"费用计算结果:")
|
||||
# for fee_name, fee_value in node_results.items():
|
||||
# print(f" {fee_name}: {fee_value}")
|
||||
|
||||
# 保存计算结果到JSON文件
|
||||
with open(output_file, "w", encoding="utf-8") as f:
|
||||
|
||||
Reference in New Issue
Block a user