{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "0cc8c06b",
   "metadata": {},
   "source": [
    "# SaaS 收入治理 — 核心指标仪表盘\n",
    "\n",
    "对应案例: [SaaS 收入治理](/docs/case-studies/strategy/saas-revenue-governance-case/)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a04504a",
   "metadata": {},
   "source": [
    "## 1. 模拟 SaaS 数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e6d9d798",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np, pandas as pd, matplotlib.pyplot as plt\n",
    "np.random.seed(42)\n",
    "months=24\n",
    "n_start=100; mrr_start=50000\n",
    "mrr=[mrr_start]; customers=[n_start]\n",
    "new_mrr=[]; churn_mrr=[]; expansion_mrr=[]\n",
    "for m in range(1,months):\n",
    "    new=round(np.random.normal(5000,1000))\n",
    "    churn=round(mrr[-1]*np.random.uniform(0.03,0.06))\n",
    "    expansion=round(mrr[-1]*np.random.uniform(0.01,0.04))\n",
    "    curr=mrr[-1]+new-churn+expansion\n",
    "    if curr<1000: curr=1000\n",
    "    mrr.append(curr)\n",
    "    customers.append(round(customers[-1]*(1+np.random.normal(0.03,0.01))))\n",
    "    new_mrr.append(new); churn_mrr.append(churn); expansion_mrr.append(expansion)\n",
    "df=pd.DataFrame({'month':range(months),'MRR':mrr,'Customers':customers})\n",
    "df['ARPU']=df['MRR']/df['Customers']\n",
    "print(df.tail().round(0))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4f8c76d8",
   "metadata": {},
   "source": [
    "## 2. 关键指标"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a5ea2d49",
   "metadata": {},
   "outputs": [],
   "source": [
    "growth=(df['MRR'].iloc[-1]/df['MRR'].iloc[0])**(1/months)-1\n",
    "churn_rate=np.mean(churn_mrr)/np.mean(mrr[1:])\n",
    "ltv_guess=df['ARPU'].iloc[-1]/churn_rate if churn_rate>0 else float('inf')\n",
    "print(f'MRR: ${mrr_start:,.0f} -> ${mrr[-1]:,.0f}')\n",
    "print(f'Monthly growth: {growth:.1%}')\n",
    "print(f'Avg churn rate: {churn_rate:.1%}')\n",
    "print(f'ARPU: ${df.ARPU.iloc[-1]:.0f}')\n",
    "print(f'LTV (guess): ${ltv_guess:,.0f}')\n",
    "# Rule of 40\n",
    "growth_pct=growth*100\n",
    "profit_margin=15  # assume\n",
    "rule_40_score=growth_pct+profit_margin\n",
    "print(f'Rule of 40: {rule_40_score:.0f}% ({\"PASS\" if rule_40_score>=40 else \"FAIL\"})')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7ab25cb0",
   "metadata": {},
   "source": [
    "## 3. 瀑布图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4d8b36b5",
   "metadata": {},
   "outputs": [],
   "source": [
    "# MRR waterfall\n",
    "labels=['Start','+New','-Churn','+Expansion','End']\n",
    "values=[mrr_start,sum(new_mrr),-sum(churn_mrr),sum(expansion_mrr),mrr[-1]]\n",
    "colors=['#2196F3','#4CAF50','#F44336','#FF9800','#2196F3']\n",
    "fig,ax=plt.subplots(figsize=(10,6))\n",
    "bottom=0\n",
    "for i,(l,v,c) in enumerate(zip(labels,values,colors)):\n",
    "    if v>=0:\n",
    "        ax.bar(l,v,bottom=bottom,color=c,alpha=0.8)\n",
    "        ax.text(i,bottom+v/2,f'${v:,.0f}',ha='center',va='center')\n",
    "        bottom+=v\n",
    "    else:\n",
    "        ax.bar(l,abs(v),bottom=bottom-abs(v),color=c,alpha=0.8)\n",
    "        ax.text(i,bottom-abs(v)/2,f'-${abs(v):,.0f}',ha='center',va='center')\n",
    "        bottom-=abs(v)\n",
    "ax.set_ylabel('MRR ($)'); ax.set_title('MRR Waterfall')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f0c0539f",
   "metadata": {},
   "source": [
    "---\n",
    "*更多分析见 [案例文档](/docs/case-studies/strategy/saas-revenue-governance-case/)*"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.10.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
