mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
test(modelling): characterise the portfolio aggregation over plan_id
Pin the FE-facing aggregate_portfolio_recommendations (previously untested): it sums a Scenario's default Recommendations onto the Scenario row, joining Recommendation → Plan on recommendation.plan_id. Locks the m2m→plan_id read cut for the FE-critical path, now testable thanks to the full-parity ScenarioModel. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
c18968ba3c
commit
6f0dcc0455
1 changed files with 96 additions and 0 deletions
96
backend/app/db/functions/tests/test_portfolio_functions.py
Normal file
96
backend/app/db/functions/tests/test_portfolio_functions.py
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
"""Characterisation of the FE-facing portfolio aggregation
|
||||
(`aggregate_portfolio_recommendations`): it sums a Scenario's **default**
|
||||
Recommendations and writes the totals onto the Scenario row.
|
||||
|
||||
This pins the `recommendation.plan_id` linkage the m2m retirement introduced
|
||||
(ADR-0017 amendment): the aggregation joins Recommendation → Plan on
|
||||
`recommendation.plan_id`, so only measures carrying the right `plan_id` (and
|
||||
`default = True`) are summed.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from sqlmodel import Session
|
||||
|
||||
from backend.app.db.functions.portfolio_functions import (
|
||||
aggregate_portfolio_recommendations,
|
||||
)
|
||||
from backend.app.db.models.recommendations import (
|
||||
PlanModel,
|
||||
Recommendation,
|
||||
ScenarioModel,
|
||||
)
|
||||
from domain.modelling.portfolio_goal import PortfolioGoal
|
||||
|
||||
|
||||
def _rec(
|
||||
*, plan_id: int, default: bool, cost: float, kwh: float, gbp: float, co2: float
|
||||
) -> Recommendation:
|
||||
return Recommendation(
|
||||
property_id=10,
|
||||
plan_id=plan_id,
|
||||
type="cavity_wall_insulation",
|
||||
measure_type="cavity_wall_insulation",
|
||||
description="Cavity wall insulation",
|
||||
estimated_cost=cost,
|
||||
kwh_savings=kwh,
|
||||
energy_cost_savings=gbp,
|
||||
co2_equivalent_savings=co2,
|
||||
total_work_hours=4.0,
|
||||
default=default,
|
||||
already_installed=False,
|
||||
)
|
||||
|
||||
|
||||
def test_aggregation_sums_default_measures_linked_by_plan_id(
|
||||
db_session: Session,
|
||||
) -> None:
|
||||
# Arrange — one Scenario + Plan, two default measures (summed) plus a
|
||||
# non-default one (excluded), all linked by recommendation.plan_id.
|
||||
db_session.add(
|
||||
ScenarioModel(
|
||||
id=7,
|
||||
portfolio_id=1,
|
||||
goal=PortfolioGoal.INCREASING_EPC,
|
||||
goal_value="C",
|
||||
is_default=True,
|
||||
)
|
||||
)
|
||||
db_session.add(
|
||||
PlanModel(id=100, portfolio_id=1, property_id=10, scenario_id=7, is_default=True)
|
||||
)
|
||||
db_session.add_all(
|
||||
[
|
||||
_rec(plan_id=100, default=True, cost=1000.0, kwh=500.0, gbp=120.0, co2=0.5),
|
||||
_rec(plan_id=100, default=True, cost=500.0, kwh=300.0, gbp=80.0, co2=0.2),
|
||||
# excluded: not default
|
||||
_rec(plan_id=100, default=False, cost=9.0, kwh=9.0, gbp=9.0, co2=9.0),
|
||||
]
|
||||
)
|
||||
db_session.commit()
|
||||
|
||||
# Act
|
||||
aggregate_portfolio_recommendations(
|
||||
db_session,
|
||||
portfolio_id=1,
|
||||
scenario_id=7,
|
||||
total_valuation_increase=2500.0,
|
||||
labour_days=3.0,
|
||||
aggregated_data={},
|
||||
)
|
||||
db_session.commit()
|
||||
|
||||
# Assert — the default measures' sums land on the Scenario row
|
||||
scenario = db_session.query(ScenarioModel).filter_by(id=7).one()
|
||||
assert scenario.cost is not None
|
||||
assert abs(scenario.cost - 1500.0) <= 1e-9 # 1000 + 500
|
||||
assert scenario.energy_savings is not None
|
||||
assert abs(scenario.energy_savings - 800.0) <= 1e-9 # Σ kwh_savings
|
||||
assert scenario.energy_cost_savings is not None
|
||||
assert abs(scenario.energy_cost_savings - 200.0) <= 1e-9 # 120 + 80
|
||||
assert scenario.co2_equivalent_savings is not None
|
||||
assert abs(scenario.co2_equivalent_savings - 0.7) <= 1e-9 # 0.5 + 0.2
|
||||
assert scenario.total_work_hours is not None
|
||||
assert abs(scenario.total_work_hours - 8.0) <= 1e-9 # 4 + 4
|
||||
assert scenario.property_valuation_increase == 2500.0
|
||||
assert scenario.labour_days == 3.0
|
||||
Loading…
Add table
Reference in a new issue