Files
sankofa-hw-infra/apps/api/src/routes/v1/reports.ts
defiQUG 93df3c8c20
Some checks failed
CI / lint-and-test (push) Has been cancelled
Initial commit: add .gitignore and README
2026-02-09 21:51:50 -08:00

47 lines
2.5 KiB
TypeScript

import type { FastifyInstance } from "fastify";
import { eq, and } from "drizzle-orm";
import { assets as assetsTable, integrationMappings as mappingsTable, unifiProductCatalog as catalogTable } from "@sankofa/schema";
export async function reportsRoutes(app: FastifyInstance) {
const db = app.db;
app.get<{ Querystring: { org_id?: string; site_id?: string } }>("/bom", async (req, reply) => {
const orgId = (req.query as { org_id?: string }).org_id ?? app.orgId(req);
const siteId = (req.query as { site_id?: string }).site_id;
const assetList = siteId
? await db.select().from(assetsTable).where(and(eq(assetsTable.orgId, orgId), eq(assetsTable.siteId, siteId)))
: await db.select().from(assetsTable).where(eq(assetsTable.orgId, orgId));
const mappings = await db.select().from(mappingsTable).where(eq(mappingsTable.orgId, orgId));
const catalog = await db.select().from(catalogTable);
const items = assetList.map((a) => {
const mapping = mappings.find((m) => m.assetId === a.id && m.provider === "unifi");
const catalogEntry = mapping ? catalog.find((c) => c.sku === mapping.externalId || c.modelName === mapping.externalId) : null;
return {
assetId: a.assetId,
category: a.category,
siteId: a.siteId,
catalogSku: catalogEntry?.sku,
generation: catalogEntry?.generation,
supportHorizon: catalogEntry?.supportHorizon,
};
});
return reply.send({ orgId, siteId: siteId ?? null, items });
});
app.get<{ Querystring: { org_id?: string; horizon_months?: string } }>("/support-risk", async (req, reply) => {
const orgId = (req.query as { org_id?: string }).org_id ?? app.orgId(req);
const horizonMonths = Math.min(24, Math.max(1, parseInt((req.query as { horizon_months?: string }).horizon_months ?? "12", 10) || 12));
const catalog = await db.select().from(catalogTable);
const mappings = await db.select().from(mappingsTable).where(and(eq(mappingsTable.orgId, orgId), eq(mappingsTable.provider, "unifi")));
const cutoff = new Date();
cutoff.setMonth(cutoff.getMonth() + horizonMonths);
const atRisk = catalog.filter((c) => {
if (!c.eolDate) return false;
const eol = new Date(c.eolDate);
return eol <= cutoff;
});
const bySku = atRisk.map((c) => ({ sku: c.sku, modelName: c.modelName, generation: c.generation, eolDate: c.eolDate, supportHorizon: c.supportHorizon }));
return reply.send({ orgId, horizonMonths, atRisk: bySku, deviceCount: mappings.length });
});
}