|
133 | 133 | arpu_uplift_percent: number | null; |
134 | 134 | churn_reduction: number | null; |
135 | 135 | acquisition_uplift: number | null; |
| 136 | + gross_margin: number | null; |
| 137 | + adoption_ramp_months: number | null; |
136 | 138 | }; |
137 | 139 | let overrides = $state<OverrideRow[]>([]); |
138 | 140 | let openOverrides = $state<Record<string, boolean>>({}); |
|
147 | 149 | arpu_uplift: o.arpu_uplift !== null ? parseFloat(o.arpu_uplift as any) : null, |
148 | 150 | arpu_uplift_percent: o.arpu_uplift_percent !== null ? o.arpu_uplift_percent / 100 : null, |
149 | 151 | churn_reduction: o.churn_reduction !== null ? o.churn_reduction / 100 : null, |
150 | | - acquisition_uplift: o.acquisition_uplift !== null ? o.acquisition_uplift / 100 : null |
| 152 | + acquisition_uplift: o.acquisition_uplift !== null ? o.acquisition_uplift / 100 : null, |
| 153 | + gross_margin: o.gross_margin !== null ? o.gross_margin / 100 : null, |
| 154 | + adoption_ramp_months: o.adoption_ramp_months !== null ? parseInt(o.adoption_ramp_months as any) : null |
151 | 155 | })))); |
152 | 156 |
|
153 | 157 | // Sync overrides structure to selection |
|
164 | 168 | target_type: 'all_clients', target_id: 'all', name: 'Global Client Base', |
165 | 169 | monthly_churn_rate: null, monthly_acquisition: null, acquisition_growth_rate: null, |
166 | 170 | ai_adoption_rate: null, retention_floor: null, expansion_rate: null, arpu_override: null, |
167 | | - arpu_uplift: null, arpu_uplift_percent: null, churn_reduction: null, acquisition_uplift: null |
| 171 | + arpu_uplift: null, arpu_uplift_percent: null, churn_reduction: null, acquisition_uplift: null, |
| 172 | + gross_margin: null, adoption_ramp_months: null |
168 | 173 | }); |
169 | 174 | } else if (_scopeType === 'cohorts') { |
170 | 175 | for (const c of data.cohorts) { |
|
174 | 179 | target_type: 'cohort', target_id: c.id, name: c.name, |
175 | 180 | monthly_churn_rate: null, monthly_acquisition: null, acquisition_growth_rate: null, |
176 | 181 | ai_adoption_rate: null, retention_floor: null, expansion_rate: null, arpu_override: null, |
177 | | - arpu_uplift: null, arpu_uplift_percent: null, churn_reduction: null, acquisition_uplift: null |
| 182 | + arpu_uplift: null, arpu_uplift_percent: null, churn_reduction: null, acquisition_uplift: null, |
| 183 | + gross_margin: null, adoption_ramp_months: null |
178 | 184 | }); |
179 | 185 | } |
180 | 186 | } |
|
311 | 317 | arpu_uplift: ov.arpu_uplift, |
312 | 318 | arpu_uplift_percent: ov.arpu_uplift_percent !== null ? Math.round(ov.arpu_uplift_percent * 1000) / 10 : null, |
313 | 319 | churn_reduction: ov.churn_reduction !== null ? Math.round(ov.churn_reduction * 1000) / 10 : null, |
314 | | - acquisition_uplift: ov.acquisition_uplift !== null ? Math.round(ov.acquisition_uplift * 1000) / 10 : null |
| 320 | + acquisition_uplift: ov.acquisition_uplift !== null ? Math.round(ov.acquisition_uplift * 1000) / 10 : null, |
| 321 | + gross_margin: ov.gross_margin !== null && ov.gross_margin !== undefined ? ov.gross_margin * 100 : null, |
| 322 | + adoption_ramp_months: ov.adoption_ramp_months ?? null |
315 | 323 | }; |
316 | 324 | }); |
317 | 325 | } else { |
|
369 | 377 | arpu_uplift: o.arpu_uplift !== null ? parseFloat(o.arpu_uplift as any) : null, |
370 | 378 | arpu_uplift_percent: o.arpu_uplift_percent !== null ? o.arpu_uplift_percent / 100 : null, |
371 | 379 | churn_reduction: o.churn_reduction !== null ? o.churn_reduction / 100 : null, |
372 | | - acquisition_uplift: o.acquisition_uplift !== null ? o.acquisition_uplift / 100 : null |
| 380 | + acquisition_uplift: o.acquisition_uplift !== null ? o.acquisition_uplift / 100 : null, |
| 381 | + gross_margin: o.gross_margin !== null ? o.gross_margin / 100 : null, |
| 382 | + adoption_ramp_months: o.adoption_ramp_months !== null ? parseInt(o.adoption_ramp_months as any) : null |
373 | 383 | })); |
374 | 384 | return resolveScenarioCohortsClient(scopeType, data.cohorts, selectedCohorts, formattedOverrides as any[]); |
375 | 385 | }); |
|
385 | 395 | arpu_uplift: o.arpu_uplift !== null ? parseFloat(o.arpu_uplift as any) : null, |
386 | 396 | arpu_uplift_percent: o.arpu_uplift_percent !== null ? o.arpu_uplift_percent / 100 : null, |
387 | 397 | churn_reduction: o.churn_reduction !== null ? o.churn_reduction / 100 : null, |
388 | | - acquisition_uplift: o.acquisition_uplift !== null ? o.acquisition_uplift / 100 : null |
| 398 | + acquisition_uplift: o.acquisition_uplift !== null ? o.acquisition_uplift / 100 : null, |
| 399 | + gross_margin: o.gross_margin !== null ? o.gross_margin / 100 : null, |
| 400 | + adoption_ramp_months: o.adoption_ramp_months !== null ? parseInt(o.adoption_ramp_months as any) : null |
389 | 401 | })); |
390 | 402 |
|
391 | 403 | return buildDraftScenario( |
|
846 | 858 | arpu_uplift: { label: 'AI ARPU Uplift ($ Flat)', chip: 'ARPU Uplift $', isPercent: false, symbol: '$' }, |
847 | 859 | arpu_uplift_percent: { label: 'AI ARPU Uplift (%)', chip: 'ARPU Uplift %', isPercent: true, symbol: '%' }, |
848 | 860 | churn_reduction: { label: 'AI Churn Reduction', chip: 'Churn Reduction', isPercent: true, symbol: '%' }, |
849 | | - acquisition_uplift: { label: 'AI Acquisition Uplift', chip: 'Acquisition Uplift', isPercent: true, symbol: '%' } |
| 861 | + acquisition_uplift: { label: 'AI Acquisition Uplift', chip: 'Acquisition Uplift', isPercent: true, symbol: '%' }, |
| 862 | + gross_margin: { label: 'Gross Margin (%)', chip: 'Gross Margin', isPercent: true, symbol: '%' }, |
| 863 | + adoption_ramp_months: { label: 'Adoption Ramp (months)', chip: 'Ramp Months', isPercent: false, symbol: 'mo' } |
850 | 864 | }; |
851 | 865 |
|
852 | 866 | function getCohortListForTarget(ov: OverrideRow) { |
|
1373 | 1387 | <Label class="text-xs font-semibold">AI Adoption Rate (%)</Label> |
1374 | 1388 | <Input type="number" step="0.1" min="0" max="100" placeholder="Inherit" bind:value={ov.ai_adoption_rate} class="bg-background text-xs font-mono" /> |
1375 | 1389 | </div> |
| 1390 | + <div class="space-y-1"> |
| 1391 | + <Label class="text-xs font-semibold">Gross Margin (%)</Label> |
| 1392 | + <Input type="number" step="0.1" min="0" max="100" placeholder="Inherit" bind:value={ov.gross_margin} class="bg-background text-xs font-mono" /> |
| 1393 | + </div> |
| 1394 | + <div class="space-y-1"> |
| 1395 | + <Label class="text-xs font-semibold">Adoption Ramp (months)</Label> |
| 1396 | + <Input type="number" step="1" min="0" max="120" placeholder="Inherit" bind:value={ov.adoption_ramp_months} class="bg-background text-xs font-mono" /> |
| 1397 | + </div> |
1376 | 1398 | </div> |
1377 | 1399 | </div> |
1378 | 1400 |
|
|
0 commit comments