Model/tests/domain/property/test_property_landlord_overlay.py
2026-06-22 14:38:00 +00:00

120 lines
4.2 KiB
Python

"""Effective EPC on the `epc_with_overlay` path folds Landlord Overrides (ADR-0032).
When a Property has a lodged EPC and resolved Landlord Overrides (as Simulation
Overlays), the Effective EPC is the lodged EPC with those overlays applied — so
the calculator scores what the landlord knows beyond the cert. With no overrides
the lodged EPC is returned unchanged.
"""
from __future__ import annotations
import json
from pathlib import Path
from typing import Any
from datatypes.epc.domain.epc_property_data import (
BuildingPartIdentifier,
EpcPropertyData,
)
from domain.epc.property_overlays.attribute_overlay import property_type_overlay_for
from domain.epc.property_overlays.wall_type_overlay import wall_overlay_for
from domain.property.property import Property, PropertyIdentity
_JSON_SAMPLES = Path(__file__).resolve().parents[3] / "backend/epc_api/json_samples"
def _epc() -> EpcPropertyData:
raw: dict[str, Any] = json.loads(
(_JSON_SAMPLES / "RdSAP-Schema-21.0.0" / "epc.json").read_text()
)
from datatypes.epc.domain.mapper import EpcPropertyDataMapper
return EpcPropertyDataMapper.from_api_response(raw)
def _identity() -> PropertyIdentity:
return PropertyIdentity(
portfolio_id=1, postcode="A0 0AA", address="1 Some Street", uprn=12345
)
def _main_wall(epc: EpcPropertyData) -> Any:
return next(
part
for part in epc.sap_building_parts
if part.identifier is BuildingPartIdentifier.MAIN
)
def test_effective_epc_folds_the_wall_override_onto_the_main_part() -> None:
# Arrange — a Property with a lodged EPC and a solid-brick/internal-insulation
# wall override.
overlay = wall_overlay_for("Solid brick, with internal insulation", 0)
assert overlay is not None
prop = Property(identity=_identity(), epc=_epc(), landlord_overrides=[overlay])
# Act
main = _main_wall(prop.effective_epc)
# Assert — the override's codes are present on the main wall.
assert main.wall_construction == 3
assert main.wall_insulation_type == 3
def test_effective_epc_reflects_a_property_type_override() -> None:
# Arrange — the landlord corrects the dwelling's property type to House.
overlay = property_type_overlay_for("House", 0)
assert overlay is not None
prop = Property(identity=_identity(), epc=_epc(), landlord_overrides=[overlay])
# Act / Assert — the Effective EPC carries the corrected property type.
assert prop.effective_epc.property_type == "House"
def test_effective_epc_is_the_lodged_epc_when_there_are_no_overrides() -> None:
# Arrange — a Property with an EPC and no Landlord Overrides.
prop = Property(identity=_identity(), epc=_epc())
# Act
effective = prop.effective_epc
# Assert — the lodged EPC is returned untouched (same object, no fold).
assert effective is prop.epc
def test_baseline_wall_is_unchanged_when_no_override_applies() -> None:
# Arrange — the lodged main wall is cavity (construction 4).
prop = Property(identity=_identity(), epc=_epc())
# Act
main = _main_wall(prop.effective_epc)
# Assert
assert main.wall_construction == 4
def test_effective_epc_folds_overrides_onto_a_predicted_epc() -> None:
# Arrange — an EPC-less Property whose EPC was neighbour-synthesised, plus a
# solid-brick/internal-insulation wall override the landlord knows.
overlay = wall_overlay_for("Solid brick, with internal insulation", 0)
assert overlay is not None
prop = Property(
identity=_identity(), predicted_epc=_epc(), landlord_overrides=[overlay]
)
# Act
main = _main_wall(prop.effective_epc)
# Assert — the override's codes correct the synthesised main wall, exactly as
# they do on the lodged path (the cohort fills the rest).
assert main.wall_construction == 3
assert main.wall_insulation_type == 3
def test_effective_epc_predicted_is_returned_as_is_when_no_overrides() -> None:
# Arrange — a predicted Property with no Landlord Overrides.
predicted = _epc()
prop = Property(identity=_identity(), predicted_epc=predicted)
# Act / Assert — the synthesised EPC is returned untouched (same object).
assert prop.effective_epc is predicted