diff --git a/backend/documents_parser/tests/test_summary_pdf_mapper_chain.py b/backend/documents_parser/tests/test_summary_pdf_mapper_chain.py index 164063c6..f8a79eef 100644 --- a/backend/documents_parser/tests/test_summary_pdf_mapper_chain.py +++ b/backend/documents_parser/tests/test_summary_pdf_mapper_chain.py @@ -313,6 +313,33 @@ def test_summary_001479_secondary_heating_routes_mains_gas_fuel() -> None: assert epc.sap_heating.secondary_fuel_type == 26 +def test_summary_2102_secondary_heating_routes_house_coal_for_open_fire() -> None: + # Arrange — cohort-2 cert 2102-3018-0205-7886-5204 §14.1 lodges + # "Secondary Heating Code: SAP code 631" — "Open fire in grate" + # per SAP 10.2 Table 4a Category 10 (Room heaters), solid fuel + # column. Without the per-code routing the cascade defaults to + # standard electricity at 13.19 p/kWh and over-charges secondary + # heating by ~£340/yr, pushing SAP -15.81 below the worksheet's + # 63.87. Worksheet line (242) "Space heating - secondary 3585.24 + # × 3.6700 = 131.58" confirms house-coal pricing (Table 32 fuel + # code 11 = 3.67 p/kWh). + cert_dir = Path( + "sap worksheets/additional with api 2/2102-3018-0205-7886-5204" + ) + summary_pdf = next(cert_dir.glob("Summary_*.pdf")) + pages = _summary_pdf_to_textract_style_pages(summary_pdf) + site_notes = ElmhurstSiteNotesExtractor(pages).extract() + + # Act + epc = EpcPropertyDataMapper.from_elmhurst_site_notes(site_notes) + + # Assert + assert epc.sap_heating.secondary_heating_type == 631 + # 11 = "Coal" in `_ELMHURST_MAIN_FUEL_TO_SAP10` → Table 32 lookup + # returns 3.67 p/kWh (house coal). + assert epc.sap_heating.secondary_fuel_type == 11 + + def test_summary_9501_flat_has_no_built_form_in_summary_pdf() -> None: # Arrange — cert 9501 (Summary_000784.pdf) is a flat. The Elmhurst # Summary's §1.0 "Property type" section lodges the built-form diff --git a/datatypes/epc/domain/mapper.py b/datatypes/epc/domain/mapper.py index ce8162ed..194d6d7d 100644 --- a/datatypes/epc/domain/mapper.py +++ b/datatypes/epc/domain/mapper.py @@ -3350,14 +3350,31 @@ def _elmhurst_secondary_fuel_from_sap_code( fitting live effect gas fire") but not the fuel int separately; the cascade's `_secondary_fuel_cost_gbp_per_kwh` defaults to standard electricity when `secondary_fuel_type` is None — correct for the - portable-electric default but wrong for cert 001479's mains-gas fire. - Returns 26 (mains gas) for SAP codes in the 600-630 range; None for - other codes (cascade default fires, matching cohort 000490 SAP code - 691 electric panel).""" + portable-electric default but wrong for fuel-fired room heaters. + + SAP 10.2 Table 4a Category 10 ("Room heaters") code blocks: + 601-613: Gas (mains gas / LPG / biogas) — column A is mains gas; + column B for LPG. Cohort default is mains gas + (`_ELMHURST_MAIN_FUEL_TO_SAP10["Mains gas"] = 26`). + 621-625: Liquid fuel room heaters (oil / bioethanol). Cohort + not yet exercised; deferred until a fixture surfaces. + 631-634: Solid fuel room heaters (open fire, closed room + heater with/without boiler). House coal is the modal + default per Table 12 secondary rate (3.67 p/kWh). + 691-699: Electric room heaters. Cascade default (None) routes + to standard electricity (13.19 p/kWh). + + Cohort cert 2102-3018-0205-7886-5204 surfaces the 631 ("Open fire + in grate") path — pre-slice the cascade defaulted to electricity + at 13.19 p/kWh, over-charging secondary by ~£340/yr and pushing + SAP -15.81 below the worksheet's 63.87. + """ if sap_code is None: return None - if 601 <= sap_code <= 630: + if 601 <= sap_code <= 613: return 26 # Mains gas, matching `_ELMHURST_MAIN_FUEL_TO_SAP10` + if 631 <= sap_code <= 634: + return 11 # House coal (Coal in `_ELMHURST_MAIN_FUEL_TO_SAP10`) return None