From ccd97c66ae36a66bdc65e845e5762d4c4b7c9d7b Mon Sep 17 00:00:00 2001 From: falken10 Date: Tue, 24 Jun 2025 22:28:22 +0200 Subject: [PATCH] refactor and black formatting --- src/bonsai/bonsai/bim/module/cost/data.py | 3 +- src/bonsai/bonsai/bim/module/cost/operator.py | 50 ++++--------------- src/bonsai/bonsai/bim/module/cost/ui.py | 2 +- src/bonsai/bonsai/core/cost.py | 39 +++++++++++++-- 4 files changed, 50 insertions(+), 44 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/cost/data.py b/src/bonsai/bonsai/bim/module/cost/data.py index ac05c5001b..fb28039827 100644 --- a/src/bonsai/bonsai/bim/module/cost/data.py +++ b/src/bonsai/bonsai/bim/module/cost/data.py @@ -56,7 +56,7 @@ class CostSchedulesData: "cost_values": cls.cost_values(), "quantity_types": cls.quantity_types(), "currency": cls.currency(), - "csv_filepaths": cls.get_csv_filepaths(), # Add this line + "csv_filepaths": cls.get_csv_filepaths(), } cls.is_loaded = True @@ -199,6 +199,7 @@ class CostSchedulesData: # parametric_quantities.extend(quantities) data["TotalCostQuantity"] = ifcopenshell.util.cost.get_total_quantity(cost_item) data["UnitSymbol"] = "-" + data["QuantityType"] = None quantities: list[ifcopenshell.entity_instance] = cost_item.CostQuantities if quantities: quantity = quantities[0] diff --git a/src/bonsai/bonsai/bim/module/cost/operator.py b/src/bonsai/bonsai/bim/module/cost/operator.py index bdf1743f77..34e75ba092 100644 --- a/src/bonsai/bonsai/bim/module/cost/operator.py +++ b/src/bonsai/bonsai/bim/module/cost/operator.py @@ -25,6 +25,9 @@ import bonsai.tool as tool from bpy_extras.io_utils import ImportHelper, ExportHelper import bonsai.tool as tool import bonsai.core.cost as core +from bonsai.bim.module.cost.data import CostSchedulesData +from pathlib import Path + from typing import get_args, TYPE_CHECKING, Literal @@ -100,6 +103,7 @@ class EnableEditingCostItems(bpy.types.Operator, tool.Ifc.Operator): def _execute(self, context): core.enable_editing_cost_items(tool.Cost, cost_schedule=tool.Ifc.get().by_id(self.cost_schedule)) + CostSchedulesData.is_loaded = False class DisableEditingCostSchedule(bpy.types.Operator, tool.Ifc.Operator): @@ -565,8 +569,6 @@ class ImportCostScheduleCsv(bpy.types.Operator, ImportHelper, tool.Ifc.Operator) return True def _execute(self, context): - from pathlib import Path - from bonsai.bim.module.cost.data import CostSchedulesData store_path = self.filepath if self.use_relative_path: @@ -604,7 +606,7 @@ class RefreshCostScheduleCsv(bpy.types.Operator, tool.Ifc.Operator): cls.poll_message_set("No active cost schedule") return False - file_path = tool.Cost.get_cost_schedule_csv_filepath(props.active_cost_schedule_id) + file_path = core.get_cost_schedule_csv_filepath(tool.Cost, props.active_cost_schedule_id) if not file_path: cls.poll_message_set("No CSV file associated with this cost schedule") return False @@ -612,44 +614,14 @@ class RefreshCostScheduleCsv(bpy.types.Operator, tool.Ifc.Operator): return True def _execute(self, context): - from pathlib import Path - from bonsai.bim.module.cost.data import CostSchedulesData - - props = tool.Cost.get_cost_props() - cost_schedule_id = props.active_cost_schedule_id - - file_path = tool.Cost.get_cost_schedule_csv_filepath(cost_schedule_id) - if not file_path: - self.report({"ERROR"}, "No CSV file associated with this cost schedule") + error_message = core.refresh_cost_schedule_csv(tool.Cost) + if error_message: + self.report({"ERROR"}, error_message) return {"CANCELLED"} - - resolved_path = Path(tool.Ifc.resolve_uri(file_path)) - if not resolved_path.exists(): - self.report({"ERROR"}, f"File does not exist: '{file_path}' (resolved to '{resolved_path}')") - return {"CANCELLED"} - - tool.Cost.delete_all_cost_items() - - cost_schedule = tool.Ifc.get_entity_by_id(cost_schedule_id) - is_schedule_of_rates = tool.Cost.is_schedule_of_rates_csv(cost_schedule_id) + CostSchedulesData.is_loaded = False + + return {"FINISHED"} - try: - from ifc5d.csv2ifc import Csv2Ifc - - csv2ifc = Csv2Ifc() - csv2ifc.csv = str(resolved_path) - csv2ifc.file = tool.Ifc.get() - csv2ifc.cost_schedule = cost_schedule - csv2ifc.is_schedule_of_rates = is_schedule_of_rates - csv2ifc.refresh() - - tool.Cost.load_cost_schedule_tree() - CostSchedulesData.is_loaded = False - - return {"FINISHED"} - except Exception as e: - self.report({"ERROR"}, f"Error refreshing CSV: {str(e)}") - return {"CANCELLED"} class AddCostColumn(bpy.types.Operator): bl_idname = "bim.add_cost_column" diff --git a/src/bonsai/bonsai/bim/module/cost/ui.py b/src/bonsai/bonsai/bim/module/cost/ui.py index 98997abffd..dd7cb4c34b 100644 --- a/src/bonsai/bonsai/bim/module/cost/ui.py +++ b/src/bonsai/bonsai/bim/module/cost/ui.py @@ -222,7 +222,7 @@ class BIM_PT_cost_schedules(Panel): quantities = CostSchedulesData.data["cost_quantities"] row = self.layout.row(align=True) # In IFC, all quantities of IfcCostTime should have 1 type. - if quantities: + if quantities and cost_item.get("QuantityType"): quantity_class = cost_item["QuantityType"] row.label(text=quantity_class) else: diff --git a/src/bonsai/bonsai/core/cost.py b/src/bonsai/bonsai/core/cost.py index f6c26a5ac7..d5456cd56f 100644 --- a/src/bonsai/bonsai/core/cost.py +++ b/src/bonsai/bonsai/core/cost.py @@ -18,12 +18,14 @@ from __future__ import annotations from typing import TYPE_CHECKING, Optional, Union, Literal +import bonsai.tool as tool +import os +from bonsai.bim.module.cost.data import CostSchedulesData if TYPE_CHECKING: import bpy import ifcopenshell import ifcopenshell.util.cost - import bonsai.tool as tool def add_cost_schedule(ifc: type[tool.Ifc], name: str, predefined_type: str) -> None: @@ -342,7 +344,13 @@ def select_cost_schedule_products( def import_cost_schedule_csv( cost: type[tool.Cost], file_path: str, is_schedule_of_rates: bool ) -> ifcopenshell.entity_instance: - cost_schedule = cost.import_cost_schedule_csv(file_path, is_schedule_of_rates) + + resolved_path = tool.Ifc.resolve_uri(file_path) + if not os.path.exists(resolved_path): + print(f"Error: Could not find CSV file at {file_path} (resolved to {resolved_path})") + return None + + cost_schedule = cost.import_cost_schedule_csv(resolved_path, is_schedule_of_rates) return cost_schedule @@ -354,11 +362,28 @@ def remove_csv_filepath(cost: type[tool.Cost], cost_schedule) -> None: cost.remove_csv_filepath(cost_schedule) -def refresh_cost_schedule_csv(ifc: type[tool.Ifc], cost: type[tool.Cost]) -> None: +def refresh_cost_schedule_csv(cost: type[tool.Cost]) -> Optional[str]: + + props = cost.get_cost_props() + cost_schedule_id = props.active_cost_schedule_id + file_path = cost.get_cost_schedule_csv_filepath(cost_schedule_id) + + if not file_path: + return "No CSV file associated with this cost schedule" + + resolved_path = tool.Ifc.resolve_uri(file_path) + + if not os.path.exists(resolved_path): + return f"Could not find CSV file at {file_path} (resolved to {resolved_path})" + cost.delete_all_cost_items() cost.refresh_cost_schedule_csv() cost.load_cost_schedule_tree() + CostSchedulesData.is_loaded = False + + return None + def add_cost_column(cost: type[tool.Cost], name: str) -> None: cost.add_cost_column(name) @@ -460,3 +485,11 @@ def add_currency(ifc: type[tool.Ifc], cost: type[tool.Cost]) -> ifcopenshell.ent def generate_cost_schedule_browser(cost: type[tool.Cost], cost_schedule: ifcopenshell.entity_instance) -> None: return cost.generate_cost_schedule_browser(cost_schedule) + + +def get_cost_schedule_csv_filepath(cost: type[tool.Cost], cost_schedule_id: int) -> Optional[str]: + return cost.get_cost_schedule_csv_filepath(cost_schedule_id) + + +def is_schedule_of_rates_csv(cost: type[tool.Cost], cost_schedule_id: int) -> bool: + return cost.is_schedule_of_rates_csv(cost_schedule_id)