From ed690d9e36b58f0f8b10220a8e122394ec249eb3 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Mon, 13 Jul 2026 23:36:43 +0000 Subject: [PATCH] =?UTF-8?q?Populate=20export=20rows=20with=20the=20lodged?= =?UTF-8?q?=20EPC's=20descriptive=20fields=20=F0=9F=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- ...est_scenario_export_postgres_repository.py | 134 ++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/tests/repositories/scenario_export/test_scenario_export_postgres_repository.py b/tests/repositories/scenario_export/test_scenario_export_postgres_repository.py index a6199f32f..bcd0e8037 100644 --- a/tests/repositories/scenario_export/test_scenario_export_postgres_repository.py +++ b/tests/repositories/scenario_export/test_scenario_export_postgres_repository.py @@ -4,21 +4,103 @@ read-model, from persisted data only (no live EPC calls).""" from __future__ import annotations +from typing import Optional + from sqlalchemy import Engine from sqlmodel import Session from datatypes.epc.domain.epc import Epc +from infrastructure.postgres.epc_property_table import ( # registers epc tables + EpcEnergyElementModel, + EpcPropertyEnergyPerformanceModel, + EpcPropertyModel, +) from infrastructure.postgres.modelling import ( # registers `plan` + `recommendation` PlanModel, RecommendationModel, ) from infrastructure.postgres.product_table import MaterialRow # registers `material` +from infrastructure.postgres.property_override_table import ( # registers overrides + PropertyOverrideRow, +) from infrastructure.postgres.property_table import PropertyRow # registers `property` from repositories.scenario_export.scenario_export_postgres_repository import ( ScenarioExportPostgresRepository, ) +def _add_epc( + session: Session, + *, + property_id: int, + epc_id: int, + source: str = "lodged", + property_type: Optional[str] = None, + total_floor_area_m2: float = 90.0, + registration_date: str = "2005-01-01", + habitable_rooms_count: int = 4, + energy_rating_current: Optional[int] = 58, + band: Optional[str] = "D", + elements: Optional[dict[str, str]] = None, +) -> None: + """Seed one EPC slot (lodged/predicted) with its energy-performance child and + descriptive energy elements. Fills every NOT-NULL column with a benign + default so the test only has to state the fields it cares about.""" + session.add( + EpcPropertyModel( + id=epc_id, + property_id=property_id, + source=source, + property_type=property_type, + total_floor_area_m2=total_floor_area_m2, + registration_date=registration_date, + habitable_rooms_count=habitable_rooms_count, + dwelling_type="House", + tenure="owner-occupied", + transaction_type="none", + inspection_date=registration_date, + solar_water_heating=False, + has_hot_water_cylinder=False, + has_fixed_air_conditioning=False, + door_count=1, + wet_rooms_count=1, + extensions_count=0, + heated_rooms_count=1, + open_chimneys_count=0, + insulated_door_count=0, + cfl_fixed_lighting_bulbs_count=0, + led_fixed_lighting_bulbs_count=0, + incandescent_fixed_lighting_bulbs_count=0, + energy_gas_connection_available=False, + energy_meter_type="standard", + energy_pv_battery_count=0, + energy_wind_turbines_count=0, + energy_gas_smart_meter_present=False, + energy_is_dwelling_export_capable=False, + energy_wind_turbines_terrain_type="none", + energy_electricity_smart_meter_present=False, + ) + ) + session.flush() # parent epc_property before its FK children + session.add( + EpcPropertyEnergyPerformanceModel( + epc_property_id=epc_id, + energy_rating_current=energy_rating_current, + current_energy_efficiency_band=band, + ) + ) + for element_type, description in (elements or {}).items(): + session.add( + EpcEnergyElementModel( + epc_property_id=epc_id, + element_type=element_type, + description=description, + energy_efficiency_rating=3, + environmental_efficiency_rating=3, + ) + ) + + def test_returns_a_row_for_a_property_with_a_default_plan_under_the_scenario( db_engine: Engine, ) -> None: @@ -183,3 +265,55 @@ def test_maps_the_default_plans_selected_measures_with_battery_and_exclusions( assert by_type["loft_insulation"].kwh_savings == 900.0 assert by_type["loft_insulation"].includes_battery is False assert by_type["solar_pv"].includes_battery is True + + +def test_effective_epc_descriptive_fields_come_from_the_lodged_epc( + db_engine: Engine, +) -> None: + # arrange — a Property with a default Plan under scenario 5 and a lodged EPC + # carrying descriptive energy elements and current performance. + with Session(db_engine) as session: + session.add(PropertyRow(id=1, portfolio_id=100, landlord_property_id="LP1")) + session.add( + PlanModel(portfolio_id=100, property_id=1, scenario_id=5, is_default=True) + ) + _add_epc( + session, + property_id=1, + epc_id=1, + source="lodged", + property_type="House", + total_floor_area_m2=92.5, + registration_date="2005-01-01", + habitable_rooms_count=5, + energy_rating_current=58, + band="D", + elements={ + "wall": "Cavity wall, as built, insulated", + "roof": "Pitched, 250mm loft insulation", + "main_heating": "Boiler and radiators, mains gas", + "window": "Fully double glazed", + }, + ) + session.commit() + + # act + with Session(db_engine) as session: + rows = ScenarioExportPostgresRepository(session).rows_for( + portfolio_id=100, scenario_id=5, property_ids=[1] + ) + + # assert — descriptive prose, current performance, floor area, lodgement and + # property_type all come from the persisted lodged EPC (no live calls). + row = rows[0] + assert row.walls == "Cavity wall, as built, insulated" + assert row.roof == "Pitched, 250mm loft insulation" + assert row.heating == "Boiler and radiators, mains gas" + assert row.windows == "Fully double glazed" + assert row.property_type == "House" + assert row.total_floor_area == 92.5 + assert row.number_of_rooms == 5 + assert row.current_epc_rating == "D" + assert row.current_sap_points == 58 + assert row.lodgement_date == "2005-01-01" + assert row.is_expired is True