Initial commit - Horux Despachos NL
This commit is contained in:
89
apps/api/src/services/admin-dashboard.service.ts
Normal file
89
apps/api/src/services/admin-dashboard.service.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { prisma } from '../config/database.js';
|
||||
|
||||
export async function getDashboardMetrics() {
|
||||
const now = new Date();
|
||||
const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
|
||||
|
||||
const [
|
||||
totalTenants,
|
||||
activeTenants,
|
||||
trialTenants,
|
||||
cancelledSubs,
|
||||
recentSignups,
|
||||
connectorStatuses,
|
||||
payments,
|
||||
] = await Promise.all([
|
||||
prisma.tenant.count(),
|
||||
prisma.tenant.count({ where: { active: true } }),
|
||||
prisma.tenant.count({ where: { trialEndsAt: { gt: now } } }),
|
||||
prisma.subscription.count({ where: { status: 'cancelled' } }),
|
||||
prisma.tenant.count({ where: { createdAt: { gte: thirtyDaysAgo } } }),
|
||||
prisma.tenant.findMany({
|
||||
where: { dbMode: 'BYO', connectorTunnelHostname: { not: null } },
|
||||
select: { id: true, nombre: true, rfc: true, connectorLastSeen: true, connectorVersion: true },
|
||||
}),
|
||||
prisma.payment.aggregate({
|
||||
where: { status: 'approved', createdAt: { gte: thirtyDaysAgo } },
|
||||
_sum: { amount: true },
|
||||
_count: true,
|
||||
}),
|
||||
]);
|
||||
|
||||
const connectors = connectorStatuses.map(t => {
|
||||
let status: 'connected' | 'degraded' | 'disconnected' = 'disconnected';
|
||||
if (t.connectorLastSeen) {
|
||||
const diff = now.getTime() - t.connectorLastSeen.getTime();
|
||||
if (diff < 60_000) status = 'connected';
|
||||
else if (diff < 300_000) status = 'degraded';
|
||||
}
|
||||
return { id: t.id, nombre: t.nombre, rfc: t.rfc, status, lastSeen: t.connectorLastSeen?.toISOString(), version: t.connectorVersion };
|
||||
});
|
||||
|
||||
const connectorsDown = connectors.filter(c => c.status === 'disconnected').length;
|
||||
|
||||
return {
|
||||
tenants: { total: totalTenants, active: activeTenants, trial: trialTenants, cancelled: cancelledSubs },
|
||||
signupsLast30Days: recentSignups,
|
||||
revenue: { last30Days: Number(payments._sum.amount || 0), paymentsCount: payments._count },
|
||||
connectors: { total: connectors.length, down: connectorsDown, list: connectors },
|
||||
};
|
||||
}
|
||||
|
||||
export async function listAllDespachos(filters?: { vertical?: string; status?: string; search?: string }) {
|
||||
const where: any = {};
|
||||
if (filters?.vertical) where.verticalProfile = filters.vertical;
|
||||
if (filters?.status === 'active') where.active = true;
|
||||
if (filters?.status === 'inactive') where.active = false;
|
||||
if (filters?.search) {
|
||||
where.OR = [
|
||||
{ nombre: { contains: filters.search, mode: 'insensitive' } },
|
||||
{ rfc: { contains: filters.search, mode: 'insensitive' } },
|
||||
];
|
||||
}
|
||||
|
||||
const tenants = await prisma.tenant.findMany({
|
||||
where,
|
||||
select: {
|
||||
id: true, nombre: true, rfc: true, plan: true, active: true, verticalProfile: true,
|
||||
dbMode: true, connectorLastSeen: true, createdAt: true, trialEndsAt: true,
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 100,
|
||||
});
|
||||
|
||||
return tenants.map(t => ({
|
||||
...t,
|
||||
connectorLastSeen: t.connectorLastSeen?.toISOString(),
|
||||
createdAt: t.createdAt.toISOString(),
|
||||
trialEndsAt: t.trialEndsAt?.toISOString(),
|
||||
}));
|
||||
}
|
||||
|
||||
export async function getRecentActivity(limit = 20) {
|
||||
const logs = await prisma.auditLog.findMany({
|
||||
where: { action: { in: ['user.register', 'user.login', 'subscription.created', 'subscription.cancelled', 'subscription.upgraded', 'price.updated'] } },
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: limit,
|
||||
});
|
||||
return logs;
|
||||
}
|
||||
Reference in New Issue
Block a user