"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const express_1 = require("express"); const prisma_1 = __importDefault(require("../lib/prisma")); const auth_1 = require("../middleware/auth"); const router = (0, express_1.Router)(); // GET /analytics/dashboard router.get('/dashboard', auth_1.requireAuth, async (req, res) => { try { const companyId = req.user.companyId; const today = new Date(); today.setHours(0, 0, 0, 0); const [headcount, onLeave, pendingLeave, openJobs, latestPayroll,] = await Promise.all([ prisma_1.default.employee.count({ where: { companyId, status: { in: ['ACTIVE', 'PROBATION'] } } }), prisma_1.default.leaveRequest.count({ where: { status: 'APPROVED', startDate: { lte: new Date() }, endDate: { gte: today }, employee: { companyId }, }, }), prisma_1.default.leaveRequest.count({ where: { status: 'PENDING', employee: { companyId } }, }), prisma_1.default.job.count({ where: { companyId, status: 'OPEN' } }), prisma_1.default.payrollRun.findFirst({ where: { companyId, status: 'PROCESSED' }, orderBy: { createdAt: 'desc' }, }), ]); return res.json({ headcount, onLeave, pendingLeave, openJobs, monthlyPayroll: latestPayroll?.totalNet || 0, avgEngagement: 78, // placeholder }); } catch (err) { return res.status(500).json({ error: 'Internal server error' }); } }); // GET /analytics/workforce router.get('/workforce', auth_1.requireAuth, async (req, res) => { try { const companyId = req.user.companyId; const employees = await prisma_1.default.employee.findMany({ where: { companyId, status: { not: 'TERMINATED' } }, include: { department: { select: { name: true } }, }, }); // Department breakdown const deptMap = {}; const genderMap = {}; const typeMap = {}; const tenureBuckets = { '0-1yr': 0, '1-3yr': 0, '3-5yr': 0, '5yr+': 0 }; const now = new Date(); employees.forEach(e => { const dept = e.department?.name || 'Unassigned'; deptMap[dept] = (deptMap[dept] || 0) + 1; const gender = e.gender || 'Not specified'; genderMap[gender] = (genderMap[gender] || 0) + 1; typeMap[e.employmentType] = (typeMap[e.employmentType] || 0) + 1; const tenure = (now.getTime() - e.startDate.getTime()) / (1000 * 60 * 60 * 24 * 365); if (tenure < 1) tenureBuckets['0-1yr']++; else if (tenure < 3) tenureBuckets['1-3yr']++; else if (tenure < 5) tenureBuckets['3-5yr']++; else tenureBuckets['5yr+']++; }); return res.json({ departmentBreakdown: Object.entries(deptMap).map(([name, count]) => ({ name, count })), genderRatio: Object.entries(genderMap).map(([name, count]) => ({ name, count })), employmentTypes: Object.entries(typeMap).map(([name, count]) => ({ name, count })), tenureBuckets: Object.entries(tenureBuckets).map(([name, count]) => ({ name, count })), }); } catch (err) { return res.status(500).json({ error: 'Internal server error' }); } }); // GET /analytics/leave router.get('/leave', auth_1.requireAuth, async (req, res) => { try { const companyId = req.user.companyId; const requests = await prisma_1.default.leaveRequest.findMany({ where: { employee: { companyId }, status: { not: 'REJECTED' } }, include: { policy: { select: { name: true, type: true } }, employee: { select: { department: { select: { name: true } } } }, }, }); const byType = {}; const byDept = {}; requests.forEach(r => { const type = r.policy.name; byType[type] = (byType[type] || 0) + r.days; const dept = r.employee.department?.name || 'Unassigned'; if (!byDept[dept]) byDept[dept] = { total: 0, approved: 0 }; byDept[dept].total += r.days; if (r.status === 'APPROVED') byDept[dept].approved += r.days; }); return res.json({ byType: Object.entries(byType).map(([name, days]) => ({ name, days })), byDepartment: Object.entries(byDept).map(([name, data]) => ({ name, ...data })), }); } catch (err) { return res.status(500).json({ error: 'Internal server error' }); } }); // GET /analytics/recruitment router.get('/recruitment', auth_1.requireAuth, async (req, res) => { try { const companyId = req.user.companyId; const [openJobs, totalCandidates, hiredCandidates] = await Promise.all([ prisma_1.default.job.count({ where: { companyId, status: 'OPEN' } }), prisma_1.default.candidate.count({ where: { job: { companyId } }, }), prisma_1.default.candidate.count({ where: { job: { companyId }, currentStage: 'HIRED' }, }), ]); const stages = await prisma_1.default.candidate.groupBy({ by: ['currentStage'], where: { job: { companyId } }, _count: true, }); return res.json({ openJobs, totalCandidates, hiredCandidates, conversionRate: totalCandidates > 0 ? Math.round((hiredCandidates / totalCandidates) * 100) : 0, pipeline: stages.map(s => ({ stage: s.currentStage, count: s._count })), }); } catch (err) { return res.status(500).json({ error: 'Internal server error' }); } }); exports.default = router; //# sourceMappingURL=analytics.js.map