- 순찰/점검 기능 개선 (zone-detail 페이지 추가) - 출근/근태 시스템 개선 (연차 조회, 근무현황) - 작업분석 대분류 그룹화 및 마이그레이션 스크립트 - 모바일 네비게이션 UI 추가 - NAS 배포 도구 및 문서 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
272 lines
7.1 KiB
JavaScript
272 lines
7.1 KiB
JavaScript
/**
|
|
* vacationRequestModel.js
|
|
* 휴가 신청 관련 데이터베이스 쿼리 모델
|
|
*/
|
|
|
|
const { getDb } = require('../dbPool');
|
|
|
|
const vacationRequestModel = {
|
|
/**
|
|
* 휴가 신청 생성
|
|
*/
|
|
async create(requestData, callback) {
|
|
try {
|
|
const db = await getDb();
|
|
const query = `INSERT INTO vacation_requests SET ?`;
|
|
const [result] = await db.query(query, requestData);
|
|
callback(null, result);
|
|
} catch (error) {
|
|
callback(error);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 휴가 신청 목록 조회 (필터링 지원)
|
|
*/
|
|
async getAll(filters = {}, callback) {
|
|
try {
|
|
const db = await getDb();
|
|
|
|
let query = `
|
|
SELECT
|
|
vr.*,
|
|
w.worker_name,
|
|
vt.type_name as vacation_type_name,
|
|
vt.deduct_days as vacation_deduct_days,
|
|
requester.name as requester_name,
|
|
reviewer.name as reviewer_name
|
|
FROM vacation_requests vr
|
|
INNER JOIN workers w ON vr.worker_id = w.worker_id
|
|
INNER JOIN vacation_types vt ON vr.vacation_type_id = vt.id
|
|
LEFT JOIN users requester ON vr.requested_by = requester.user_id
|
|
LEFT JOIN users reviewer ON vr.reviewed_by = reviewer.user_id
|
|
WHERE 1=1
|
|
`;
|
|
|
|
const params = [];
|
|
|
|
// 작업자 필터
|
|
if (filters.worker_id) {
|
|
query += ` AND vr.worker_id = ?`;
|
|
params.push(filters.worker_id);
|
|
}
|
|
|
|
// 상태 필터
|
|
if (filters.status) {
|
|
query += ` AND vr.status = ?`;
|
|
params.push(filters.status);
|
|
}
|
|
|
|
// 기간 필터
|
|
if (filters.start_date) {
|
|
query += ` AND vr.start_date >= ?`;
|
|
params.push(filters.start_date);
|
|
}
|
|
|
|
if (filters.end_date) {
|
|
query += ` AND vr.end_date <= ?`;
|
|
params.push(filters.end_date);
|
|
}
|
|
|
|
// 휴가 유형 필터
|
|
if (filters.vacation_type_id) {
|
|
query += ` AND vr.vacation_type_id = ?`;
|
|
params.push(filters.vacation_type_id);
|
|
}
|
|
|
|
query += ` ORDER BY vr.created_at DESC`;
|
|
|
|
const [rows] = await db.query(query, params);
|
|
callback(null, rows);
|
|
} catch (error) {
|
|
callback(error);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 특정 휴가 신청 조회
|
|
*/
|
|
async getById(requestId, callback) {
|
|
try {
|
|
const db = await getDb();
|
|
const query = `
|
|
SELECT
|
|
vr.*,
|
|
w.worker_name,
|
|
w.phone_number as worker_phone,
|
|
w.email as worker_email,
|
|
vt.type_name as vacation_type_name,
|
|
vt.type_code as vacation_type_code,
|
|
vt.deduct_days as vacation_deduct_days,
|
|
requester.name as requester_name,
|
|
requester.username as requester_username,
|
|
reviewer.name as reviewer_name,
|
|
reviewer.username as reviewer_username
|
|
FROM vacation_requests vr
|
|
INNER JOIN workers w ON vr.worker_id = w.worker_id
|
|
INNER JOIN vacation_types vt ON vr.vacation_type_id = vt.id
|
|
LEFT JOIN users requester ON vr.requested_by = requester.user_id
|
|
LEFT JOIN users reviewer ON vr.reviewed_by = reviewer.user_id
|
|
WHERE vr.request_id = ?
|
|
`;
|
|
const [rows] = await db.query(query, [requestId]);
|
|
callback(null, rows);
|
|
} catch (error) {
|
|
callback(error);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 휴가 신청 수정
|
|
*/
|
|
async update(requestId, updateData, callback) {
|
|
try {
|
|
const db = await getDb();
|
|
const query = `UPDATE vacation_requests SET ? WHERE request_id = ?`;
|
|
const [result] = await db.query(query, [updateData, requestId]);
|
|
callback(null, result);
|
|
} catch (error) {
|
|
callback(error);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 휴가 신청 삭제
|
|
*/
|
|
async delete(requestId, callback) {
|
|
try {
|
|
const db = await getDb();
|
|
const query = `DELETE FROM vacation_requests WHERE request_id = ?`;
|
|
const [result] = await db.query(query, [requestId]);
|
|
callback(null, result);
|
|
} catch (error) {
|
|
callback(error);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 휴가 신청 승인/거부
|
|
*/
|
|
async updateStatus(requestId, statusData, callback) {
|
|
try {
|
|
const db = await getDb();
|
|
const query = `
|
|
UPDATE vacation_requests
|
|
SET
|
|
status = ?,
|
|
reviewed_by = ?,
|
|
reviewed_at = NOW(),
|
|
review_note = ?
|
|
WHERE request_id = ?
|
|
`;
|
|
const [result] = await db.query(query, [
|
|
statusData.status,
|
|
statusData.reviewed_by,
|
|
statusData.review_note || null,
|
|
requestId
|
|
]);
|
|
callback(null, result);
|
|
} catch (error) {
|
|
callback(error);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 특정 작업자의 대기 중인 휴가 신청 수
|
|
*/
|
|
async getPendingCount(workerId, callback) {
|
|
try {
|
|
const db = await getDb();
|
|
const query = `
|
|
SELECT COUNT(*) as count
|
|
FROM vacation_requests
|
|
WHERE worker_id = ? AND status = 'pending'
|
|
`;
|
|
const [rows] = await db.query(query, [workerId]);
|
|
callback(null, rows);
|
|
} catch (error) {
|
|
callback(error);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 특정 작업자의 승인된 휴가 일수 합계 (특정 기간)
|
|
*/
|
|
async getApprovedDaysInPeriod(workerId, startDate, endDate, callback) {
|
|
try {
|
|
const db = await getDb();
|
|
const query = `
|
|
SELECT COALESCE(SUM(days_used), 0) as total_days
|
|
FROM vacation_requests
|
|
WHERE worker_id = ?
|
|
AND status = 'approved'
|
|
AND start_date >= ?
|
|
AND end_date <= ?
|
|
`;
|
|
const [rows] = await db.query(query, [workerId, startDate, endDate]);
|
|
callback(null, rows);
|
|
} catch (error) {
|
|
callback(error);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 휴가 기간 중복 체크
|
|
*/
|
|
async checkOverlap(workerId, startDate, endDate, excludeRequestId = null, callback) {
|
|
try {
|
|
const db = await getDb();
|
|
let query = `
|
|
SELECT COUNT(*) as count
|
|
FROM vacation_requests
|
|
WHERE worker_id = ?
|
|
AND status IN ('pending', 'approved')
|
|
AND (
|
|
(start_date <= ? AND end_date >= ?) OR
|
|
(start_date <= ? AND end_date >= ?) OR
|
|
(start_date >= ? AND end_date <= ?)
|
|
)
|
|
`;
|
|
const params = [workerId, startDate, startDate, endDate, endDate, startDate, endDate];
|
|
|
|
if (excludeRequestId) {
|
|
query += ` AND request_id != ?`;
|
|
params.push(excludeRequestId);
|
|
}
|
|
|
|
const [rows] = await db.query(query, params);
|
|
callback(null, rows);
|
|
} catch (error) {
|
|
callback(error);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 모든 대기 중인 휴가 신청 (관리자용)
|
|
*/
|
|
async getAllPending(callback) {
|
|
try {
|
|
const db = await getDb();
|
|
const query = `
|
|
SELECT
|
|
vr.*,
|
|
w.worker_name,
|
|
vt.type_name as vacation_type_name,
|
|
requester.name as requester_name
|
|
FROM vacation_requests vr
|
|
INNER JOIN workers w ON vr.worker_id = w.worker_id
|
|
INNER JOIN vacation_types vt ON vr.vacation_type_id = vt.id
|
|
LEFT JOIN users requester ON vr.requested_by = requester.user_id
|
|
WHERE vr.status = 'pending'
|
|
ORDER BY vr.created_at ASC
|
|
`;
|
|
const [rows] = await db.query(query);
|
|
callback(null, rows);
|
|
} catch (error) {
|
|
callback(error);
|
|
}
|
|
}
|
|
};
|
|
|
|
module.exports = vacationRequestModel;
|