2025-07-16 15:12:25 +02:00
|
|
|
{% extends 'base.html' %}
|
|
|
|
|
{% load static %}
|
|
|
|
|
|
|
|
|
|
{% block title %}CSP ROI Calculator{% endblock %}
|
|
|
|
|
|
2025-07-22 08:33:54 +02:00
|
|
|
{% block extra_head %}
|
|
|
|
|
<meta name="csrf-token" content="{{ csrf_token }}">
|
|
|
|
|
{% endblock %}
|
|
|
|
|
|
2025-07-16 15:12:25 +02:00
|
|
|
{% block extra_css %}
|
2025-07-21 16:04:53 +02:00
|
|
|
<link rel="stylesheet" type="text/css" href='{% static "css/roi-calculator.css" %}'>
|
|
|
|
|
{% endblock %}
|
2025-07-16 15:15:34 +02:00
|
|
|
|
2025-07-21 16:04:53 +02:00
|
|
|
{% block extra_js %}
|
|
|
|
|
<script src="{% static "js/chart.umd.min.js" %}"></script>
|
|
|
|
|
<script src="{% static "js/jspdf.umd.min.js" %}"></script>
|
2025-07-22 08:50:48 +02:00
|
|
|
<!-- ROI Calculator Modules -->
|
|
|
|
|
<script src="{% static "js/roi-calculator/input-utils.js" %}"></script>
|
|
|
|
|
<script src="{% static "js/roi-calculator/calculator-core.js" %}"></script>
|
|
|
|
|
<script src="{% static "js/roi-calculator/chart-manager.js" %}"></script>
|
|
|
|
|
<script src="{% static "js/roi-calculator/ui-manager.js" %}"></script>
|
|
|
|
|
<script src="{% static "js/roi-calculator/export-manager.js" %}"></script>
|
|
|
|
|
<script src="{% static "js/roi-calculator/roi-calculator-app.js" %}"></script>
|
|
|
|
|
<script>
|
|
|
|
|
// Global function wrappers for HTML onclick handlers
|
|
|
|
|
function updateCalculations() { window.ROICalculatorApp?.updateCalculations(); }
|
|
|
|
|
function exportToPDF() { window.ROICalculatorApp?.exportToPDF(); }
|
|
|
|
|
function exportToCSV() { window.ROICalculatorApp?.exportToCSV(); }
|
|
|
|
|
function handleInvestmentAmountInput(input) { InputUtils.handleInvestmentAmountInput(input); }
|
|
|
|
|
function updateInvestmentAmount(value) { window.ROICalculatorApp?.updateInvestmentAmount(value); }
|
|
|
|
|
function updateRevenuePerInstance(value) { window.ROICalculatorApp?.updateRevenuePerInstance(value); }
|
|
|
|
|
function updateServalaShare(value) { window.ROICalculatorApp?.updateServalaShare(value); }
|
|
|
|
|
function updateGracePeriod(value) { window.ROICalculatorApp?.updateGracePeriod(value); }
|
|
|
|
|
function updateLoanRate(value) { window.ROICalculatorApp?.updateLoanRate(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(); }
|
|
|
|
|
function toggleScenario(scenarioKey) { window.ROICalculatorApp?.toggleScenario(scenarioKey); }
|
|
|
|
|
function toggleCollapsible(elementId) { window.ROICalculatorApp?.toggleCollapsible(elementId); }
|
|
|
|
|
function resetCalculator() { window.ROICalculatorApp?.resetCalculator(); }
|
|
|
|
|
function toggleInvestmentModel() { window.ROICalculatorApp?.toggleInvestmentModel(); }
|
|
|
|
|
function logout() { window.ROICalculatorApp?.logout(); }
|
2025-07-22 17:30:37 +02:00
|
|
|
|
|
|
|
|
// Manual toggle functions for collapse elements
|
|
|
|
|
function toggleAdvancedControls() {
|
|
|
|
|
const element = document.getElementById('advancedControls');
|
|
|
|
|
const button = document.getElementById('advancedToggleBtn');
|
|
|
|
|
|
|
|
|
|
console.log('Toggling advanced controls, current classes:', element.className);
|
|
|
|
|
|
|
|
|
|
if (element.style.display === 'none' || element.style.display === '') {
|
|
|
|
|
element.style.display = 'block';
|
|
|
|
|
button.innerHTML = '<i class="bi bi-gear"></i> Less';
|
|
|
|
|
console.log('Showing advanced controls');
|
|
|
|
|
} else {
|
|
|
|
|
element.style.display = 'none';
|
|
|
|
|
button.innerHTML = '<i class="bi bi-gear"></i> More';
|
|
|
|
|
console.log('Hiding advanced controls');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function toggleDataCollapse() {
|
|
|
|
|
const element = document.getElementById('dataCollapse');
|
|
|
|
|
const button = document.getElementById('dataToggleBtn');
|
|
|
|
|
|
|
|
|
|
console.log('Toggling data collapse, current style:', element.style.display);
|
|
|
|
|
|
|
|
|
|
if (element.style.display === 'none' || element.style.display === '') {
|
|
|
|
|
element.style.display = 'block';
|
|
|
|
|
button.classList.remove('collapsed');
|
|
|
|
|
button.setAttribute('aria-expanded', 'true');
|
|
|
|
|
console.log('Showing data collapse');
|
|
|
|
|
} else {
|
|
|
|
|
element.style.display = 'none';
|
|
|
|
|
button.classList.add('collapsed');
|
|
|
|
|
button.setAttribute('aria-expanded', 'false');
|
|
|
|
|
console.log('Hiding data collapse');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Initialize collapse states
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
// Ensure both sections start collapsed
|
|
|
|
|
const advancedControls = document.getElementById('advancedControls');
|
|
|
|
|
const dataCollapse = document.getElementById('dataCollapse');
|
|
|
|
|
|
|
|
|
|
if (advancedControls) {
|
|
|
|
|
advancedControls.style.display = 'none';
|
|
|
|
|
}
|
|
|
|
|
if (dataCollapse) {
|
|
|
|
|
dataCollapse.style.display = 'none';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log('Collapse elements initialized as hidden');
|
|
|
|
|
});
|
2025-07-22 08:50:48 +02:00
|
|
|
</script>
|
2025-07-16 15:12:25 +02:00
|
|
|
{% endblock %}
|
|
|
|
|
|
|
|
|
|
{% block content %}
|
2025-07-22 17:30:37 +02:00
|
|
|
<div class="container-fluid p-0" style="min-height: 100vh;">
|
|
|
|
|
<!-- Minimal Header with Controls -->
|
|
|
|
|
<div class="bg-light border-bottom sticky-top" style="z-index: 1030;">
|
|
|
|
|
<div class="container-fluid">
|
|
|
|
|
<!-- Title Row -->
|
|
|
|
|
<div class="row py-2 border-bottom">
|
|
|
|
|
<div class="col-md-6">
|
|
|
|
|
<h4 class="mb-0">CSP ROI Calculator</h4>
|
|
|
|
|
<small class="text-muted">Real-time investment analysis</small>
|
2025-07-16 15:12:25 +02:00
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
<div class="col-md-6 text-end">
|
|
|
|
|
<button type="button" class="btn btn-sm btn-outline-primary me-1" onclick="exportToPDF()">
|
2025-07-21 16:14:32 +02:00
|
|
|
<i class="bi bi-file-pdf"></i> PDF
|
|
|
|
|
</button>
|
2025-07-22 17:30:37 +02:00
|
|
|
<button type="button" class="btn btn-sm btn-outline-success me-1" onclick="exportToCSV()">
|
2025-07-21 16:14:32 +02:00
|
|
|
<i class="bi bi-file-csv"></i> CSV
|
|
|
|
|
</button>
|
2025-07-22 17:30:37 +02:00
|
|
|
<button type="button" class="btn btn-sm btn-outline-secondary me-1" onclick="resetCalculator()">
|
2025-07-16 15:12:25 +02:00
|
|
|
<i class="bi bi-arrow-clockwise"></i> Reset
|
|
|
|
|
</button>
|
2025-07-22 17:30:37 +02:00
|
|
|
<button type="button" class="btn btn-sm btn-danger" onclick="logout()">
|
2025-07-16 15:12:25 +02:00
|
|
|
<i class="bi bi-box-arrow-right"></i> Logout
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
|
|
|
|
|
<!-- Compact Controls Row -->
|
|
|
|
|
<div class="row py-3">
|
|
|
|
|
<!-- Core Investment Parameters -->
|
|
|
|
|
<div class="col-lg-2 col-md-3 mb-2">
|
|
|
|
|
<label class="form-label small fw-semibold mb-1">Investment</label>
|
|
|
|
|
<div class="input-group input-group-sm">
|
|
|
|
|
<span class="input-group-text">CHF</span>
|
2025-07-16 15:19:04 +02:00
|
|
|
<input type="text" class="form-control" id="investment-amount"
|
2025-07-22 17:30:37 +02:00
|
|
|
data-value="500000" value="500,000"
|
2025-07-16 15:19:04 +02:00
|
|
|
oninput="handleInvestmentAmountInput(this)"
|
2025-07-16 15:12:25 +02:00
|
|
|
onchange="updateCalculations()">
|
|
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
<input type="range" class="form-range mt-1" id="investment-slider"
|
|
|
|
|
min="100000" max="2000000" step="50000" value="500000"
|
|
|
|
|
onchange="updateInvestmentAmount(this.value)">
|
2025-07-16 15:12:25 +02:00
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
|
|
|
|
|
<div class="col-lg-1 col-md-2 mb-2">
|
|
|
|
|
<label class="form-label small fw-semibold mb-1">Years</label>
|
|
|
|
|
<select class="form-select form-select-sm" id="timeframe" onchange="updateCalculations()">
|
|
|
|
|
<option value="1">1</option>
|
|
|
|
|
<option value="2">2</option>
|
|
|
|
|
<option value="3" selected>3</option>
|
|
|
|
|
<option value="4">4</option>
|
|
|
|
|
<option value="5">5</option>
|
2025-07-16 15:12:25 +02:00
|
|
|
</select>
|
|
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
|
|
|
|
|
<!-- Investment Model -->
|
|
|
|
|
<div class="col-lg-2 col-md-3 mb-2">
|
|
|
|
|
<label class="form-label small fw-semibold mb-1">Model</label>
|
2025-07-21 17:06:29 +02:00
|
|
|
<div class="btn-group w-100" role="group">
|
|
|
|
|
<input type="radio" class="btn-check" name="investment-model" id="loan-model" value="loan" onchange="toggleInvestmentModel()">
|
2025-07-22 17:30:37 +02:00
|
|
|
<label class="btn btn-outline-warning btn-sm" for="loan-model">Loan</label>
|
2025-07-21 17:06:29 +02:00
|
|
|
<input type="radio" class="btn-check" name="investment-model" id="direct-model" value="direct" checked onchange="toggleInvestmentModel()">
|
2025-07-22 17:30:37 +02:00
|
|
|
<label class="btn btn-outline-success btn-sm" for="direct-model">Direct</label>
|
2025-07-21 17:06:29 +02:00
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
|
|
|
|
|
<!-- Revenue/Instance -->
|
|
|
|
|
<div class="col-lg-1 col-md-2 mb-2">
|
|
|
|
|
<label class="form-label small fw-semibold mb-1">Revenue</label>
|
|
|
|
|
<div class="input-group input-group-sm">
|
2025-07-16 15:12:25 +02:00
|
|
|
<input type="number" class="form-control" id="revenue-per-instance"
|
2025-07-22 17:30:37 +02:00
|
|
|
min="20" max="200" step="5" value="50" onchange="updateCalculations()">
|
|
|
|
|
<span class="input-group-text">CHF</span>
|
2025-07-16 15:12:25 +02:00
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
<input type="range" class="form-range mt-1" id="revenue-slider"
|
|
|
|
|
min="20" max="200" step="5" value="50"
|
|
|
|
|
onchange="updateRevenuePerInstance(this.value)">
|
2025-07-16 15:12:25 +02:00
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
|
|
|
|
|
<!-- Scenarios Toggle -->
|
|
|
|
|
<div class="col-lg-2 col-md-3 mb-2">
|
|
|
|
|
<label class="form-label small fw-semibold mb-1">Scenarios</label>
|
|
|
|
|
<div class="d-flex gap-1">
|
|
|
|
|
<div class="form-check form-check-inline">
|
|
|
|
|
<input class="form-check-input" type="checkbox" id="conservative-enabled" checked onchange="toggleScenario('conservative')">
|
|
|
|
|
<label class="form-check-label small text-success" for="conservative-enabled" data-bs-toggle="tooltip" title="Conservative: 2% churn, steady growth">Safe</label>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="form-check form-check-inline">
|
|
|
|
|
<input class="form-check-input" type="checkbox" id="moderate-enabled" checked onchange="toggleScenario('moderate')">
|
|
|
|
|
<label class="form-check-label small text-warning" for="moderate-enabled" data-bs-toggle="tooltip" title="Moderate: 3% churn, balanced growth">Balanced</label>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="form-check form-check-inline">
|
|
|
|
|
<input class="form-check-input" type="checkbox" id="aggressive-enabled" checked onchange="toggleScenario('aggressive')">
|
|
|
|
|
<label class="form-check-label small text-danger" for="aggressive-enabled" data-bs-toggle="tooltip" title="Aggressive: 5% churn, rapid growth">Fast</label>
|
|
|
|
|
</div>
|
2025-07-16 15:12:25 +02:00
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
|
|
|
|
|
<!-- Advanced Controls Toggle -->
|
|
|
|
|
<div class="col-lg-2 col-md-3 mb-2">
|
|
|
|
|
<label class="form-label small fw-semibold mb-1">Controls</label>
|
|
|
|
|
<div class="d-flex gap-1">
|
|
|
|
|
<button class="btn btn-outline-info btn-sm" type="button" onclick="toggleAdvancedControls()" id="advancedToggleBtn">
|
|
|
|
|
<i class="bi bi-gear"></i> More
|
|
|
|
|
</button>
|
|
|
|
|
<a href="{% url 'services:roi_calculator_help' %}" class="btn btn-outline-secondary btn-sm" target="_blank">
|
|
|
|
|
<i class="bi bi-question-circle"></i> Help
|
|
|
|
|
</a>
|
2025-07-16 15:12:25 +02:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2025-07-22 17:30:37 +02:00
|
|
|
<!-- Remaining space for metrics -->
|
|
|
|
|
<div class="col-lg-2 col-md-4 mb-2 text-end">
|
|
|
|
|
<div class="d-flex justify-content-end gap-3">
|
|
|
|
|
<div class="text-center">
|
|
|
|
|
<div class="fw-bold text-success" id="net-position" style="font-size: 1.1rem; white-space: nowrap; line-height: 1.2;">CHF 0</div>
|
|
|
|
|
<div style="font-size: 0.8rem;" class="text-muted">Net Position</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="text-center">
|
|
|
|
|
<div class="fw-bold text-primary" id="roi-percentage" style="font-size: 1.1rem; white-space: nowrap; line-height: 1.2;">0%</div>
|
|
|
|
|
<div style="font-size: 0.8rem;" class="text-muted">ROI</div>
|
|
|
|
|
</div>
|
2025-07-16 15:12:25 +02:00
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Collapsible Advanced Controls -->
|
|
|
|
|
<div class="collapse" id="advancedControls">
|
|
|
|
|
<div class="row py-2 bg-white border-top">
|
|
|
|
|
<!-- Loan Rate (conditional) -->
|
|
|
|
|
<div class="col-md-2" id="loan-rate-section" style="display: none;">
|
|
|
|
|
<label class="form-label small mb-1">Loan Rate (%)</label>
|
|
|
|
|
<input type="number" class="form-control form-control-sm" id="loan-interest-rate"
|
|
|
|
|
min="3" max="8" step="0.1" value="5.0" onchange="updateCalculations()">
|
|
|
|
|
<input type="range" class="form-range mt-1" id="loan-rate-slider"
|
|
|
|
|
min="3" max="8" step="0.1" value="5.0" onchange="updateLoanRate(this.value)">
|
2025-07-16 15:12:25 +02:00
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
|
|
|
|
|
<!-- Servala Share -->
|
|
|
|
|
<div class="col-md-2">
|
|
|
|
|
<label class="form-label small mb-1">Servala Share (%)</label>
|
|
|
|
|
<input type="number" class="form-control form-control-sm" id="servala-share"
|
|
|
|
|
min="10" max="40" step="1" value="25" onchange="updateCalculations()">
|
|
|
|
|
<input type="range" class="form-range mt-1" id="share-slider"
|
|
|
|
|
min="10" max="40" step="1" value="25" onchange="updateServalaShare(this.value)">
|
2025-07-16 15:12:25 +02:00
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
|
|
|
|
|
<!-- Grace Period -->
|
|
|
|
|
<div class="col-md-2">
|
|
|
|
|
<label class="form-label small mb-1">Grace Period (Mo)</label>
|
|
|
|
|
<input type="number" class="form-control form-control-sm" id="grace-period"
|
|
|
|
|
min="0" max="24" step="1" value="6" onchange="updateCalculations()">
|
|
|
|
|
<input type="range" class="form-range mt-1" id="grace-slider"
|
|
|
|
|
min="0" max="24" step="1" value="6" onchange="updateGracePeriod(this.value)">
|
2025-07-16 15:12:25 +02:00
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
|
|
|
|
|
<!-- Scenario Tuning -->
|
|
|
|
|
<div class="col-md-6">
|
|
|
|
|
<div class="row">
|
|
|
|
|
<div class="col-4">
|
|
|
|
|
<label class="form-label small mb-1">Conservative Churn (%)</label>
|
|
|
|
|
<input type="number" class="form-control form-control-sm" id="conservative-churn"
|
|
|
|
|
min="0" max="10" step="0.1" value="2.0" onchange="updateScenarioChurn('conservative', this.value)">
|
2025-07-16 15:31:29 +02:00
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
<div class="col-4">
|
|
|
|
|
<label class="form-label small mb-1">Moderate Churn (%)</label>
|
|
|
|
|
<input type="number" class="form-control form-control-sm" id="moderate-churn"
|
|
|
|
|
min="0" max="10" step="0.1" value="3.0" onchange="updateScenarioChurn('moderate', this.value)">
|
2025-07-16 15:31:29 +02:00
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
<div class="col-4">
|
|
|
|
|
<label class="form-label small mb-1">Aggressive Churn (%)</label>
|
|
|
|
|
<input type="number" class="form-control form-control-sm" id="aggressive-churn"
|
|
|
|
|
min="0" max="15" step="0.1" value="5.0" onchange="updateScenarioChurn('aggressive', this.value)">
|
2025-07-16 15:31:29 +02:00
|
|
|
</div>
|
2025-07-16 15:12:25 +02:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
|
2025-07-16 15:12:25 +02:00
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
</div>
|
2025-07-16 15:12:25 +02:00
|
|
|
|
2025-07-22 17:30:37 +02:00
|
|
|
<!-- CHARTS - Maximum Space -->
|
|
|
|
|
<div class="container-fluid px-3 py-3" style="background: #f8f9fa;">
|
|
|
|
|
<!-- Loading Spinner -->
|
|
|
|
|
<div class="loading-spinner text-center py-5" id="loading-spinner" style="display: none;">
|
|
|
|
|
<div class="spinner-border text-primary" role="status">
|
|
|
|
|
<span class="visually-hidden">Calculating...</span>
|
2025-07-16 15:12:25 +02:00
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
<p class="mt-2">Calculating scenarios...</p>
|
|
|
|
|
</div>
|
2025-07-16 15:12:25 +02:00
|
|
|
|
2025-07-22 17:30:37 +02:00
|
|
|
<!-- Additional Key Metrics (Horizontal) -->
|
|
|
|
|
<div class="row mb-3" id="summary-metrics">
|
|
|
|
|
<div class="col-12">
|
|
|
|
|
<div class="card border-0 shadow-sm">
|
|
|
|
|
<div class="card-body py-3">
|
|
|
|
|
<div class="row text-center">
|
|
|
|
|
<div class="col-lg-3 col-md-6 mb-2">
|
|
|
|
|
<div class="h5 mb-0" id="csp-revenue">CHF 0</div>
|
|
|
|
|
<div class="small text-muted">Your Total Revenue</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="col-lg-3 col-md-6 mb-2">
|
|
|
|
|
<div class="h5 mb-0" id="breakeven-time">N/A</div>
|
|
|
|
|
<div class="small text-muted">Break-Even Time</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="col-lg-3 col-md-6 mb-2">
|
|
|
|
|
<div class="h5 mb-0 text-info" id="model-description-display">Direct Investment</div>
|
|
|
|
|
<div class="small text-muted">Investment Model</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="col-lg-3 col-md-6 mb-2">
|
|
|
|
|
<div class="h5 mb-0 text-secondary">3 Scenarios</div>
|
|
|
|
|
<div class="small text-muted">Active Comparisons</div>
|
|
|
|
|
</div>
|
2025-07-16 15:59:51 +02:00
|
|
|
</div>
|
2025-07-16 15:12:25 +02:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
</div>
|
2025-07-16 15:12:25 +02:00
|
|
|
|
2025-07-22 17:30:37 +02:00
|
|
|
<!-- PRIMARY CHART - Full Width, Large Height -->
|
|
|
|
|
<div class="row mb-4">
|
|
|
|
|
<div class="col-12">
|
|
|
|
|
<div class="card border-0 shadow-sm">
|
|
|
|
|
<div class="card-header bg-white border-0 pb-0">
|
|
|
|
|
<h5 class="mb-1"><i class="bi bi-graph-up-arrow text-primary"></i> ROI Progression Over Time</h5>
|
|
|
|
|
<p class="small text-muted mb-0">Investment profitability timeline - when you'll break even and achieve target returns</p>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="card-body pt-3">
|
|
|
|
|
<canvas id="instanceGrowthChart" style="height: 500px; width: 100%;"></canvas>
|
2025-07-16 15:12:25 +02:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
</div>
|
2025-07-16 15:12:25 +02:00
|
|
|
|
2025-07-22 17:30:37 +02:00
|
|
|
<!-- SECONDARY CHARTS - Side by Side, Large -->
|
|
|
|
|
<div class="row mb-4">
|
|
|
|
|
<div class="col-xl-6 mb-4">
|
|
|
|
|
<div class="card border-0 shadow-sm h-100">
|
|
|
|
|
<div class="card-header bg-white border-0 pb-0">
|
|
|
|
|
<h5 class="mb-1"><i class="bi bi-cash-stack text-success"></i> Net Financial Position</h5>
|
|
|
|
|
<p class="small text-muted mb-0">Cumulative profit/loss over time</p>
|
2025-07-16 15:12:25 +02:00
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
<div class="card-body pt-3">
|
|
|
|
|
<canvas id="revenueChart" style="height: 400px; width: 100%;"></canvas>
|
2025-07-16 15:12:25 +02:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
<div class="col-xl-6 mb-4">
|
|
|
|
|
<div class="card border-0 shadow-sm h-100">
|
|
|
|
|
<div class="card-header bg-white border-0 pb-0">
|
|
|
|
|
<h5 class="mb-1"><i class="bi bi-bar-chart text-warning"></i> Performance Comparison</h5>
|
|
|
|
|
<p class="small text-muted mb-0">ROI performance across growth scenarios</p>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="card-body pt-3">
|
|
|
|
|
<canvas id="cashFlowChart" style="height: 400px; width: 100%;"></canvas>
|
2025-07-21 17:06:29 +02:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
</div>
|
2025-07-21 17:06:29 +02:00
|
|
|
|
2025-07-22 17:30:37 +02:00
|
|
|
<!-- TERTIARY CHART - Full Width -->
|
|
|
|
|
<div class="row mb-4">
|
|
|
|
|
<div class="col-12">
|
|
|
|
|
<div class="card border-0 shadow-sm">
|
|
|
|
|
<div class="card-header bg-white border-0 pb-0">
|
|
|
|
|
<h5 class="mb-1"><i class="bi bi-graph-up text-info"></i> Investment Model Comparison</h5>
|
|
|
|
|
<p class="small text-muted mb-0">Net profit comparison: Fixed loan returns vs. performance-based direct investment across scenarios</p>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="card-body pt-3">
|
|
|
|
|
<canvas id="modelComparisonChart" style="height: 400px; width: 100%;"></canvas>
|
2025-07-16 15:12:25 +02:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
</div>
|
2025-07-16 15:12:25 +02:00
|
|
|
|
2025-07-22 17:30:37 +02:00
|
|
|
<!-- DATA TABLE - Collapsible to Save Space -->
|
|
|
|
|
<div class="row mb-4">
|
|
|
|
|
<div class="col-12">
|
|
|
|
|
<div class="accordion" id="dataAccordion">
|
|
|
|
|
<div class="accordion-item border-0 shadow-sm">
|
|
|
|
|
<h2 class="accordion-header" id="dataHeading">
|
|
|
|
|
<button class="accordion-button collapsed" type="button" onclick="toggleDataCollapse()" id="dataToggleBtn">
|
|
|
|
|
<i class="bi bi-table me-2"></i> Detailed Financial Analysis
|
|
|
|
|
<span class="badge bg-secondary ms-2">Optional</span>
|
|
|
|
|
</button>
|
|
|
|
|
</h2>
|
|
|
|
|
<div id="dataCollapse" class="accordion-collapse collapse" aria-labelledby="dataHeading" data-bs-parent="#dataAccordion">
|
|
|
|
|
<div class="accordion-body">
|
|
|
|
|
<!-- Comparison Table -->
|
|
|
|
|
<h6 class="mb-3">Scenario Performance Summary</h6>
|
|
|
|
|
<div class="table-responsive mb-4">
|
|
|
|
|
<table class="table table-sm table-striped" id="comparison-table">
|
|
|
|
|
<thead class="table-dark">
|
|
|
|
|
<tr>
|
|
|
|
|
<th>Scenario</th>
|
|
|
|
|
<th>Model</th>
|
|
|
|
|
<th>Final Scale</th>
|
|
|
|
|
<th>Total Revenue</th>
|
|
|
|
|
<th>Your Revenue</th>
|
|
|
|
|
<th>Servala Share</th>
|
|
|
|
|
<th>ROI & Bonuses</th>
|
|
|
|
|
<th>Break-even</th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody id="comparison-tbody">
|
|
|
|
|
<!-- Dynamic content -->
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Monthly Breakdown -->
|
|
|
|
|
<h6 class="mb-3">Monthly Financial Flow</h6>
|
2025-07-16 15:12:25 +02:00
|
|
|
<div class="table-responsive" style="max-height: 400px; overflow-y: auto;">
|
|
|
|
|
<table class="table table-sm table-striped" id="monthly-table">
|
|
|
|
|
<thead class="table-dark sticky-top">
|
|
|
|
|
<tr>
|
|
|
|
|
<th>Month</th>
|
|
|
|
|
<th>Scenario</th>
|
2025-07-22 09:16:40 +02:00
|
|
|
<th>Growth</th>
|
|
|
|
|
<th>Churn</th>
|
|
|
|
|
<th>Scale</th>
|
2025-07-16 15:12:25 +02:00
|
|
|
<th>Monthly Revenue</th>
|
2025-07-22 09:16:40 +02:00
|
|
|
<th>Your Share</th>
|
|
|
|
|
<th>Servala Share</th>
|
|
|
|
|
<th>Net Position</th>
|
2025-07-16 15:12:25 +02:00
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody id="monthly-tbody">
|
|
|
|
|
<!-- Dynamic content -->
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-07-22 17:30:37 +02:00
|
|
|
{% endblock %}
|