mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-20 23:36:20 +00:00
See #1848. Refactor cost data class.
This commit is contained in:
@@ -0,0 +1,290 @@
|
|||||||
|
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||||
|
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
|
||||||
|
#
|
||||||
|
# This file is part of BlenderBIM Add-on.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
import ifcopenshell
|
||||||
|
import ifcopenshell.util.cost
|
||||||
|
import ifcopenshell.util.element
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
|
||||||
|
|
||||||
|
def refresh():
|
||||||
|
CostSchedulesData.is_loaded = False
|
||||||
|
CostItemRatesData.is_loaded = False
|
||||||
|
CostItemQuantitiesData.is_loaded = False
|
||||||
|
|
||||||
|
|
||||||
|
class CostSchedulesData:
|
||||||
|
data = {}
|
||||||
|
is_loaded = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(cls):
|
||||||
|
cls.data = {
|
||||||
|
"schedules": cls.schedules(),
|
||||||
|
"is_editing_rates": cls.is_editing_rates(),
|
||||||
|
"cost_items": cls.cost_items(),
|
||||||
|
"cost_quantities": cls.cost_quantities(),
|
||||||
|
"cost_values": cls.cost_values(),
|
||||||
|
"quantity_types": cls.quantity_types(),
|
||||||
|
}
|
||||||
|
cls.is_loaded = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def schedules(cls):
|
||||||
|
results = []
|
||||||
|
if bpy.context.scene.BIMCostProperties.active_cost_schedule_id:
|
||||||
|
schedule = tool.Ifc.get().by_id(bpy.context.scene.BIMCostProperties.active_cost_schedule_id)
|
||||||
|
results.append(
|
||||||
|
{
|
||||||
|
"id": schedule.id(),
|
||||||
|
"name": schedule.Name or "Unnamed",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
for schedule in tool.Ifc.get().by_type("IfcCostSchedule"):
|
||||||
|
results.append(
|
||||||
|
{
|
||||||
|
"id": schedule.id(),
|
||||||
|
"name": schedule.Name or "Unnamed",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return results
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_editing_rates(cls):
|
||||||
|
ifc_id = bpy.context.scene.BIMCostProperties.active_cost_schedule_id
|
||||||
|
if not ifc_id:
|
||||||
|
return
|
||||||
|
return tool.Ifc.get().by_id(ifc_id).PredefinedType == "SCHEDULEOFRATES"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def cost_items(cls):
|
||||||
|
cls._cost_values = {}
|
||||||
|
results = {}
|
||||||
|
for cost_item in tool.Ifc.get().by_type("IfcCostItem"):
|
||||||
|
data = {}
|
||||||
|
cls._load_cost_item_quantities(cost_item, data)
|
||||||
|
cls._load_cost_values(cost_item, data)
|
||||||
|
results[cost_item.id()] = data
|
||||||
|
return results
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _load_cost_values(cls, root_element, data):
|
||||||
|
# data["CostValues"] = []
|
||||||
|
data["CategoryValues"] = {}
|
||||||
|
data["UnitBasisValueComponent"] = None
|
||||||
|
data["UnitBasisUnitSymbol"] = None
|
||||||
|
data["TotalAppliedValue"] = 0.0
|
||||||
|
data["TotalCost"] = 0.0
|
||||||
|
if root_element.is_a("IfcCostItem"):
|
||||||
|
values = root_element.CostValues
|
||||||
|
elif root_element.is_a("IfcConstructionResource"):
|
||||||
|
values = root_element.BaseCosts
|
||||||
|
for cost_value in values or []:
|
||||||
|
cls._load_cost_value(root_element, data, cost_value)
|
||||||
|
# data["CostValues"].append(cost_value.id())
|
||||||
|
data["TotalAppliedValue"] += cls._cost_values[cost_value.id()]["AppliedValue"]
|
||||||
|
if cost_value.UnitBasis:
|
||||||
|
cost_value_data = cls._cost_values[cost_value.id()]
|
||||||
|
data["UnitBasisValueComponent"] = cost_value_data["UnitBasis"]["ValueComponent"]
|
||||||
|
data["UnitBasisUnitSymbol"] = cost_value_data["UnitBasis"]["UnitSymbol"]
|
||||||
|
if data["UnitBasisValueComponent"]:
|
||||||
|
data["TotalCost"] = data["TotalCostQuantity"] / data["UnitBasisValueComponent"] * data["TotalAppliedValue"]
|
||||||
|
else:
|
||||||
|
data["TotalCost"] = data["TotalCostQuantity"] * data["TotalAppliedValue"]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _load_cost_item_quantities(cls, cost_item, data):
|
||||||
|
parametric_quantities = []
|
||||||
|
for rel in cost_item.Controls:
|
||||||
|
for related_object in rel.RelatedObjects or []:
|
||||||
|
quantities = cls._get_object_quantities(cost_item, related_object)
|
||||||
|
# data["Controls"][related_object.id()] = quantities
|
||||||
|
parametric_quantities.extend(quantities)
|
||||||
|
|
||||||
|
# data["CostQuantities"] = []
|
||||||
|
data["TotalCostQuantity"] = ifcopenshell.util.cost.get_total_quantity(cost_item)
|
||||||
|
for quantity in cost_item.CostQuantities or []:
|
||||||
|
if quantity.id() in parametric_quantities:
|
||||||
|
continue
|
||||||
|
# quantity_data = quantity.get_info()
|
||||||
|
# del quantity_data["Unit"]
|
||||||
|
# cls.physical_quantities[quantity.id()] = quantity_data
|
||||||
|
# data["CostQuantities"].append(quantity.id())
|
||||||
|
# data["Unit"] = None
|
||||||
|
data["UnitSymbol"] = "?"
|
||||||
|
if cost_item.CostQuantities:
|
||||||
|
quantity = cost_item.CostQuantities[0]
|
||||||
|
unit = ifcopenshell.util.unit.get_property_unit(quantity, tool.Ifc.get())
|
||||||
|
if unit:
|
||||||
|
# data["Unit"] = unit.id()
|
||||||
|
data["UnitSymbol"] = ifcopenshell.util.unit.get_unit_symbol(unit)
|
||||||
|
else:
|
||||||
|
# data["Unit"] = None
|
||||||
|
data["UnitSymbol"] = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _get_object_quantities(cls, cost_item, element):
|
||||||
|
if not element.is_a("IfcObject"):
|
||||||
|
return []
|
||||||
|
results = []
|
||||||
|
for relationship in element.IsDefinedBy:
|
||||||
|
if not relationship.is_a("IfcRelDefinesByProperties"):
|
||||||
|
continue
|
||||||
|
qto = relationship.RelatingPropertyDefinition
|
||||||
|
if not qto.is_a("IfcElementQuantity"):
|
||||||
|
continue
|
||||||
|
for prop in qto.Quantities:
|
||||||
|
if prop in cost_item.CostQuantities or []:
|
||||||
|
results.append(prop.id())
|
||||||
|
return results
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _load_cost_value(cls, root_element, root_element_data, cost_value):
|
||||||
|
value_data = cost_value.get_info()
|
||||||
|
del value_data["AppliedValue"]
|
||||||
|
if value_data["UnitBasis"]:
|
||||||
|
data = cost_value.UnitBasis.get_info()
|
||||||
|
data["ValueComponent"] = data["ValueComponent"].wrappedValue
|
||||||
|
data["UnitComponent"] = data["UnitComponent"].id()
|
||||||
|
data["UnitSymbol"] = ifcopenshell.util.unit.get_unit_symbol(cost_value.UnitBasis.UnitComponent)
|
||||||
|
value_data["UnitBasis"] = data
|
||||||
|
if value_data["ApplicableDate"]:
|
||||||
|
value_data["ApplicableDate"] = ifcopenshell.util.date.ifc2datetime(value_data["ApplicableDate"])
|
||||||
|
if value_data["FixedUntilDate"]:
|
||||||
|
value_data["FixedUntilDate"] = ifcopenshell.util.date.ifc2datetime(value_data["FixedUntilDate"])
|
||||||
|
value_data["Components"] = [c.id() for c in value_data["Components"] or []]
|
||||||
|
value_data["AppliedValue"] = ifcopenshell.util.cost.calculate_applied_value(root_element, cost_value)
|
||||||
|
|
||||||
|
if cost_value.Category not in [None, "*"]:
|
||||||
|
root_element_data["CategoryValues"].setdefault(cost_value.Category, 0)
|
||||||
|
root_element_data["CategoryValues"][cost_value.Category] += value_data["AppliedValue"]
|
||||||
|
|
||||||
|
value_data["Formula"] = ifcopenshell.util.cost.serialise_cost_value(cost_value)
|
||||||
|
|
||||||
|
cls._cost_values[cost_value.id()] = value_data
|
||||||
|
for component in cost_value.Components or []:
|
||||||
|
cls._load_cost_value(root_element, root_element_data, component)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def cost_quantities(cls):
|
||||||
|
results = []
|
||||||
|
ifc_id = bpy.context.scene.BIMCostProperties.active_cost_item_id
|
||||||
|
if not ifc_id:
|
||||||
|
return results
|
||||||
|
for quantity in tool.Ifc.get().by_id(ifc_id).CostQuantities or []:
|
||||||
|
results.append({"id": quantity.id(), "name": quantity.Name, "value": "{0:.2f}".format(quantity[3])})
|
||||||
|
return results
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def cost_values(cls):
|
||||||
|
results = []
|
||||||
|
ifc_id = bpy.context.scene.BIMCostProperties.active_cost_item_id
|
||||||
|
if not ifc_id:
|
||||||
|
return results
|
||||||
|
cost_item = tool.Ifc.get().by_id(ifc_id)
|
||||||
|
for cost_value in cost_item.CostValues or []:
|
||||||
|
label = "{0:.2f}".format(ifcopenshell.util.cost.calculate_applied_value(cost_item, cost_value))
|
||||||
|
label += " = {}".format(ifcopenshell.util.cost.serialise_cost_value(cost_value))
|
||||||
|
results.append({"id": cost_value.id(), "label": label})
|
||||||
|
return results
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def quantity_types(cls):
|
||||||
|
return [
|
||||||
|
(t.name(), t.name(), "")
|
||||||
|
for t in tool.Ifc.schema().declaration_by_name("IfcPhysicalSimpleQuantity").subtypes()
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class CostItemRatesData:
|
||||||
|
data = {}
|
||||||
|
is_loaded = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(cls):
|
||||||
|
cls.data = {
|
||||||
|
"schedule_of_rates": cls.schedule_of_rates(),
|
||||||
|
}
|
||||||
|
cls.is_loaded = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def schedule_of_rates(cls):
|
||||||
|
return [
|
||||||
|
(str(s.id()), s.Name or "Unnamed", "")
|
||||||
|
for s in tool.Ifc.get().by_type("IfcCostSchedule")
|
||||||
|
if s.PredefinedType == "SCHEDULEOFRATES"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class CostItemQuantitiesData:
|
||||||
|
data = {}
|
||||||
|
is_loaded = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(cls):
|
||||||
|
cls.data = {
|
||||||
|
"product_quantity_names": cls.product_quantity_names(),
|
||||||
|
"process_quantity_names": cls.process_quantity_names(),
|
||||||
|
"resource_quantity_names": cls.resource_quantity_names(),
|
||||||
|
}
|
||||||
|
cls.is_loaded = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def product_quantity_names(cls):
|
||||||
|
total_selected_objects = len(bpy.context.selected_objects)
|
||||||
|
names = set()
|
||||||
|
for obj in bpy.context.selected_objects:
|
||||||
|
element = tool.Ifc.get_entity(obj)
|
||||||
|
if not element:
|
||||||
|
continue
|
||||||
|
potential_names = set()
|
||||||
|
qtos = ifcopenshell.util.element.get_psets(element, qtos_only=True)
|
||||||
|
for qset, quantities in qtos.items():
|
||||||
|
potential_names.update(quantities.keys())
|
||||||
|
names = names.intersection(potential_names) if names else potential_names
|
||||||
|
return [(n, n, "") for n in names if n != "id"]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def process_quantity_names(cls):
|
||||||
|
active_task_index = bpy.context.scene.BIMWorkScheduleProperties.active_task_index
|
||||||
|
total_tasks = len(bpy.context.scene.BIMTaskTreeProperties.tasks)
|
||||||
|
if not total_tasks or active_task_index >= total_tasks:
|
||||||
|
return []
|
||||||
|
ifc_definition_id = bpy.context.scene.BIMTaskTreeProperties.tasks[active_task_index].ifc_definition_id
|
||||||
|
element = tool.Ifc.get().by_id(ifc_definition_id)
|
||||||
|
names = set()
|
||||||
|
qtos = ifcopenshell.util.element.get_psets(element, qtos_only=True)
|
||||||
|
for qset, quantities in qtos.items():
|
||||||
|
names = set(quantities.keys())
|
||||||
|
return [(n, n, "") for n in names if n != "id"]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def resource_quantity_names(cls):
|
||||||
|
active_resource_index = bpy.context.scene.BIMResourceProperties.active_resource_index
|
||||||
|
total_resources = len(bpy.context.scene.BIMResourceTreeProperties.resources)
|
||||||
|
if not total_resources or active_resource_index >= total_resources:
|
||||||
|
return []
|
||||||
|
ifc_definition_id = bpy.context.scene.BIMResourceTreeProperties.resources[active_resource_index].ifc_definition_id
|
||||||
|
element = tool.Ifc.get().by_id(ifc_definition_id)
|
||||||
|
names = set()
|
||||||
|
qtos = ifcopenshell.util.element.get_psets(element, qtos_only=True)
|
||||||
|
for qset, quantities in qtos.items():
|
||||||
|
names = set(quantities.keys())
|
||||||
|
return [(n, n, "") for n in names if n != "id"]
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -18,10 +18,10 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
|
import blenderbim.tool as tool
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from blenderbim.bim.module.classification.data import CostClassificationsData
|
from blenderbim.bim.module.classification.data import CostClassificationsData
|
||||||
from ifcopenshell.api.cost.data import Data
|
from blenderbim.bim.module.cost.data import CostSchedulesData, CostItemRatesData, CostItemQuantitiesData
|
||||||
from ifcopenshell.api.pset.data import Data as PsetData
|
|
||||||
from blenderbim.bim.prop import StrProperty, Attribute
|
from blenderbim.bim.prop import StrProperty, Attribute
|
||||||
from bpy.types import PropertyGroup
|
from bpy.types import PropertyGroup
|
||||||
from bpy.props import (
|
from bpy.props import (
|
||||||
@@ -36,44 +36,10 @@ from bpy.props import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
quantitytypes_enum = []
|
|
||||||
productquantitynames_enum = []
|
|
||||||
productquantitynames_count = []
|
|
||||||
processquantitynames_enum = []
|
|
||||||
processquantitynames_id = 0
|
|
||||||
resourcequantitynames_enum = []
|
|
||||||
resourcequantitynames_id = 0
|
|
||||||
scheduleofrates_enum = []
|
|
||||||
|
|
||||||
|
|
||||||
def purge():
|
|
||||||
global quantitytypes_enum
|
|
||||||
global productquantitynames_enum
|
|
||||||
global productquantitynames_count
|
|
||||||
global processquantitynames_enum
|
|
||||||
global processquantitynames_id
|
|
||||||
global resourcequantitynames_enum
|
|
||||||
global resourcequantitynames_id
|
|
||||||
global scheduleofrates_enum
|
|
||||||
quantitytypes_enum = []
|
|
||||||
productquantitynames_enum = []
|
|
||||||
productquantitynames_count = []
|
|
||||||
processquantitynames_enum = []
|
|
||||||
processquantitynames_id = 0
|
|
||||||
resourcequantitynames_enum = []
|
|
||||||
resourcequantitynames_id = 0
|
|
||||||
scheduleofrates_enum = []
|
|
||||||
|
|
||||||
|
|
||||||
def get_schedule_of_rates(self, context):
|
def get_schedule_of_rates(self, context):
|
||||||
global scheduleofrates_enum
|
if not CostItemRatesData.is_loaded:
|
||||||
if len(scheduleofrates_enum) == 0:
|
CostItemRatesData.load()
|
||||||
scheduleofrates_enum.extend(
|
return CostItemRatesData.data["schedule_of_rates"]
|
||||||
(str(ifc_definition_id), schedule["Name"] or "Unnamed", "")
|
|
||||||
for ifc_definition_id, schedule in Data.cost_schedules.items()
|
|
||||||
if schedule["PredefinedType"] == "SCHEDULEOFRATES"
|
|
||||||
)
|
|
||||||
return scheduleofrates_enum
|
|
||||||
|
|
||||||
|
|
||||||
def update_schedule_of_rates(self, context):
|
def update_schedule_of_rates(self, context):
|
||||||
@@ -81,87 +47,32 @@ def update_schedule_of_rates(self, context):
|
|||||||
|
|
||||||
|
|
||||||
def get_quantity_types(self, context):
|
def get_quantity_types(self, context):
|
||||||
global quantitytypes_enum
|
if not CostSchedulesData.is_loaded:
|
||||||
if len(quantitytypes_enum) == 0 and IfcStore.get_schema():
|
CostSchedulesData.load()
|
||||||
quantitytypes_enum.extend(
|
return CostSchedulesData.data["quantity_types"]
|
||||||
[
|
|
||||||
(t.name(), t.name(), "")
|
|
||||||
for t in IfcStore.get_schema().declaration_by_name("IfcPhysicalSimpleQuantity").subtypes()
|
|
||||||
]
|
|
||||||
)
|
|
||||||
return quantitytypes_enum
|
|
||||||
|
|
||||||
|
|
||||||
def get_product_quantity_names(self, context):
|
def get_product_quantity_names(self, context):
|
||||||
global productquantitynames_enum
|
if not CostItemQuantitiesData.is_loaded:
|
||||||
global productquantitynames_count
|
CostItemQuantitiesData.load()
|
||||||
ifc_file = IfcStore.get_file()
|
return CostItemQuantitiesData.data["product_quantity_names"]
|
||||||
total_selected_objects = len(context.selected_objects)
|
|
||||||
if total_selected_objects != productquantitynames_count or total_selected_objects == 1:
|
|
||||||
productquantitynames_enum = []
|
|
||||||
productquantitynames_count = total_selected_objects
|
|
||||||
names = set()
|
|
||||||
for obj in context.selected_objects:
|
|
||||||
element_id = obj.BIMObjectProperties.ifc_definition_id
|
|
||||||
if not element_id:
|
|
||||||
continue
|
|
||||||
potential_names = set()
|
|
||||||
if element_id not in PsetData.products:
|
|
||||||
PsetData.load(ifc_file, element_id)
|
|
||||||
for qto_id in PsetData.products[element_id]["qtos"]:
|
|
||||||
qto = PsetData.qtos[qto_id]
|
|
||||||
[potential_names.add(PsetData.properties[p]["Name"]) for p in qto["Properties"]]
|
|
||||||
names = names.intersection(potential_names) if names else potential_names
|
|
||||||
productquantitynames_enum.extend([(n, n, "") for n in names])
|
|
||||||
return productquantitynames_enum
|
|
||||||
|
|
||||||
|
|
||||||
def get_process_quantity_names(self, context):
|
def get_process_quantity_names(self, context):
|
||||||
global processquantitynames_enum
|
if not CostItemQuantitiesData.is_loaded:
|
||||||
global processquantitynames_id
|
CostItemQuantitiesData.load()
|
||||||
ifc_file = IfcStore.get_file()
|
return CostItemQuantitiesData.data["process_quantity_names"]
|
||||||
active_task_index = context.scene.BIMWorkScheduleProperties.active_task_index
|
|
||||||
total_tasks = len(context.scene.BIMTaskTreeProperties.tasks)
|
|
||||||
if not total_tasks or active_task_index >= total_tasks:
|
|
||||||
return []
|
|
||||||
ifc_definition_id = context.scene.BIMTaskTreeProperties.tasks[active_task_index].ifc_definition_id
|
|
||||||
if processquantitynames_id != ifc_definition_id:
|
|
||||||
processquantitynames_enum = []
|
|
||||||
processquantitynames_id = ifc_definition_id
|
|
||||||
names = set()
|
|
||||||
if ifc_definition_id not in PsetData.products:
|
|
||||||
PsetData.load(ifc_file, ifc_definition_id)
|
|
||||||
for qto_id in PsetData.products[ifc_definition_id]["qtos"]:
|
|
||||||
qto = PsetData.qtos[qto_id]
|
|
||||||
[names.add(PsetData.properties[p]["Name"]) for p in qto["Properties"]]
|
|
||||||
processquantitynames_enum.extend([(n, n, "") for n in names])
|
|
||||||
return processquantitynames_enum
|
|
||||||
|
|
||||||
|
|
||||||
def get_resource_quantity_names(self, context):
|
def get_resource_quantity_names(self, context):
|
||||||
global resourcequantitynames_enum
|
if not CostItemQuantitiesData.is_loaded:
|
||||||
global resourcequantitynames_id
|
CostItemQuantitiesData.load()
|
||||||
ifc_file = IfcStore.get_file()
|
return CostItemQuantitiesData.data["resource_quantity_names"]
|
||||||
active_resource_index = context.scene.BIMResourceProperties.active_resource_index
|
|
||||||
total_resources = len(context.scene.BIMResourceTreeProperties.resources)
|
|
||||||
if not total_resources or active_resource_index >= total_resources:
|
|
||||||
return []
|
|
||||||
ifc_definition_id = context.scene.BIMResourceTreeProperties.resources[active_resource_index].ifc_definition_id
|
|
||||||
if resourcequantitynames_id != ifc_definition_id:
|
|
||||||
resourcequantitynames_enum = []
|
|
||||||
resourcequantitynames_id = ifc_definition_id
|
|
||||||
names = set()
|
|
||||||
if ifc_definition_id not in PsetData.products:
|
|
||||||
PsetData.load(ifc_file, ifc_definition_id)
|
|
||||||
for qto_id in PsetData.products[ifc_definition_id]["qtos"]:
|
|
||||||
qto = PsetData.qtos[qto_id]
|
|
||||||
[names.add(PsetData.properties[p]["Name"]) for p in qto["Properties"]]
|
|
||||||
resourcequantitynames_enum.extend([(n, n, "") for n in names])
|
|
||||||
return resourcequantitynames_enum
|
|
||||||
|
|
||||||
|
|
||||||
def update_active_cost_item_index(self, context):
|
def update_active_cost_item_index(self, context):
|
||||||
if Data.cost_schedules[self.active_cost_schedule_id]["PredefinedType"] == "SCHEDULEOFRATES":
|
schedule = tool.Ifc.get().by_id(self.active_cost_schedule_id)
|
||||||
|
if schedule.PredefinedType == "SCHEDULEOFRATES":
|
||||||
bpy.ops.bim.load_cost_item_types()
|
bpy.ops.bim.load_cost_item_types()
|
||||||
else:
|
else:
|
||||||
bpy.ops.bim.load_cost_item_quantities()
|
bpy.ops.bim.load_cost_item_quantities()
|
||||||
@@ -178,7 +89,6 @@ def update_cost_item_identification(self, context):
|
|||||||
self.file,
|
self.file,
|
||||||
**{"cost_item": self.file.by_id(self.ifc_definition_id), "attributes": {"Identification": self.identification}},
|
**{"cost_item": self.file.by_id(self.ifc_definition_id), "attributes": {"Identification": self.identification}},
|
||||||
)
|
)
|
||||||
Data.load(self.file)
|
|
||||||
if props.active_cost_item_id == self.ifc_definition_id:
|
if props.active_cost_item_id == self.ifc_definition_id:
|
||||||
attribute = props.cost_item_attributes.get("Identification")
|
attribute = props.cost_item_attributes.get("Identification")
|
||||||
attribute.string_value = self.identification
|
attribute.string_value = self.identification
|
||||||
@@ -194,7 +104,6 @@ def update_cost_item_name(self, context):
|
|||||||
self.file,
|
self.file,
|
||||||
**{"cost_item": self.file.by_id(self.ifc_definition_id), "attributes": {"Name": self.name}},
|
**{"cost_item": self.file.by_id(self.ifc_definition_id), "attributes": {"Name": self.name}},
|
||||||
)
|
)
|
||||||
Data.load(IfcStore.get_file())
|
|
||||||
if props.active_cost_item_id == self.ifc_definition_id:
|
if props.active_cost_item_id == self.ifc_definition_id:
|
||||||
attribute = props.cost_item_attributes.get("Name")
|
attribute = props.cost_item_attributes.get("Name")
|
||||||
attribute.string_value = self.name
|
attribute.string_value = self.name
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ import blenderbim.bim.helper
|
|||||||
import blenderbim.bim.module.cost.prop as CostProp
|
import blenderbim.bim.module.cost.prop as CostProp
|
||||||
from bpy.types import Panel, UIList
|
from bpy.types import Panel, UIList
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from ifcopenshell.api.cost.data import Data
|
from blenderbim.bim.module.cost.data import CostSchedulesData
|
||||||
from ifcopenshell.api.unit.data import Data as UnitData
|
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_cost_schedules(Panel):
|
class BIM_PT_cost_schedules(Panel):
|
||||||
@@ -39,54 +38,46 @@ class BIM_PT_cost_schedules(Panel):
|
|||||||
return file and hasattr(file, "schema") and file.schema != "IFC2X3"
|
return file and hasattr(file, "schema") and file.schema != "IFC2X3"
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
|
if not CostSchedulesData.is_loaded:
|
||||||
|
CostSchedulesData.load()
|
||||||
|
|
||||||
self.props = context.scene.BIMCostProperties
|
self.props = context.scene.BIMCostProperties
|
||||||
|
|
||||||
if not Data.is_loaded:
|
|
||||||
Data.load(IfcStore.get_file())
|
|
||||||
|
|
||||||
if not UnitData.is_loaded:
|
|
||||||
UnitData.load(IfcStore.get_file())
|
|
||||||
|
|
||||||
row = self.layout.row()
|
row = self.layout.row()
|
||||||
row.operator("bim.add_cost_schedule", icon="ADD")
|
row.operator("bim.add_cost_schedule", icon="ADD")
|
||||||
|
|
||||||
if self.props.active_cost_schedule_id:
|
for schedule in CostSchedulesData.data["schedules"]:
|
||||||
self.draw_cost_schedule_ui(
|
self.draw_cost_schedule_ui(schedule)
|
||||||
self.props.active_cost_schedule_id, Data.cost_schedules[self.props.active_cost_schedule_id]
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
for cost_schedule_id, cost_schedule in Data.cost_schedules.items():
|
|
||||||
self.draw_cost_schedule_ui(cost_schedule_id, cost_schedule)
|
|
||||||
|
|
||||||
def draw_cost_schedule_ui(self, cost_schedule_id, cost_schedule):
|
def draw_cost_schedule_ui(self, cost_schedule):
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.label(text=cost_schedule["Name"] or "Unnamed", icon="LINENUMBERS_ON")
|
row.label(text=cost_schedule["name"], icon="LINENUMBERS_ON")
|
||||||
|
|
||||||
if self.props.active_cost_schedule_id and self.props.active_cost_schedule_id == cost_schedule_id:
|
if self.props.active_cost_schedule_id and self.props.active_cost_schedule_id == cost_schedule["id"]:
|
||||||
op = row.operator("bim.select_cost_schedule_products", icon="RESTRICT_SELECT_OFF", text="")
|
op = row.operator("bim.select_cost_schedule_products", icon="RESTRICT_SELECT_OFF", text="")
|
||||||
op.cost_schedule = cost_schedule_id
|
op.cost_schedule = cost_schedule["id"]
|
||||||
row.prop(self.props, "should_show_column_ui", text="", icon="SHORTDISPLAY")
|
row.prop(self.props, "should_show_column_ui", text="", icon="SHORTDISPLAY")
|
||||||
if self.props.is_editing == "COST_SCHEDULE":
|
if self.props.is_editing == "COST_SCHEDULE":
|
||||||
row.operator("bim.edit_cost_schedule", text="", icon="CHECKMARK")
|
row.operator("bim.edit_cost_schedule", text="", icon="CHECKMARK")
|
||||||
elif self.props.is_editing == "COST_ITEMS":
|
elif self.props.is_editing == "COST_ITEMS":
|
||||||
row.operator("bim.add_summary_cost_item", text="", icon="ADD").cost_schedule = cost_schedule_id
|
row.operator("bim.add_summary_cost_item", text="", icon="ADD").cost_schedule = cost_schedule["id"]
|
||||||
row.operator("bim.disable_editing_cost_schedule", text="", icon="CANCEL")
|
row.operator("bim.disable_editing_cost_schedule", text="", icon="CANCEL")
|
||||||
elif self.props.active_cost_schedule_id:
|
elif self.props.active_cost_schedule_id:
|
||||||
row.operator("bim.remove_cost_schedule", text="", icon="X").cost_schedule = cost_schedule_id
|
row.operator("bim.remove_cost_schedule", text="", icon="X").cost_schedule = cost_schedule["id"]
|
||||||
else:
|
else:
|
||||||
row.operator("bim.enable_editing_cost_items", text="", icon="OUTLINER").cost_schedule = cost_schedule_id
|
row.operator("bim.enable_editing_cost_items", text="", icon="OUTLINER").cost_schedule = cost_schedule["id"]
|
||||||
row.operator(
|
row.operator(
|
||||||
"bim.enable_editing_cost_schedule", text="", icon="GREASEPENCIL"
|
"bim.enable_editing_cost_schedule", text="", icon="GREASEPENCIL"
|
||||||
).cost_schedule = cost_schedule_id
|
).cost_schedule = cost_schedule["id"]
|
||||||
row.operator("bim.remove_cost_schedule", text="", icon="X").cost_schedule = cost_schedule_id
|
row.operator("bim.remove_cost_schedule", text="", icon="X").cost_schedule = cost_schedule["id"]
|
||||||
|
|
||||||
if self.props.active_cost_schedule_id == cost_schedule_id:
|
if self.props.active_cost_schedule_id == cost_schedule["id"]:
|
||||||
if self.props.is_editing == "COST_SCHEDULE":
|
if self.props.is_editing == "COST_SCHEDULE":
|
||||||
self.draw_editable_cost_schedule_ui()
|
self.draw_editable_cost_schedule_ui()
|
||||||
elif self.props.is_editing == "COST_ITEMS":
|
elif self.props.is_editing == "COST_ITEMS":
|
||||||
if self.props.should_show_column_ui:
|
if self.props.should_show_column_ui:
|
||||||
self.draw_column_ui()
|
self.draw_column_ui()
|
||||||
self.draw_editable_cost_item_ui(cost_schedule_id)
|
self.draw_editable_cost_item_ui()
|
||||||
|
|
||||||
def draw_column_ui(self):
|
def draw_column_ui(self):
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
@@ -97,7 +88,7 @@ class BIM_PT_cost_schedules(Panel):
|
|||||||
def draw_editable_cost_schedule_ui(self):
|
def draw_editable_cost_schedule_ui(self):
|
||||||
blenderbim.bim.helper.draw_attributes(self.props.cost_schedule_attributes, self.layout)
|
blenderbim.bim.helper.draw_attributes(self.props.cost_schedule_attributes, self.layout)
|
||||||
|
|
||||||
def draw_editable_cost_item_ui(self, cost_schedule_id):
|
def draw_editable_cost_item_ui(self):
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.alignment = "RIGHT"
|
row.alignment = "RIGHT"
|
||||||
ifc_definition_id = None
|
ifc_definition_id = None
|
||||||
@@ -105,7 +96,7 @@ class BIM_PT_cost_schedules(Panel):
|
|||||||
ifc_definition_id = self.props.cost_items[self.props.active_cost_item_index].ifc_definition_id
|
ifc_definition_id = self.props.cost_items[self.props.active_cost_item_index].ifc_definition_id
|
||||||
if ifc_definition_id:
|
if ifc_definition_id:
|
||||||
|
|
||||||
if Data.cost_schedules[self.props.active_cost_schedule_id]["PredefinedType"] != "SCHEDULEOFRATES":
|
if not CostSchedulesData.data["is_editing_rates"]:
|
||||||
op = row.operator("bim.enable_editing_cost_item_quantities", text="", icon="PROPERTIES")
|
op = row.operator("bim.enable_editing_cost_item_quantities", text="", icon="PROPERTIES")
|
||||||
op.cost_item = ifc_definition_id
|
op.cost_item = ifc_definition_id
|
||||||
|
|
||||||
@@ -150,33 +141,27 @@ class BIM_PT_cost_schedules(Panel):
|
|||||||
op.cost_item = self.props.active_cost_item_id
|
op.cost_item = self.props.active_cost_item_id
|
||||||
op.ifc_class = self.props.quantity_types
|
op.ifc_class = self.props.quantity_types
|
||||||
|
|
||||||
for quantity_id in Data.cost_items[self.props.active_cost_item_id]["CostQuantities"]:
|
for quantity in CostSchedulesData.data["cost_quantities"]:
|
||||||
quantity = Data.physical_quantities[quantity_id]
|
|
||||||
value = quantity[[k for k in quantity.keys() if "Value" in k][0]]
|
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.label(text=quantity["Name"])
|
row.label(text=quantity["name"])
|
||||||
row.label(text="{0:.2f}".format(value))
|
row.label(text=quantity["value"])
|
||||||
if self.props.active_cost_item_quantity_id and self.props.active_cost_item_quantity_id == quantity_id:
|
if self.props.active_cost_item_quantity_id and self.props.active_cost_item_quantity_id == quantity["id"]:
|
||||||
op = row.operator("bim.edit_cost_item_quantity", text="", icon="CHECKMARK")
|
op = row.operator("bim.edit_cost_item_quantity", text="", icon="CHECKMARK")
|
||||||
op.physical_quantity = quantity_id
|
op.physical_quantity = quantity["id"]
|
||||||
row.operator("bim.disable_editing_cost_item_quantity", text="", icon="CANCEL")
|
row.operator("bim.disable_editing_cost_item_quantity", text="", icon="CANCEL")
|
||||||
elif self.props.active_cost_item_quantity_id:
|
elif self.props.active_cost_item_quantity_id:
|
||||||
op = row.operator("bim.remove_cost_item_quantity", text="", icon="X")
|
op = row.operator("bim.remove_cost_item_quantity", text="", icon="X")
|
||||||
op.cost_item = self.props.active_cost_item_id
|
op.cost_item = self.props.active_cost_item_id
|
||||||
op.physical_quantity = quantity_id
|
op.physical_quantity = quantity["id"]
|
||||||
else:
|
else:
|
||||||
op = row.operator("bim.enable_editing_cost_item_quantity", text="", icon="GREASEPENCIL")
|
op = row.operator("bim.enable_editing_cost_item_quantity", text="", icon="GREASEPENCIL")
|
||||||
op.physical_quantity = quantity_id
|
op.physical_quantity = quantity["id"]
|
||||||
op = row.operator("bim.remove_cost_item_quantity", text="", icon="X")
|
op = row.operator("bim.remove_cost_item_quantity", text="", icon="X")
|
||||||
op.cost_item = self.props.active_cost_item_id
|
op.cost_item = self.props.active_cost_item_id
|
||||||
op.physical_quantity = quantity_id
|
op.physical_quantity = quantity["id"]
|
||||||
|
|
||||||
if self.props.active_cost_item_quantity_id and self.props.active_cost_item_quantity_id == quantity_id:
|
if self.props.active_cost_item_quantity_id and self.props.active_cost_item_quantity_id == quantity["id"]:
|
||||||
box = self.layout.box()
|
blenderbim.bim.helper.draw_attributes(self.props.quantity_attributes, self.layout.box())
|
||||||
self.draw_editable_cost_item_quantity_ui(box)
|
|
||||||
|
|
||||||
def draw_editable_cost_item_quantity_ui(self, layout):
|
|
||||||
blenderbim.bim.helper.draw_attributes(self.props.quantity_attributes, self.layout)
|
|
||||||
|
|
||||||
def draw_editable_cost_item_values_ui(self):
|
def draw_editable_cost_item_values_ui(self):
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
@@ -189,25 +174,20 @@ class BIM_PT_cost_schedules(Panel):
|
|||||||
if self.props.cost_types == "CATEGORY":
|
if self.props.cost_types == "CATEGORY":
|
||||||
op.cost_category = self.props.cost_category
|
op.cost_category = self.props.cost_category
|
||||||
|
|
||||||
for cost_value_id in Data.cost_items[self.props.active_cost_item_id]["CostValues"]:
|
for cost_value in CostSchedulesData.data["cost_values"]:
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
self.draw_readonly_cost_value_ui(row, cost_value_id)
|
self.draw_readonly_cost_value_ui(row, cost_value)
|
||||||
|
|
||||||
if self.props.cost_value_editing_type == "ATTRIBUTES":
|
if self.props.cost_value_editing_type == "ATTRIBUTES":
|
||||||
box = self.layout.box()
|
blenderbim.bim.helper.draw_attributes(self.props.cost_value_attributes, self.layout.box())
|
||||||
self.draw_editable_cost_value_ui(box, Data.cost_values[self.props.active_cost_value_id])
|
|
||||||
|
|
||||||
def draw_readonly_cost_value_ui(self, layout, cost_value_id):
|
def draw_readonly_cost_value_ui(self, layout, cost_value):
|
||||||
cost_value = Data.cost_values[cost_value_id]
|
if self.props.active_cost_value_id == cost_value["id"] and self.props.cost_value_editing_type == "FORMULA":
|
||||||
|
|
||||||
if self.props.active_cost_value_id == cost_value_id and self.props.cost_value_editing_type == "FORMULA":
|
|
||||||
layout.prop(self.props, "cost_value_formula", text="")
|
layout.prop(self.props, "cost_value_formula", text="")
|
||||||
else:
|
else:
|
||||||
cost_value_label = "{0:.2f}".format(cost_value["AppliedValue"])
|
layout.label(text=cost_value["label"], icon="DISC")
|
||||||
cost_value_label += " = " + cost_value["Formula"]
|
|
||||||
layout.label(text=cost_value_label, icon="DISC")
|
|
||||||
|
|
||||||
self.draw_cost_value_operator_ui(layout, cost_value_id, self.props.active_cost_item_id)
|
self.draw_cost_value_operator_ui(layout, cost_value["id"], self.props.active_cost_item_id)
|
||||||
|
|
||||||
def draw_cost_value_operator_ui(self, layout, cost_value_id, parent_id):
|
def draw_cost_value_operator_ui(self, layout, cost_value_id, parent_id):
|
||||||
if self.props.active_cost_value_id and self.props.active_cost_value_id == cost_value_id:
|
if self.props.active_cost_value_id and self.props.active_cost_value_id == cost_value_id:
|
||||||
@@ -231,9 +211,6 @@ class BIM_PT_cost_schedules(Panel):
|
|||||||
op.parent = parent_id
|
op.parent = parent_id
|
||||||
op.cost_value = cost_value_id
|
op.cost_value = cost_value_id
|
||||||
|
|
||||||
def draw_editable_cost_value_ui(self, layout, cost_value):
|
|
||||||
blenderbim.bim.helper.draw_attributes(self.props.cost_value_attributes, layout)
|
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_cost_item_types(Panel):
|
class BIM_PT_cost_item_types(Panel):
|
||||||
bl_label = "IFC Cost Item Types"
|
bl_label = "IFC Cost Item Types"
|
||||||
@@ -250,7 +227,9 @@ class BIM_PT_cost_item_types(Panel):
|
|||||||
total_cost_items = len(props.cost_items)
|
total_cost_items = len(props.cost_items)
|
||||||
if not props.active_cost_schedule_id:
|
if not props.active_cost_schedule_id:
|
||||||
return False
|
return False
|
||||||
if Data.cost_schedules[props.active_cost_schedule_id]["PredefinedType"] != "SCHEDULEOFRATES":
|
if not CostSchedulesData.is_loaded:
|
||||||
|
return False
|
||||||
|
if not CostSchedulesData.data["is_editing_rates"]:
|
||||||
return False
|
return False
|
||||||
if total_cost_items > 0 and props.active_cost_item_index < total_cost_items:
|
if total_cost_items > 0 and props.active_cost_item_index < total_cost_items:
|
||||||
return True
|
return True
|
||||||
@@ -336,18 +315,15 @@ class BIM_PT_cost_item_quantities(Panel):
|
|||||||
total_cost_items = len(props.cost_items)
|
total_cost_items = len(props.cost_items)
|
||||||
if not props.active_cost_schedule_id:
|
if not props.active_cost_schedule_id:
|
||||||
return False
|
return False
|
||||||
if Data.cost_schedules[props.active_cost_schedule_id]["PredefinedType"] == "SCHEDULEOFRATES":
|
if not CostSchedulesData.is_loaded:
|
||||||
|
return False
|
||||||
|
if CostSchedulesData.data["is_editing_rates"]:
|
||||||
return False
|
return False
|
||||||
if total_cost_items > 0 and props.active_cost_item_index < total_cost_items:
|
if total_cost_items > 0 and props.active_cost_item_index < total_cost_items:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
if not Data.is_loaded:
|
|
||||||
Data.load(IfcStore.get_file())
|
|
||||||
|
|
||||||
if not UnitData.is_loaded:
|
|
||||||
UnitData.load(IfcStore.get_file())
|
|
||||||
self.props = context.scene.BIMCostProperties
|
self.props = context.scene.BIMCostProperties
|
||||||
|
|
||||||
cost_item = self.props.cost_items[self.props.active_cost_item_index]
|
cost_item = self.props.cost_items[self.props.active_cost_item_index]
|
||||||
@@ -485,7 +461,9 @@ class BIM_PT_cost_item_rates(Panel):
|
|||||||
total_cost_items = len(props.cost_items)
|
total_cost_items = len(props.cost_items)
|
||||||
if not props.active_cost_schedule_id:
|
if not props.active_cost_schedule_id:
|
||||||
return False
|
return False
|
||||||
if Data.cost_schedules[props.active_cost_schedule_id]["PredefinedType"] == "SCHEDULEOFRATES":
|
if not CostSchedulesData.is_loaded:
|
||||||
|
return False
|
||||||
|
if CostSchedulesData.data["is_editing_rates"]:
|
||||||
return False
|
return False
|
||||||
if total_cost_items > 0 and props.active_cost_item_index < total_cost_items:
|
if total_cost_items > 0 and props.active_cost_item_index < total_cost_items:
|
||||||
return True
|
return True
|
||||||
@@ -514,7 +492,7 @@ class BIM_UL_cost_items_trait:
|
|||||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||||
if item:
|
if item:
|
||||||
self.props = context.scene.BIMCostProperties
|
self.props = context.scene.BIMCostProperties
|
||||||
cost_item = Data.cost_items[item.ifc_definition_id]
|
cost_item = CostSchedulesData.data["cost_items"][item.ifc_definition_id]
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
|
|
||||||
self.draw_hierarchy(row, item)
|
self.draw_hierarchy(row, item)
|
||||||
@@ -550,7 +528,7 @@ class BIM_UL_cost_items_trait:
|
|||||||
layout.label(text="{0:.2f}".format(cost_item["TotalCost"]))
|
layout.label(text="{0:.2f}".format(cost_item["TotalCost"]))
|
||||||
|
|
||||||
def draw_quantity_column(self, layout, cost_item):
|
def draw_quantity_column(self, layout, cost_item):
|
||||||
if Data.cost_schedules[self.props.active_cost_schedule_id]["PredefinedType"] == "SCHEDULEOFRATES":
|
if CostSchedulesData.data["is_editing_rates"]:
|
||||||
self.draw_uom_column(layout, cost_item)
|
self.draw_uom_column(layout, cost_item)
|
||||||
else:
|
else:
|
||||||
self.draw_total_quantity_column(layout, cost_item)
|
self.draw_total_quantity_column(layout, cost_item)
|
||||||
|
|||||||
@@ -6,17 +6,376 @@ Scenario: Add cost schedule
|
|||||||
When I press "bim.add_cost_schedule"
|
When I press "bim.add_cost_schedule"
|
||||||
Then nothing happens
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Enable editing cost schedule
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
When I press "bim.enable_editing_cost_schedule(cost_schedule={cost_schedule})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Disable editing cost schedule
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_schedule(cost_schedule={cost_schedule})"
|
||||||
|
When I press "bim.disable_editing_cost_schedule"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Edit cost schedule
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_schedule(cost_schedule={cost_schedule})"
|
||||||
|
When I press "bim.edit_cost_schedule"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Remove cost schedule
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
When I press "bim.remove_cost_schedule(cost_schedule={cost_schedule})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
Scenario: Enable editing cost items
|
Scenario: Enable editing cost items
|
||||||
Given an empty IFC project
|
Given an empty IFC project
|
||||||
When I press "bim.add_cost_schedule"
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
When I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Disable editing cost schedule - after editing items
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
When I press "bim.disable_editing_cost_schedule"
|
||||||
Then nothing happens
|
Then nothing happens
|
||||||
|
|
||||||
Scenario: Add summary cost item
|
Scenario: Add summary cost item
|
||||||
Given an empty IFC project
|
Given an empty IFC project
|
||||||
When I press "bim.add_cost_schedule"
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
When I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Remove cost item
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
When I press "bim.remove_cost_item(cost_item={cost_item})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Enable editing cost item
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
When I press "bim.enable_editing_cost_item(cost_item={cost_item})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Disable editing cost item
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_item(cost_item={cost_item})"
|
||||||
|
When I press "bim.disable_editing_cost_item"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Edit cost item
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_item(cost_item={cost_item})"
|
||||||
|
When I press "bim.edit_cost_item"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Add cost item
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
When I press "bim.add_cost_item(cost_item={cost_item})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Enable editing cost item quantities
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
When I press "bim.enable_editing_cost_item_quantities(cost_item={cost_item})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Add cost item quantity
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_item_quantities(cost_item={cost_item})"
|
||||||
|
When I press "bim.add_cost_item_quantity(cost_item={cost_item}, ifc_class='IfcQuantityArea')"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Remove cost item quantity
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_item_quantities(cost_item={cost_item})"
|
||||||
|
And I press "bim.add_cost_item_quantity(cost_item={cost_item}, ifc_class='IfcQuantityArea')"
|
||||||
|
And the variable "quantity" is "{ifc}.by_type('IfcQuantityArea')[0].id()"
|
||||||
|
When I press "bim.remove_cost_item_quantity(cost_item={cost_item}, physical_quantity={quantity})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Enable editing cost item quantity
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_item_quantities(cost_item={cost_item})"
|
||||||
|
And I press "bim.add_cost_item_quantity(cost_item={cost_item}, ifc_class='IfcQuantityArea')"
|
||||||
|
And the variable "quantity" is "{ifc}.by_type('IfcQuantityArea')[0].id()"
|
||||||
|
When I press "bim.enable_editing_cost_item_quantity(physical_quantity={quantity})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Disable editing cost item quantity
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_item_quantities(cost_item={cost_item})"
|
||||||
|
And I press "bim.add_cost_item_quantity(cost_item={cost_item}, ifc_class='IfcQuantityArea')"
|
||||||
|
And the variable "quantity" is "{ifc}.by_type('IfcQuantityArea')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_item_quantity(physical_quantity={quantity})"
|
||||||
|
When I press "bim.disable_editing_cost_item_quantity"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Edit cost item quantity
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_item_quantities(cost_item={cost_item})"
|
||||||
|
And I press "bim.add_cost_item_quantity(cost_item={cost_item}, ifc_class='IfcQuantityArea')"
|
||||||
|
And the variable "quantity" is "{ifc}.by_type('IfcQuantityArea')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_item_quantity(physical_quantity={quantity})"
|
||||||
|
And I set "scene.BIMCostProperties.quantity_attributes[2].float_value" to "3"
|
||||||
|
When I press "bim.edit_cost_item_quantity(physical_quantity={quantity})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Enable editing cost item quantity
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
When I press "bim.enable_editing_cost_item_values(cost_item={cost_item})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Add cost value - fixed
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_item_values(cost_item={cost_item})"
|
||||||
|
And I set "scene.BIMCostProperties.cost_types" to "FIXED"
|
||||||
|
When I press "bim.add_cost_value(parent={cost_item}, cost_type='FIXED')"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Enable editing cost item value
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_item_values(cost_item={cost_item})"
|
||||||
|
And I set "scene.BIMCostProperties.cost_types" to "FIXED"
|
||||||
|
And I press "bim.add_cost_value(parent={cost_item}, cost_type='FIXED')"
|
||||||
|
And the variable "cost_value" is "{ifc}.by_type('IfcCostValue')[0].id()"
|
||||||
|
When I press "bim.enable_editing_cost_item_value(cost_value={cost_value})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Disable editing cost item value
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_item_values(cost_item={cost_item})"
|
||||||
|
And I set "scene.BIMCostProperties.cost_types" to "FIXED"
|
||||||
|
And I press "bim.add_cost_value(parent={cost_item}, cost_type='FIXED')"
|
||||||
|
And the variable "cost_value" is "{ifc}.by_type('IfcCostValue')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_item_value(cost_value={cost_value})"
|
||||||
|
When I press "bim.disable_editing_cost_item_value"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Edit cost item value
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_item_values(cost_item={cost_item})"
|
||||||
|
And I set "scene.BIMCostProperties.cost_types" to "FIXED"
|
||||||
|
And I press "bim.add_cost_value(parent={cost_item}, cost_type='FIXED')"
|
||||||
|
And the variable "cost_value" is "{ifc}.by_type('IfcCostValue')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_item_value(cost_value={cost_value})"
|
||||||
|
When I press "bim.edit_cost_value(cost_value={cost_value})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Enable editing cost item value formula
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_item_values(cost_item={cost_item})"
|
||||||
|
And I set "scene.BIMCostProperties.cost_types" to "FIXED"
|
||||||
|
And I press "bim.add_cost_value(parent={cost_item}, cost_type='FIXED')"
|
||||||
|
And the variable "cost_value" is "{ifc}.by_type('IfcCostValue')[0].id()"
|
||||||
|
When I press "bim.enable_editing_cost_item_value_formula(cost_value={cost_value})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Edit cost item value formula
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_item_values(cost_item={cost_item})"
|
||||||
|
And I set "scene.BIMCostProperties.cost_types" to "FIXED"
|
||||||
|
And I press "bim.add_cost_value(parent={cost_item}, cost_type='FIXED')"
|
||||||
|
And the variable "cost_value" is "{ifc}.by_type('IfcCostValue')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_item_value_formula(cost_value={cost_value})"
|
||||||
|
And I set "scene.BIMCostProperties.cost_value_formula" to "3 + 2"
|
||||||
|
When I press "bim.edit_cost_value_formula(cost_value={cost_value})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Add cost column
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And I set "scene.BIMCostProperties.should_show_column_ui" to "True"
|
||||||
|
And I set "scene.BIMCostProperties.cost_column" to "Foobar"
|
||||||
|
When I press "bim.add_cost_column(name='Foobar')"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Remove cost column
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And I set "scene.BIMCostProperties.should_show_column_ui" to "True"
|
||||||
|
And I set "scene.BIMCostProperties.cost_column" to "Foobar"
|
||||||
|
And I press "bim.add_cost_column(name='Foobar')"
|
||||||
|
When I press "bim.remove_cost_column(name='Foobar')"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Assign cost item quantity - count based
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
And I add a cube
|
||||||
|
And the object "Cube" is selected
|
||||||
|
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
|
||||||
|
And I press "bim.assign_class"
|
||||||
|
When I press "bim.assign_cost_item_quantity(cost_item={cost_item}, related_object_type='PRODUCT', prop_name='')"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Assign cost item quantity - quantity based
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
And I add a cube
|
||||||
|
And the object "Cube" is selected
|
||||||
|
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
|
||||||
|
And I press "bim.assign_class"
|
||||||
|
And the object "IfcWall/Cube" is selected
|
||||||
|
And I press "bim.add_qto(obj='IfcWall/Cube', obj_type='Object')"
|
||||||
|
And I press "bim.calculate_all_quantities"
|
||||||
|
When I press "bim.assign_cost_item_quantity(cost_item={cost_item}, related_object_type='PRODUCT', prop_name='NetVolume')"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Unassign cost item quantity - selection based
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
And I add a cube
|
||||||
|
And the object "Cube" is selected
|
||||||
|
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
|
||||||
|
And I press "bim.assign_class"
|
||||||
|
And the object "IfcWall/Cube" is selected
|
||||||
|
And I press "bim.assign_cost_item_quantity(cost_item={cost_item}, related_object_type='PRODUCT', prop_name='')"
|
||||||
|
When I press "bim.unassign_cost_item_quantity(cost_item={cost_item}, related_object=0)"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Unassign cost item quantity - explicit object
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
And I add a cube
|
||||||
|
And the object "Cube" is selected
|
||||||
|
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
|
||||||
|
And I press "bim.assign_class"
|
||||||
|
And the object "IfcWall/Cube" is selected
|
||||||
|
And I press "bim.assign_cost_item_quantity(cost_item={cost_item}, related_object_type='PRODUCT', prop_name='')"
|
||||||
|
And the variable "wall" is "{ifc}.by_type('IfcWall')[0].id()"
|
||||||
|
When I press "bim.unassign_cost_item_quantity(cost_item={cost_item}, related_object={wall})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Select cost item products
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_cost_schedule"
|
||||||
|
And the variable "cost_schedule" is "{ifc}.by_type('IfcCostSchedule')[0].id()"
|
||||||
|
And I press "bim.enable_editing_cost_items(cost_schedule={cost_schedule})"
|
||||||
|
And I press "bim.add_summary_cost_item(cost_schedule={cost_schedule})"
|
||||||
|
And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()"
|
||||||
|
And I add a cube
|
||||||
|
And the object "Cube" is selected
|
||||||
|
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
|
||||||
|
And I press "bim.assign_class"
|
||||||
|
And the object "IfcWall/Cube" is selected
|
||||||
|
And I press "bim.assign_cost_item_quantity(cost_item={cost_item}, related_object_type='PRODUCT', prop_name='')"
|
||||||
|
When I press "bim.select_cost_item_products(cost_item={cost_item})"
|
||||||
Then nothing happens
|
Then nothing happens
|
||||||
|
|||||||
@@ -23,6 +23,82 @@ arithmetic_operator_symbols = {"ADD": "+", "DIVIDE": "/", "MULTIPLY": "*", "SUBT
|
|||||||
symbol_arithmetic_operators = {"+": "ADD", "/": "DIVIDE", "*": "MULTIPLY", "-": "SUBTRACT"}
|
symbol_arithmetic_operators = {"+": "ADD", "/": "DIVIDE", "*": "MULTIPLY", "-": "SUBTRACT"}
|
||||||
|
|
||||||
|
|
||||||
|
def get_primitive_applied_value(applied_value):
|
||||||
|
if not applied_value:
|
||||||
|
return 0.0
|
||||||
|
elif isinstance(applied_value, float):
|
||||||
|
return applied_value
|
||||||
|
elif hasattr(applied_value, "wrappedValue") and isinstance(applied_value.wrappedValue, float):
|
||||||
|
return applied_value.wrappedValue
|
||||||
|
elif applied_value.is_a("IfcMeasureWithUnit"):
|
||||||
|
return applied_value.ValueComponent
|
||||||
|
assert False, "Applied value {applied_value} not implemented"
|
||||||
|
|
||||||
|
|
||||||
|
def get_total_quantity(root_element):
|
||||||
|
if root_element.is_a("IfcCostItem"):
|
||||||
|
return sum([q[3] for q in root_element.CostQuantities or []]) or 1.0
|
||||||
|
elif root_element.is_a("IfcConstructionResource"):
|
||||||
|
return root_element.BaseQuantity[3] if root_element.BaseQuantity else 1.0
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_applied_value(root_element, cost_value, category_filter=None):
|
||||||
|
if cost_value.ArithmeticOperator and cost_value.Components:
|
||||||
|
component_values = []
|
||||||
|
for component in cost_value.Components:
|
||||||
|
component_values.append(calculate_applied_value(root_element, component, category_filter))
|
||||||
|
if cost_value.ArithmeticOperator == "ADD":
|
||||||
|
return sum(component_values)
|
||||||
|
result = component_values.pop(0)
|
||||||
|
if cost_value.ArithmeticOperator == "DIVIDE":
|
||||||
|
for value in component_values:
|
||||||
|
try:
|
||||||
|
result /= value
|
||||||
|
except ZeroDivisionError:
|
||||||
|
pass
|
||||||
|
elif cost_value.ArithmeticOperator == "MULTIPLY":
|
||||||
|
for value in component_values:
|
||||||
|
result *= value
|
||||||
|
elif cost_value.ArithmeticOperator == "SUBTRACT":
|
||||||
|
for value in component_values:
|
||||||
|
result -= value
|
||||||
|
return result
|
||||||
|
if cost_value.Category is None:
|
||||||
|
return get_primitive_applied_value(cost_value.AppliedValue)
|
||||||
|
elif cost_value.Category == "*":
|
||||||
|
if root_element.IsNestedBy:
|
||||||
|
return sum_child_root_elements(root_element)
|
||||||
|
else:
|
||||||
|
return get_primitive_applied_value(cost_value.AppliedValue)
|
||||||
|
elif cost_value.Category:
|
||||||
|
if root_element.IsNestedBy:
|
||||||
|
return sum_child_root_elements(root_element, category_filter=cost_value.Category)
|
||||||
|
else:
|
||||||
|
return get_primitive_applied_value(cost_value.AppliedValue)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def sum_child_root_elements(root_element, category_filter=None):
|
||||||
|
result = 0
|
||||||
|
for rel in root_element.IsNestedBy:
|
||||||
|
for child_root_element in rel.RelatedObjects:
|
||||||
|
if root_element.is_a("IfcCostItem"):
|
||||||
|
values = child_root_element.CostValues
|
||||||
|
elif root_element.is_a("IfcConstructionResource"):
|
||||||
|
values = child_root_element.BaseCosts
|
||||||
|
for child_cost_value in values or []:
|
||||||
|
if category_filter and child_cost_value.Category != category_filter:
|
||||||
|
continue
|
||||||
|
child_applied_value = calculate_applied_value(child_root_element, child_cost_value)
|
||||||
|
child_quantity = get_total_quantity(child_root_element)
|
||||||
|
if child_cost_value.UnitBasis:
|
||||||
|
value_component = child_cost_value.UnitBasis.ValueComponent.wrappedValue
|
||||||
|
result += child_quantity / value_component * child_applied_value
|
||||||
|
else:
|
||||||
|
result += child_quantity * child_applied_value
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def serialise_cost_value(cost_value):
|
def serialise_cost_value(cost_value):
|
||||||
result = _serialise_cost_value(cost_value)
|
result = _serialise_cost_value(cost_value)
|
||||||
if result and result[0] == "(" and result[-1] == ")":
|
if result and result[0] == "(" and result[-1] == ")":
|
||||||
|
|||||||
Reference in New Issue
Block a user