/** * vacationRequestController.js * 휴가 신청 관련 컨트롤러 */ const vacationRequestModel = require('../models/vacationRequestModel'); const logger = require('../utils/logger'); const vacationRequestController = { /** * 휴가 신청 생성 */ async createRequest(req, res) { try { const { worker_id, vacation_type_id, start_date, end_date, days_used, reason } = req.body; const requested_by = req.user.user_id; if (!worker_id || !vacation_type_id || !start_date || !end_date || !days_used) { return res.status(400).json({ success: false, message: '필수 필드가 누락되었습니다' }); } if (new Date(end_date) < new Date(start_date)) { return res.status(400).json({ success: false, message: '종료일은 시작일보다 이후여야 합니다' }); } // 기간 중복 체크 const overlapRows = await vacationRequestModel.checkOverlap(worker_id, start_date, end_date); if (overlapRows[0].count > 0) { return res.status(400).json({ success: false, message: '해당 기간에 이미 신청된 휴가가 있습니다' }); } const result = await vacationRequestModel.create({ worker_id, vacation_type_id, start_date, end_date, days_used, reason: reason || null, status: 'pending', requested_by }); res.status(201).json({ success: true, message: '휴가 신청이 완료되었습니다', data: { request_id: result.insertId } }); } catch (error) { logger.error('휴가 신청 생성 오류:', error); res.status(500).json({ success: false, message: '서버 오류가 발생했습니다' }); } }, /** * 휴가 신청 목록 조회 */ async getAllRequests(req, res) { try { const filters = { worker_id: req.query.worker_id, status: req.query.status, start_date: req.query.start_date, end_date: req.query.end_date, vacation_type_id: req.query.vacation_type_id }; // 일반 사용자는 자신의 신청만 조회 가능 if (req.user.access_level !== 'system') { if (req.user.worker_id) { filters.worker_id = req.user.worker_id; } else { return res.status(403).json({ success: false, message: '권한이 없습니다' }); } } const results = await vacationRequestModel.getAll(filters); res.json({ success: true, data: results }); } catch (error) { logger.error('휴가 신청 목록 조회 오류:', error); res.status(500).json({ success: false, message: '서버 오류가 발생했습니다' }); } }, /** * 특정 휴가 신청 조회 */ async getRequestById(req, res) { try { const results = await vacationRequestModel.getById(req.params.id); if (results.length === 0) { return res.status(404).json({ success: false, message: '해당 휴가 신청을 찾을 수 없습니다' }); } const request = results[0]; if (req.user.access_level !== 'system' && req.user.worker_id !== request.worker_id) { return res.status(403).json({ success: false, message: '권한이 없습니다' }); } res.json({ success: true, data: request }); } catch (error) { logger.error('휴가 신청 조회 오류:', error); res.status(500).json({ success: false, message: '서버 오류가 발생했습니다' }); } }, /** * 휴가 신청 수정 (대기 중인 신청만) */ async updateRequest(req, res) { try { const { id } = req.params; const { start_date, end_date, days_used, reason } = req.body; const results = await vacationRequestModel.getById(id); if (results.length === 0) { return res.status(404).json({ success: false, message: '해당 휴가 신청을 찾을 수 없습니다' }); } const existingRequest = results[0]; if (req.user.access_level !== 'system' && req.user.worker_id !== existingRequest.worker_id) { return res.status(403).json({ success: false, message: '권한이 없습니다' }); } if (existingRequest.status !== 'pending') { return res.status(400).json({ success: false, message: '승인/거부된 신청은 수정할 수 없습니다' }); } const updateData = {}; if (start_date) updateData.start_date = start_date; if (end_date) updateData.end_date = end_date; if (days_used) updateData.days_used = days_used; if (reason !== undefined) updateData.reason = reason; // 날짜가 변경된 경우 중복 체크 if (start_date || end_date) { const newStartDate = start_date || existingRequest.start_date; const newEndDate = end_date || existingRequest.end_date; const overlapRows = await vacationRequestModel.checkOverlap( existingRequest.worker_id, newStartDate, newEndDate, id ); if (overlapRows[0].count > 0) { return res.status(400).json({ success: false, message: '해당 기간에 이미 신청된 휴가가 있습니다' }); } } await vacationRequestModel.update(id, updateData); res.json({ success: true, message: '휴가 신청이 수정되었습니다' }); } catch (error) { logger.error('휴가 신청 수정 오류:', error); res.status(500).json({ success: false, message: '서버 오류가 발생했습니다' }); } }, /** * 휴가 신청 삭제 (대기 중인 신청만) */ async deleteRequest(req, res) { try { const { id } = req.params; const results = await vacationRequestModel.getById(id); if (results.length === 0) { return res.status(404).json({ success: false, message: '해당 휴가 신청을 찾을 수 없습니다' }); } const existingRequest = results[0]; if (req.user.access_level !== 'system' && req.user.worker_id !== existingRequest.worker_id) { return res.status(403).json({ success: false, message: '권한이 없습니다' }); } if (existingRequest.status !== 'pending') { return res.status(400).json({ success: false, message: '승인/거부된 신청은 삭제할 수 없습니다' }); } await vacationRequestModel.delete(id); res.json({ success: true, message: '휴가 신청이 삭제되었습니다' }); } catch (error) { logger.error('휴가 신청 삭제 오류:', error); res.status(500).json({ success: false, message: '서버 오류가 발생했습니다' }); } }, /** * 휴가 신청 승인 (관리자만) */ async approveRequest(req, res) { try { const { id } = req.params; const { review_note } = req.body; const reviewed_by = req.user.user_id; if (req.user.access_level !== 'system') { return res.status(403).json({ success: false, message: '관리자만 승인할 수 있습니다' }); } const results = await vacationRequestModel.getById(id); if (results.length === 0) { return res.status(404).json({ success: false, message: '해당 휴가 신청을 찾을 수 없습니다' }); } if (results[0].status !== 'pending') { return res.status(400).json({ success: false, message: '이미 처리된 신청입니다' }); } await vacationRequestModel.updateStatus(id, { status: 'approved', reviewed_by, review_note }); res.json({ success: true, message: '휴가 신청이 승인되었습니다' }); } catch (error) { logger.error('휴가 승인 오류:', error); res.status(500).json({ success: false, message: '서버 오류가 발생했습니다' }); } }, /** * 휴가 신청 거부 (관리자만) */ async rejectRequest(req, res) { try { const { id } = req.params; const { review_note } = req.body; const reviewed_by = req.user.user_id; if (req.user.access_level !== 'system') { return res.status(403).json({ success: false, message: '관리자만 거부할 수 있습니다' }); } const results = await vacationRequestModel.getById(id); if (results.length === 0) { return res.status(404).json({ success: false, message: '해당 휴가 신청을 찾을 수 없습니다' }); } if (results[0].status !== 'pending') { return res.status(400).json({ success: false, message: '이미 처리된 신청입니다' }); } await vacationRequestModel.updateStatus(id, { status: 'rejected', reviewed_by, review_note }); res.json({ success: true, message: '휴가 신청이 거부되었습니다' }); } catch (error) { logger.error('휴가 거부 오류:', error); res.status(500).json({ success: false, message: '서버 오류가 발생했습니다' }); } }, /** * 대기 중인 휴가 신청 목록 (관리자용) */ async getPendingRequests(req, res) { try { if (req.user.access_level !== 'system') { return res.status(403).json({ success: false, message: '관리자만 조회할 수 있습니다' }); } const results = await vacationRequestModel.getAllPending(); res.json({ success: true, data: results }); } catch (error) { logger.error('대기 중인 휴가 신청 조회 오류:', error); res.status(500).json({ success: false, message: '서버 오류가 발생했습니다' }); } } }; module.exports = vacationRequestController;