mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-12 13:29:04 +00:00
Merge pull request #1381 from Hestia-Homes/fix/rdsap-17-0-sap-heating-drops
Fix RdSAP-17.0 mapper dropping the rest of the lodged sap_heating block
This commit is contained in:
commit
f1299cc554
2 changed files with 96 additions and 6 deletions
|
|
@ -620,8 +620,13 @@ class EpcPropertyDataMapper:
|
|||
MainHeatingDetail(
|
||||
has_fghrs=d.has_fghrs == "Y",
|
||||
main_fuel_type=d.main_fuel_type,
|
||||
boiler_flue_type=None,
|
||||
fan_flue_present=None,
|
||||
# Preserve the lodged flue/pump/PCDB fields, matching the
|
||||
# 19.0/20.0/… paths. The 17.0 schema *does* lodge all of
|
||||
# these (RdSapSchema17_0.MainHeatingDetail); hardcoding
|
||||
# them to None silently dropped a PCDB main-heating index
|
||||
# (efficiency lookup) and the flue/pump SAP adjustments.
|
||||
boiler_flue_type=d.boiler_flue_type,
|
||||
fan_flue_present=d.fan_flue_present == "Y",
|
||||
heat_emitter_type=d.heat_emitter_type,
|
||||
emitter_temperature=d.emitter_temperature,
|
||||
main_heating_number=d.main_heating_number,
|
||||
|
|
@ -629,9 +634,9 @@ class EpcPropertyDataMapper:
|
|||
main_heating_category=d.main_heating_category,
|
||||
main_heating_fraction=d.main_heating_fraction,
|
||||
sap_main_heating_code=d.sap_main_heating_code,
|
||||
central_heating_pump_age=None,
|
||||
central_heating_pump_age=d.central_heating_pump_age,
|
||||
main_heating_data_source=d.main_heating_data_source,
|
||||
main_heating_index_number=None,
|
||||
main_heating_index_number=d.main_heating_index_number,
|
||||
)
|
||||
for d in schema.sap_heating.main_heating_details
|
||||
],
|
||||
|
|
@ -642,7 +647,15 @@ class EpcPropertyDataMapper:
|
|||
water_heating_fuel=schema.sap_heating.water_heating_fuel,
|
||||
immersion_heating_type=schema.sap_heating.immersion_heating_type,
|
||||
cylinder_insulation_type=schema.sap_heating.cylinder_insulation_type,
|
||||
cylinder_thermostat=None,
|
||||
# Preserve the lodged cylinder thermostat + insulation thickness,
|
||||
# matching the 19.0/20.0/… paths. Both are lodged by the 17.0
|
||||
# schema; hardcoding them to None (a) read as "no cylinder
|
||||
# thermostat" so the water-heating worksheet over-applied its
|
||||
# ×1.3 penalty and `recommend_cylinder_thermostat` could fire on
|
||||
# a dwelling that already has one, and (b) discarded the measured
|
||||
# insulation thickness so the cylinder-loss cascade fell back to
|
||||
# age-band defaults.
|
||||
cylinder_thermostat=schema.sap_heating.cylinder_thermostat,
|
||||
# Preserve the lodged secondary heating from the 17.0 sap_heating
|
||||
# block, matching every other API path (19.0/20.0/…). Hardcoding
|
||||
# these to None silently dropped a lodged FIXED secondary (SAP
|
||||
|
|
@ -654,7 +667,7 @@ class EpcPropertyDataMapper:
|
|||
schema.sap_heating.secondary_heating_type,
|
||||
),
|
||||
secondary_heating_type=schema.sap_heating.secondary_heating_type,
|
||||
cylinder_insulation_thickness_mm=None,
|
||||
cylinder_insulation_thickness_mm=schema.sap_heating.cylinder_insulation_thickness,
|
||||
),
|
||||
# ADR-0028: 990/1000 omit sap_windows -> synthesised from the
|
||||
# glazed_area band + TFA via the shared reduced-field core. The 10
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
"""Regression: the RdSAP-Schema-17.0 mapper path must preserve the whole lodged
|
||||
`sap_heating` block, like every other API path (19.0/20.0/…).
|
||||
|
||||
`from_rdsap_schema_17_0` was an older copy that hardcoded a cluster of lodged
|
||||
`sap_heating` fields to None while the 19.0+ paths read them from
|
||||
`schema.sap_heating`:
|
||||
|
||||
* MainHeatingDetail.boiler_flue_type / fan_flue_present / central_heating_pump_age
|
||||
/ main_heating_index_number (the last is the PCDB efficiency index)
|
||||
* SapHeating.cylinder_thermostat — gates the water-heating ×1.3 penalty
|
||||
and `recommend_cylinder_thermostat`
|
||||
* SapHeating.cylinder_insulation_thickness — drives the cylinder-loss cascade
|
||||
|
||||
The 17.0 schema lodges all of them (see RdSapSchema17_0), so the hardcode silently
|
||||
degraded both the SAP water-heating figure and the hot-water recommendations for
|
||||
17.0 certs. This guard makes sure the block stays mapped. (The `secondary_*_type`
|
||||
pair of the same block is covered by its own dedicated secondary-heating test.)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from datatypes.epc.domain.mapper import EpcPropertyDataMapper
|
||||
|
||||
# A real RdSAP-Schema-17.0 cert that lodges a cylinder thermostat, a measured
|
||||
# cylinder-insulation thickness and flue/pump fields on its main heating.
|
||||
_FIXTURE = Path("tests/fixtures/epc_prediction/PE71NT/cert-26619d8e7f8e.json")
|
||||
|
||||
# A PCDB main-heating index the fixture happens not to carry; injected to prove
|
||||
# the field flows through (it used to be dropped to None unconditionally).
|
||||
_MAIN_HEATING_INDEX = 4321
|
||||
|
||||
|
||||
def _load_17_0_cert() -> dict[str, Any]:
|
||||
data: dict[str, Any] = json.loads(_FIXTURE.read_text())
|
||||
assert data["schema_type"] == "RdSAP-Schema-17.0"
|
||||
return data
|
||||
|
||||
|
||||
def test_17_0_path_preserves_lodged_cylinder_fields() -> None:
|
||||
# Arrange — the real cert lodges a cylinder thermostat + measured thickness.
|
||||
data = _load_17_0_cert()
|
||||
assert data["sap_heating"]["cylinder_thermostat"] == "Y"
|
||||
assert data["sap_heating"]["cylinder_insulation_thickness"] == 25
|
||||
|
||||
# Act
|
||||
epc = EpcPropertyDataMapper.from_api_response(data)
|
||||
|
||||
# Assert — both survive the 17.0 path now (they used to be dropped to None),
|
||||
# so the water-heating worksheet and cylinder-thermostat recommendation see
|
||||
# the real dwelling.
|
||||
assert epc.sap_heating.cylinder_thermostat == "Y"
|
||||
assert epc.sap_heating.cylinder_insulation_thickness_mm == 25
|
||||
|
||||
|
||||
def test_17_0_path_preserves_lodged_main_heating_detail_fields() -> None:
|
||||
# Arrange — the fixture lodges flue/pump on the main heating; inject a PCDB
|
||||
# index (absent on this cert) to cover the efficiency-lookup field too.
|
||||
data = _load_17_0_cert()
|
||||
detail = data["sap_heating"]["main_heating_details"][0]
|
||||
assert detail["boiler_flue_type"] == 2
|
||||
assert detail["fan_flue_present"] == "Y"
|
||||
assert detail["central_heating_pump_age"] == 1
|
||||
detail["main_heating_index_number"] = _MAIN_HEATING_INDEX
|
||||
|
||||
# Act
|
||||
epc = EpcPropertyDataMapper.from_api_response(data)
|
||||
|
||||
# Assert — the whole MainHeatingDetail block carries through (was all None).
|
||||
mapped = epc.sap_heating.main_heating_details[0]
|
||||
assert mapped.boiler_flue_type == 2
|
||||
assert mapped.fan_flue_present is True
|
||||
assert mapped.central_heating_pump_age == 1
|
||||
assert mapped.main_heating_index_number == _MAIN_HEATING_INDEX
|
||||
Loading…
Add table
Reference in a new issue