From b52b38e6f330413ec5c2b66a9cd4cc1938aeb3b5 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Mon, 13 Jul 2026 23:11:36 +0000 Subject: [PATCH] =?UTF-8?q?Roll=20up=20each=20Property's=20SAP=20points=20?= =?UTF-8?q?and=20savings=20across=20its=20measures=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- domain/scenario_export/scenario_sheet.py | 25 +++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/domain/scenario_export/scenario_sheet.py b/domain/scenario_export/scenario_sheet.py index 3d9dfda7b..33871d923 100644 --- a/domain/scenario_export/scenario_sheet.py +++ b/domain/scenario_export/scenario_sheet.py @@ -44,6 +44,20 @@ MEASURE_COLUMNS: tuple[str, ...] = ( # Property identity columns, leading every sheet before the measure columns. _ID_COLUMNS: tuple[str, ...] = ("property_id", "landlord_property_id") +# Per-Property roll-ups of the selected measures' attributed impact, trailing the +# measure columns (ADR-0065). +_SAVINGS_COLUMNS: tuple[str, ...] = ( + "sap_points", + "co2_equivalent_savings", + "kwh_savings", + "energy_cost_savings", +) + + +def _sum(values: Sequence[Optional[float]]) -> float: + """Sum optional numbers, treating an absent contribution as zero.""" + return sum(value or 0.0 for value in values) + @dataclass(frozen=True) class ExportMeasure: @@ -111,7 +125,7 @@ def shape_scenario_sheet( properties: Sequence[PropertyScenarioData], ) -> ExportSheet: """Shape one Scenario's Properties into a wide export sheet (ADR-0065).""" - columns: tuple[str, ...] = _ID_COLUMNS + MEASURE_COLUMNS + columns: tuple[str, ...] = _ID_COLUMNS + MEASURE_COLUMNS + _SAVINGS_COLUMNS rows: list[dict[str, Any]] = [] for prop in properties: row: dict[str, Any] = { @@ -125,5 +139,14 @@ def shape_scenario_sheet( for measure in prop.measures: if measure.measure_type in MEASURE_COLUMNS: row[measure.measure_type] = measure.estimated_cost + # Roll the selected measures' attributed impact up to the Property. + row["sap_points"] = _sum([m.sap_points for m in prop.measures]) + row["co2_equivalent_savings"] = _sum( + [m.co2_equivalent_savings for m in prop.measures] + ) + row["kwh_savings"] = _sum([m.kwh_savings for m in prop.measures]) + row["energy_cost_savings"] = _sum( + [m.energy_cost_savings for m in prop.measures] + ) rows.append(row) return ExportSheet(columns=columns, rows=tuple(rows))