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))