Fixing costs unit tests

This commit is contained in:
Khalim Conn-Kowlessar 2023-12-02 16:58:34 +00:00
parent 036f3c562e
commit 43a2196580
4 changed files with 77 additions and 64 deletions

2
.idea/Model.iml generated
View file

@ -7,7 +7,7 @@
<sourceFolder url="file://$MODULE_DIR$/open_uprn" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/recommendations" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="Python 3.10 (backend)" jdkType="Python SDK" />
<orderEntry type="jdk" jdkName="Python 3.10 (model_data)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyNamespacePackagesService">

2
.idea/misc.xml generated
View file

@ -3,7 +3,7 @@
<component name="Black">
<option name="sdkName" value="Python 3.10 (backend)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (backend)" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (model_data)" project-jdk-type="Python SDK" />
<component name="PythonCompatibilityInspectionAdvertiser">
<option name="version" value="3" />
</component>

View file

@ -40,6 +40,10 @@ class Costs:
# We assume a conservative 10% contingency for all works which is a rate defined by SPONs
CONTINGENCY = 0.1
# We use a higher contingency rate for internal wall insulation because of the potential for issues with moving
# fittings and trimming doors, as well as scope for damage to the existing wall during preparation.
IWI_CONTINGENCY = 0.15
# Where there is more uncertainty, a higher contingency rate is used
HIGH_RISK_CONTINGENCY = 0.2
# When there is less uncertainty, a lower contingency rate is used
@ -232,7 +236,7 @@ class Costs:
subtotal_before_profit = labour_costs + materials_costs + demolition_plant_costs
contingency_cost = subtotal_before_profit * self.CONTINGENCY
contingency_cost = subtotal_before_profit * self.IWI_CONTINGENCY
preliminaries_cost = subtotal_before_profit * self.PRELIMINARIES
profit_cost = subtotal_before_profit * self.PROFIT_MARGIN

View file

