mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
The Plan derives its Valuation Uplift (ADR-0018) from its baseline -> post band jump and works+contingency cost, given one external input — the Property's current market value (a Property Valuation, mostly absent). `Plan.valuation` / `Plan.baseline_epc_rating` are derived like the other headline figures; `PlanModel.from_domain` maps the £ forms to the live plan.valuation_* columns (NULL when no value — the percentage is not persisted on those columns). `Property.current_market_value` is the new optional source; the orchestrator threads it onto the Plan. `run_one` takes a `current_market_value` so the harness can value the uplift, and the sense-check table shows the average % (always) plus the £ forms when known. Sourcing the current market value (upload / default) remains deferred (ADR-0018); it is None throughout until that lands, so the columns stay NULL at scale. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
90 lines
2.9 KiB
Python
90 lines
2.9 KiB
Python
"""The sense-check table the DB-less harness prints for a Plan."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from domain.modelling.plan import Plan, PlanMeasure
|
|
from domain.modelling.recommendation import Cost
|
|
from domain.modelling.scoring.package_scorer import Score
|
|
from domain.modelling.scoring.scoring import MeasureImpact
|
|
from harness.plan_table import format_plan_table
|
|
|
|
|
|
def _plan() -> Plan:
|
|
baseline = Score(
|
|
sap_continuous=57.4, co2_kg_per_yr=3000.0, primary_energy_kwh_per_yr=300.0
|
|
)
|
|
post = Score(
|
|
sap_continuous=61.2, co2_kg_per_yr=2100.0, primary_energy_kwh_per_yr=240.0
|
|
)
|
|
measures = (
|
|
PlanMeasure(
|
|
measure_type="cavity_wall_insulation",
|
|
description="Cavity wall insulation",
|
|
cost=Cost(total=500.0, contingency_rate=0.1),
|
|
impact=MeasureImpact(
|
|
sap_points=3.1,
|
|
co2_savings_kg_per_yr=600.0,
|
|
energy_savings_kwh_per_yr=1200.0,
|
|
),
|
|
kwh_savings=900.0,
|
|
energy_cost_savings=120.0,
|
|
),
|
|
PlanMeasure(
|
|
measure_type="mechanical_ventilation",
|
|
description="Mechanical extract ventilation",
|
|
cost=Cost(total=900.0, contingency_rate=0.26),
|
|
impact=MeasureImpact(
|
|
sap_points=-1.3,
|
|
co2_savings_kg_per_yr=-50.0,
|
|
energy_savings_kwh_per_yr=-200.0,
|
|
),
|
|
kwh_savings=-150.0,
|
|
energy_cost_savings=-30.0,
|
|
),
|
|
)
|
|
return Plan(measures=measures, baseline=baseline, post_retrofit=post)
|
|
|
|
|
|
def test_table_shows_valuation_uplift_with_pounds() -> None:
|
|
# Arrange — a £200k property modelled D (57.4) -> C (72.0).
|
|
baseline = Score(
|
|
sap_continuous=57.4, co2_kg_per_yr=3000.0, primary_energy_kwh_per_yr=300.0
|
|
)
|
|
post = Score(
|
|
sap_continuous=72.0, co2_kg_per_yr=2100.0, primary_energy_kwh_per_yr=240.0
|
|
)
|
|
plan = Plan(
|
|
measures=(),
|
|
baseline=baseline,
|
|
post_retrofit=post,
|
|
current_market_value=200_000.0,
|
|
)
|
|
|
|
# Act
|
|
table: str = format_plan_table(plan)
|
|
|
|
# Assert — the valuation line shows the average % uplift and its £ forms.
|
|
assert "valuation uplift" in table
|
|
assert "+2.5%" in table
|
|
assert "£5,000" in table
|
|
assert "£205,000" in table
|
|
|
|
|
|
def test_table_shows_package_transition_and_each_measure() -> None:
|
|
# Arrange
|
|
plan: Plan = _plan()
|
|
|
|
# Act
|
|
table: str = format_plan_table(plan)
|
|
|
|
# Assert — the package SAP transition (both bands resolve to D), and each
|
|
# measure's signed SAP contribution against its type.
|
|
assert "57.4" in table
|
|
assert "61.2" in table
|
|
assert "(D)" in table
|
|
assert "cavity_wall_insulation" in table
|
|
assert "+3.1" in table
|
|
assert "mechanical_ventilation" in table
|
|
assert "-1.3" in table
|
|
# The package cost of works (500 + 900) appears.
|
|
assert "1,400" in table
|