docs: add migration notebook and clarify export usage

This commit is contained in:
2026-07-07 21:29:29 -04:00
parent 99da955377
commit 0c3e927f23
7 changed files with 8981 additions and 1536 deletions

View File

@@ -0,0 +1,83 @@
"""
Migration + WFM scenario — the no-AI business case.
Current state → Genesys Cloud CX migration, NA users migrated onto
Genesys WFM, WFM implemented for APAC (ANZ + ASIA). Migration and WFM
are included in the base implementation price (the verbatim PS +
training), so the only cost lines are the existing-platform run-off,
the licence ramp, and base PS — no token consumption, no AI
implementation labour. The only benefits kept are the deck's verbatim
WFM lines for the regions in WFM scope.
Single source of truth behind ``notebooks/ctm_migration_wfm.ipynb``
(served with Mercury) — the presentation layer holds no math. All
primitives come from :mod:`tokencalc.appendix4`; this module only
scopes and extrapolates.
"""
from __future__ import annotations
import math
import pandas as pd
from . import appendix4 as a4
#: WFM scope in this scenario. NA is a migration off its existing
#: WFM-like tool (verbatim benefit $0 — "has similar feature"); ANZ and
#: ASIA are new implementations ("APAC"); EMEA is out of scope, so the
#: deck's EMEA WFM benefit line is dropped.
DEFAULT_WFM_REGIONS = ["NA", "ANZ", "ASIA"]
def wfm_benefits_by_year(
benefit_rollout, regions: list[str] | None = None
) -> pd.DataFrame:
"""Verbatim WFM benefits for the scoped regions, phased on the
deck's deployment schedule (realize = impl + 3 months, inclusive).
Long DataFrame: region, capability, year, benefit — the WFM slice
of :func:`tokencalc.appendix4.benefits_by_year`.
"""
scope = DEFAULT_WFM_REGIONS if regions is None else regions
df = a4.benefits_by_year(benefit_rollout)
return df[(df["capability"] == "WFM")
& (df["region"].isin(scope))].reset_index(drop=True)
def wfm_annual_runrate(regions: list[str] | None = None) -> float:
"""Sum of the verbatim WFM *annual* values for the scoped regions."""
scope = DEFAULT_WFM_REGIONS if regions is None else regions
return float(sum(annual for (r, c), (annual, _t) in
a4.VERBATIM_BENEFITS.items()
if c == "WFM" and r in scope))
def runrate_saving_annual(
licence_annual: float | None = None,
regions: list[str] | None = None,
baseline_annual: float | None = None,
) -> float:
"""Steady-state annual saving once term contracts end and the ramp
is over: (baseline licence run-rate) + scoped WFM annual values.
"""
lic = a4.TCO_VERBATIM["ccaas_annual"] if licence_annual is None else licence_annual
base = a4.TCO_VERBATIM["current_annual"] if baseline_annual is None else baseline_annual
return (base - lic) + wfm_annual_runrate(regions)
def runrate_breakeven_label(
net_by_year: dict[int, float], runrate_annual: float
) -> str:
"""Payback label, extrapolated past the model window at a run-rate.
Inside 2026-28 this defers to :func:`tokencalc.appendix4.payback_label`;
a deficit at end-2028 fills at ``runrate_annual`` per year.
"""
deficit = -sum(net_by_year[y] for y in a4.YEARS)
if deficit <= 0:
return a4.payback_label(net_by_year)
if runrate_annual <= 0:
return "never at current run-rate"
m = 12 * len(a4.YEARS) + math.ceil(12 * deficit / runrate_annual)
return f"{m} months (~{a4.month_label(m)}, extrapolated)"