From 6ec098928333516ed957995a744f28d6f23d585d Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Mon, 29 Jun 2026 18:54:51 +0000 Subject: [PATCH] =?UTF-8?q?Translate=20full-SAP=20electricity=20tariff=20i?= =?UTF-8?q?nto=20the=20RdSAP=20meter=20type=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Full-SAP energy_tariff (1=standard/2=7hr/3=10hr/4=24hr) and RdSAP meter_type (1=dual/2=single/3=unknown/4=24hr) are different code spaces; the mapper passed the code through untranslated, reading standard-tariff full-SAP certs as Economy 7 (over-rated) and Economy-7 certs as single (under-rated). Map onto the RdSAP word aliases so the resolved Table 12a tariff is correct; absent/ND -> unknown. Co-Authored-By: Claude Opus 4.8 (1M context) --- datatypes/epc/domain/mapper.py | 20 ++++++++++++++-- .../epc/domain/tests/test_from_sap_schema.py | 23 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/datatypes/epc/domain/mapper.py b/datatypes/epc/domain/mapper.py index ec3b38fc..20b66638 100644 --- a/datatypes/epc/domain/mapper.py +++ b/datatypes/epc/domain/mapper.py @@ -866,7 +866,9 @@ class EpcPropertyDataMapper: # explicit flag); tariff → meter_type; wind turbines pass through. sap_energy_source=SapEnergySource( mains_gas=_sap_dwelling_on_mains_gas(schema), - meter_type=str(schema.sap_energy_source.electricity_tariff or ""), + meter_type=_sap_17_1_meter_type( + schema.sap_energy_source.electricity_tariff + ), pv_battery_count=0, wind_turbines_count=schema.sap_energy_source.wind_turbines_count or 0, gas_smart_meter_present=False, @@ -2943,7 +2945,21 @@ def _sap_17_1_meter_type(electricity_tariff: Optional[int]) -> str: standard-tariff cert as Economy 7 (over-rated) and an Economy-7 cert as single (under-rated). Map onto the RdSAP word aliases so the resolved tariff is correct; absent/ND → "" (the unknown→standard sentinel).""" - raise NotImplementedError(electricity_tariff) + if electricity_tariff is None: + return "" + return _SAP_TARIFF_TO_RDSAP_METER_TYPE.get(electricity_tariff, "") + + +# full-SAP `energy_tariff` code → RdSAP `meter_type` word alias (consumed by +# `tariff_from_meter_type` / `_METER_STR_TO_INT`). 10-hour (3) has no dedicated +# RdSAP meter code — it maps to "dual", and the §12 dispatch resolves 7-/10-hour +# from the heating system. +_SAP_TARIFF_TO_RDSAP_METER_TYPE: dict[int, str] = { + 1: "single", # standard tariff + 2: "dual", # off-peak 7 hour (Economy 7) + 3: "dual", # off-peak 10 hour (§12 dispatch resolves 7/10hr) + 4: "dual (24 hour)", # 24-hour tariff +} def _sap_17_1_heating(schema: SapSchema17_1) -> SapHeating: diff --git a/datatypes/epc/domain/tests/test_from_sap_schema.py b/datatypes/epc/domain/tests/test_from_sap_schema.py index 32656e95..de23ded0 100644 --- a/datatypes/epc/domain/tests/test_from_sap_schema.py +++ b/datatypes/epc/domain/tests/test_from_sap_schema.py @@ -156,6 +156,29 @@ class TestFullSapElectricityTariffTranslation: assert tariff_from_meter_type(meter_type) is Tariff.SEVEN_HOUR + @pytest.mark.parametrize( + ("energy_tariff", "expected"), + [ + (1, "STANDARD"), # standard tariff → single-rate (was over-rated as E7) + (2, "SEVEN_HOUR"), # off-peak 7-hour → Economy 7 + (3, "SEVEN_HOUR"), # off-peak 10-hour → dual (§12 resolves 7/10hr) + (4, "TWENTY_FOUR_HOUR"), # 24-hour tariff (e.g. property 709874 — unchanged) + (None, "STANDARD"), # absent/ND → unknown → standard + ], + ) + def test_energy_tariff_resolves_to_the_correct_calculator_tariff( + self, energy_tariff: Any, expected: str + ) -> None: + from domain.sap10_calculator.tables.table_12a import ( + tariff_from_meter_type, + ) + + from datatypes.epc.domain.mapper import _sap_17_1_meter_type + + resolved = tariff_from_meter_type(_sap_17_1_meter_type(energy_tariff)) + + assert resolved.name == expected + class TestFromSapSchema17_1DisplayElements: """Display EnergyElements the WIP mapper dropped, leaving the FE