diff --git a/services/arbiter-3.0/src/routes/admin.js b/services/arbiter-3.0/src/routes/admin.js
index 44c4add..96b59ba 100644
--- a/services/arbiter-3.0/src/routes/admin.js
+++ b/services/arbiter-3.0/src/routes/admin.js
@@ -1,6 +1,7 @@
const express = require('express');
const router = express.Router();
const { getRoleMappings, saveRoleMappings } = require('../utils/roleMappings');
+const { getFinancialMetrics } = require('../services/FinancialsService');
const isAdmin = (req, res, next) => {
if (req.isAuthenticated()) {
@@ -107,11 +108,17 @@ router.get('/audit', isAdmin, async (req, res) => {
// Financials Module
router.get('/financials', isAdmin, async (req, res) => {
try {
+ // Fetch real financial data from PostgreSQL
+ const financialData = await getFinancialMetrics();
+
res.render('admin/financials/index', {
title: 'Financials',
adminUser: req.user,
csrfToken: req.csrfToken(),
- currentPath: '/financials'
+ currentPath: '/financials',
+ metrics: financialData.metrics,
+ paths: financialData.paths,
+ tierBreakdown: financialData.tierBreakdown
});
} catch (error) {
console.error('Financials error:', error);
diff --git a/services/arbiter-3.0/src/views/admin/financials/index.ejs b/services/arbiter-3.0/src/views/admin/financials/index.ejs
index db4978f..f9a40c6 100644
--- a/services/arbiter-3.0/src/views/admin/financials/index.ejs
+++ b/services/arbiter-3.0/src/views/admin/financials/index.ejs
@@ -1,5 +1,3 @@
-// Build the body content as a string variable
-let bodyContent = `
💰 Revenue Analytics
@@ -12,39 +10,37 @@ let bodyContent = `
Active Subscribers
-
${metrics.activeSubs}
+
<%= metrics.activeSubs %>
Monthly Revenue
-
$${metrics.recognizedMrr.toFixed(2)}
+
$<%= metrics.recognizedMrr.toFixed(2) %>
Annual Run Rate
-
$${metrics.arr}
+
$<%= (metrics.recognizedMrr * 12).toFixed(2) %>
At Risk
-
${metrics.atRiskSubs}
-
$${metrics.atRiskMrr.toFixed(2)} MRR
+
<%= metrics.atRiskSubs %>
+
$<%= metrics.atRiskMrr.toFixed(2) %> MRR
Lifetime Revenue
-
$${metrics.lifetimeRevenue.toFixed(2)}
-
${metrics.lifetimeSubs} Sovereign
+
$<%= metrics.lifetimeRevenue.toFixed(2) %>
+
<%= metrics.lifetimeSubs %> Sovereign
-`;
-// Fire vs Frost Path Comparison
-bodyContent += `
+
@@ -58,11 +54,11 @@ bodyContent += `
Subscribers:
- ${paths.fire.subs}
+ <%= paths.fire.subs %>
Monthly Revenue:
- $${paths.fire.mrr.toFixed(2)}
+ $<%= paths.fire.mrr.toFixed(2) %>
@@ -79,19 +75,17 @@ bodyContent += `
Subscribers:
- ${paths.frost.subs}
+ <%= paths.frost.subs %>
Monthly Revenue:
- $${paths.frost.mrr.toFixed(2)}
+ $<%= paths.frost.mrr.toFixed(2) %>
-`;
-// Tier Breakdown Table
-bodyContent += `
+
Tier Performance
@@ -109,41 +103,36 @@ bodyContent += `
-`;
-
-// Loop through tiers and add rows
-Object.keys(tierBreakdown).sort((a, b) => parseInt(b) - parseInt(a)).forEach(tierLevel => {
- const tier = tierBreakdown[tierLevel];
- const pathColor = tier.path === 'fire' ? 'text-orange-600 dark:text-orange-400' :
- tier.path === 'frost' ? 'text-cyan-600 dark:text-cyan-400' :
- 'text-purple-600 dark:text-purple-400';
-
- bodyContent += `
-
- |
- ${tier.name}
- |
-
- ${tier.path.charAt(0).toUpperCase() + tier.path.slice(1)}
- |
-
- ${tier.activeCount}
- |
-
- ${tier.graceCount}
- |
-
- $${tier.totalMrr.toFixed(2)}
- |
-
- `;
-});
-
-bodyContent += `
+ <% if (tierBreakdown && Object.keys(tierBreakdown).length > 0) { %>
+ <% Object.keys(tierBreakdown).sort((a, b) => parseInt(b) - parseInt(a)).forEach(tierLevel => { %>
+ <% const tier = tierBreakdown[tierLevel]; %>
+ <% const pathColor = tier.path === 'fire' ? 'text-orange-600 dark:text-orange-400' :
+ tier.path === 'frost' ? 'text-cyan-600 dark:text-cyan-400' :
+ 'text-purple-600 dark:text-purple-400'; %>
+
+ |
+ <%= tier.name %>
+ |
+
+ <%= tier.path.charAt(0).toUpperCase() + tier.path.slice(1) %>
+ |
+
+ <%= tier.activeCount %>
+ |
+
+ <%= tier.graceCount %>
+ |
+
+ $<%= tier.totalMrr.toFixed(2) %>
+ |
+
+ <% }); %>
+ <% } else { %>
+
+ | No subscription data available |
+
+ <% } %>
-`;
-%>
-