Merge pull request #1328 from Hestia-Homes/fix/flat-location-banded-string

fix(epc-mapper): coerce banded flat_location "20+" to its floor integer
This commit is contained in:
KhalimCK 2026-06-25 16:02:26 +01:00 committed by GitHub
commit 2c49ca630c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 31 additions and 1 deletions

View file

@ -2549,7 +2549,9 @@ class EpcPropertyDataMapper:
SapFlatDetails(
level=schema.sap_flat_details.level,
top_storey=schema.sap_flat_details.top_storey,
flat_location=schema.sap_flat_details.flat_location,
flat_location=_flat_location_int(
schema.sap_flat_details.flat_location
),
heat_loss_corridor=schema.sap_flat_details.heat_loss_corridor,
storey_count=schema.sap_flat_details.storey_count,
unheated_corridor_length_m=(
@ -3111,6 +3113,17 @@ def _clear_basement_flag_when_system_built(
return replace(epc, sap_building_parts=new_parts)
def _flat_location_int(value: Any) -> int:
"""`sap_flat_details.flat_location` is the flat's floor number, lodged by the
gov API as a plain int on most certs but as a banded string `"20+"` (floor 20
or above) on high floors. The `epc_flat_details.flat_location` column is a
NOT-NULL integer, so the raw band crashed the modelling_e2e insert. Coerce the
band to its floor (`"20+"` 20); Elmhurst caps the floor number at 30."""
if isinstance(value, int):
return value
return int(str(value).strip().rstrip("+"))
def _measurement_value(field: Any) -> float:
"""SAP measurements arrive as a `Measurement` (with `.value`), a raw dict
{'value': N, 'quantity': '...'} when `from_dict` didn't coerce, or a plain

View file

@ -458,6 +458,23 @@ class TestFromRdSapSchema21_0_1:
assert result.led_fixed_lighting_bulbs_count == 0
def test_banded_flat_location_string_coerced_to_band_floor_int(self) -> None:
# The gov API lodges flat_location (the flat's floor number) as a plain
# int on most certs, but on high floors as a banded string "20+" (floor
# 20 or above) — e.g. cert 2481-2122-4211-1172-4722 (UPRN 6027561).
# The epc_flat_details.flat_location column is a NOT-NULL integer, so the
# raw string crashed the modelling_e2e insert (psycopg2
# InvalidTextRepresentation, portfolio 796 run). Coerce the band to its
# floor (20); Elmhurst caps the floor number at 30.
data = load("21_0_1.json")
data["sap_flat_details"]["flat_location"] = "20+"
schema = from_dict(RdSapSchema21_0_1, data)
result = EpcPropertyDataMapper.from_rdsap_schema_21_0_1(schema)
assert result.sap_flat_details is not None
assert result.sap_flat_details.flat_location == 20
def test_uprn(self, result: EpcPropertyData) -> None:
assert result.uprn == 12457