From 43fac405950a5097f19120b4d0be8199222ab388 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Tue, 14 Jul 2026 13:45:04 +0000 Subject: [PATCH] =?UTF-8?q?Overlay=20PasHub=20as-surveyed=20performance=20?= =?UTF-8?q?onto=20saved=20Site-Notes=20property=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) --- .../tests/test_pashub_service.py | 113 +++++++++++++++++- 1 file changed, 112 insertions(+), 1 deletion(-) diff --git a/backend/pashub_fetcher/tests/test_pashub_service.py b/backend/pashub_fetcher/tests/test_pashub_service.py index 09635c924..4cec4ac67 100644 --- a/backend/pashub_fetcher/tests/test_pashub_service.py +++ b/backend/pashub_fetcher/tests/test_pashub_service.py @@ -1,5 +1,5 @@ import pytest -from datetime import datetime +from datetime import date, datetime from typing import Any, Callable, Optional from unittest.mock import MagicMock, call, patch @@ -9,16 +9,74 @@ from backend.pashub_fetcher.pashub_client import ( DownloadedFile, DownloadedFiles, PashubClient, + RdSapSummary, UnauthorizedError, ) from backend.pashub_fetcher.pashub_service import PashubService from backend.pashub_fetcher.pashub_to_ara_trigger_request import ( PashubToAraTriggerRequest, ) +from datatypes.epc.domain.epc import Epc +from datatypes.epc.domain.epc_property_data import ( + EpcPropertyData, + SapEnergySource, + SapHeating, +) from utils.sharepoint.domna_sharepoint_client import DomnaSharepointClient FAKE_JOB_LINK = "https://pashub.net/jobs/job-id-123/details" +RD_SAP_SITE_NOTE_PATH = "/tmp/RdSAP_SiteNote_001.pdf" + + +def make_epc_property_data() -> EpcPropertyData: + """A minimal, real EpcPropertyData whose as-surveyed performance block is + empty — mirroring a freshly parsed Site Notes PDF the overlay fills in.""" + return EpcPropertyData( + dwelling_type="House", + inspection_date=date(2024, 1, 1), + tenure="1", + transaction_type="1", + address_line_1="1 Test Street", + postcode="AB1 2CD", + post_town="Testville", + roofs=[], + walls=[], + floors=[], + main_heating=[], + door_count=0, + sap_heating=SapHeating( + instantaneous_wwhrs=None, + main_heating_details=[], + has_fixed_air_conditioning=False, + ), + sap_windows=[], + sap_energy_source=SapEnergySource( + gas_connection_available=False, + meter_type="Single", + pv_battery_count=0, + wind_turbines_count=0, + gas_smart_meter_present=False, + is_dwelling_export_capable=False, + wind_turbines_terrain_type="Suburban", + electricity_smart_meter_present=False, + ), + sap_building_parts=[], + solar_water_heating=False, + has_hot_water_cylinder=False, + has_fixed_air_conditioning=False, + 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, + total_floor_area_m2=80.0, + ) + def make_request( pashub_link: str = FAKE_JOB_LINK, @@ -670,3 +728,56 @@ def test_run_warns_and_continues_when_site_notes_parsing_fails() -> None: assert result == ["/tmp/RdSAP_SiteNote_001.pdf"] mock_logger.warning.assert_called() mock_save.assert_not_called() + + +# --------------------------------------------------------------------------- +# run(): RdSAP Summary overlaid onto Site-Notes Lodged Performance +# --------------------------------------------------------------------------- + + +def _site_note_client( + summary: Any = None, + core: Optional[list[str]] = None, +) -> MagicMock: + mock_client = MagicMock(spec=PashubClient) + mock_client.get_uprn_by_job_id.return_value = None + mock_client.get_evidence_files_by_job_id.return_value = make_downloaded( + core=core if core is not None else [RD_SAP_SITE_NOTE_PATH] + ) + mock_client.get_rdsap_summary_by_job_id.return_value = summary + return mock_client + + +def test_run_overlays_full_lodged_performance_onto_saved_site_notes() -> None: + # Arrange + mock_client = _site_note_client( + summary=RdSapSummary( + pre_sap_rating=78.0, + pre_current_co2_emissions=1.70, + pre_current_energy_consumption=117.0, + ) + ) + parsed = make_epc_property_data() + service = make_service(pashub_client=mock_client) + + # Act + with ( + patch("backend.pashub_fetcher.pashub_service.upload_file_to_s3"), + patch( + "backend.pashub_fetcher.pashub_service.parse_site_notes_pdf", + return_value=parsed, + ), + patch( + "backend.pashub_fetcher.pashub_service.save_epc_property_data" + ) as mock_save, + patch("backend.pashub_fetcher.pashub_service.db_session"), + patch("backend.pashub_fetcher.pashub_service.os.remove"), + ): + service.run(make_request(uprn="12345")) + + # Assert + saved: EpcPropertyData = mock_save.call_args[0][1] + assert saved.energy_rating_current == 78 + assert saved.current_energy_efficiency_band == Epc.C + assert saved.co2_emissions_current == 1.70 + assert saved.energy_consumption_current == 117