@ -19,7 +19,7 @@ class TestCosts:
"prime_cost": 5.17,
"material_cost": 5.62,
"labour_cost": 1.125,
"labour_hours": 0.065
"labour_hours_per_unit": 0.065,
}
cwi_results = costs.cavity_wall_insulation(
@ -27,10 +27,12 @@ class TestCosts:
material=cwi_material,
)
assert cwi_results == {'total': 1027.0280465530302, 'subtotal': 855.8567054608585, 'vat': 171.1713410921717,
'contingency': 63.396792997100626, 'preliminaries': 63.396792997100626,
'material': 539.0166061175574, 'profit': 95.09518949565093,
'labour_hours': 6.234177828761786, 'labour_cost': 94.95132385344874}
assert cwi_results == {
'total': 1065.0661223512907, 'subtotal': 887.5551019594088, 'vat': 177.51102039188177,
'contingency': 63.396792997100626, 'preliminaries': 63.396792997100626, 'material': 539.0166061175574,
'profit': 126.79358599420125, 'labour_hours': 6.234177828761786, 'labour_cost': 94.95132385344874,
'labour_days': 0.38963611429761164
}
def test_loft_insulation(self):
mock_property = Mock()
@ -46,7 +48,7 @@ class TestCosts:
"prime_cost": None,
"material_cost": 5.91938,
"labour_cost": 1.96,
"labour_hours": 0.11
"labour_hours_per_unit": 0.11
}
loft_results = costs.loft_insulation(
@ -54,10 +56,11 @@ class TestCosts:
material=loft_material,
)
assert loft_results == {'total': 414.8496486, 'subtotal': 345.70804050000004, 'vat': 69.14160810000001,
'contingency': 25.608003000000004, 'preliminaries': 25.608003000000004,
'material': 198.29923000000002, 'profit': 38.4120045, 'labour_hours': 3.685,
'labour_cost': 57.7808}
assert loft_results == {
'total': 430.21445040000003, 'subtotal': 358.512042, 'vat': 71.70240840000001,
'contingency': 25.608003000000004, 'preliminaries': 25.608003000000004, 'material': 198.29923000000002,
'profit': 51.21600600000001, 'labour_hours': 3.685, 'labour_cost': 57.7808, 'labour_days': 0.460625
}
def test_internal_wall_insulation(self):
mock_property = Mock()
@ -171,11 +174,14 @@ class TestCosts:
non_insulation_materials=iwi_non_insulation_materials
)
assert iwi_results == {'total': 6421.5484411659245, 'subtotal': 5351.29036763827, 'vat': 1070.258073527654,
'contingency': 573.3525393898148, 'preliminaries': 382.2350262598765,
'material': 1747.488000615996, 'profit': 573.3525393898148,
'labour_hours': 88.23759388401297, 'labour_days': 2.757424808875405,
'labour_cost': 1927.1602026551818}
assert iwi_results == {
'total': 6650.889456921851, 'subtotal': 5542.407880768209, 'vat': 1108.4815761536418,
'contingency': 573.3525393898148, 'preliminaries': 382.2350262598765,
'material': 1747.488000615996,
'profit': 764.470052519753, 'labour_hours': 88.23759388401297,
'labour_days': 2.757424808875405,
'labour_cost': 1927.1602026551818
}
def test_suspended_floor_insulation(self):
mock_property = Mock()
@ -185,16 +191,18 @@ class TestCosts:
costs = Costs(mock_property)
sus_floor_material = {'type': 'suspended_floor_insulation', 'description': 'Thermafleece CosyWool Roll',
'depth': 140.0,
'depth_unit': 'mm', 'cost_unit': 'gbp_per_m2', 'thermal_conductivity': 0.039,
'thermal_conductivity_unit': 'watt_per_meter_kelvin', 'prime_material_cost': 0,
'material_cost': 11.68, 'labour_cost': 1.78, 'labour_hours_per_unit': 0.1,
'plant_cost': 0,
'total_cost': 13.46, 'link': 'SPONs',
'Notes': 'Spons did not contain labour costs so we use values for similar insulations. '
'We use the '
'same values as in Crown loft roll 44, since it is also an insulation roll'}
sus_floor_material = {
'type': 'suspended_floor_insulation', 'description': 'Thermafleece CosyWool Roll',
'depth': 140.0,
'depth_unit': 'mm', 'cost_unit': 'gbp_per_m2', 'thermal_conductivity': 0.039,
'thermal_conductivity_unit': 'watt_per_meter_kelvin', 'prime_material_cost': 0,
'material_cost': 11.68, 'labour_cost': 1.78, 'labour_hours_per_unit': 0.1,
'plant_cost': 0,
'total_cost': 13.46, 'link': 'SPONs',
'Notes': 'Spons did not contain labour costs so we use values for similar insulations. '
'We use the '
'same values as in Crown loft roll 44, since it is also an insulation roll'
}
sus_floor_non_insulation_materials = [
{'type': 'suspended_floor_demolition', 'description': 'Removal of carpet and underfelt', 'depth': 0,
@ -231,9 +239,8 @@ class TestCosts:
)
assert sus_floor_results == {
'total': 3003.366924, 'subtotal': 2502.80577, 'vat': 500.561154,
'contingency': 185.39302, 'preliminaries': 185.39302, 'material': 483.405,
'profit': 278.08952999999997, 'labour_hours': 54.940000000000005,
'total': 3114.6027360000003, 'subtotal': 2595.50228, 'vat': 519.100456, 'contingency': 185.39302,
'preliminaries': 185.39302, 'material': 483.405, 'profit': 370.78604, 'labour_hours': 54.940000000000005,
'labour_days': 2.289166666666667, 'labour_cost': 1370.5252
}
@ -263,28 +270,29 @@ class TestCosts:
'description': 'clean surface of concrete to receive new damp-proof membrane', 'depth': 0,
'depth_unit': 0, 'cost_unit': 0, 'thermal_conductivity': 0, 'thermal_conductivity_unit': 0,
'prime_material_cost': 0, 'material_cost': 0, 'labour_cost': 4.36, 'labour_hours_per_unit': 0.14,
'plant_cost': 0, 'total_cost': 4.36, 'link': 0, 'Notes': 0}, {'type': 'solid_floor_preparation',
'description': 'Clean out crack to '
'form a 20mm×20mm '
'groove and fill with '
'cement: mortar mixed '
'with bonding agent',
'depth': 0, 'depth_unit': 0,
'cost_unit': 0,
'thermal_conductivity': 0,
'thermal_conductivity_unit': 0,
'prime_material_cost': 0,
'material_cost': 6.91,
'labour_cost': 18.99,
'labour_hours_per_unit': 0.61,
'plant_cost': 0.16,
'total_cost': 26.06, 'link': 0,
'Notes': 'This step is the '
'assessment and repair of '
'any damage to the concrete '
'floor such as filling '
'cracks or levelling uneven '
'areas'},
'plant_cost': 0, 'total_cost': 4.36, 'link': 0, 'Notes': 0}, {
'type': 'solid_floor_preparation',
'description': 'Clean out crack to '
'form a 20mm×20mm '
'groove and fill with '
'cement: mortar mixed '
'with bonding agent',
'depth': 0, 'depth_unit': 0,
'cost_unit': 0,
'thermal_conductivity': 0,
'thermal_conductivity_unit': 0,
'prime_material_cost': 0,
'material_cost': 6.91,
'labour_cost': 18.99,
'labour_hours_per_unit': 0.61,
'plant_cost': 0.16,
'total_cost': 26.06, 'link': 0,
'Notes': 'This step is the '
'assessment and repair of '
'any damage to the concrete '
'floor such as filling '
'cracks or levelling uneven '
'areas'},
{'type': 'solid_floor_vapour_barrier', 'description': 'Visqueen High Performance Vapour Barrier',
'depth': 0, 'depth_unit': 0, 'cost_unit': 0, 'thermal_conductivity': 0,
'thermal_conductivity_unit': 0, 'prime_material_cost': 0.58, 'material_cost': 1.21, 'labour_cost': 0.48,
@ -316,8 +324,8 @@ class TestCosts:
)
assert sol_floor_results == {
'total': 3962.021952, 'subtotal': 3301.68496, 'vat': 660.336992, 'contingency': 353.75196,
'preliminaries': 235.83464, 'material': 1006.3399999999999, 'profit': 353.75196, 'labour_hours': 57.285,
'total': 4245.023520000001, 'subtotal': 3537.5196, 'vat': 707.5039200000001, 'contingency': 471.66928,
'preliminaries': 235.83464, 'material': 1006.3399999999999, 'profit': 471.66928, 'labour_hours': 57.285,
'labour_days': 2.386875, 'labour_cost': 1346.6464
}
@ -331,11 +339,13 @@ class TestCosts:
costs = Costs(mock_property)
ewi_material = {'type': 'external_wall_insulation', 'description': 'Ecotherm Eco-Versal PIR Insulation Board',
'depth': 150.0, 'depth_unit': 'mm', 'cost_unit': 'gbp_per_m2', 'thermal_conductivity': 0.022,
'thermal_conductivity_unit': 'watt_per_meter_kelvin', 'prime_material_cost': 23.53,
'material_cost': 34.62, 'labour_cost': 33.06, 'labour_hours_per_unit': 1.4, 'plant_cost': 0,
'total_cost': 67.68, 'link': 'SPONs', 'Notes': 0}
ewi_material = {
'type': 'external_wall_insulation', 'description': 'Ecotherm Eco-Versal PIR Insulation Board',
'depth': 150.0, 'depth_unit': 'mm', 'cost_unit': 'gbp_per_m2', 'thermal_conductivity': 0.022,
'thermal_conductivity_unit': 'watt_per_meter_kelvin', 'prime_material_cost': 23.53,
'material_cost': 34.62, 'labour_cost': 33.06, 'labour_hours_per_unit': 1.4, 'plant_cost': 0,
'total_cost': 67.68, 'link': 'SPONs', 'Notes': 0
}
ewi_non_insulation_materials = [
{'type': 'ewi_wall_demolition',
'description': 'Solid & Dry Lined walls: Hack of wall finishes with chipping '
@ -403,9 +413,8 @@ class TestCosts:
)
assert ewi_results == {
'total': 13590.909723215433, 'subtotal': 11325.758102679527, 'vat': 2265.1516205359053,
'contingency': 808.9827216199662, 'preliminaries': 1213.4740824299492,
'material': 4020.565147410677, 'profit': 1213.4740824299492,
'labour_hours': 187.02533486285358, 'labour_days': 5.8445417144641745,
'total': 14561.688989159393, 'subtotal': 12134.740824299493, 'vat': 2426.948164859899,
'contingency': 808.9827216199662, 'preliminaries': 1617.9654432399325, 'material': 4020.565147410677,
'profit': 1617.9654432399325, 'labour_hours': 187.02533486285358, 'labour_days': 5.8445417144641745,
'labour_cost': 3921.5600094613983
}