From 714105b9fdde841dc62aa1a888ea3895b7854456 Mon Sep 17 00:00:00 2001 From: Massimo Fabbro Date: Fri, 23 Jan 2026 11:01:50 +0100 Subject: [PATCH] See #6570. Tests for import cost schedule from csv and minor fix --- src/bonsai/test/bim/feature/cost.feature | 28 +++++++++++++++++++ .../test/files/Ex1-BoQ-without-query.csv | 10 +++++++ src/bonsai/test/files/Ex2-SoR.csv | 7 +++++ src/bonsai/test/files/Ex3-BoQ-with-query.csv | 10 +++++++ .../test/files/Ex4-BoQ-with-description.csv | 10 +++++++ .../test/files/Ex5-SoR-with-description.csv | 7 +++++ .../test/files/Ex6-BoQ-with-categories.csv | 10 +++++++ src/bonsai/test/files/Ex7-BoQ-with-Rates.csv | 10 +++++++ .../test/files/Ex8-BoQ-with-formula.csv | 14 ++++++++++ src/ifc5d/ifc5d/csv2ifc.py | 1 - 10 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 src/bonsai/test/files/Ex1-BoQ-without-query.csv create mode 100644 src/bonsai/test/files/Ex2-SoR.csv create mode 100644 src/bonsai/test/files/Ex3-BoQ-with-query.csv create mode 100644 src/bonsai/test/files/Ex4-BoQ-with-description.csv create mode 100644 src/bonsai/test/files/Ex5-SoR-with-description.csv create mode 100644 src/bonsai/test/files/Ex6-BoQ-with-categories.csv create mode 100644 src/bonsai/test/files/Ex7-BoQ-with-Rates.csv create mode 100644 src/bonsai/test/files/Ex8-BoQ-with-formula.csv diff --git a/src/bonsai/test/bim/feature/cost.feature b/src/bonsai/test/bim/feature/cost.feature index 3b4cb3507a..6c2a38c911 100644 --- a/src/bonsai/test/bim/feature/cost.feature +++ b/src/bonsai/test/bim/feature/cost.feature @@ -455,6 +455,7 @@ Scenario: Select Cost Schedule Products And I press "bim.assign_cost_item_quantity(cost_item={cost_item}, related_object_type='PRODUCT', prop_name='')" When I press "bim.select_cost_schedule_products(cost_schedule={cost_schedule})" Then nothing happens + Scenario: Load Cost Item Types Given an empty IFC project And I press "bim.add_cost_schedule" @@ -465,3 +466,30 @@ Scenario: Load Cost Item Types When I press "bim.add_cost_item(cost_item={cost_item})" And I press "bim.load_cost_item_types" Then nothing happens + +Scenario: Import one cost schedule from CSV + Given an empty IFC project + When I press "bim.import_cost_schedule_csv(filepath='{cwd}/test/files/Ex1-BoQ-without-query.csv')" + 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()" + And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()" + And I press "bim.add_cost_item(cost_item={cost_item})" + Then nothing happens + +Scenario: Import multiple cost schedules from CSV + Given an empty IFC project + When I press "bim.import_cost_schedule_csv(filepath='{cwd}/test/files/Ex1-BoQ-without-query.csv')" + When I press "bim.import_cost_schedule_csv(filepath='{cwd}/test/files/Ex2-SoR.csv')" + When I press "bim.import_cost_schedule_csv(filepath='{cwd}/test/files/Ex3-BoQ-with-query.csv')" + When I press "bim.import_cost_schedule_csv(filepath='{cwd}/test/files/Ex4-BoQ-with-description.csv')" + When I press "bim.import_cost_schedule_csv(filepath='{cwd}/test/files/Ex5-SoR-with-description.csv')" + When I press "bim.import_cost_schedule_csv(filepath='{cwd}/test/files/Ex6-BoQ-with-categories.csv')" + When I press "bim.import_cost_schedule_csv(filepath='{cwd}/test/files/Ex7-BoQ-with-Rates.csv')" + When I press "bim.import_cost_schedule_csv(filepath='{cwd}/test/files/Ex8-BoQ-with-formula.csv')" + 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()" + And the variable "cost_item" is "{ifc}.by_type('IfcCostItem')[0].id()" + And I press "bim.add_cost_item(cost_item={cost_item})" + Then nothing happens diff --git a/src/bonsai/test/files/Ex1-BoQ-without-query.csv b/src/bonsai/test/files/Ex1-BoQ-without-query.csv new file mode 100644 index 0000000000..85dc89019e --- /dev/null +++ b/src/bonsai/test/files/Ex1-BoQ-without-query.csv @@ -0,0 +1,10 @@ +Index,Identification,Name,Unit,Value,Quantity +1,E.01,Walls,m3,, +2,E.01.01,Ground floor walls,m3,100,42 +2,E.01.02,First floor walls,m3,200,35 +1,A.02,Paintings,m2,, +2,A.03,Paintings with water,m2,, +3,B.05,White paintings,m2,25,45 +3,B.06,Colored paintings,m2,32,33 +2,C-01,Paintings with machine,m2,17,133 +2,C-02,Decorated paintings,m2,40,8 diff --git a/src/bonsai/test/files/Ex2-SoR.csv b/src/bonsai/test/files/Ex2-SoR.csv new file mode 100644 index 0000000000..07615e4f7d --- /dev/null +++ b/src/bonsai/test/files/Ex2-SoR.csv @@ -0,0 +1,7 @@ +Index,Identification,Name,Unit,Value,Quantity +1,A,Group A,,, +2,A.02,Paintings,m2,20,1 +2,A.03,Paintings with water,m2,23,1 +1,C,Group C,,, +2,C-01,Paintings with machine,m2,32,1 +2,C-02,Decorated paintings,m2,40,2 diff --git a/src/bonsai/test/files/Ex3-BoQ-with-query.csv b/src/bonsai/test/files/Ex3-BoQ-with-query.csv new file mode 100644 index 0000000000..d96d1adcd8 --- /dev/null +++ b/src/bonsai/test/files/Ex3-BoQ-with-query.csv @@ -0,0 +1,10 @@ +Index,Identification,Name,Unit,Value,Quantity,Query,Property +1,E.01,Walls,m3,,,, +2,E.01.01,Ground floor walls,m3,100,,"IfcWall, location=""Ground Floor""",GrossVolume +2,E.01.02,First floor walls,m3,200,,"IfcWall, location=""First Floor""",GrossVolume +1,A.02,Paintings,m2,,,, +2,A.03,Paintings with water,m2,,,, +3,B.05,White paintings,m2,25,45,, +3,B.06,Colored paintings,m2,32,33,, +2,C-01,Paintings with machine,m2,17,133,, +2,C-02,Decorated paintings,m2,40,8,, diff --git a/src/bonsai/test/files/Ex4-BoQ-with-description.csv b/src/bonsai/test/files/Ex4-BoQ-with-description.csv new file mode 100644 index 0000000000..ce3d5350cc --- /dev/null +++ b/src/bonsai/test/files/Ex4-BoQ-with-description.csv @@ -0,0 +1,10 @@ +Index,Identification,Name,Unit,Value,Quantity,Description +1,E.01,Walls,m3,,, +2,E.01.01,Ground floor walls,m3,100,42,"Semi-solid blocks of plain-faced common brick, with an apparent density (excluding holes) of 800 kg/m³; minor drilling 45%; apparent thermal conductivity 0.21 W/mK; characteristic mechanical strength parallel to the holes greater than or equal to 10 N/mm2, perpendicular to the holes greater than or equal to 2N/mm2" +2,E.01.02,First floor walls,m3,200,35,"Semi-solid blocks of plain-faced common brick, with an apparent density (excluding holes) of 800 kg/m³; minor drilling 45%; apparent thermal conductivity 0.21 W/mK; characteristic mechanical strength parallel to the holes greater than or equal to 10 N/mm2, perpendicular to the holes greater than or equal to 2N/mm2" +1,A.02,Painting,m2,,,"Painting with washable water-based wall paint for indoor/outdoor. The price includes and compensates the costs for the supply of paint, any scaffolding up to a maximum height of 4 m from the support surface, the costs for the protection of furniture, fixed systems or the protection of floors, the cleaning of the surfaces to be treated through the use of rags or net purposes in order to remove residues that can be easily removed. The cost of occasional and partial grouting of surfaces, in order to eliminate any small scratches, including sanding of the grouted parts, is also to be considered included and compensated. For 2 coats with brush or roller." +2,A.03,Washable painting,m2,,,"Supply and installation of washable tempera paint for interiors and exteriors. The price includes and compensates for the costs of supplying the paint, any scaffolding up to a maximum height of 4 meters from the support surface, the costs of protecting furnishings, fixed installations, or floors, and cleaning the surfaces to be treated using rags or clean brushes to remove easily removable residues. On previously prepared plaster. Apply two coats with a brush or roller. (Tempera colors from the color chart)." +3,B.05,White paintings,m2,25,45, +3,B.06,Colored paintings,m2,32,33, +2,C-01,External painting,m2,17,133,"Painting with plastic coating. The price includes and compensates for the costs of supplying the paint, any scaffolding up to a maximum height of 4 meters from the support surface, the costs of protecting furnishings, fixed systems, or floors, and cleaning the surfaces to be treated using rags or clean brushes to remove easily removable residues. On already prepared plaster. For 2 coats (interior textured finish)." +2,C-02,Decorated paintings,m2,40,8, diff --git a/src/bonsai/test/files/Ex5-SoR-with-description.csv b/src/bonsai/test/files/Ex5-SoR-with-description.csv new file mode 100644 index 0000000000..0517abcbde --- /dev/null +++ b/src/bonsai/test/files/Ex5-SoR-with-description.csv @@ -0,0 +1,7 @@ +Index,Identification,Name,Unit,Value,Quantity,Description +1,A,Group A,,,, +2,A.02,Paintings,m2,20,1,Paint made by the best painter in the world +2,A.03,Paintings with water,m2,23,1, +1,C,Group C,,,, +2,C-01,Paintings with machine,m2,32,1,Best painting in the world painted with the best painted machine accordingly with ISO9001 +2,C-02,Decorated paintings,m2,40,2, diff --git a/src/bonsai/test/files/Ex6-BoQ-with-categories.csv b/src/bonsai/test/files/Ex6-BoQ-with-categories.csv new file mode 100644 index 0000000000..b87f708333 --- /dev/null +++ b/src/bonsai/test/files/Ex6-BoQ-with-categories.csv @@ -0,0 +1,10 @@ +Index,Identification,Name,Unit,Material,Labor,Quantity +1,E.01,Walls,m3,,, +2,E.01.01,Ground floor walls,m3,55,45,42 +2,E.01.02,First floor walls,m3,120,80,35 +1,A.02,Painting,m2,,, +2,A.03,Washable painting,m2,,, +3,B.05,White paintings,m2,,,45 +3,B.06,Colored paintings,m2,,,33 +2,C-01,External painting,m2,,,133 +2,C-02,Decorated paintings,m2,,,8 diff --git a/src/bonsai/test/files/Ex7-BoQ-with-Rates.csv b/src/bonsai/test/files/Ex7-BoQ-with-Rates.csv new file mode 100644 index 0000000000..dc5a0da63d --- /dev/null +++ b/src/bonsai/test/files/Ex7-BoQ-with-Rates.csv @@ -0,0 +1,10 @@ +Index,Identification,Name,Unit,Value,Quantity,RateSchedule,RateID +1,E.01,Walls,m3,,,, +2,E.01.01,Ground floor walls,m3,100,42,, +2,E.01.02,First floor walls,m3,200,35,, +1,A.02,Paintings,m2,,,, +2,A.03,Paintings with water,m2,,,, +3,B.05,White paintings,m2,,45,Ex2-SoR,A.03 +3,B.06,Colored paintings,m2,32,33,, +2,C-01,Paintings with machine,m2,17,133,, +2,C-02,Decorated paintings,m2,40,8,, diff --git a/src/bonsai/test/files/Ex8-BoQ-with-formula.csv b/src/bonsai/test/files/Ex8-BoQ-with-formula.csv new file mode 100644 index 0000000000..a3e8d77b60 --- /dev/null +++ b/src/bonsai/test/files/Ex8-BoQ-with-formula.csv @@ -0,0 +1,14 @@ +Index,Identification,Name,Unit,Value,Quantity,Query,Property,Formula +1,E.01,Walls,m3,,,,, +2,E.01.01,Ground floor walls,m3,100,,"IfcWall, location=""Ground Floor""",GrossVolume, +2,E.01.02,First floor walls,m3,200,,"IfcWall, location=""First Floor""",GrossVolume, +1,A.02,Paintings,m2,,,,, +2,A.03,Paintings with water,m2,,,,, +3,B.05,White paintings,m2,25,,IfcWall,GrossVolume, +3,B.06,Colored paintings,m2,32,33,,, +3,B.07,Double paintings,m,,,IfcWall,,NetSideArea*2 +2,C-01,Paintings with machine,m2,17,133,,, +2,C-02,Decorated paintings,m2,40,8,,, +1,D,Reinforcements,,,,,, +2,D.1,Walls reinforcements weight,kg,,,IfcWall,,Pset_ConcreteElementGeneral.ReinforcementVolumeRatio * GrossVolume +2,D.2,Beams reinforcements weight,kg,,,,, diff --git a/src/ifc5d/ifc5d/csv2ifc.py b/src/ifc5d/ifc5d/csv2ifc.py index d43eb907e9..3a876f1098 100644 --- a/src/ifc5d/ifc5d/csv2ifc.py +++ b/src/ifc5d/ifc5d/csv2ifc.py @@ -169,7 +169,6 @@ class Csv2Ifc: if not self.headers: self.has_categories = True self.has_rates = False - self.has_categories = False self.has_formula = False self.headers = {col: i for i, col in enumerate(row) if col} if "RateSchedule" in self.headers and "RateID" in self.headers: