Carry donor's display heating + control into predicted EPC 🟥

_apply_heating_donor copies the donor's calc sap_heating but leaves the
display rows (main_heating, main_heating_controls) on the structural template
— incoherent, and 'Heating Control: Unknown' when the template lodged no
control (predicted property 721167, ADR-0029 follow-up).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-06-26 10:37:36 +00:00
parent 56b365f488
commit 5cf5b67420

View file

@ -10,6 +10,7 @@ from typing import Optional, Union
from datatypes.epc.domain.epc_property_data import (
BuildingPartIdentifier,
EnergyElement,
EpcPropertyData,
MainHeatingDetail,
SapBuildingPart,
@ -51,6 +52,8 @@ def _epc(
has_hot_water_cylinder: bool = True,
solar_water_heating: bool = False,
meter_type: str = "2",
main_heating_label: str = "Boiler and radiators, mains gas",
main_heating_controls_label: Optional[str] = None,
) -> EpcPropertyData:
epc: EpcPropertyData = object.__new__(EpcPropertyData)
epc.property_type = "2"
@ -87,6 +90,22 @@ def _epc(
heating.cylinder_insulation_type = 1
heating.secondary_heating_type = None
epc.sap_heating = heating
epc.main_heating = [
EnergyElement(
description=main_heating_label,
energy_efficiency_rating=4,
environmental_efficiency_rating=4,
)
]
epc.main_heating_controls = (
EnergyElement(
description=main_heating_controls_label,
energy_efficiency_rating=4,
environmental_efficiency_rating=4,
)
if main_heating_controls_label is not None
else None
)
epc.has_hot_water_cylinder = has_hot_water_cylinder
epc.solar_water_heating = solar_water_heating
energy: SapEnergySource = object.__new__(SapEnergySource)
@ -637,3 +656,32 @@ def test_heating_donor_carries_the_donors_off_peak_meter() -> None:
donor = _epc(meter_type="Dual", main_fuel_type=29) # the cohort's heating
EpcPrediction._apply_heating_donor(predicted, _cohort(donor))
assert predicted.sap_energy_source.meter_type == "Dual"
def test_heating_donor_carries_the_donors_display_heating_and_control() -> None:
# The displayed heating panel (Main Heating + Heating Control rows) describes
# the same system as the calc cluster, so it must travel with the donor — not
# be left on the size-representative structural template. Two failures
# otherwise: (1) the displayed heating is incoherent with the donated calc
# system, and (2) "Heating Control: Unknown" whenever the template lodged no
# control row (the donor's is dropped). Predicted property 721167 (ADR-0029
# follow-up): the template carried no main_heating_controls, so its passport
# showed Heating Control = Unknown despite a coherent gas-boiler donor.
predicted = _epc(
main_heating_label="Room heaters, electric",
main_heating_controls_label=None, # template lodged no control
)
donor = _epc(
main_fuel_type=29,
main_heating_label="Boiler and radiators, mains gas",
main_heating_controls_label="Programmer, room thermostat and TRVs",
)
EpcPrediction._apply_heating_donor(predicted, _cohort(donor))
assert predicted.main_heating[0].description == "Boiler and radiators, mains gas"
assert predicted.main_heating_controls is not None
assert (
predicted.main_heating_controls.description
== "Programmer, room thermostat and TRVs"
)