multi-currency support in roi calculator
This commit is contained in:
parent
adc3a6b905
commit
5cc6b779c5
7 changed files with 231 additions and 45 deletions
|
|
@ -82,6 +82,10 @@ class ROICalculator {
|
|||
const coreRevenueElement = document.getElementById('core-service-revenue');
|
||||
const coreServiceRevenue = coreRevenueElement ? parseFloat(coreRevenueElement.value) || 0 : 0;
|
||||
|
||||
// Get currency with validation
|
||||
const currencyElement = document.getElementById('currency');
|
||||
const currency = currencyElement ? currencyElement.value || 'CHF' : 'CHF';
|
||||
|
||||
return {
|
||||
investmentAmount,
|
||||
timeframe,
|
||||
|
|
@ -90,7 +94,8 @@ class ROICalculator {
|
|||
revenuePerInstance,
|
||||
coreServiceRevenue,
|
||||
servalaShare,
|
||||
gracePeriod
|
||||
gracePeriod,
|
||||
currency
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error getting input values:', error);
|
||||
|
|
@ -103,6 +108,7 @@ class ROICalculator {
|
|||
revenuePerInstance: 50,
|
||||
coreServiceRevenue: 0,
|
||||
servalaShare: 0.25,
|
||||
currency: 'CHF',
|
||||
gracePeriod: 6
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ class ExportManager {
|
|||
|
||||
doc.setFontSize(12);
|
||||
doc.setTextColor(...colors.dark);
|
||||
doc.text(`Investment Amount: ${this.formatCHF(inputs.investmentAmount)}`, pageWidth/2, boxY + 22, { align: 'center' });
|
||||
doc.text(`Investment Amount: ${this.formatCurrency(inputs.investmentAmount)}`, pageWidth/2, boxY + 22, { align: 'center' });
|
||||
doc.text(`Analysis Period: ${inputs.timeframe} years`, pageWidth/2, boxY + 32, { align: 'center' });
|
||||
|
||||
// Generated date
|
||||
|
|
@ -191,7 +191,7 @@ class ExportManager {
|
|||
doc.setFont('helvetica', 'normal');
|
||||
doc.setFontSize(10);
|
||||
doc.text(`Average ROI: ${this.uiManager.formatPercentage(avgDirectROI)}`, margin + 5, yPos + 16);
|
||||
doc.text(`Average Net Profit: ${this.formatCHF(avgDirectNetPos)}`, margin + 5, yPos + 24);
|
||||
doc.text(`Average Net Profit: ${this.formatCurrency(avgDirectNetPos)}`, margin + 5, yPos + 24);
|
||||
doc.text('Performance-based with bonuses', margin + 5, yPos + 32);
|
||||
|
||||
// Loan Model Summary
|
||||
|
|
@ -208,7 +208,7 @@ class ExportManager {
|
|||
doc.setFont('helvetica', 'normal');
|
||||
doc.setFontSize(10);
|
||||
doc.text(`Average ROI: ${this.uiManager.formatPercentage(avgLoanROI)}`, loanBoxX + 5, yPos + 16);
|
||||
doc.text(`Average Net Profit: ${this.formatCHF(avgLoanNetPos)}`, loanBoxX + 5, yPos + 24);
|
||||
doc.text(`Average Net Profit: ${this.formatCurrency(avgLoanNetPos)}`, loanBoxX + 5, yPos + 24);
|
||||
doc.text('Fixed returns, guaranteed', loanBoxX + 5, yPos + 32);
|
||||
|
||||
yPos += 45;
|
||||
|
|
@ -228,11 +228,11 @@ class ExportManager {
|
|||
|
||||
// Create parameter table
|
||||
const params = [
|
||||
['Investment Amount', this.formatCHF(inputs.investmentAmount)],
|
||||
['Investment Amount', this.formatCurrency(inputs.investmentAmount)],
|
||||
['Investment Timeframe', `${inputs.timeframe} years`],
|
||||
['Service Revenue per Instance', `${this.formatCHF(inputs.revenuePerInstance)} / month`],
|
||||
['Core Service Revenue per Instance', `${this.formatCHF(inputs.coreServiceRevenue)} / month`],
|
||||
['Total Revenue per Instance', `${this.formatCHF(inputs.revenuePerInstance + inputs.coreServiceRevenue)} / month`],
|
||||
['Service Revenue per Instance', `${this.formatCurrency(inputs.revenuePerInstance)} / month`],
|
||||
['Core Service Revenue per Instance', `${this.formatCurrency(inputs.coreServiceRevenue)} / month`],
|
||||
['Total Revenue per Instance', `${this.formatCurrency(inputs.revenuePerInstance + inputs.coreServiceRevenue)} / month`],
|
||||
['Loan Interest Rate', `${(inputs.loanInterestRate * 100).toFixed(1)}%`],
|
||||
['Direct Investment Share', `${(inputs.servalaShare * 100).toFixed(0)}% to Servala`],
|
||||
['Grace Period', `${inputs.gracePeriod} months`]
|
||||
|
|
@ -271,9 +271,9 @@ class ExportManager {
|
|||
if (directResult && loanResult) {
|
||||
tableData.push([
|
||||
scenarioName,
|
||||
this.formatCHF(directResult.netPosition),
|
||||
this.formatCurrency(directResult.netPosition),
|
||||
this.uiManager.formatPercentage(directResult.roi),
|
||||
this.formatCHF(loanResult.netPosition),
|
||||
this.formatCurrency(loanResult.netPosition),
|
||||
this.uiManager.formatPercentage(loanResult.roi)
|
||||
]);
|
||||
}
|
||||
|
|
@ -339,7 +339,7 @@ class ExportManager {
|
|||
tableData.push([
|
||||
result.scenario,
|
||||
result.investmentModel === 'direct' ? 'Direct' : 'Loan',
|
||||
this.formatCHF(result.netPosition),
|
||||
this.formatCurrency(result.netPosition),
|
||||
this.uiManager.formatPercentage(result.roi),
|
||||
result.breakEvenMonth ? `${result.breakEvenMonth} months` : 'N/A'
|
||||
]);
|
||||
|
|
@ -498,17 +498,24 @@ class ExportManager {
|
|||
});
|
||||
}
|
||||
|
||||
formatCHF(amount) {
|
||||
formatCurrency(amount) {
|
||||
try {
|
||||
// Consistent CHF formatting: CHF in front, no decimals for whole numbers
|
||||
return new Intl.NumberFormat('de-CH', {
|
||||
// Get current currency from the page
|
||||
const currencyElement = document.getElementById('currency');
|
||||
const currency = currencyElement ? currencyElement.value : 'CHF';
|
||||
|
||||
// Determine locale based on currency
|
||||
const locale = currency === 'EUR' ? 'de-DE' : 'de-CH';
|
||||
|
||||
// Consistent currency formatting: currency in front, no decimals for whole numbers
|
||||
return new Intl.NumberFormat(locale, {
|
||||
style: 'currency',
|
||||
currency: 'CHF',
|
||||
currency: currency,
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: 0
|
||||
}).format(amount);
|
||||
} catch (error) {
|
||||
console.error('Error formatting CHF:', error);
|
||||
console.error('Error formatting currency:', error);
|
||||
return `CHF ${Math.round(amount).toLocaleString()}`;
|
||||
}
|
||||
}
|
||||
|
|
@ -522,15 +529,16 @@ class ExportManager {
|
|||
// Add input parameters
|
||||
csvContent += 'INPUT PARAMETERS\n';
|
||||
const inputs = this.calculator.getInputValues();
|
||||
csvContent += `Currency,${inputs.currency}\n`;
|
||||
csvContent += `Investment Amount,${inputs.investmentAmount}\n`;
|
||||
csvContent += `Timeframe (years),${inputs.timeframe}\n`;
|
||||
csvContent += `Investment Model,${inputs.investmentModel === 'loan' ? 'Loan Model' : 'Direct Investment'}\n`;
|
||||
if (inputs.investmentModel === 'loan') {
|
||||
csvContent += `Loan Interest Rate (%),${(inputs.loanInterestRate * 100).toFixed(1)}\n`;
|
||||
}
|
||||
csvContent += `Service Revenue per Instance,${inputs.revenuePerInstance}\n`;
|
||||
csvContent += `Core Service Revenue per Instance,${inputs.coreServiceRevenue}\n`;
|
||||
csvContent += `Total Revenue per Instance,${inputs.revenuePerInstance + inputs.coreServiceRevenue}\n`;
|
||||
csvContent += `Service Revenue per Instance (${inputs.currency}),${inputs.revenuePerInstance}\n`;
|
||||
csvContent += `Core Service Revenue per Instance (${inputs.currency}),${inputs.coreServiceRevenue}\n`;
|
||||
csvContent += `Total Revenue per Instance (${inputs.currency}),${inputs.revenuePerInstance + inputs.coreServiceRevenue}\n`;
|
||||
if (inputs.investmentModel === 'direct') {
|
||||
csvContent += `Servala Share (%),${(inputs.servalaShare * 100).toFixed(0)}\n`;
|
||||
csvContent += `Grace Period (months),${inputs.gracePeriod}\n`;
|
||||
|
|
@ -539,7 +547,7 @@ class ExportManager {
|
|||
|
||||
// Add scenario summary
|
||||
csvContent += 'SCENARIO SUMMARY\n';
|
||||
csvContent += 'Scenario,Investment Model,Final Instances,Total Revenue,CSP Revenue,Servala Revenue,ROI (%),Break-even (months)\n';
|
||||
csvContent += `Scenario,Investment Model,Final Instances,Total Revenue (${inputs.currency}),CSP Revenue (${inputs.currency}),Servala Revenue (${inputs.currency}),ROI (%),Break-even (months)\n`;
|
||||
|
||||
Object.values(this.calculator.results).forEach(result => {
|
||||
const modelText = result.investmentModel === 'loan' ? 'Loan' : 'Direct';
|
||||
|
|
@ -550,7 +558,7 @@ class ExportManager {
|
|||
|
||||
// Add detailed monthly data
|
||||
csvContent += 'MONTHLY BREAKDOWN\n';
|
||||
csvContent += 'Month,Scenario,New Instances,Churned Instances,Total Instances,Monthly Revenue,CSP Revenue,Servala Revenue,Cumulative CSP Revenue,Cumulative Servala Revenue\n';
|
||||
csvContent += `Month,Scenario,New Instances,Churned Instances,Total Instances,Service Revenue (${inputs.currency}),Core Revenue (${inputs.currency}),Total Revenue (${inputs.currency}),CSP Revenue (${inputs.currency}),Servala Revenue (${inputs.currency}),Cumulative CSP Revenue (${inputs.currency}),Cumulative Servala Revenue (${inputs.currency})\n`;
|
||||
|
||||
// Combine all monthly data
|
||||
const allData = [];
|
||||
|
|
@ -563,7 +571,7 @@ class ExportManager {
|
|||
allData.sort((a, b) => a.month - b.month || a.scenario.localeCompare(b.scenario));
|
||||
|
||||
allData.forEach(data => {
|
||||
csvContent += `${data.month},${data.scenario},${data.newInstances},${data.churnedInstances},${data.totalInstances},${data.monthlyRevenue.toFixed(2)},${data.cspRevenue.toFixed(2)},${data.servalaRevenue.toFixed(2)},${data.cumulativeCSPRevenue.toFixed(2)},${data.cumulativeServalaRevenue.toFixed(2)}\n`;
|
||||
csvContent += `${data.month},${data.scenario},${data.newInstances},${data.churnedInstances},${data.totalInstances},${(data.serviceRevenue || data.monthlyRevenue || 0).toFixed(2)},${(data.coreRevenue || 0).toFixed(2)},${(data.totalRevenue || data.monthlyRevenue || 0).toFixed(2)},${data.cspRevenue.toFixed(2)},${data.servalaRevenue.toFixed(2)},${data.cumulativeCSPRevenue.toFixed(2)},${data.cumulativeServalaRevenue.toFixed(2)}\n`;
|
||||
});
|
||||
|
||||
// Create and download file
|
||||
|
|
|
|||
|
|
@ -3,9 +3,17 @@
|
|||
* Handles input formatting, validation, and parsing
|
||||
*/
|
||||
class InputUtils {
|
||||
static formatNumberWithCommas(num) {
|
||||
static formatNumberWithCommas(num, currency = null) {
|
||||
try {
|
||||
return parseInt(num).toLocaleString('en-US');
|
||||
// Get current currency if not provided
|
||||
if (!currency) {
|
||||
const currencyElement = document.getElementById('currency');
|
||||
currency = currencyElement ? currencyElement.value : 'CHF';
|
||||
}
|
||||
|
||||
// Use appropriate locale for number formatting
|
||||
const locale = currency === 'EUR' ? 'de-DE' : 'de-CH';
|
||||
return parseInt(num).toLocaleString(locale);
|
||||
} catch (error) {
|
||||
console.error('Error formatting number with commas:', error);
|
||||
return String(num);
|
||||
|
|
|
|||
|
|
@ -210,6 +210,85 @@ class ROICalculatorApp {
|
|||
}
|
||||
}
|
||||
|
||||
updateCurrency(value) {
|
||||
try {
|
||||
const currencyElement = document.getElementById('currency');
|
||||
if (currencyElement) {
|
||||
currencyElement.value = value;
|
||||
}
|
||||
|
||||
// Update all currency-related UI labels
|
||||
this.updateCurrencyLabels(value);
|
||||
|
||||
// Update calculations to reflect new currency formatting
|
||||
this.updateCalculations();
|
||||
} catch (error) {
|
||||
console.error('Error updating currency:', error);
|
||||
}
|
||||
}
|
||||
|
||||
updateCurrencyLabels(currency) {
|
||||
try {
|
||||
// Update investment amount prefix
|
||||
const investmentPrefix = document.getElementById('investment-currency-prefix');
|
||||
if (investmentPrefix) {
|
||||
investmentPrefix.textContent = currency;
|
||||
}
|
||||
|
||||
// Update investment min/max labels
|
||||
const investmentMinLabel = document.getElementById('investment-min-label');
|
||||
if (investmentMinLabel) {
|
||||
investmentMinLabel.textContent = `${currency} 100K`;
|
||||
}
|
||||
|
||||
const investmentMaxLabel = document.getElementById('investment-max-label');
|
||||
if (investmentMaxLabel) {
|
||||
investmentMaxLabel.textContent = `${currency} 2M`;
|
||||
}
|
||||
|
||||
// Update revenue per instance suffix
|
||||
const revenueSuffix = document.getElementById('revenue-currency-suffix');
|
||||
if (revenueSuffix) {
|
||||
revenueSuffix.textContent = `${currency}/month`;
|
||||
}
|
||||
|
||||
// Update core service revenue suffix (it's a direct span, not ID-based)
|
||||
const coreRevenueInput = document.getElementById('core-service-revenue');
|
||||
if (coreRevenueInput) {
|
||||
const coreRevenueSpan = coreRevenueInput.parentElement.querySelector('.input-group-text');
|
||||
if (coreRevenueSpan) {
|
||||
coreRevenueSpan.textContent = `${currency}/month`;
|
||||
}
|
||||
}
|
||||
|
||||
// Update all other currency labels throughout the interface
|
||||
const currencyLabels = document.querySelectorAll('.currency-label');
|
||||
currencyLabels.forEach(label => {
|
||||
label.textContent = currency;
|
||||
});
|
||||
|
||||
// Update range slider labels with currency
|
||||
const revenueLabel = document.querySelector('label[for="revenue-per-instance"]');
|
||||
if (revenueLabel) {
|
||||
revenueLabel.innerHTML = revenueLabel.innerHTML.replace(/(CHF|EUR)/, currency);
|
||||
}
|
||||
|
||||
const coreRevenueLabel = document.querySelector('label[for="core-service-revenue"]');
|
||||
if (coreRevenueLabel) {
|
||||
coreRevenueLabel.innerHTML = coreRevenueLabel.innerHTML.replace(/(CHF|EUR)/, currency);
|
||||
}
|
||||
|
||||
// Update investment amount field display if it has a value
|
||||
const investmentInput = document.getElementById('investment-amount');
|
||||
if (investmentInput && investmentInput.getAttribute('data-value')) {
|
||||
const currentValue = investmentInput.getAttribute('data-value');
|
||||
investmentInput.value = InputUtils.formatNumberWithCommas(currentValue, currency);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error updating currency labels:', error);
|
||||
}
|
||||
}
|
||||
|
||||
updateScenarioChurn(scenarioKey, churnRate) {
|
||||
try {
|
||||
if (this.calculator && this.calculator.scenarios[scenarioKey]) {
|
||||
|
|
|
|||
|
|
@ -203,43 +203,61 @@ class UIManager {
|
|||
}
|
||||
}
|
||||
|
||||
formatCurrency(amount) {
|
||||
formatCurrency(amount, currency = null) {
|
||||
try {
|
||||
// Get current currency if not provided
|
||||
if (!currency) {
|
||||
const currencyElement = document.getElementById('currency');
|
||||
currency = currencyElement ? currencyElement.value : 'CHF';
|
||||
}
|
||||
|
||||
// Determine locale based on currency
|
||||
const locale = currency === 'EUR' ? 'de-DE' : 'de-CH';
|
||||
|
||||
// Use compact notation for large numbers in metric cards
|
||||
if (amount >= 1000000) {
|
||||
return new Intl.NumberFormat('de-CH', {
|
||||
return new Intl.NumberFormat(locale, {
|
||||
style: 'currency',
|
||||
currency: 'CHF',
|
||||
currency: currency,
|
||||
notation: 'compact',
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: 1
|
||||
}).format(amount);
|
||||
} else {
|
||||
return new Intl.NumberFormat('de-CH', {
|
||||
return new Intl.NumberFormat(locale, {
|
||||
style: 'currency',
|
||||
currency: 'CHF',
|
||||
currency: currency,
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: 0
|
||||
}).format(amount);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error formatting currency:', error);
|
||||
return `CHF ${amount.toFixed(0)}`;
|
||||
return `${currency || 'CHF'} ${amount.toFixed(0)}`;
|
||||
}
|
||||
}
|
||||
|
||||
formatCurrencyDetailed(amount) {
|
||||
formatCurrencyDetailed(amount, currency = null) {
|
||||
try {
|
||||
// Get current currency if not provided
|
||||
if (!currency) {
|
||||
const currencyElement = document.getElementById('currency');
|
||||
currency = currencyElement ? currencyElement.value : 'CHF';
|
||||
}
|
||||
|
||||
// Determine locale based on currency
|
||||
const locale = currency === 'EUR' ? 'de-DE' : 'de-CH';
|
||||
|
||||
// Use full formatting for detailed views (tables, exports)
|
||||
return new Intl.NumberFormat('de-CH', {
|
||||
return new Intl.NumberFormat(locale, {
|
||||
style: 'currency',
|
||||
currency: 'CHF',
|
||||
currency: currency,
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: 0
|
||||
}).format(amount);
|
||||
} catch (error) {
|
||||
console.error('Error formatting detailed currency:', error);
|
||||
return `CHF ${amount.toFixed(0)}`;
|
||||
return `${currency || 'CHF'} ${amount.toFixed(0)}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,11 @@ function updateServalaShare(value) { window.ROICalculatorApp?.updateServalaShare
|
|||
function updateGracePeriod(value) { window.ROICalculatorApp?.updateGracePeriod(value); }
|
||||
function updateLoanRate(value) { window.ROICalculatorApp?.updateLoanRate(value); }
|
||||
function updateCoreServiceRevenue(value) { window.ROICalculatorApp?.updateCoreServiceRevenue(value); }
|
||||
function updateCurrency() {
|
||||
const currencyElement = document.getElementById('currency');
|
||||
const value = currencyElement ? currencyElement.value : 'CHF';
|
||||
window.ROICalculatorApp?.updateCurrency(value);
|
||||
}
|
||||
function updateScenarioChurn(scenarioKey, churnRate) { window.ROICalculatorApp?.updateScenarioChurn(scenarioKey, churnRate); }
|
||||
function updateScenarioPhase(scenarioKey, phaseIndex, newInstancesPerMonth) { window.ROICalculatorApp?.updateScenarioPhase(scenarioKey, phaseIndex, newInstancesPerMonth); }
|
||||
function resetAdvancedParameters() { window.ROICalculatorApp?.resetAdvancedParameters(); }
|
||||
|
|
@ -137,7 +142,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
<div class="mb-4">
|
||||
<label class="form-label fw-semibold mb-2">Initial Investment</label>
|
||||
<div class="input-group input-group-lg">
|
||||
<span class="input-group-text">CHF</span>
|
||||
<span class="input-group-text" id="investment-currency-prefix">CHF</span>
|
||||
<input type="text" class="form-control" id="investment-amount"
|
||||
data-value="500000" value="500,000"
|
||||
oninput="handleInvestmentAmountInput(this)"
|
||||
|
|
@ -149,14 +154,21 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
min="100000" max="2000000" step="50000" value="500000"
|
||||
onchange="updateInvestmentAmount(this.value)">
|
||||
<div class="d-flex justify-content-between mt-1">
|
||||
<small class="text-muted">CHF 100K</small>
|
||||
<small class="text-muted">CHF 2M</small>
|
||||
<small class="text-muted" id="investment-min-label">CHF 100K</small>
|
||||
<small class="text-muted" id="investment-max-label">CHF 2M</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Analysis Period & Service Revenue Row -->
|
||||
<!-- Currency, Analysis Period & Service Revenue Row -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-3">
|
||||
<label class="form-label fw-semibold mb-2">Currency</label>
|
||||
<select class="form-select form-select-lg" id="currency" onchange="updateCurrency()">
|
||||
<option value="CHF" selected>CHF (Swiss Franc)</option>
|
||||
<option value="EUR">EUR (Euro)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label fw-semibold mb-2">Analysis Period</label>
|
||||
<select class="form-select form-select-lg" id="timeframe" onchange="updateCalculations()">
|
||||
<option value="1">1 Year</option>
|
||||
|
|
@ -171,14 +183,14 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
<div class="input-group input-group-lg">
|
||||
<input type="number" class="form-control" id="revenue-per-instance"
|
||||
min="20" max="200" step="5" value="50" onchange="updateCalculations()">
|
||||
<span class="input-group-text">CHF/month</span>
|
||||
<span class="input-group-text" id="revenue-currency-suffix">CHF/month</span>
|
||||
</div>
|
||||
<input type="range" class="form-range mt-3" id="revenue-slider"
|
||||
min="20" max="200" step="5" value="50"
|
||||
onchange="updateRevenuePerInstance(this.value)">
|
||||
<div class="d-flex justify-content-between mt-1">
|
||||
<small class="text-muted">CHF 20</small>
|
||||
<small class="text-muted">CHF 200</small>
|
||||
<small class="text-muted" id="revenue-min-label">CHF 20</small>
|
||||
<small class="text-muted" id="revenue-max-label">CHF 200</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -114,6 +114,9 @@ html {
|
|||
<a class="list-group-item list-group-item-action" href="#calculator-guide">
|
||||
<i class="bi bi-calculator me-2"></i>Using the Calculator
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action" href="#currency-support">
|
||||
<i class="bi bi-cash-stack me-2"></i>Currency Support
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action" href="#scenarios">
|
||||
<i class="bi bi-speedometer2 me-2"></i>Growth Scenarios
|
||||
</a>
|
||||
|
|
@ -153,6 +156,58 @@ html {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Currency Support Section -->
|
||||
<div class="help-section" id="currency-support">
|
||||
<h2><i class="bi bi-cash-stack"></i> Currency Support</h2>
|
||||
<p>The ROI Calculator supports multiple currencies to accommodate different regional markets and business requirements.</p>
|
||||
|
||||
<h3>Supported Currencies</h3>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="model-card">
|
||||
<h5><i class="bi bi-cash"></i> Swiss Franc (CHF)</h5>
|
||||
<p><strong>Default Currency</strong></p>
|
||||
<ul>
|
||||
<li>Swiss locale formatting (de-CH)</li>
|
||||
<li>Standard decimal separators</li>
|
||||
<li>Traditional Swiss business format</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="model-card">
|
||||
<h5><i class="bi bi-currency-euro"></i> Euro (EUR)</h5>
|
||||
<p><strong>European Markets</strong></p>
|
||||
<ul>
|
||||
<li>European locale formatting (de-DE)</li>
|
||||
<li>Standard European decimal separators</li>
|
||||
<li>EU business format compliance</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>How Currency Selection Works</h3>
|
||||
<p>Currency can be selected in the main configuration section of the calculator. When you change currency:</p>
|
||||
<ul>
|
||||
<li><strong>All displays update automatically:</strong> Investment amounts, revenue figures, and results</li>
|
||||
<li><strong>Proper localization:</strong> Numbers are formatted according to the selected currency's regional standards</li>
|
||||
<li><strong>Export consistency:</strong> PDF and CSV exports use the selected currency throughout</li>
|
||||
<li><strong>Real-time conversion:</strong> All calculations maintain the same values while updating display format</li>
|
||||
</ul>
|
||||
|
||||
<h3>Important Notes</h3>
|
||||
<div class="alert alert-info">
|
||||
<h6><i class="bi bi-info-circle"></i> Currency Display Only</h6>
|
||||
<p>The calculator displays amounts in your selected currency but does not perform currency conversion. All input values should be entered in your chosen currency. For example, if you select EUR, enter your investment amounts in Euros.</p>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
<h6><i class="bi bi-exclamation-triangle"></i> Consistency Important</h6>
|
||||
<p>Ensure all your inputs (investment amount, revenue per instance, etc.) are in the same currency for accurate calculations. Mixing currencies will produce incorrect results.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Loan Model Section -->
|
||||
<div class="help-section" id="loan-model">
|
||||
<h2><i class="bi bi-bank"></i> Loan Model (3-7% Returns)</h2>
|
||||
|
|
@ -162,7 +217,7 @@ html {
|
|||
|
||||
<h4>Key Features</h4>
|
||||
<ul>
|
||||
<li><strong>Investment Range:</strong> CHF 100,000 - CHF 2,000,000</li>
|
||||
<li><strong>Investment Range:</strong> 100,000 - 2,000,000 (in your selected currency)</li>
|
||||
<li><strong>Interest Rates:</strong> 3-8% annually</li>
|
||||
<li><strong>Payment Schedule:</strong> Fixed monthly payments</li>
|
||||
<li><strong>Risk Level:</strong> Very low - contractually guaranteed</li>
|
||||
|
|
@ -306,9 +361,9 @@ html {
|
|||
<div class="col-md-6">
|
||||
<h5>Primary Settings</h5>
|
||||
<ul>
|
||||
<li><strong>Initial Investment:</strong> CHF 100K - 2M (with slider)</li>
|
||||
<li><strong>Initial Investment:</strong> 100K - 2M in selected currency (with slider)</li>
|
||||
<li><strong>Timeframe:</strong> 1-5 years</li>
|
||||
<li><strong>Service Revenue/Instance:</strong> Monthly Servala service fee per managed instance (CHF 20-200)</li>
|
||||
<li><strong>Service Revenue/Instance:</strong> Monthly Servala service fee per managed instance (20-200 in selected currency)</li>
|
||||
<li><strong>Growth Scenarios:</strong> Conservative, Moderate, Aggressive</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue