"""Appendix-4 corrected business case — hand-check acceptance numbers.""" from __future__ import annotations import datetime as dt import math import pytest from tokencalc import appendix4 as a4 from tokencalc.defaults import CTM_DEFAULT_SITES, DEFAULT_METERS, DEFAULT_PRICING SITES = list(CTM_DEFAULT_SITES) def test_verbatim_crossfoots_to_slide_totals(): df = a4.verbatim_dataframe() for r, expect in a4.SLIDE_TOTALS["regional_3yr"].items(): got = df.loc[df.region == r, "three_yr"].sum() assert abs(got - expect) <= a4.crossfoot_tolerance(expect), r for c, expect in a4.SLIDE_TOTALS["capability_3yr"].items(): got = df.loc[df.capability == c, "three_yr"].sum() assert abs(got - expect) <= a4.crossfoot_tolerance(expect), c assert abs(df["three_yr"].sum() - a4.SLIDE_TOTALS["total_3yr"]) <= \ a4.crossfoot_tolerance(a4.SLIDE_TOTALS["total_3yr"]) def test_benefits_phase_on_the_deck_schedule(): _, _, benefit_rollout = a4.build_rollouts(SITES) long = a4.benefits_by_year(benefit_rollout) by_year = long.groupby("year")["benefit"].sum() assert by_year[2026] == 0.0, "2026 must be $0 under Genesys's own schedule" # Scaling at the finest grain reproduces every verbatim 3-yr value exactly. for (region, cap), (_, three_yr) in a4.VERBATIM_BENEFITS.items(): got = long.query("region == @region and capability == @cap")["benefit"].sum() assert got == pytest.approx(three_yr) def test_ramp_zeroes_year_one_licences(): assert a4.licence_costs_by_year(12) == {2026: 0.0, 2027: 4_300_000.0, 2028: 4_300_000.0} assert a4.licence_costs_by_year(0)[2026] == 4_300_000.0 assert a4.licence_costs_by_year(18)[2027] == pytest.approx(4_300_000 * 6 / 12) # The order form's ramp is 6 months — licences bill from July 2026. assert a4.DEFAULT_RAMP_MONTHS == 6 assert a4.licence_costs_by_year() == {2026: 2_150_000.0, 2027: 4_300_000.0, 2028: 4_300_000.0} def test_current_state_run_off(): cs = a4.current_state_inputs(SITES) assert cs["annual_cost"].sum() == pytest.approx(7_300_000) by_year = a4.current_costs_by_year(cs) assert by_year == {2026: pytest.approx(7_300_000), 2027: pytest.approx(7_300_000), 2028: 0.0} cs.loc["NA", "contract_termination"] = dt.date(2028, 6, 30) assert a4.current_costs_by_year(cs)[2028] == pytest.approx( cs.loc["NA", "annual_cost"] * 6 / 12) def test_token_hand_checks(): token_ro, email_ro, _ = a4.build_rollouts(SITES) core, email = a4.build_scopes(SITES, copilot_includes_asia=False) meters = {**DEFAULT_METERS, "Email AI (Auto-Respond)": a4.autorespond_meter(0.05)} long = a4.token_costs_by_year(SITES, meters, DEFAULT_PRICING, a4.claim_scenario(0.255), core, email, token_ro, email_ro) # STA 2028: NAM/AUZ/EMEA × 12 months + ASIA × 10 months, by hand. sta = long.query("cost_line == 'Speech & Text Analytics [named]'") assert sta.query("year == 2028")["annual_cost"].sum() == pytest.approx(715_800) # Agent Copilot 2028 (ASIA off): 1,490 users × 40 tokens × 12 months. cp = long.query("cost_line == 'Agent Copilot [named]' and year == 2028") assert cp["annual_cost"].sum() == pytest.approx(1_490 * 40 * 12) # Rule 1: Copilot covers AI Summary at Copilot sites. assert (long.query("cost_line == 'AI Summary & Insights'")["annual_cost"] == 0).all() # Nothing is live in 2026. assert long.query("year == 2026")["annual_cost"].sum() == 0 # PR NAM steady-month tokens. assert math.ceil( 1_214_358 * DEFAULT_METERS["Predictive Routing"].tokens_per_unit) == 71_433 def test_impl_costs_reconcile_with_v2_doc(): _, impl_y, kb_y, steady_y = a4.build_impl_costs(SITES, "mid", 225.0, include_kb=True) assert sum(impl_y.values()) == pytest.approx(5_850 * 225) # V2's "$1.3M" assert sum(kb_y.values()) == pytest.approx(1_000 * 225) assert steady_y == {2026: 0.0, 2027: pytest.approx(700 * 225), 2028: pytest.approx(700 * 225)} # Impl spend is fully booked by each region's implementation month. assert a4.impl_year_fractions(18) == pytest.approx([12 / 18, 6 / 18, 0.0]) assert a4.impl_year_fractions(27) == pytest.approx([12 / 27, 12 / 27, 3 / 27]) def test_case_flows_and_kpis(): benefits = {2026: 0.0, 2027: 2_000_000.0, 2028: 12_000_000.0} costs = {2026: 10_000_000.0, 2027: 13_000_000.0, 2028: 8_000_000.0} inc, net = a4.case_flows(costs, benefits) assert inc == {2026: pytest.approx(2_700_000), 2027: pytest.approx(5_700_000), 2028: pytest.approx(700_000)} for y in a4.YEARS: assert net[y] == pytest.approx(benefits[y] - inc[y]) kpis = a4.case_kpis(inc, net) assert kpis["benefits_3yr"] == pytest.approx(sum(benefits.values())) assert kpis["net_3yr"] == pytest.approx(sum(net.values())) assert kpis["roi"] == pytest.approx(kpis["net_3yr"] / kpis["incremental_cost_3yr"]) assert kpis["discount_rate"] == 0.135 # Net cost saving → ROI undefined. inc2 = {y: -1.0 for y in a4.YEARS} net2 = {y: benefits[y] + 1.0 for y in a4.YEARS} assert a4.case_kpis(inc2, net2)["roi"] is None def test_contracted_overlays_verbatim(): assert a4.tco("ccaas_annual") == 3_200_000 # signed contract assert a4.TCO_VERBATIM["ccaas_annual"] == 4_300_000 # deck record intact assert a4.tco("current_annual") == a4.TCO_VERBATIM["current_annual"] assert a4.licence_costs_by_year(12, a4.tco("ccaas_annual"))[2027] == 3_200_000 def test_sow_milestones_and_managed_services(): assert a4.PS_CONTRACTED_TOTAL == pytest.approx(2_025_446.48) for m in a4.PS_MILESTONES: # amounts match the shares assert m["amount"] == pytest.approx(m["share"] * a4.PS_CONTRACTED_TOTAL, abs=0.01) ps = a4.ps_costs_by_year(contracted=True) # 50/50 across 2026-27 assert ps[2026] == pytest.approx(607_633.94 + 405_089.30 + 167_000) assert ps[2027] == pytest.approx(607_633.94 + 405_089.30) assert ps[2028] == 0.0 # The deck's verbatim year-1 lump stays intact for the as-pitched frame. assert a4.ps_costs_by_year() == {2026: 2_567_000, 2027: 0.0, 2028: 0.0} # Managed services bill from the month after MCX go-live (Sep 30 → Oct). ms = a4.managed_services_by_year() assert ms[2026] == pytest.approx(410_918.40 * 3 / 12) assert ms[2027] == pytest.approx(410_918.40) assert ms[2028] == pytest.approx(410_918.40)