mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-12 13:29:04 +00:00
154 lines
6.3 KiB
Python
154 lines
6.3 KiB
Python
"""The main-heating reclassify maps the garbage-drawer archetypes (old storage,
|
|
Gas CPSU) onto the faithful ones the guard resolves, leaves correctly-classified
|
|
rows alone, and is idempotent (#1376 / ADR-0044, ADR-0045)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from domain.epc.property_overlays.main_heating_system_overlay import (
|
|
main_heating_overlay_for,
|
|
)
|
|
from domain.epc.property_overrides.main_heating_guard import main_heating_guard
|
|
from domain.epc.property_overrides.main_heating_system_type import (
|
|
MainHeatingSystemType,
|
|
)
|
|
from scripts.reclassify_main_heating import (
|
|
electric_cpsu_for,
|
|
main_heating_corrections,
|
|
)
|
|
|
|
|
|
def test_garbage_drawer_rows_are_remapped_to_faithful_archetypes() -> None:
|
|
# Arrange — HHRSH funnelled into old storage, and the Gas CPSU dumping ground
|
|
# (solid-fuel room heaters + electric "NA" boiler); plus correctly-classified
|
|
# rows (genuine old storage, a gas combi) that must be left untouched.
|
|
stored = [
|
|
(
|
|
"electric storage systems: high heat retention storage heaters",
|
|
"Electric storage heaters, old",
|
|
),
|
|
("solid fuel room heaters: open fire in grate", "Gas CPSU"),
|
|
(
|
|
"solid fuel room heaters: open fire with back boiler (no radiators)",
|
|
"Gas CPSU",
|
|
),
|
|
(
|
|
"solid fuel room heaters: closed room heater with boiler (no radiators)",
|
|
"Gas CPSU",
|
|
),
|
|
("boiler: a rated na", "Gas CPSU"),
|
|
# Correctly classified — the guard does not claim these.
|
|
(
|
|
"electric storage systems: old (large volume) storage heaters",
|
|
"Electric storage heaters, old",
|
|
),
|
|
("boiler: a rated combi", "Gas boiler, combi"),
|
|
]
|
|
|
|
# Act
|
|
corrections = main_heating_corrections(stored)
|
|
|
|
# Assert — every mis-classified row moves to its faithful archetype.
|
|
assert corrections == {
|
|
"electric storage systems: high heat retention storage heaters": (
|
|
"Electric storage heaters, high heat retention"
|
|
),
|
|
"solid fuel room heaters: open fire in grate": (
|
|
"Solid fuel room heater, open fire"
|
|
),
|
|
"solid fuel room heaters: open fire with back boiler (no radiators)": (
|
|
"Solid fuel room heater, open fire with back boiler"
|
|
),
|
|
"solid fuel room heaters: closed room heater with boiler (no radiators)": (
|
|
"Solid fuel room heater, closed with boiler"
|
|
),
|
|
"boiler: a rated na": "Electric boiler",
|
|
}
|
|
|
|
|
|
def test_electric_underfloor_rows_are_remapped_off_direct_acting_and_old_storage() -> None:
|
|
# Underfloor dumped into Direct-acting (191) / old storage (401) → its own codes
|
|
# (ADR-0046). Description-determined, so the guard-based reclassify handles it.
|
|
stored = [
|
|
(
|
|
"electric underfloor heating: in concrete slab (off-peak only)",
|
|
"Direct-acting electric",
|
|
),
|
|
(
|
|
"electric underfloor heating: integrated (storage+direct-acting) (off peak)",
|
|
"Electric storage heaters, old",
|
|
),
|
|
(
|
|
"electric underfloor heating: in screed above insulation (standard or off peak)",
|
|
"Direct-acting electric",
|
|
),
|
|
]
|
|
|
|
# Act
|
|
corrections = main_heating_corrections(stored)
|
|
|
|
# Assert
|
|
assert corrections == {
|
|
"electric underfloor heating: in concrete slab (off-peak only)": (
|
|
"Electric underfloor, in concrete slab (off-peak)"
|
|
),
|
|
"electric underfloor heating: integrated (storage+direct-acting) (off peak)": (
|
|
"Electric underfloor, integrated storage and direct-acting"
|
|
),
|
|
"electric underfloor heating: in screed above insulation (standard or off peak)": (
|
|
"Electric underfloor, in screed above insulation"
|
|
),
|
|
}
|
|
|
|
|
|
def test_every_guard_target_round_trips_to_a_resolvable_archetype() -> None:
|
|
# Every archetype the guard emits for the rescued descriptions must decode to a
|
|
# real SAP heating code — a guard/overlay drift can't silently write an
|
|
# unmodellable value (ADR-0044, ADR-0045, ADR-0046).
|
|
descriptions = [
|
|
"Electric Storage Systems: High heat retention storage heaters",
|
|
"Electric Underfloor Heating: In concrete slab (off-peak only)",
|
|
"Electric Underfloor Heating: Integrated (storage+direct-acting) (off peak)",
|
|
"Electric Underfloor Heating: In screed above insulation (standard or off peak)",
|
|
"Solid fuel room heaters: Open fire in grate",
|
|
"Solid fuel room heaters: Open fire with back boiler (no radiators)",
|
|
"Solid fuel room heaters: Closed room heater with boiler (no radiators)",
|
|
"Boiler: A rated NA",
|
|
]
|
|
|
|
for description in descriptions:
|
|
member = main_heating_guard(description)
|
|
|
|
assert member is not None, description
|
|
assert member in MainHeatingSystemType, description
|
|
simulation = main_heating_overlay_for(member.value, 0)
|
|
assert simulation is not None, description
|
|
assert simulation.heating is not None, description
|
|
assert simulation.heating.sap_main_heating_code is not None, description
|
|
|
|
|
|
def test_electric_cpsu_is_resolved_from_the_fuel_not_the_description() -> None:
|
|
# "Boiler: A/C rated CPSU" is identical bar the band — the electric/gas split is
|
|
# fuel-determined (the pure-string guard can't see it), so the reclassify keys
|
|
# on the property's main_fuel override: electricity → Electric CPSU (192);
|
|
# mains gas / unknown → keep Gas CPSU (120). A non-CPSU boiler is ignored here
|
|
# (the guard handles "NA" electric boilers) — ADR-0045.
|
|
assert electric_cpsu_for("boiler: a rated cpsu", "electricity") == "Electric CPSU"
|
|
assert electric_cpsu_for("boiler: c rated cpsu", "mains gas") is None
|
|
assert electric_cpsu_for("boiler: c rated cpsu", None) is None
|
|
assert electric_cpsu_for("boiler: a rated na", "electricity") is None
|
|
|
|
|
|
def test_already_corrected_rows_need_no_change() -> None:
|
|
# Act / Assert — idempotent.
|
|
assert (
|
|
main_heating_corrections(
|
|
[
|
|
(
|
|
"electric storage systems: high heat retention storage heaters",
|
|
"Electric storage heaters, high heat retention",
|
|
),
|
|
("boiler: a rated na", "Electric boiler"),
|
|
]
|
|
)
|
|
== {}
|
|
)
|