Files
mercadodevida/project/src/modules/admin-stats/api/stats.routes.ts
2026-08-17 22:23:10 +02:00

96 lines
2.9 KiB
TypeScript

import type { FastifyInstance } from 'fastify';
import type pg from 'pg';
import { z } from 'zod';
import { requireRole, type Authenticate } from '../../../shared/auth.js';
import { parseJson } from '../../../shared/http-input.js';
interface AdminStatsDeps {
pool: pg.Pool;
authenticate: Authenticate;
}
export async function registerAdminStatsRoutes(
app: FastifyInstance,
deps: AdminStatsDeps,
): Promise<void> {
app.get('/admin/stats', async (request, reply) => {
const user = await deps.authenticate(request);
requireRole(user, 'admin');
const pool = deps.pool;
// All queries run in parallel for speed
const [
ordersToday,
revenueToday,
ordersByState,
outOfStockVariants,
totalProducts,
newCustomersThisMonth,
] = await Promise.all([
// Orders today
pool
.query<{ count: string }>(
`SELECT COUNT(*)::text AS count FROM orders_orders
WHERE created_at >= CURRENT_DATE`,
)
.then((r) => parseInt(r.rows[0]?.count ?? '0', 10)),
// Revenue today (sum of PAID, PROCESSING, SHIPPED, DELIVERED orders)
pool
.query<{ total: string }>(
`SELECT COALESCE(SUM(total_cents), 0)::text AS total FROM orders_orders
WHERE created_at >= CURRENT_DATE
AND state IN ('PAID','PROCESSING','SHIPPED','DELIVERED')`,
)
.then((r) => parseInt(r.rows[0]?.total ?? '0', 10)),
// Orders by state
pool
.query<{ state: string; count: string }>(
`SELECT state, COUNT(*)::text AS count FROM orders_orders
GROUP BY state ORDER BY count DESC`,
)
.then((r) =>
Object.fromEntries(r.rows.map((row) => [row.state, parseInt(row.count, 10)])),
),
// Out-of-stock variants
pool
.query<{ count: string }>(
`SELECT COUNT(*)::text AS count
FROM inventory_stock s
WHERE s.available <= 0`,
)
.then((r) => parseInt(r.rows[0]?.count ?? '0', 10)),
// Total active products
pool
.query<{ count: string }>(
`SELECT COUNT(*)::text AS count FROM catalog_products WHERE state = 'active'`,
)
.then((r) => parseInt(r.rows[0]?.count ?? '0', 10)),
// New customers this month
pool
.query<{ count: string }>(
`SELECT COUNT(*)::text AS count FROM identity_users
WHERE role = 'customer'
AND created_at >= DATE_TRUNC('month', CURRENT_DATE)`,
)
.then((r) => parseInt(r.rows[0]?.count ?? '0', 10)),
]);
return reply.send({
ordersToday,
revenueTodayCents: revenueToday,
revenueTodayFormatted: `${(revenueToday / 100).toFixed(2)}`,
ordersByState,
outOfStockVariants,
totalActiveProducts: totalProducts,
newCustomersThisMonth,
generatedAt: new Date().toISOString(),
});
});
}