"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 /leave/policies router.get('/policies', auth_1.requireAuth, async (req, res) => { const policies = await prisma_1.default.leavePolicy.findMany({ where: { companyId: req.user.companyId }, }); return res.json(policies); }); // POST /leave/policies router.post('/policies', auth_1.requireAuth, async (req, res) => { try { const policy = await prisma_1.default.leavePolicy.create({ data: { ...req.body, companyId: req.user.companyId }, }); return res.status(201).json(policy); } catch (err) { return res.status(500).json({ error: 'Internal server error' }); } }); // GET /leave/balances router.get('/balances', auth_1.requireAuth, async (req, res) => { try { const { employeeId } = req.query; const empId = employeeId || req.user.employeeId; if (!empId) return res.status(400).json({ error: 'Employee not found' }); const year = new Date().getFullYear(); const balances = await prisma_1.default.leaveBalance.findMany({ where: { employeeId: empId, year }, include: { policy: true }, }); return res.json(balances); } catch (err) { return res.status(500).json({ error: 'Internal server error' }); } }); // GET /leave/requests router.get('/requests', auth_1.requireAuth, async (req, res) => { try { const { status, employeeId, page = '1', limit = '20' } = req.query; const skip = (parseInt(page) - 1) * parseInt(limit); const where = {}; if (req.user.role === 'EMPLOYEE') { where.employeeId = req.user.employeeId; } else if (req.user.role === 'MANAGER') { // Get team members const reports = await prisma_1.default.employee.findMany({ where: { managerId: req.user.employeeId }, select: { id: true }, }); const ids = [req.user.employeeId, ...reports.map(r => r.id)]; where.employeeId = { in: ids }; } if (status) where.status = status; if (employeeId && req.user.role !== 'EMPLOYEE') where.employeeId = employeeId; const [requests, total] = await Promise.all([ prisma_1.default.leaveRequest.findMany({ where, skip, take: parseInt(limit), include: { employee: { select: { firstName: true, lastName: true, employeeCode: true } }, policy: { select: { name: true, type: true } }, }, orderBy: { createdAt: 'desc' }, }), prisma_1.default.leaveRequest.count({ where }), ]); return res.json({ data: requests, total, page: parseInt(page), totalPages: Math.ceil(total / parseInt(limit)) }); } catch (err) { return res.status(500).json({ error: 'Internal server error' }); } }); // POST /leave/requests router.post('/requests', auth_1.requireAuth, async (req, res) => { try { const { policyId, startDate, endDate, reason } = req.body; const employeeId = req.user.employeeId; if (!employeeId) return res.status(400).json({ error: 'Employee not found' }); const start = new Date(startDate); const end = new Date(endDate); const days = Math.ceil((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)) + 1; // Check balance const year = start.getFullYear(); const balance = await prisma_1.default.leaveBalance.findUnique({ where: { employeeId_policyId_year: { employeeId, policyId, year } }, }); if (!balance || balance.balance < days) { return res.status(400).json({ error: 'Insufficient leave balance' }); } // Check overlap const overlap = await prisma_1.default.leaveRequest.findFirst({ where: { employeeId, status: { in: ['PENDING', 'APPROVED'] }, OR: [ { startDate: { lte: end }, endDate: { gte: start } }, ], }, }); if (overlap) { return res.status(409).json({ error: 'Leave request overlaps with existing request' }); } const request = await prisma_1.default.leaveRequest.create({ data: { employeeId, policyId, startDate: start, endDate: end, days, reason, status: 'PENDING' }, include: { policy: true, employee: { select: { firstName: true, lastName: true } } }, }); return res.status(201).json(request); } catch (err) { return res.status(500).json({ error: 'Internal server error' }); } }); // PATCH /leave/requests/:id/approve router.patch('/requests/:id/approve', auth_1.requireAuth, async (req, res) => { try { const request = await prisma_1.default.leaveRequest.findUnique({ where: { id: req.params.id } }); if (!request) return res.status(404).json({ error: 'Request not found' }); if (request.status !== 'PENDING') return res.status(400).json({ error: 'Request already processed' }); await prisma_1.default.leaveRequest.update({ where: { id: req.params.id }, data: { status: 'APPROVED', approverId: req.user.employeeId, approvedAt: new Date(), approverNote: req.body.note, }, }); // Deduct from balance const year = request.startDate.getFullYear(); await prisma_1.default.leaveBalance.update({ where: { employeeId_policyId_year: { employeeId: request.employeeId, policyId: request.policyId, year, }, }, data: { used: { increment: request.days }, balance: { decrement: request.days }, }, }); return res.json({ message: 'Approved' }); } catch (err) { return res.status(500).json({ error: 'Internal server error' }); } }); // PATCH /leave/requests/:id/reject router.patch('/requests/:id/reject', auth_1.requireAuth, async (req, res) => { try { await prisma_1.default.leaveRequest.update({ where: { id: req.params.id }, data: { status: 'REJECTED', approverId: req.user.employeeId, approverNote: req.body.note, }, }); return res.json({ message: 'Rejected' }); } catch (err) { return res.status(500).json({ error: 'Internal server error' }); } }); // GET /leave/calendar router.get('/calendar', auth_1.requireAuth, async (req, res) => { try { const { month, year } = req.query; const y = parseInt(year) || new Date().getFullYear(); const m = parseInt(month) || new Date().getMonth() + 1; const startOfMonth = new Date(y, m - 1, 1); const endOfMonth = new Date(y, m, 0); const requests = await prisma_1.default.leaveRequest.findMany({ where: { status: 'APPROVED', employee: { companyId: req.user.companyId }, startDate: { lte: endOfMonth }, endDate: { gte: startOfMonth }, }, include: { employee: { select: { firstName: true, lastName: true } }, policy: { select: { name: true } }, }, }); return res.json(requests); } catch (err) { return res.status(500).json({ error: 'Internal server error' }); } }); exports.default = router; //# sourceMappingURL=leave.js.map