Files
EmployeeManagementSystem/backend/routes/attendance.js
2025-11-27 22:50:08 +00:00

260 lines
7.9 KiB
JavaScript

import express from 'express';
import db from '../config/database.js';
import { authenticateToken, authorize } from '../middleware/auth.js';
const router = express.Router();
// Get all attendance records
router.get('/', authenticateToken, async (req, res) => {
try {
const { employeeId, startDate, endDate, status } = req.query;
let query = `
SELECT a.*,
e.name as employee_name, e.username as employee_username,
s.name as supervisor_name,
d.name as department_name,
c.name as contractor_name
FROM attendance a
JOIN users e ON a.employee_id = e.id
JOIN users s ON a.supervisor_id = s.id
LEFT JOIN departments d ON e.department_id = d.id
LEFT JOIN users c ON e.contractor_id = c.id
WHERE 1=1
`;
const params = [];
// Role-based filtering
if (req.user.role === 'Supervisor') {
query += ' AND a.supervisor_id = ?';
params.push(req.user.id);
} else if (req.user.role === 'Employee') {
query += ' AND a.employee_id = ?';
params.push(req.user.id);
}
if (employeeId) {
query += ' AND a.employee_id = ?';
params.push(employeeId);
}
if (startDate) {
query += ' AND a.work_date >= ?';
params.push(startDate);
}
if (endDate) {
query += ' AND a.work_date <= ?';
params.push(endDate);
}
if (status) {
query += ' AND a.status = ?';
params.push(status);
}
query += ' ORDER BY a.work_date DESC, a.check_in_time DESC';
const [records] = await db.query(query, params);
res.json(records);
} catch (error) {
console.error('Get attendance error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Get attendance by ID
router.get('/:id', authenticateToken, async (req, res) => {
try {
const [records] = await db.query(
`SELECT a.*,
e.name as employee_name, e.username as employee_username,
s.name as supervisor_name,
d.name as department_name,
c.name as contractor_name
FROM attendance a
JOIN users e ON a.employee_id = e.id
JOIN users s ON a.supervisor_id = s.id
LEFT JOIN departments d ON e.department_id = d.id
LEFT JOIN users c ON e.contractor_id = c.id
WHERE a.id = ?`,
[req.params.id]
);
if (records.length === 0) {
return res.status(404).json({ error: 'Attendance record not found' });
}
res.json(records[0]);
} catch (error) {
console.error('Get attendance error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Check in employee (Supervisor or SuperAdmin)
router.post('/check-in', authenticateToken, authorize('Supervisor', 'SuperAdmin'), async (req, res) => {
try {
const { employeeId, workDate } = req.body;
if (!employeeId || !workDate) {
return res.status(400).json({ error: 'Employee ID and work date required' });
}
// Verify employee exists (SuperAdmin can check in any employee, Supervisor only their department)
let employeeQuery = 'SELECT * FROM users WHERE id = ? AND role = ?';
let employeeParams = [employeeId, 'Employee'];
if (req.user.role === 'Supervisor') {
employeeQuery += ' AND department_id = ?';
employeeParams.push(req.user.departmentId);
}
const [employees] = await db.query(employeeQuery, employeeParams);
if (employees.length === 0) {
return res.status(403).json({ error: 'Employee not found or not in your department' });
}
// Check if already checked in today
const [existing] = await db.query(
'SELECT * FROM attendance WHERE employee_id = ? AND work_date = ? AND status = ?',
[employeeId, workDate, 'CheckedIn']
);
if (existing.length > 0) {
return res.status(400).json({ error: 'Employee already checked in today' });
}
const checkInTime = new Date();
const [result] = await db.query(
'INSERT INTO attendance (employee_id, supervisor_id, check_in_time, work_date, status) VALUES (?, ?, ?, ?, ?)',
[employeeId, req.user.id, checkInTime, workDate, 'CheckedIn']
);
const [newRecord] = await db.query(
`SELECT a.*,
e.name as employee_name, e.username as employee_username,
s.name as supervisor_name,
d.name as department_name,
c.name as contractor_name
FROM attendance a
JOIN users e ON a.employee_id = e.id
JOIN users s ON a.supervisor_id = s.id
LEFT JOIN departments d ON e.department_id = d.id
LEFT JOIN users c ON e.contractor_id = c.id
WHERE a.id = ?`,
[result.insertId]
);
res.status(201).json(newRecord[0]);
} catch (error) {
console.error('Check in error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Check out employee (Supervisor or SuperAdmin)
router.post('/check-out', authenticateToken, authorize('Supervisor', 'SuperAdmin'), async (req, res) => {
try {
const { employeeId, workDate } = req.body;
if (!employeeId || !workDate) {
return res.status(400).json({ error: 'Employee ID and work date required' });
}
// Find the check-in record (SuperAdmin can check out any, Supervisor only their own)
let query = 'SELECT * FROM attendance WHERE employee_id = ? AND work_date = ? AND status = ?';
let params = [employeeId, workDate, 'CheckedIn'];
if (req.user.role === 'Supervisor') {
query += ' AND supervisor_id = ?';
params.push(req.user.id);
}
const [records] = await db.query(query, params);
if (records.length === 0) {
return res.status(404).json({ error: 'No check-in record found for today' });
}
const checkOutTime = new Date();
await db.query(
'UPDATE attendance SET check_out_time = ?, status = ? WHERE id = ?',
[checkOutTime, 'CheckedOut', records[0].id]
);
const [updatedRecord] = await db.query(
`SELECT a.*,
e.name as employee_name, e.username as employee_username,
s.name as supervisor_name,
d.name as department_name,
c.name as contractor_name
FROM attendance a
JOIN users e ON a.employee_id = e.id
JOIN users s ON a.supervisor_id = s.id
LEFT JOIN departments d ON e.department_id = d.id
LEFT JOIN users c ON e.contractor_id = c.id
WHERE a.id = ?`,
[records[0].id]
);
res.json(updatedRecord[0]);
} catch (error) {
console.error('Check out error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Get attendance summary
router.get('/summary/stats', authenticateToken, async (req, res) => {
try {
const { startDate, endDate, departmentId } = req.query;
let query = `
SELECT
COUNT(DISTINCT a.employee_id) as total_employees,
COUNT(DISTINCT CASE WHEN a.status = 'CheckedIn' THEN a.employee_id END) as checked_in,
COUNT(DISTINCT CASE WHEN a.status = 'CheckedOut' THEN a.employee_id END) as checked_out,
d.name as department_name
FROM attendance a
JOIN users e ON a.employee_id = e.id
LEFT JOIN departments d ON e.department_id = d.id
WHERE 1=1
`;
const params = [];
if (req.user.role === 'Supervisor') {
query += ' AND a.supervisor_id = ?';
params.push(req.user.id);
}
if (startDate) {
query += ' AND a.work_date >= ?';
params.push(startDate);
}
if (endDate) {
query += ' AND a.work_date <= ?';
params.push(endDate);
}
if (departmentId) {
query += ' AND e.department_id = ?';
params.push(departmentId);
}
query += ' GROUP BY d.id, d.name';
const [summary] = await db.query(query, params);
res.json(summary);
} catch (error) {
console.error('Get attendance summary error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
export default router;