mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-12 13:29:04 +00:00
Slice 7 of the Solar PV Recommendation Generator (ADR-0026). Adds the composite per-dwelling Solar PV cost on the Products collection (ADR-0025 pattern): pv_system(kWp band, nearest of the ECOPV06-13 EA bands 1.0→4.5 kWp, floor/cap at the ends) + scaffolding(£900 first elevation + £450 each additional, default 2) + enabling base (EICR £150 + DNO £50 + 2-way consumer unit £330) + [diverter £980 if cylinder] + [battery if the with-battery variant] → Cost(total, contingency_rate 0.15). Rates are data in the committed solar_rates.json (Southern Housing "SOLAR PV & BATTERY" EA column), loaded via SolarRates.from_json/.default and injectable. The £2,000 / 5 kWh battery is NOT on the rate sheet — a flagged estimate (battery_estimate=true), confirmed with the user to stand in until a DB rate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
35 lines
1.2 KiB
Python
35 lines
1.2 KiB
Python
"""Per-Measure-Type contingency rates.
|
|
|
|
The one cost component carried separately from a Product's fully-loaded total
|
|
(CONTEXT.md). Mirrors the legacy `recommendations/Costs.py::Costs.CONTINGENCIES`;
|
|
extended as each measure type lands.
|
|
"""
|
|
|
|
_CONTINGENCY_RATES: dict[str, float] = {
|
|
"cavity_wall_insulation": 0.10,
|
|
"loft_insulation": 0.10,
|
|
"sloping_ceiling_insulation": 0.10,
|
|
"flat_roof_insulation": 0.10,
|
|
"suspended_floor_insulation": 0.20,
|
|
"solid_floor_insulation": 0.26,
|
|
"mechanical_ventilation": 0.26,
|
|
"external_wall_insulation": 0.26,
|
|
"internal_wall_insulation": 0.26,
|
|
"double_glazing": 0.15,
|
|
"secondary_glazing": 0.15,
|
|
"low_energy_lighting": 0.26,
|
|
"high_heat_retention_storage_heaters": 0.10,
|
|
"air_source_heat_pump": 0.25,
|
|
"solar_pv": 0.15,
|
|
}
|
|
|
|
|
|
def contingency_rate(measure_type: str) -> float:
|
|
"""Return the contingency rate for a Measure Type, raising if unknown
|
|
(strict — do not silently default, per the repo's strict-raise convention)."""
|
|
try:
|
|
return _CONTINGENCY_RATES[measure_type]
|
|
except KeyError as exc:
|
|
raise ValueError(
|
|
f"no contingency rate configured for measure type {measure_type!r}"
|
|
) from exc
|