260 lines
7.9 KiB
JavaScript
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;
|