{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 03 — Business Case\n", "\n", "Combine the benefits and costs into the consolidated TEI summary,\n", "render the Cash Flow chart, and run scenario analysis. This notebook\n", "should reproduce the headline numbers from the PDF Financial Summary:\n", "\n", "* **NPV $78.7M • ROI 342% • Payback <6 months**" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import sys\n", "from pathlib import Path\n", "\n", "ROOT = Path.cwd().resolve()\n", "while ROOT != ROOT.parent and not (ROOT / 'core').is_dir():\n", " ROOT = ROOT.parent\n", "if str(ROOT) not in sys.path:\n", " sys.path.insert(0, str(ROOT))\n", "STUDY = ROOT / 'studies' / '202602_AmazonConnect'\n", "if str(STUDY) not in sys.path:\n", " sys.path.insert(0, str(STUDY))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import config\n", "import seed_data\n", "from core.export import build_report_data\n", "from core.export.report_data import _compute_summary\n", "from core.notebook_helpers import charts, display, tables" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Local summary (no Athena round-trip)\n", "\n", "Compute the moderate-case TEI summary directly from `seed_data` so the\n", "notebook produces results even before the Athena tool is provisioned." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "summary = _compute_summary(\n", " seed_data.BENEFITS,\n", " seed_data.COSTS,\n", " config.DISCOUNT_RATE,\n", " config.ANALYSIS_YEARS,\n", ")\n", "# `_compute_summary` returns roi_pct; expose it as `roi` for kpi_cards.\n", "summary['roi'] = summary.get('roi_pct')\n", "display.kpi_cards(summary, title='Forrester composite — moderate case')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df_cash = tables.cashflow_table(summary)\n", "df_cash.style.format({c: '${:,.0f}' for c in df_cash.columns if c != 'Year'})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Cash flow chart\n", "\n", "Mirrors the chart on PDF page 25: stacked benefits/costs by year +\n", "cumulative-net line." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "charts.cashflow_chart(\n", " summary['yearly_breakdown'],\n", " initial_cost=summary.get('initial_costs', 0),\n", ").show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Waterfall: Benefits PV → Costs PV → NPV" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "charts.waterfall([\n", " ('Benefits PV', summary['total_benefits_pv']),\n", " ('Costs PV', -summary['total_costs_pv']),\n", " ('NPV', summary['npv']),\n", "]).show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Scenario analysis\n", "\n", "Apply the default Palladium multipliers (see `core.calculations.SCENARIOS`):\n", "\n", "* **Conservative** — 80% adoption, +10pp risk on benefits / -10pp on costs\n", "* **Moderate** — base case (= the published Forrester study)\n", "* **Aggressive** — 115% adoption, -5pp risk on benefits / +5pp on costs" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from core.calculations import apply_scenario\n", "import pandas as pd\n", "\n", "scenario_summaries = {}\n", "for name in ('conservative', 'moderate', 'aggressive'):\n", " sb = apply_scenario(seed_data.BENEFITS, name, table='benefits')\n", " sc = apply_scenario(seed_data.COSTS, name, table='costs')\n", " scenario_summaries[name] = _compute_summary(sb, sc, config.DISCOUNT_RATE, config.ANALYSIS_YEARS)\n", "\n", "scen_df = pd.DataFrame([\n", " {\n", " 'Scenario': k,\n", " 'Benefits PV': v['total_benefits_pv'],\n", " 'Costs PV': v['total_costs_pv'],\n", " 'NPV': v['npv'],\n", " 'ROI %': v['roi_pct'],\n", " 'Payback (mo)': round(v['payback_months'], 1) if v['payback_months'] is not None else None,\n", " }\n", " for k, v in scenario_summaries.items()\n", "])\n", "scen_df.style.format({\n", " 'Benefits PV': '${:,.0f}', 'Costs PV': '${:,.0f}', 'NPV': '${:,.0f}', 'ROI %': '{:,.0f}%'\n", "})" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "charts.scenario_comparison(scenario_summaries).show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Cross-check vs Athena (optional)\n", "\n", "When `TOOL_PUBLIC_ID` is set, ask Athena to recalculate the summary on\n", "the server side and confirm it matches our local computation." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if config.TOOL_PUBLIC_ID:\n", " from core.tei_client import TEIClient\n", "\n", " client = TEIClient()\n", " client.calculate(config.TOOL_PUBLIC_ID)\n", " server_summary = client.get_summary(config.TOOL_PUBLIC_ID)\n", " display.kpi_cards(server_summary, title='Athena server-side summary')\n", "else:\n", " display.alert('Set TOOL_PUBLIC_ID to compare Athena vs local.', 'info')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Continue with [`04_export.ipynb`](04_export.ipynb) →" ] } ], "metadata": { "kernelspec": {"display_name": "Python 3", "language": "python", "name": "python3"}, "language_info": {"name": "python", "version": "3.11"} }, "nbformat": 4, "nbformat_minor": 5 }