diff --git a/scripts/reclassify_main_heating.py b/scripts/reclassify_main_heating.py index c958458b4..0d070445e 100644 --- a/scripts/reclassify_main_heating.py +++ b/scripts/reclassify_main_heating.py @@ -38,7 +38,14 @@ from scripts.e2e_common import build_engine, load_env def electric_cpsu_for(description: str, main_fuel: Optional[str]) -> Optional[str]: - raise NotImplementedError + """``"Electric CPSU"`` for a CPSU-boiler override whose property's ``main_fuel`` + override is electricity, else ``None`` (ADR-0045). ``"Boiler: A/C rated CPSU"`` + is identical bar the band — the electric/gas split is *fuel*-determined, so this + keys on the fuel the guard cannot see; a gas / unknown fuel keeps Gas CPSU + (120), and a non-CPSU description is left to the guard.""" + if "cpsu" in description.lower() and main_fuel == "electricity": + return MainHeatingSystemType.ELECTRIC_CPSU.value + return None def main_heating_corrections( @@ -94,6 +101,30 @@ _ENUM_VALUES = text( "SELECT e.enumlabel FROM pg_enum e JOIN pg_type t ON t.oid = e.enumtypid " "WHERE t.typname = 'main_heating_system'" ) +# CPSU boilers still on Gas CPSU, each with its property's main_fuel override — +# the electric/gas split the description can't carry (ADR-0045). +_CPSU_ROWS = text( + """ + SELECT mh.property_id AS property_id, + lower(mh.original_spreadsheet_description) AS description, + mf.override_value AS main_fuel + FROM property_overrides mh + LEFT JOIN property_overrides mf + ON mf.property_id = mh.property_id AND mf.override_component = 'main_fuel' + WHERE mh.override_component = 'main_heating_system' + AND mh.override_value = 'Gas CPSU' + AND lower(mh.original_spreadsheet_description) LIKE '%cpsu%' + """ +) +_CPSU_PROPERTY_UPDATE = text( + """ + UPDATE property_overrides + SET override_value = :new_value + WHERE property_id = :property_id + AND override_component = 'main_heating_system' + AND override_value = 'Gas CPSU' + """ +) def reclassify(conn: Connection, *, apply: bool) -> tuple[int, set[str]]: @@ -115,6 +146,21 @@ def reclassify(conn: Connection, *, apply: bool) -> tuple[int, set[str]]: conn.execute(_OVERRIDES_UPDATE, params) if in_enum: conn.execute(_CACHE_UPDATE, params) + + # Fuel-aware phase: an electric CPSU (fuel-determined, per-property) — update + # only the TEXT layer. The description-keyed classifier cache cannot represent + # a fuel-dependent value, and "Electric CPSU" is a deferred pgEnum value anyway. + for row in conn.execute(_CPSU_ROWS): + new_value = electric_cpsu_for(row.description, row.main_fuel) + if new_value is None: + continue + total += 1 + deferred.add(new_value) + if apply: + conn.execute( + _CPSU_PROPERTY_UPDATE, + {"property_id": row.property_id, "new_value": new_value}, + ) return total, deferred