remove npv in roi calculator

This commit is contained in:
Tobias Brunner 2025-07-21 16:12:53 +02:00
parent cea00c7e8c
commit 25400be405
Signed by: tobru
SSH key fingerprint: SHA256:kOXg1R6c11XW3/Pt9dbLdQvOJGFAy+B2K6v6PtRWBGQ
2 changed files with 3 additions and 67 deletions

View file

@ -51,7 +51,6 @@ class ROICalculator {
return {
investmentAmount: parseFloat(document.getElementById('investment-amount').getAttribute('data-value')),
timeframe: parseInt(document.getElementById('timeframe').value),
discountRate: parseFloat(document.getElementById('discount-rate').value) / 100,
revenuePerInstance: parseFloat(document.getElementById('revenue-per-instance').value),
servalaShare: parseFloat(document.getElementById('servala-share').value) / 100,
gracePeriod: parseInt(document.getElementById('grace-period').value)
@ -81,11 +80,6 @@ class ROICalculator {
let cumulativeCSPRevenue = 0;
let cumulativeServalaRevenue = 0;
let breakEvenMonth = null;
let npvBreakEvenMonth = null;
let totalDiscountedCashFlow = -inputs.investmentAmount;
// Calculate monthly discount rate
const monthlyDiscountRate = Math.pow(1 + inputs.discountRate, 1 / 12) - 1;
// Track phase progression
let currentPhase = 0;
@ -130,15 +124,6 @@ class ROICalculator {
breakEvenMonth = month;
}
// Calculate NPV break-even
const discountFactor = Math.pow(1 + monthlyDiscountRate, month);
const discountedCashFlow = cspRevenue / discountFactor;
totalDiscountedCashFlow += discountedCashFlow;
if (npvBreakEvenMonth === null && totalDiscountedCashFlow >= 0) {
npvBreakEvenMonth = month;
}
monthlyData.push({
month,
scenario: scenario.name,
@ -150,8 +135,6 @@ class ROICalculator {
servalaRevenue,
cumulativeCSPRevenue,
cumulativeServalaRevenue,
discountedCashFlow,
totalDiscountedCashFlow: totalDiscountedCashFlow + inputs.investmentAmount,
investmentScaleFactor: investmentScaleFactor,
adjustedChurnRate: adjustedChurnRate
});
@ -162,7 +145,6 @@ class ROICalculator {
// Calculate final metrics
const totalRevenue = cumulativeCSPRevenue + cumulativeServalaRevenue;
const roi = ((cumulativeCSPRevenue - inputs.investmentAmount) / inputs.investmentAmount) * 100;
const npv = totalDiscountedCashFlow;
return {
scenario: scenario.name,
@ -171,9 +153,7 @@ class ROICalculator {
cspRevenue: cumulativeCSPRevenue,
servalaRevenue: cumulativeServalaRevenue,
roi,
npv,
breakEvenMonth,
npvBreakEvenMonth,
monthlyData,
investmentScaleFactor: investmentScaleFactor,
adjustedChurnRate: adjustedChurnRate * 100
@ -370,7 +350,6 @@ class ROICalculator {
<td>${this.formatCurrencyDetailed(result.servalaRevenue)}</td>
<td class="${result.roi >= 0 ? 'text-success' : 'text-danger'}">${this.formatPercentage(result.roi)}</td>
<td>${result.breakEvenMonth ? result.breakEvenMonth + ' months' : 'N/A'}</td>
<td>${result.npvBreakEvenMonth ? result.npvBreakEvenMonth + ' months' : 'N/A'}</td>
`;
});
}
@ -552,11 +531,6 @@ function updateInvestmentAmount(value) {
updateCalculations();
}
function updateDiscountRate(value) {
document.getElementById('discount-rate').value = value;
updateCalculations();
}
function updateRevenuePerInstance(value) {
document.getElementById('revenue-per-instance').value = value;
updateCalculations();
@ -716,7 +690,6 @@ function exportToPDF() {
const params = [
['Investment Amount:', calculator.formatCurrencyDetailed(inputs.investmentAmount)],
['Investment Timeframe:', `${inputs.timeframe} years`],
['Discount Rate:', `${(inputs.discountRate * 100).toFixed(1)}%`],
['Revenue per Instance:', calculator.formatCurrencyDetailed(inputs.revenuePerInstance)],
['Servala Revenue Share:', `${(inputs.servalaShare * 100).toFixed(0)}%`],
['Grace Period:', `${inputs.gracePeriod} months`]
@ -756,8 +729,7 @@ function exportToPDF() {
['CSP Revenue:', calculator.formatCurrencyDetailed(result.cspRevenue)],
['Servala Revenue:', calculator.formatCurrencyDetailed(result.servalaRevenue)],
['ROI:', calculator.formatPercentage(result.roi)],
['Break-even:', result.breakEvenMonth ? `${result.breakEvenMonth} months` : 'Not achieved'],
['NPV Break-even:', result.npvBreakEvenMonth ? `${result.npvBreakEvenMonth} months` : 'Not achieved']
['Break-even:', result.breakEvenMonth ? `${result.breakEvenMonth} months` : 'Not achieved']
];
resultData.forEach(([label, value]) => {
@ -803,8 +775,6 @@ function exportToPDF() {
doc.text('• Churn rates reflect typical SaaS industry standards', 30, yPos);
yPos += 6;
doc.text('• Revenue calculations include grace period provisions', 30, yPos);
yPos += 6;
doc.text('• NPV calculations use specified discount rate', 30, yPos);
}
// Add footer
@ -838,17 +808,16 @@ function exportToCSV() {
const inputs = calculator.getInputValues();
csvContent += `Investment Amount,${inputs.investmentAmount}\n`;
csvContent += `Timeframe (years),${inputs.timeframe}\n`;
csvContent += `Discount Rate (%),${(inputs.discountRate * 100).toFixed(1)}\n`;
csvContent += `Revenue per Instance,${inputs.revenuePerInstance}\n`;
csvContent += `Servala Share (%),${(inputs.servalaShare * 100).toFixed(0)}\n`;
csvContent += `Grace Period (months),${inputs.gracePeriod}\n\n`;
// Add scenario summary
csvContent += 'SCENARIO SUMMARY\n';
csvContent += 'Scenario,Final Instances,Total Revenue,CSP Revenue,Servala Revenue,ROI (%),Break-even (months),NPV Break-even (months)\n';
csvContent += 'Scenario,Final Instances,Total Revenue,CSP Revenue,Servala Revenue,ROI (%),Break-even (months)\n';
Object.values(calculator.results).forEach(result => {
csvContent += `${result.scenario},${result.finalInstances},${result.totalRevenue.toFixed(2)},${result.cspRevenue.toFixed(2)},${result.servalaRevenue.toFixed(2)},${result.roi.toFixed(2)},${result.breakEvenMonth || 'N/A'},${result.npvBreakEvenMonth || 'N/A'}\n`;
csvContent += `${result.scenario},${result.finalInstances},${result.totalRevenue.toFixed(2)},${result.cspRevenue.toFixed(2)},${result.servalaRevenue.toFixed(2)},${result.roi.toFixed(2)},${result.breakEvenMonth || 'N/A'}\n`;
});
csvContent += '\n';
@ -903,8 +872,6 @@ function resetCalculator() {
investmentInput.value = '500,000';
document.getElementById('investment-slider').value = 500000;
document.getElementById('timeframe').value = 3;
document.getElementById('discount-rate').value = 10;
document.getElementById('discount-slider').value = 10;
document.getElementById('revenue-per-instance').value = 50;
document.getElementById('revenue-slider').value = 50;
document.getElementById('servala-share').value = 25;

View file

@ -57,7 +57,6 @@
<p><strong>Monthly Revenue per Instance:</strong> The recurring revenue generated from each managed service instance (excl. compute).</p>
<p><strong>Servala Revenue Share:</strong> Percentage of revenue shared with Servala after the grace period. This is Servala's platform fee.</p>
<p><strong>Grace Period:</strong> Initial months where you keep 100% of revenue before sharing begins with Servala.</p>
<p><strong>Discount Rate:</strong> Used for NPV calculations - represents your required rate of return or cost of capital.</p>
</div>
<h6 class="text-primary mb-2 mt-3"><i class="bi bi-graph-up"></i> Growth Scenarios</h6>
@ -68,14 +67,10 @@
<p>Each scenario has 4 growth phases with customizable instance acquisition rates in Advanced Parameters.</p>
</div>
<h6 class="text-primary mb-2 mt-3"><i class="bi bi-calculator"></i> What is NPV?</h6>
<p class="small"><strong>Net Present Value (NPV)</strong> represents the current worth of future cash flows, discounted back to today's value using your discount rate. A positive NPV indicates the investment is profitable. NPV accounts for the time value of money - money received today is worth more than the same amount received in the future.</p>
<h6 class="text-primary mb-2 mt-3"><i class="bi bi-bullseye"></i> Understanding Results</h6>
<div class="small">
<p><strong>ROI:</strong> Return on Investment as a percentage of your initial investment.</p>
<p><strong>Break-even:</strong> Month when cumulative revenue equals your initial investment.</p>
<p><strong>NPV Break-even:</strong> Month when discounted cash flows become positive (more accurate timing).</p>
<p><strong>Churn:</strong> Monthly percentage of instances that stop generating revenue (customer loss).</p>
</div>
</div>
@ -158,31 +153,6 @@
</select>
</div>
<div class="input-group-custom">
<label for="discount-rate">
Discount Rate for NPV (%)
<i class="bi bi-question-circle-fill text-muted ms-1"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="The discount rate represents your required rate of return or cost of capital. It's used to calculate the present value of future cash flows. A higher rate means you need higher returns to justify the investment. For example: 8-10% for conservative investors, 12-15% for moderate risk tolerance, 15-20% for high-risk/high-return expectations. This rate accounts for inflation, risk, and opportunity cost of your capital."
style="cursor: help; font-size: 0.8rem;"></i>
</label>
<input type="number" class="form-control" id="discount-rate"
min="5" max="20" step="0.5" value="10"
onchange="updateCalculations()">
<div class="slider-container">
<input type="range" class="slider" id="discount-slider"
min="5" max="20" step="0.5" value="10"
onchange="updateDiscountRate(this.value)">
</div>
<small class="text-muted">5% - 20% (your required annual return rate)</small>
</div>
</div>
<!-- Revenue Model -->
<div class="calculator-section">
<h4><i class="bi bi-graph-up"></i> Revenue Model</h4>
<div class="input-group-custom">
<label for="revenue-per-instance">Monthly Revenue per Instance</label>
<div class="input-group">
@ -534,7 +504,6 @@
<th>Servala Revenue</th>
<th>ROI</th>
<th>Break-even</th>
<th>NPV Break-even</th>
</tr>
</thead>
<tbody id="comparison-tbody">