diff --git a/src/blenderbim/blenderbim/bim/module/cost/__init__.py b/src/blenderbim/blenderbim/bim/module/cost/__init__.py index 08a6dbea48..49c7199d9f 100644 --- a/src/blenderbim/blenderbim/bim/module/cost/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/cost/__init__.py @@ -68,6 +68,7 @@ classes = ( operator.ContractCostItemRate, operator.CalculateCostItemResourceValue, operator.ClearCostItemAssignments, + operator.SelectUnassignedProducts, operator.LoadCostItemElementQuantities, operator.LoadCostItemTaskQuantities, operator.LoadCostItemResourceQuantities, diff --git a/src/blenderbim/blenderbim/bim/module/cost/operator.py b/src/blenderbim/blenderbim/bim/module/cost/operator.py index baf7112f81..b25b653b13 100644 --- a/src/blenderbim/blenderbim/bim/module/cost/operator.py +++ b/src/blenderbim/blenderbim/bim/module/cost/operator.py @@ -652,3 +652,13 @@ class ClearCostItemAssignments(bpy.types.Operator, tool.Ifc.Operator): related_object_type=self.related_object_type, ) return {"FINISHED"} + + +class SelectUnassignedProducts(bpy.types.Operator): + bl_idname = "bim.select_unassigned_products" + bl_label = "Select Unassigned Products" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + core.select_unassigned_products(tool.Ifc, tool.Cost, tool.Spatial) + return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/core/cost.py b/src/blenderbim/blenderbim/core/cost.py index 995d38b711..454376a549 100644 --- a/src/blenderbim/blenderbim/core/cost.py +++ b/src/blenderbim/blenderbim/core/cost.py @@ -240,3 +240,10 @@ def clear_cost_item_assignments(ifc, cost, cost_item, related_object_type): ifc.run("cost.unassign_cost_item_quantity", cost_item=cost_item, products=products) cost.load_cost_item_quantity_assignments(cost_item, related_object_type=related_object_type) cost.load_cost_schedule_tree() + +def select_unassigned_products(ifc, cost, spatial): + spatial.deselect_all() + products = ifc.get().by_type("IfcElement") + cost_schedule = cost.get_active_cost_schedule() + selection = [product for product in products if not cost.has_cost_assignments(product, cost_schedule)] + spatial.select_products(selection) diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index cbfa2ccd52..3aaf2b0419 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -160,7 +160,7 @@ class Cost: def expand_cost_items(cls): pass def export_cost_schedules(cls, format): pass def get_active_cost_item(cls): pass - def get_all_nested_cost_items(cls, cost_item): pass + def get_active_cost_schedule(cls): pass def get_attributes_for_cost_value(cls, cost_type, cost_category): pass def get_cost_item_attributes(cls, cost_item): pass def get_cost_item_products(cls): pass @@ -172,11 +172,13 @@ class Cost: def get_cost_value_unit_component(cls): pass def get_direct_cost_item_products(cls): pass def get_highlighted_cost_item(cls): pass + def get_highlighted_cost_item(cls): pass def get_nested_cost_items(cls, cost_item): pass def get_products(cls, related_object_type): pass def get_root_cost_items(cls, cost_schedule): pass def get_schedule_cost_items(cls, cost_schedule): pass def get_units(cls):pass + def has_cost_assignments(cls, cost_item): pass def import_cost_schedule_csv(cls, file_path, is_schedule_of_rates): pass def is_active_schedule_of_rates(cls): pass def load_cost_item_attributes(cls): pass diff --git a/src/blenderbim/blenderbim/tool/cost.py b/src/blenderbim/blenderbim/tool/cost.py index 7a9138ff3a..989c73a714 100644 --- a/src/blenderbim/blenderbim/tool/cost.py +++ b/src/blenderbim/blenderbim/tool/cost.py @@ -542,3 +542,18 @@ class Cost(blenderbim.core.tool.Cost): if unit.get_info().get("Prefix", None): name = f"{unit.Prefix} {name}" return f"{unit.UnitType} / {name}" + + @classmethod + def get_active_cost_schedule(cls): + if not bpy.context.scene.BIMCostProperties.active_cost_schedule_id: + return None + return tool.Ifc.get().by_id(bpy.context.scene.BIMCostProperties.active_cost_schedule_id) + + @classmethod + def has_cost_assignments(cls, product, cost_schedule=None): + cost_items = ifcopenshell.util.cost.get_cost_items_for_product(product) + if cost_schedule: + cost_items = [ + cost_item for cost_item in cost_items or [] if cls.get_cost_schedule(cost_item) == cost_schedule + ] + return bool(cost_items)