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 + + <% } %>
-`; -%> -