Files
tk-factory-services/system1-factory/api/models/vacationRequestModel.js
Hyungi Ahn abd7564e6b refactor: worker_id → user_id 전체 마이그레이션 (Phase 1-4)
sso_users.user_id를 단일 식별자로 통합. JWT에서 worker_id 제거,
department_id/is_production 추가. 백엔드 15개 모델, 11개 컨트롤러,
4개 서비스, 7개 라우트, 프론트엔드 32+ JS/11+ HTML 변환.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 13:13:10 +09:00

201 lines
5.6 KiB
JavaScript

/**
* vacationRequestModel.js
* 휴가 신청 관련 데이터베이스 쿼리 모델
*/
const { getDb } = require('../dbPool');
const vacationRequestModel = {
/**
* 휴가 신청 생성
*/
async create(requestData) {
const db = await getDb();
const [result] = await db.query(`INSERT INTO vacation_requests SET ?`, requestData);
return result;
},
/**
* 휴가 신청 목록 조회 (필터링 지원)
*/
async getAll(filters = {}) {
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.user_id = w.user_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.user_id) {
query += ` AND vr.user_id = ?`;
params.push(filters.user_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);
return rows;
},
/**
* 특정 휴가 신청 조회
*/
async getById(requestId) {
const db = await getDb();
const [rows] = await db.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.user_id = w.user_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 = ?
`, [requestId]);
return rows;
},
/**
* 휴가 신청 수정
*/
async update(requestId, updateData) {
const db = await getDb();
const [result] = await db.query(`UPDATE vacation_requests SET ? WHERE request_id = ?`, [updateData, requestId]);
return result;
},
/**
* 휴가 신청 삭제
*/
async delete(requestId) {
const db = await getDb();
const [result] = await db.query(`DELETE FROM vacation_requests WHERE request_id = ?`, [requestId]);
return result;
},
/**
* 휴가 신청 승인/거부
*/
async updateStatus(requestId, statusData) {
const db = await getDb();
const [result] = await db.query(`
UPDATE vacation_requests
SET status = ?, reviewed_by = ?, reviewed_at = NOW(), review_note = ?
WHERE request_id = ?
`, [statusData.status, statusData.reviewed_by, statusData.review_note || null, requestId]);
return result;
},
/**
* 특정 작업자의 대기 중인 휴가 신청 수
*/
async getPendingCount(userId) {
const db = await getDb();
const [rows] = await db.query(`
SELECT COUNT(*) as count FROM vacation_requests
WHERE user_id = ? AND status = 'pending'
`, [userId]);
return rows;
},
/**
* 특정 작업자의 승인된 휴가 일수 합계 (특정 기간)
*/
async getApprovedDaysInPeriod(userId, startDate, endDate) {
const db = await getDb();
const [rows] = await db.query(`
SELECT COALESCE(SUM(days_used), 0) as total_days FROM vacation_requests
WHERE user_id = ? AND status = 'approved' AND start_date >= ? AND end_date <= ?
`, [userId, startDate, endDate]);
return rows;
},
/**
* 휴가 기간 중복 체크
*/
async checkOverlap(userId, startDate, endDate, excludeRequestId = null) {
const db = await getDb();
let query = `
SELECT COUNT(*) as count FROM vacation_requests
WHERE user_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 = [userId, startDate, startDate, endDate, endDate, startDate, endDate];
if (excludeRequestId) {
query += ` AND request_id != ?`;
params.push(excludeRequestId);
}
const [rows] = await db.query(query, params);
return rows;
},
/**
* 모든 대기 중인 휴가 신청 (관리자용)
*/
async getAllPending() {
const db = await getDb();
const [rows] = await db.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.user_id = w.user_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
`);
return rows;
}
};
module.exports = vacationRequestModel;