mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-30 13:10:47 +00:00
Map full-SAP cert identity and scalar fields to EpcPropertyData 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0079752eab
commit
c3fd9a6872
3 changed files with 98 additions and 0 deletions
|
|
@ -43,6 +43,7 @@ from datatypes.epc.schema.rdsap_schema_17_1 import (
|
||||||
RdSapSchema17_1,
|
RdSapSchema17_1,
|
||||||
EnergyElement as EnergyElement_17_1,
|
EnergyElement as EnergyElement_17_1,
|
||||||
)
|
)
|
||||||
|
from datatypes.epc.schema.sap_schema_17_1 import SapSchema17_1
|
||||||
from datatypes.epc.schema.rdsap_schema_18_0 import (
|
from datatypes.epc.schema.rdsap_schema_18_0 import (
|
||||||
RdSapSchema18_0,
|
RdSapSchema18_0,
|
||||||
EnergyElement as EnergyElement_18_0,
|
EnergyElement as EnergyElement_18_0,
|
||||||
|
|
@ -619,6 +620,63 @@ class EpcPropertyDataMapper:
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_sap_schema_17_1(schema: SapSchema17_1) -> EpcPropertyData:
|
||||||
|
# Built incrementally via TDD — see scripts/hyde/mapping_decisions.md.
|
||||||
|
# Tracer slice: identity + scalars are mapped; the load-bearing
|
||||||
|
# collections (walls/floors/roofs, sap_windows, sap_building_parts,
|
||||||
|
# door/room counts) are left empty here and filled by later slices
|
||||||
|
# (D1 perimeter, D2 openings, D3 living-area, D4 fabric-U).
|
||||||
|
return EpcPropertyData(
|
||||||
|
uprn=schema.uprn,
|
||||||
|
dwelling_type=(
|
||||||
|
schema.dwelling_type
|
||||||
|
if isinstance(schema.dwelling_type, str)
|
||||||
|
else schema.dwelling_type.value
|
||||||
|
),
|
||||||
|
inspection_date=date.fromisoformat(schema.inspection_date),
|
||||||
|
tenure=str(schema.tenure),
|
||||||
|
transaction_type=str(schema.transaction_type),
|
||||||
|
address_line_1=schema.address_line_1,
|
||||||
|
postcode=schema.postcode,
|
||||||
|
post_town=schema.post_town,
|
||||||
|
total_floor_area_m2=float(schema.total_floor_area),
|
||||||
|
has_hot_water_cylinder=schema.has_hot_water_cylinder == "true",
|
||||||
|
has_fixed_air_conditioning=schema.has_fixed_air_conditioning == "true",
|
||||||
|
solar_water_heating=False,
|
||||||
|
door_count=0,
|
||||||
|
wet_rooms_count=0,
|
||||||
|
extensions_count=0,
|
||||||
|
heated_rooms_count=0,
|
||||||
|
open_chimneys_count=0,
|
||||||
|
habitable_rooms_count=0,
|
||||||
|
insulated_door_count=0,
|
||||||
|
cfl_fixed_lighting_bulbs_count=0,
|
||||||
|
led_fixed_lighting_bulbs_count=0,
|
||||||
|
incandescent_fixed_lighting_bulbs_count=0,
|
||||||
|
roofs=[],
|
||||||
|
walls=[],
|
||||||
|
floors=[],
|
||||||
|
main_heating=[],
|
||||||
|
sap_windows=[],
|
||||||
|
sap_building_parts=[],
|
||||||
|
sap_heating=SapHeating(
|
||||||
|
instantaneous_wwhrs=InstantaneousWwhrs(),
|
||||||
|
main_heating_details=[],
|
||||||
|
has_fixed_air_conditioning=schema.has_fixed_air_conditioning == "true",
|
||||||
|
),
|
||||||
|
sap_energy_source=SapEnergySource(
|
||||||
|
mains_gas=False,
|
||||||
|
meter_type="",
|
||||||
|
pv_battery_count=0,
|
||||||
|
wind_turbines_count=0,
|
||||||
|
gas_smart_meter_present=False,
|
||||||
|
is_dwelling_export_capable=False,
|
||||||
|
wind_turbines_terrain_type="",
|
||||||
|
electricity_smart_meter_present=False,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_rdsap_schema_17_1(schema: RdSapSchema17_1) -> EpcPropertyData:
|
def from_rdsap_schema_17_1(schema: RdSapSchema17_1) -> EpcPropertyData:
|
||||||
es = schema.sap_energy_source
|
es = schema.sap_energy_source
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ from typing import Any, Dict
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from datatypes.epc.domain.epc_property_data import EpcPropertyData
|
||||||
|
from datatypes.epc.domain.mapper import EpcPropertyDataMapper
|
||||||
from datatypes.epc.schema.sap_schema_17_1 import SapSchema17_1
|
from datatypes.epc.schema.sap_schema_17_1 import SapSchema17_1
|
||||||
from datatypes.epc.schema.tests.helpers import from_dict
|
from datatypes.epc.schema.tests.helpers import from_dict
|
||||||
|
|
||||||
|
|
@ -47,3 +49,29 @@ class TestSapSchema17_1Parsing:
|
||||||
# Assert
|
# Assert
|
||||||
assert schema.uprn == 10092973954
|
assert schema.uprn == 10092973954
|
||||||
assert schema.total_floor_area == 68
|
assert schema.total_floor_area == 68
|
||||||
|
|
||||||
|
|
||||||
|
class TestFromSapSchema17_1Tracer:
|
||||||
|
"""Slice 2: the mapper produces a valid EpcPropertyData from a full-SAP cert."""
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("fixture", _ALL_FIXTURES)
|
||||||
|
def test_produces_epc_property_data(self, fixture: str) -> None:
|
||||||
|
# Arrange
|
||||||
|
schema = from_dict(SapSchema17_1, load(fixture))
|
||||||
|
|
||||||
|
# Act
|
||||||
|
result = EpcPropertyDataMapper.from_sap_schema_17_1(schema)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
assert isinstance(result, EpcPropertyData)
|
||||||
|
|
||||||
|
def test_maps_sample_uprn_and_floor_area(self) -> None:
|
||||||
|
# Arrange
|
||||||
|
schema = from_dict(SapSchema17_1, load("sap_17_1.json"))
|
||||||
|
|
||||||
|
# Act
|
||||||
|
result = EpcPropertyDataMapper.from_sap_schema_17_1(schema)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
assert result.uprn == 10092973954
|
||||||
|
assert result.total_floor_area_m2 == 68.0
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,21 @@ raises only on a missing *required* field.
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
from .common import DescriptionV1
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class SapSchema17_1:
|
class SapSchema17_1:
|
||||||
uprn: int
|
uprn: int
|
||||||
schema_type: str
|
schema_type: str
|
||||||
total_floor_area: Union[int, float]
|
total_floor_area: Union[int, float]
|
||||||
|
# full SAP lodges dwelling_type as a localised object OR a plain string.
|
||||||
|
dwelling_type: Union[str, DescriptionV1]
|
||||||
|
tenure: Union[str, int]
|
||||||
|
transaction_type: int
|
||||||
|
address_line_1: str
|
||||||
|
postcode: str
|
||||||
|
post_town: str
|
||||||
|
inspection_date: str
|
||||||
|
has_hot_water_cylinder: str
|
||||||
|
has_fixed_air_conditioning: str
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue