- Add 202512_GenesysCX TEI study (config, seed data, notebooks, README) with NPV $10.8M / ROI 266% including AI-token cost line - Add explicit `key` parameter to all chart wrappers in app/components to prevent StreamlitDuplicateElementId errors when the same figure type renders across Summary/Benefits/Costs tabs - Render benefits bar and cost pie charts on their respective tabs - Add benefits_vs_costs_by_year chart wrapper
69 lines
2.1 KiB
Python
69 lines
2.1 KiB
Python
"""Costs data-entry tab."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import streamlit as st
|
|
|
|
from app.components import charts
|
|
from app.components.tables import df_to_values, value_editor
|
|
from app.utils import icon
|
|
|
|
from app.views._helpers import report_meta, safe
|
|
from core.tei_client import TEIClient
|
|
|
|
|
|
def render(client: TEIClient, tool: dict) -> None:
|
|
st.markdown(
|
|
f"<h2>{icon('receipt')} Costs</h2>",
|
|
unsafe_allow_html=True,
|
|
)
|
|
public_id = tool["id"]
|
|
report = report_meta(client, tool)
|
|
analysis_years = int(report.get("analysis_period_years") or 3)
|
|
|
|
fields = safe(client.list_fields, report.get("id"), "costs") or []
|
|
values = [v for v in safe(client.get_values, public_id) or [] if v.get("table") == "costs"]
|
|
|
|
if not fields:
|
|
st.info("This report template has no cost fields defined.")
|
|
return
|
|
|
|
edited = value_editor(
|
|
"costs",
|
|
fields,
|
|
values,
|
|
analysis_years=analysis_years,
|
|
key=f"costs_editor_{public_id}",
|
|
)
|
|
|
|
col1, col2 = st.columns([1, 4])
|
|
with col1:
|
|
if st.button("Save costs", width="stretch"):
|
|
|
|
payload = df_to_values(edited, "costs", analysis_years)
|
|
result = safe(client.update_values, public_id, payload)
|
|
if result is not None:
|
|
st.success(f"Saved {len(payload)} cost values.")
|
|
st.cache_data.clear()
|
|
with col2:
|
|
st.caption(
|
|
"The Initial column is undiscounted year-0 spend. Year columns "
|
|
"are end-of-year cashflows. Costs are risk-adjusted upward "
|
|
"(higher risk → higher cost)."
|
|
)
|
|
|
|
if values:
|
|
st.divider()
|
|
col_pie, col_year = st.columns(2)
|
|
with col_pie:
|
|
charts.cost_pie(values, key=f"costs_tab_pie_{public_id}")
|
|
with col_year:
|
|
benefit_values = [
|
|
v
|
|
for v in safe(client.get_values, public_id) or []
|
|
if v.get("table") == "benefits"
|
|
]
|
|
charts.benefits_vs_costs_by_year(
|
|
benefit_values, values, key=f"costs_tab_by_year_{public_id}"
|
|
)
|