From ea7f4f4329cda824f3b33fdaf71a1cb157862748 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Mon, 29 Jun 2026 21:59:21 +0000 Subject: [PATCH] =?UTF-8?q?Carry=20full-SAP=20lodged=20PV=20arrays=20throu?= =?UTF-8?q?gh=20to=20the=20domain=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Full-SAP certs lodge measured PV under sap_energy_source.pv_arrays, but the SAP-Schema-17.1 SapEnergySource modelled only wind, so from_dict dropped it at parse and the mapper hardcoded no PV. A new SapPvArray schema field + the _sap_17_1_pv_arrays mapper helper carry it to the domain photovoltaic_arrays the Appendix-M generation credit reads — without it an all-electric dwelling the array lifts to A/B is mis-modelled down a band or more. Co-Authored-By: Claude Opus 4.8 (1M context) --- datatypes/epc/domain/mapper.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/datatypes/epc/domain/mapper.py b/datatypes/epc/domain/mapper.py index 20b66638..ec27d6fc 100644 --- a/datatypes/epc/domain/mapper.py +++ b/datatypes/epc/domain/mapper.py @@ -869,6 +869,7 @@ class EpcPropertyDataMapper: meter_type=_sap_17_1_meter_type( schema.sap_energy_source.electricity_tariff ), + photovoltaic_arrays=_sap_17_1_pv_arrays(schema), pv_battery_count=0, wind_turbines_count=schema.sap_energy_source.wind_turbines_count or 0, gas_smart_meter_present=False, @@ -2934,6 +2935,31 @@ def _sap_dwelling_on_mains_gas(schema: SapSchema17_1) -> bool: ) +def _sap_17_1_pv_arrays( + schema: SapSchema17_1, +) -> Optional[List[PhotovoltaicArray]]: + """Map a full-SAP cert's lodged PV (`sap_energy_source.pv_arrays`) to the + domain `PhotovoltaicArray` list the calculator's Appendix-M generation + credit reads. Without this the PV is dropped and an all-electric dwelling + that the array lifts to A/B is mis-modelled down a band or more. An array + with no peak power generates nothing, so it's skipped; orientation honours + the ND/NA sentinel (None ⇒ zero-generation array).""" + arrays = schema.sap_energy_source.pv_arrays + if not arrays: + return None + mapped = [ + PhotovoltaicArray( + peak_power=array.peak_power, + pitch=array.pitch if array.pitch is not None else 0, + overshading=array.overshading if array.overshading is not None else 0, + orientation=_pv_orientation(array.orientation), + ) + for array in arrays + if array.peak_power is not None + ] + return mapped or None + + def _sap_17_1_meter_type(electricity_tariff: Optional[int]) -> str: """Translate a full-SAP ``energy_tariff`` code into the RdSAP ``meter_type`` value the calculator's Table 12a tariff resolver consumes.