redone investment scaling logic for incentiving higher investments
This commit is contained in:
parent
59c9fff27d
commit
82e362b532
4 changed files with 283 additions and 45 deletions
|
|
@ -135,30 +135,60 @@ class ROICalculator {
|
|||
}
|
||||
|
||||
// Enhanced investment scaling factor (only for direct investment)
|
||||
// Progressive scaling provides clear incentives for larger investments
|
||||
// Exponential scaling provides strong incentives for larger investments
|
||||
const baseInvestment = 500000;
|
||||
let investmentScaleFactor;
|
||||
let churnReductionFactor;
|
||||
let revenueMultiplier;
|
||||
let acceleratedBreakEvenFactor;
|
||||
|
||||
if (inputs.investmentModel === 'loan') {
|
||||
investmentScaleFactor = 1.0;
|
||||
churnReductionFactor = 1.0;
|
||||
revenueMultiplier = 1.0;
|
||||
acceleratedBreakEvenFactor = 1.0;
|
||||
} else {
|
||||
// Progressive linear scaling with clear breakpoints
|
||||
// Exponential scaling for better ROI at higher investments
|
||||
if (inputs.investmentAmount <= baseInvestment) {
|
||||
investmentScaleFactor = inputs.investmentAmount / baseInvestment;
|
||||
} else if (inputs.investmentAmount <= 1000000) {
|
||||
// 500k to 1M: Scale from 1.0x to 1.5x
|
||||
investmentScaleFactor = 1.0 + (inputs.investmentAmount - baseInvestment) / 1000000;
|
||||
// 500k to 1M: Exponential scaling (1.0x to 2.2x)
|
||||
const ratio = inputs.investmentAmount / baseInvestment;
|
||||
investmentScaleFactor = Math.pow(ratio, 1.2);
|
||||
} else if (inputs.investmentAmount <= 1500000) {
|
||||
// 1M to 1.5M: Enhanced exponential scaling (2.2x to 3.5x)
|
||||
const ratio = inputs.investmentAmount / baseInvestment;
|
||||
investmentScaleFactor = Math.pow(ratio, 1.3);
|
||||
} else {
|
||||
// 1M to 2M: Scale from 1.5x to 2.0x
|
||||
investmentScaleFactor = 1.5 + (inputs.investmentAmount - 1000000) / 2000000;
|
||||
// 1.5M to 2M: Maximum exponential scaling (3.5x to 5.0x)
|
||||
const ratio = inputs.investmentAmount / baseInvestment;
|
||||
investmentScaleFactor = Math.pow(ratio, 1.4);
|
||||
}
|
||||
|
||||
// Enhanced churn reduction with better scaling
|
||||
// Higher investment = better customer success = lower churn
|
||||
// Revenue multipliers for large investments (economies of scale)
|
||||
if (inputs.investmentAmount >= 2000000) {
|
||||
revenueMultiplier = 1.6; // 60% premium per instance
|
||||
} else if (inputs.investmentAmount >= 1500000) {
|
||||
revenueMultiplier = 1.4; // 40% premium per instance
|
||||
} else if (inputs.investmentAmount >= 1000000) {
|
||||
revenueMultiplier = 1.2; // 20% premium per instance
|
||||
} else {
|
||||
revenueMultiplier = 1.0; // No premium
|
||||
}
|
||||
|
||||
// Accelerated break-even for large investments
|
||||
if (inputs.investmentAmount >= 1500000) {
|
||||
acceleratedBreakEvenFactor = 1.4; // 40% faster break-even
|
||||
} else if (inputs.investmentAmount >= 1000000) {
|
||||
acceleratedBreakEvenFactor = 1.2; // 20% faster break-even
|
||||
} else {
|
||||
acceleratedBreakEvenFactor = 1.0; // Standard break-even
|
||||
}
|
||||
|
||||
// Enhanced churn reduction with aggressive scaling
|
||||
// Higher investment = significantly better customer success = much lower churn
|
||||
const churnReductionRatio = Math.min((inputs.investmentAmount - baseInvestment) / 1500000, 1.0);
|
||||
churnReductionFactor = Math.max(0.6, 1 - (churnReductionRatio * 0.4));
|
||||
churnReductionFactor = Math.max(0.4, 1 - (churnReductionRatio * 0.6)); // Up to 60% churn reduction
|
||||
}
|
||||
|
||||
// Calculate adjusted churn rate with investment-based reduction
|
||||
|
|
@ -171,11 +201,18 @@ class ROICalculator {
|
|||
let cumulativeServalaRevenue = 0;
|
||||
let breakEvenMonth = null;
|
||||
|
||||
// Calculate dynamic grace period based on investment size
|
||||
// Calculate enhanced grace period based on investment size
|
||||
const baseGracePeriod = inputs.gracePeriod;
|
||||
const gracePeriodBonus = Math.floor((inputs.investmentAmount - baseInvestment) / 250000);
|
||||
let gracePeriodBonus;
|
||||
if (inputs.investmentAmount >= 1500000) {
|
||||
gracePeriodBonus = 12; // 12 months extra for large investments
|
||||
} else if (inputs.investmentAmount >= 1000000) {
|
||||
gracePeriodBonus = 6; // 6 months extra for medium investments
|
||||
} else {
|
||||
gracePeriodBonus = Math.floor((inputs.investmentAmount - baseInvestment) / 250000);
|
||||
}
|
||||
const effectiveGracePeriod = inputs.investmentModel === 'loan' ? 0 :
|
||||
Math.min(baseGracePeriod + gracePeriodBonus, Math.floor(totalMonths / 2));
|
||||
Math.min(baseGracePeriod + gracePeriodBonus, Math.floor(totalMonths * 0.6)); // Up to 60% of timeframe
|
||||
|
||||
// Track baseline performance for performance bonuses (direct investment only)
|
||||
let baselineInstances = 0; // Will track expected instances without performance scaling
|
||||
|
|
@ -217,15 +254,31 @@ class ROICalculator {
|
|||
} else {
|
||||
// Direct investment model: Revenue based on instances with performance incentives
|
||||
// Service revenue (shared with Servala) + Core service revenue (100% to CSP)
|
||||
const serviceRevenue = currentInstances * inputs.revenuePerInstance;
|
||||
const coreRevenue = currentInstances * inputs.coreServiceRevenue;
|
||||
const baseServiceRevenue = currentInstances * inputs.revenuePerInstance;
|
||||
const baseCoreRevenue = currentInstances * inputs.coreServiceRevenue;
|
||||
|
||||
// Apply revenue multiplier for large investments (economies of scale)
|
||||
const serviceRevenue = baseServiceRevenue * revenueMultiplier;
|
||||
const coreRevenue = baseCoreRevenue * revenueMultiplier;
|
||||
monthlyRevenue = serviceRevenue;
|
||||
|
||||
// Calculate scaled performance bonus based on investment size
|
||||
let maxPerformanceBonus;
|
||||
if (inputs.investmentAmount >= 2000000) {
|
||||
maxPerformanceBonus = 0.35; // 35% max bonus for largest investments
|
||||
} else if (inputs.investmentAmount >= 1500000) {
|
||||
maxPerformanceBonus = 0.25; // 25% max bonus for large investments
|
||||
} else if (inputs.investmentAmount >= 1000000) {
|
||||
maxPerformanceBonus = 0.20; // 20% max bonus for medium investments
|
||||
} else {
|
||||
maxPerformanceBonus = 0.15; // 15% max bonus for base investments
|
||||
}
|
||||
|
||||
// Calculate performance bonus if CSP exceeds baseline expectations
|
||||
if (baselineInstances > 0 && month > 6) { // Start performance tracking after 6 months
|
||||
const performanceRatio = currentInstances / Math.max(baselineInstances, 1);
|
||||
if (performanceRatio > 1.1) { // 10% threshold for performance bonus
|
||||
performanceBonus = Math.max(0, Math.min(0.15, (performanceRatio - 1.1) * 0.3)); // Up to 15% bonus
|
||||
performanceBonus = Math.max(0, Math.min(maxPerformanceBonus, (performanceRatio - 1.1) * 0.5));
|
||||
adjustedServalaShare = Math.max(0.10, inputs.servalaShare - performanceBonus);
|
||||
}
|
||||
}
|
||||
|
|
@ -246,15 +299,17 @@ class ROICalculator {
|
|||
cumulativeCSPRevenue += cspRevenue;
|
||||
cumulativeServalaRevenue += servalaRevenue;
|
||||
|
||||
// Enhanced break-even calculation
|
||||
// Enhanced break-even calculation with acceleration for large investments
|
||||
let netPosition; // CSP's net financial position
|
||||
if (inputs.investmentModel === 'loan') {
|
||||
// For loan model: net position is cumulative payments received minus loan principal outstanding
|
||||
const principalPaid = inputs.investmentAmount * (month / totalMonths); // Simplified principal tracking
|
||||
netPosition = cumulativeCSPRevenue - (inputs.investmentAmount - principalPaid);
|
||||
} else {
|
||||
// For direct investment: net position is cumulative revenue minus initial investment
|
||||
netPosition = cumulativeCSPRevenue - inputs.investmentAmount;
|
||||
// For direct investment: accelerated break-even for large investments
|
||||
// Large investments benefit from faster effective cost recovery
|
||||
const adjustedInvestment = inputs.investmentAmount / acceleratedBreakEvenFactor;
|
||||
netPosition = cumulativeCSPRevenue - adjustedInvestment;
|
||||
}
|
||||
|
||||
if (breakEvenMonth === null && netPosition >= 0) {
|
||||
|
|
@ -304,10 +359,16 @@ class ROICalculator {
|
|||
|
||||
// Calculate final metrics with enhanced business intelligence
|
||||
const totalRevenue = cumulativeCSPRevenue + cumulativeServalaRevenue;
|
||||
const finalNetPosition = inputs.investmentModel === 'loan' ?
|
||||
cumulativeCSPRevenue - inputs.investmentAmount :
|
||||
cumulativeCSPRevenue - inputs.investmentAmount;
|
||||
const roi = (finalNetPosition / inputs.investmentAmount) * 100;
|
||||
let finalNetPosition, roi;
|
||||
if (inputs.investmentModel === 'loan') {
|
||||
finalNetPosition = cumulativeCSPRevenue - inputs.investmentAmount;
|
||||
roi = (finalNetPosition / inputs.investmentAmount) * 100;
|
||||
} else {
|
||||
// For direct investment: use accelerated break-even for final ROI calculation
|
||||
const adjustedInvestment = inputs.investmentAmount / acceleratedBreakEvenFactor;
|
||||
finalNetPosition = cumulativeCSPRevenue - adjustedInvestment;
|
||||
roi = (finalNetPosition / inputs.investmentAmount) * 100;
|
||||
}
|
||||
|
||||
// Calculate average performance bonus over the investment period
|
||||
const performanceBonusMonths = monthlyData.filter(m => m.performanceBonus > 0);
|
||||
|
|
@ -329,6 +390,12 @@ class ROICalculator {
|
|||
avgPerformanceBonus,
|
||||
monthlyData,
|
||||
investmentScaleFactor: investmentScaleFactor,
|
||||
revenueMultiplier: revenueMultiplier,
|
||||
acceleratedBreakEvenFactor: acceleratedBreakEvenFactor,
|
||||
maxPerformanceBonus: inputs.investmentModel === 'direct' ?
|
||||
(inputs.investmentAmount >= 2000000 ? 35 :
|
||||
inputs.investmentAmount >= 1500000 ? 25 :
|
||||
inputs.investmentAmount >= 1000000 ? 20 : 15) : 0,
|
||||
adjustedChurnRate: adjustedChurnRate * 100,
|
||||
performanceMultiplier: baselineInstances > 0 ? (currentInstances / baselineInstances) : 1.0
|
||||
};
|
||||
|
|
|
|||
|
|
@ -122,6 +122,97 @@ class ROICalculatorApp {
|
|||
updateCalculations() {
|
||||
if (this.calculator) {
|
||||
this.calculator.updateCalculations();
|
||||
this.updateInvestmentBenefits();
|
||||
}
|
||||
}
|
||||
|
||||
updateInvestmentBenefits() {
|
||||
try {
|
||||
const inputs = this.calculator.getInputValues();
|
||||
const investmentAmount = inputs.investmentAmount;
|
||||
const baseInvestment = 500000;
|
||||
|
||||
// Calculate instance scaling factor
|
||||
let scalingFactor;
|
||||
if (investmentAmount <= baseInvestment) {
|
||||
scalingFactor = investmentAmount / baseInvestment;
|
||||
} else if (investmentAmount <= 1000000) {
|
||||
const ratio = investmentAmount / baseInvestment;
|
||||
scalingFactor = Math.pow(ratio, 1.2);
|
||||
} else if (investmentAmount <= 1500000) {
|
||||
const ratio = investmentAmount / baseInvestment;
|
||||
scalingFactor = Math.pow(ratio, 1.3);
|
||||
} else {
|
||||
const ratio = investmentAmount / baseInvestment;
|
||||
scalingFactor = Math.pow(ratio, 1.4);
|
||||
}
|
||||
|
||||
// Calculate revenue premium
|
||||
let revenuePremium;
|
||||
if (investmentAmount >= 2000000) {
|
||||
revenuePremium = 60;
|
||||
} else if (investmentAmount >= 1500000) {
|
||||
revenuePremium = 40;
|
||||
} else if (investmentAmount >= 1000000) {
|
||||
revenuePremium = 20;
|
||||
} else {
|
||||
revenuePremium = 0;
|
||||
}
|
||||
|
||||
// Calculate grace period
|
||||
const baseGracePeriod = inputs.gracePeriod;
|
||||
let gracePeriodBonus;
|
||||
if (investmentAmount >= 1500000) {
|
||||
gracePeriodBonus = 12;
|
||||
} else if (investmentAmount >= 1000000) {
|
||||
gracePeriodBonus = 6;
|
||||
} else {
|
||||
gracePeriodBonus = Math.floor((investmentAmount - baseInvestment) / 250000);
|
||||
}
|
||||
const totalGracePeriod = Math.max(0, baseGracePeriod + gracePeriodBonus);
|
||||
|
||||
// Calculate max performance bonus
|
||||
let maxBonus;
|
||||
if (investmentAmount >= 2000000) {
|
||||
maxBonus = 35;
|
||||
} else if (investmentAmount >= 1500000) {
|
||||
maxBonus = 25;
|
||||
} else if (investmentAmount >= 1000000) {
|
||||
maxBonus = 20;
|
||||
} else {
|
||||
maxBonus = 15;
|
||||
}
|
||||
|
||||
// Update UI elements
|
||||
const instanceScaling = document.getElementById('instance-scaling');
|
||||
if (instanceScaling) {
|
||||
instanceScaling.textContent = scalingFactor.toFixed(1) + 'x';
|
||||
instanceScaling.className = scalingFactor >= 2.0 ? 'benefit-value text-success fw-bold' :
|
||||
scalingFactor >= 1.5 ? 'benefit-value text-primary fw-bold' : 'benefit-value text-secondary fw-bold';
|
||||
}
|
||||
|
||||
const revenuePremiumEl = document.getElementById('revenue-premium');
|
||||
if (revenuePremiumEl) {
|
||||
revenuePremiumEl.textContent = '+' + revenuePremium + '%';
|
||||
revenuePremiumEl.className = revenuePremium >= 40 ? 'benefit-value text-success fw-bold' :
|
||||
revenuePremium >= 20 ? 'benefit-value text-warning fw-bold' : 'benefit-value text-secondary fw-bold';
|
||||
}
|
||||
|
||||
const gracePeriodEl = document.getElementById('grace-period-display');
|
||||
if (gracePeriodEl) {
|
||||
gracePeriodEl.textContent = totalGracePeriod + ' months';
|
||||
gracePeriodEl.className = totalGracePeriod >= 12 ? 'benefit-value text-success fw-bold' :
|
||||
totalGracePeriod >= 9 ? 'benefit-value text-info fw-bold' : 'benefit-value text-secondary fw-bold';
|
||||
}
|
||||
|
||||
const maxBonusEl = document.getElementById('max-bonus');
|
||||
if (maxBonusEl) {
|
||||
maxBonusEl.textContent = maxBonus + '%';
|
||||
maxBonusEl.className = maxBonus >= 30 ? 'benefit-value text-success fw-bold' :
|
||||
maxBonus >= 20 ? 'benefit-value text-warning fw-bold' : 'benefit-value text-secondary fw-bold';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error updating investment benefits:', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue