from __future__ import annotations from typing import Final from domain.fuel_rates.fuel import Fuel from domain.sap10_calculator.exceptions import UnmappedSapCode # SAP 10.2 / Table 32 fuel code -> canonical billing Fuel (ADR-0014). Bounded to # the ~47 Table 32 fuel codes (the keys of `table_12.UNIT_PRICE_P_PER_KWH`) — the # carrier, NOT the PCDB product, so a thousand PCDB heat pumps all share one code. # Input is a normalised Table 32 fuel code (the calculator sets `main_fuel_type` # to Table 32 codes); an unmapped code raises `UnmappedSapCode` rather than # guessing — a bounded, self-surfacing backlog [[reference-unmapped-sap-code]]. _CODE_TO_FUEL: Final[dict[int, Fuel]] = { **dict.fromkeys([1, 7], Fuel.MAINS_GAS), # mains gas, grid biogas **dict.fromkeys([2, 3, 5, 9], Fuel.LPG), **dict.fromkeys([4, 71, 73, 75, 76], Fuel.OIL), # heating oil + bio-liquids **dict.fromkeys([11, 15], Fuel.COAL), # house coal, anthracite **dict.fromkeys([12], Fuel.SMOKELESS), **dict.fromkeys([20, 21], Fuel.WOOD_LOGS), # logs, chips **dict.fromkeys([22, 23], Fuel.WOOD_PELLETS), **dict.fromkeys([30], Fuel.ELECTRICITY), # standard tariff # 7/10/18-hour off-peak tariffs + 24-hour heating tariff — priced once the # off-peak day/night slice lands; ELECTRICITY_OFF_PEAK is unpriced until then. **dict.fromkeys([31, 32, 33, 34, 35, 38, 40], Fuel.ELECTRICITY_OFF_PEAK), # "heat from ..." community/heat-network + distribution codes (41-58). **dict.fromkeys(range(41, 59), Fuel.HEAT_NETWORK), } def sap_code_to_fuel(code: int) -> Fuel: """Map a SAP 10.2 / Table 32 fuel code to its canonical billing Fuel. Raises ``UnmappedSapCode`` on a code with no single billing carrier — e.g. dual fuel (10) or the grid-export codes (36/60), which are not an end use's input fuel. """ fuel = _CODE_TO_FUEL.get(code) if fuel is None: raise UnmappedSapCode("fuel_code", code) return fuel