rework investment model
This commit is contained in:
parent
22bea2c53d
commit
6f6c80480f
6 changed files with 633 additions and 141 deletions
|
|
@ -11,23 +11,49 @@ class UIManager {
|
|||
try {
|
||||
const enabledResults = Object.values(this.calculator.results);
|
||||
if (enabledResults.length === 0) {
|
||||
this.setElementText('total-instances', '0');
|
||||
this.setElementText('total-revenue', 'CHF 0');
|
||||
this.setElementText('net-position', 'CHF 0');
|
||||
this.setElementText('csp-revenue', 'CHF 0');
|
||||
this.setElementText('roi-percentage', '0%');
|
||||
this.setElementText('breakeven-time', 'N/A');
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate averages across enabled scenarios
|
||||
const avgInstances = Math.round(enabledResults.reduce((sum, r) => sum + r.finalInstances, 0) / enabledResults.length);
|
||||
const avgRevenue = enabledResults.reduce((sum, r) => sum + r.totalRevenue, 0) / enabledResults.length;
|
||||
// Calculate averages across enabled scenarios with enhanced financial metrics
|
||||
const avgNetPosition = enabledResults.reduce((sum, r) => sum + (r.netPosition || 0), 0) / enabledResults.length;
|
||||
const avgCSPRevenue = enabledResults.reduce((sum, r) => sum + r.cspRevenue, 0) / enabledResults.length;
|
||||
const avgROI = enabledResults.reduce((sum, r) => sum + r.roi, 0) / enabledResults.length;
|
||||
const avgBreakeven = enabledResults.filter(r => r.breakEvenMonth).reduce((sum, r) => sum + r.breakEvenMonth, 0) / enabledResults.filter(r => r.breakEvenMonth).length;
|
||||
|
||||
this.setElementText('total-instances', avgInstances.toLocaleString());
|
||||
this.setElementText('total-revenue', this.formatCurrency(avgRevenue));
|
||||
// Update metrics with financial focus
|
||||
this.setElementText('net-position', this.formatCurrency(avgNetPosition));
|
||||
this.setElementText('csp-revenue', this.formatCurrency(avgCSPRevenue));
|
||||
this.setElementText('roi-percentage', this.formatPercentage(avgROI));
|
||||
this.setElementText('breakeven-time', isNaN(avgBreakeven) ? 'N/A' : `${Math.round(avgBreakeven)} months`);
|
||||
|
||||
// Update metric card styling based on performance
|
||||
const netPositionElement = document.getElementById('net-position');
|
||||
if (netPositionElement) {
|
||||
if (avgNetPosition > 0) {
|
||||
netPositionElement.className = 'metric-value text-success';
|
||||
} else if (avgNetPosition < 0) {
|
||||
netPositionElement.className = 'metric-value text-danger';
|
||||
} else {
|
||||
netPositionElement.className = 'metric-value';
|
||||
}
|
||||
}
|
||||
|
||||
const roiElement = document.getElementById('roi-percentage');
|
||||
if (roiElement) {
|
||||
if (avgROI > 15) {
|
||||
roiElement.className = 'metric-value text-success';
|
||||
} else if (avgROI > 5) {
|
||||
roiElement.className = 'metric-value text-warning';
|
||||
} else if (avgROI < 0) {
|
||||
roiElement.className = 'metric-value text-danger';
|
||||
} else {
|
||||
roiElement.className = 'metric-value';
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error updating summary metrics:', error);
|
||||
}
|
||||
|
|
@ -48,15 +74,23 @@ class UIManager {
|
|||
'<span class="badge bg-warning">Loan</span>' :
|
||||
'<span class="badge bg-success">Direct</span>';
|
||||
|
||||
const performanceInfo = result.investmentModel === 'direct' ?
|
||||
`<small class="text-muted d-block">Performance: ${result.performanceMultiplier.toFixed(2)}x</small>` +
|
||||
`<small class="text-muted d-block">Grace: ${result.effectiveGracePeriod} months</small>` :
|
||||
'<small class="text-muted">Fixed returns</small>';
|
||||
|
||||
const row = tbody.insertRow();
|
||||
row.innerHTML = `
|
||||
<td><strong>${result.scenario}</strong></td>
|
||||
<td><strong>${result.scenario}</strong><br>${performanceInfo}</td>
|
||||
<td>${modelLabel}</td>
|
||||
<td>${result.finalInstances.toLocaleString()}</td>
|
||||
<td>${this.formatCurrencyDetailed(result.totalRevenue)}</td>
|
||||
<td>${this.formatCurrencyDetailed(result.cspRevenue)}</td>
|
||||
<td>${this.formatCurrencyDetailed(result.servalaRevenue)}</td>
|
||||
<td class="${result.roi >= 0 ? 'text-success' : 'text-danger'}">${this.formatPercentage(result.roi)}</td>
|
||||
<td class="${result.roi >= 0 ? 'text-success' : 'text-danger'}">
|
||||
${this.formatPercentage(result.roi)}
|
||||
${result.avgPerformanceBonus > 0 ? `<br><small class="text-info">+${this.formatPercentage(result.avgPerformanceBonus * 100)} bonus</small>` : ''}
|
||||
</td>
|
||||
<td>${result.breakEvenMonth ? result.breakEvenMonth + ' months' : 'N/A'}</td>
|
||||
`;
|
||||
});
|
||||
|
|
@ -87,16 +121,22 @@ class UIManager {
|
|||
|
||||
allData.forEach(data => {
|
||||
const row = tbody.insertRow();
|
||||
|
||||
// Enhanced monthly breakdown with financial focus
|
||||
const performanceIcon = data.performanceBonus > 0 ? ' <i class="bi bi-star-fill text-warning" title="Performance Bonus Active"></i>' : '';
|
||||
const graceIcon = data.month <= (data.effectiveGracePeriod || 6) ? ' <i class="bi bi-shield-fill-check text-success" title="Grace Period Active"></i>' : '';
|
||||
const netPositionClass = (data.netPosition || 0) >= 0 ? 'text-success' : 'text-danger';
|
||||
|
||||
row.innerHTML = `
|
||||
<td>${data.month}</td>
|
||||
<td><span class="badge bg-secondary">${data.scenario}</span></td>
|
||||
<td>${data.newInstances}</td>
|
||||
<td>${data.churnedInstances}</td>
|
||||
<td><strong>${data.month}</strong>${graceIcon}</td>
|
||||
<td><span class="badge bg-secondary">${data.scenario}</span>${performanceIcon}</td>
|
||||
<td>+${data.newInstances}</td>
|
||||
<td class="text-muted">-${data.churnedInstances}</td>
|
||||
<td>${data.totalInstances.toLocaleString()}</td>
|
||||
<td>${this.formatCurrencyDetailed(data.monthlyRevenue)}</td>
|
||||
<td>${this.formatCurrencyDetailed(data.cspRevenue)}</td>
|
||||
<td>${this.formatCurrencyDetailed(data.servalaRevenue)}</td>
|
||||
<td>${this.formatCurrencyDetailed(data.cumulativeCSPRevenue)}</td>
|
||||
<td class="fw-bold">${this.formatCurrencyDetailed(data.cspRevenue)}</td>
|
||||
<td class="text-muted">${this.formatCurrencyDetailed(data.servalaRevenue)}</td>
|
||||
<td class="${netPositionClass} fw-bold">${this.formatCurrencyDetailed(data.netPosition || (data.cumulativeCSPRevenue - 500000))}</td>
|
||||
`;
|
||||
});
|
||||
} catch (error) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue