Model/tests/domain/billing/test_sap_fuel.py
Jun-te Kim 782c686969 Map fuel code 39 (electricity, any tariff) to standard electricity
modelling_e2e properties with main fuel 39 failed at the price boundary
(UnpricedFuelCode since #44fff767; previously mis-rated as non-electric →
the ~14-SAP over-rating flagged in earlier review).

Code 39 is SAP Table 12 "electricity, any tariff" (epc_codes.csv main_fuel 39 =
"electricity, unspecified tariff"; spec footnote (j): defines an electric system,
cost/CO2/PE = standard electricity). It was absent from API_FUEL_TO_TABLE_32, so
to_table_32_code(39) was None → is_electric_fuel_code(39) False and pricing
raised.

Fix: map API_FUEL_TO_TABLE_32[39] = 30 (standard electricity) — the canonical
place Khalim's fuel work added codes. One line makes classification, pricing,
CO2/PE and the billing carrier all agree (39 → 30 → ELECTRICITY).

Tests: to_table_32_code(39)==30, is_electric_fuel_code(39) True, price == standard
electricity, and the billing carrier resolves to ELECTRICITY. 0 corpus impact
(no lodged corpus cert uses 39); accuracy + mapper-corpus gates green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 11:20:32 +00:00

61 lines
2.3 KiB
Python

from __future__ import annotations
import pytest
from domain.fuel_rates.fuel import Fuel
from domain.billing.sap_fuel import sap_code_to_fuel
from domain.sap10_calculator.exceptions import UnmappedSapCode
def test_mains_gas_code_maps_to_mains_gas() -> None:
# Arrange / Act / Assert — Table 32 code 1 is mains gas.
assert sap_code_to_fuel(1) == Fuel.MAINS_GAS
@pytest.mark.parametrize(
("code", "fuel"),
[
(1, Fuel.MAINS_GAS),
(2, Fuel.LPG),
(4, Fuel.OIL),
(76, Fuel.OIL), # bioethanol — a liquid fuel row
(11, Fuel.COAL), # house coal
(15, Fuel.COAL), # anthracite
(12, Fuel.SMOKELESS),
(20, Fuel.WOOD_LOGS),
(23, Fuel.WOOD_PELLETS),
(10, Fuel.DUAL_FUEL_MINERAL_AND_WOOD), # dual fuel (mineral + wood)
(30, Fuel.ELECTRICITY), # standard tariff
(32, Fuel.ELECTRICITY_OFF_PEAK), # 7-hour tariff
(41, Fuel.HEAT_NETWORK), # heat from electric heat pump (community)
(50, Fuel.HEAT_NETWORK), # electricity for distribution pumping
],
)
def test_table_32_codes_map_to_their_billing_fuel(code: int, fuel: Fuel) -> None:
# Arrange / Act / Assert
assert sap_code_to_fuel(code) == fuel
@pytest.mark.parametrize(
("api_code", "fuel"),
[
(26, Fuel.MAINS_GAS), # gov-API mains-gas enum -> Table 32 code 1
(0, Fuel.ELECTRICITY), # API "electricity" -> Table 32 code 30
(25, Fuel.HEAT_NETWORK), # API community heat -> Table 32 code 41
(14, Fuel.COAL), # API house coal -> Table 32 code 11
(39, Fuel.ELECTRICITY), # "electricity, any tariff" -> Table 32 code 30
],
)
def test_raw_api_fuel_codes_normalize_before_mapping(api_code: int, fuel: Fuel) -> None:
# Arrange — the calculator may carry a raw gov-API fuel code (not yet a Table
# 32 code); sap_code_to_fuel normalizes via the calculator's own helper first.
# Act / Assert
assert sap_code_to_fuel(api_code) == fuel
def test_an_unmapped_code_raises_rather_than_guessing() -> None:
# Arrange — grid-export code 60 is not an end use's input fuel, so it has no
# billing carrier (code 10 dual fuel is now mapped — see the parametrized test).
# Act / Assert
with pytest.raises(UnmappedSapCode):
sap_code_to_fuel(60)