- Replace non-existent 'quotes' DB table lookup with live SalesBldr API call - Fix RMM total: was checking 'rmm_sites' (wrong), now uses 'datto_rmm_sites' - Add SALESBLDR_API_URL/KEY to .env.local (were only in .env, not loaded by container)
113 lines
3.3 KiB
TypeScript
113 lines
3.3 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server';
|
|
import { postgresClient } from '@/lib/services/postgres-client';
|
|
import { SalesBldrClient } from '@/lib/services/salesbldr-client';
|
|
|
|
async function tableExists(tableName: string): Promise<boolean> {
|
|
try {
|
|
const result = await postgresClient.query(
|
|
"SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = $1)",
|
|
[tableName]
|
|
);
|
|
return result.rows[0]?.exists || false;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export async function GET(request: NextRequest) {
|
|
try {
|
|
// Get companies count from database
|
|
const companiesResult = await postgresClient.query(
|
|
'SELECT COUNT(*) as total, COUNT(CASE WHEN is_active = true THEN 1 END) as active FROM companies WHERE company_type = 1'
|
|
);
|
|
|
|
// Get Auvik mapping stats
|
|
let auvikMapped = 0;
|
|
try {
|
|
const auvikResult = await postgresClient.query(
|
|
'SELECT COUNT(*) as mapped FROM auvik_tenant_mappings WHERE autotask_company_id IS NOT NULL'
|
|
);
|
|
auvikMapped = parseInt(auvikResult.rows[0]?.mapped || '0');
|
|
} catch {
|
|
// Table may not exist
|
|
}
|
|
|
|
// Get total Auvik tenants count (check if table exists first)
|
|
let auvikTotal = auvikMapped;
|
|
if (await tableExists('auvik_tenants')) {
|
|
try {
|
|
const auvikTotalResult = await postgresClient.query(
|
|
'SELECT COUNT(*) as total FROM auvik_tenants'
|
|
);
|
|
auvikTotal = parseInt(auvikTotalResult.rows[0]?.total || '0');
|
|
} catch {
|
|
// Ignore error
|
|
}
|
|
}
|
|
|
|
// Get RMM mapping stats
|
|
let rmmMapped = 0;
|
|
try {
|
|
const rmmResult = await postgresClient.query(
|
|
'SELECT COUNT(*) as mapped FROM rmm_site_mappings WHERE company_id IS NOT NULL'
|
|
);
|
|
rmmMapped = parseInt(rmmResult.rows[0]?.mapped || '0');
|
|
} catch {
|
|
// Table may not exist
|
|
}
|
|
|
|
// Get total RMM sites count from datto_rmm_sites
|
|
let rmmTotal = rmmMapped;
|
|
if (await tableExists('datto_rmm_sites')) {
|
|
try {
|
|
const rmmTotalResult = await postgresClient.query(
|
|
'SELECT COUNT(*) as total FROM datto_rmm_sites'
|
|
);
|
|
rmmTotal = parseInt(rmmTotalResult.rows[0]?.total || '0');
|
|
} catch {
|
|
// Ignore error
|
|
}
|
|
}
|
|
|
|
// Get quotes count from SalesBldr API
|
|
let quotesOpen = 0;
|
|
let quotesTotal = 0;
|
|
try {
|
|
const salesbldr = new SalesBldrClient();
|
|
const openQuotes = await salesbldr.getOpenQuotes(1000);
|
|
quotesOpen = openQuotes.total ?? openQuotes.results?.length ?? 0;
|
|
quotesTotal = quotesOpen;
|
|
} catch {
|
|
// SalesBldr not configured or unavailable
|
|
}
|
|
|
|
const stats = {
|
|
companies: {
|
|
total: parseInt(companiesResult.rows[0]?.total || '0'),
|
|
active: parseInt(companiesResult.rows[0]?.active || '0'),
|
|
},
|
|
mappings: {
|
|
auvik: {
|
|
mapped: auvikMapped,
|
|
unmapped: Math.max(0, auvikTotal - auvikMapped),
|
|
},
|
|
rmm: {
|
|
mapped: rmmMapped,
|
|
unmapped: Math.max(0, rmmTotal - rmmMapped),
|
|
},
|
|
},
|
|
quotes: {
|
|
open: quotesOpen,
|
|
total: quotesTotal,
|
|
},
|
|
};
|
|
|
|
return NextResponse.json(stats);
|
|
} catch (error) {
|
|
console.error('Error fetching dashboard stats:', error);
|
|
return NextResponse.json(
|
|
{ error: 'Failed to fetch dashboard stats' },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|