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>
This commit is contained in:
@@ -12,7 +12,7 @@ class WorkAnalysis {
|
||||
COALESCE(SUM(work_hours), 0) as total_hours,
|
||||
COUNT(*) as total_reports,
|
||||
COUNT(DISTINCT project_id) as active_projects,
|
||||
COUNT(DISTINCT worker_id) as active_workers,
|
||||
COUNT(DISTINCT user_id) as active_workers,
|
||||
SUM(CASE WHEN work_status_id = 2 THEN 1 ELSE 0 END) as error_reports,
|
||||
ROUND(AVG(work_hours), 2) as avg_hours_per_report
|
||||
FROM daily_work_reports
|
||||
@@ -47,7 +47,7 @@ class WorkAnalysis {
|
||||
report_date as date,
|
||||
SUM(work_hours) as hours,
|
||||
COUNT(*) as reports,
|
||||
COUNT(DISTINCT worker_id) as workers,
|
||||
COUNT(DISTINCT user_id) as workers,
|
||||
SUM(CASE WHEN work_status_id = 2 THEN 1 ELSE 0 END) as errors
|
||||
FROM daily_work_reports
|
||||
WHERE report_date BETWEEN ? AND ?
|
||||
@@ -73,7 +73,7 @@ class WorkAnalysis {
|
||||
async getWorkerStats(startDate, endDate) {
|
||||
const query = `
|
||||
SELECT
|
||||
dwr.worker_id,
|
||||
dwr.user_id,
|
||||
w.worker_name,
|
||||
SUM(dwr.work_hours) as totalHours,
|
||||
COUNT(*) as totalReports,
|
||||
@@ -82,17 +82,17 @@ class WorkAnalysis {
|
||||
SUM(CASE WHEN dwr.work_status_id = 2 THEN 1 ELSE 0 END) as errorCount,
|
||||
COUNT(DISTINCT dwr.report_date) as workingDays
|
||||
FROM daily_work_reports dwr
|
||||
LEFT JOIN workers w ON dwr.worker_id = w.worker_id
|
||||
LEFT JOIN workers w ON dwr.user_id = w.user_id
|
||||
WHERE dwr.report_date BETWEEN ? AND ?
|
||||
GROUP BY dwr.worker_id, w.worker_name
|
||||
GROUP BY dwr.user_id, w.worker_name
|
||||
ORDER BY totalHours DESC
|
||||
`;
|
||||
|
||||
try {
|
||||
const [results] = await this.db.execute(query, [startDate, endDate]);
|
||||
return results.map(row => ({
|
||||
worker_id: row.worker_id,
|
||||
worker_name: row.worker_name || `작업자 ${row.worker_id}`,
|
||||
user_id: row.user_id,
|
||||
worker_name: row.worker_name || `작업자 ${row.user_id}`,
|
||||
totalHours: parseFloat(row.totalHours) || 0,
|
||||
totalReports: parseInt(row.totalReports) || 0,
|
||||
avgHours: parseFloat(row.avgHours) || 0,
|
||||
@@ -114,7 +114,7 @@ class WorkAnalysis {
|
||||
p.project_name,
|
||||
SUM(dwr.work_hours) as totalHours,
|
||||
COUNT(*) as totalReports,
|
||||
COUNT(DISTINCT dwr.worker_id) as workerCount,
|
||||
COUNT(DISTINCT dwr.user_id) as workerCount,
|
||||
ROUND(AVG(dwr.work_hours), 2) as avgHours,
|
||||
SUM(CASE WHEN dwr.work_status_id = 2 THEN 1 ELSE 0 END) as errorCount,
|
||||
COUNT(DISTINCT dwr.report_date) as activeDays
|
||||
@@ -152,7 +152,7 @@ class WorkAnalysis {
|
||||
SUM(dwr.work_hours) as totalHours,
|
||||
COUNT(*) as totalReports,
|
||||
ROUND(AVG(dwr.work_hours), 2) as avgHours,
|
||||
COUNT(DISTINCT dwr.worker_id) as workerCount,
|
||||
COUNT(DISTINCT dwr.user_id) as workerCount,
|
||||
SUM(CASE WHEN dwr.work_status_id = 2 THEN 1 ELSE 0 END) as errorCount,
|
||||
COUNT(DISTINCT dwr.project_id) as projectCount
|
||||
FROM daily_work_reports dwr
|
||||
@@ -190,7 +190,7 @@ class WorkAnalysis {
|
||||
SELECT
|
||||
dwr.id,
|
||||
dwr.report_date,
|
||||
dwr.worker_id,
|
||||
dwr.user_id,
|
||||
w.worker_name,
|
||||
dwr.project_id,
|
||||
p.project_name,
|
||||
@@ -215,7 +215,7 @@ class WorkAnalysis {
|
||||
u.name as created_by_name,
|
||||
dwr.created_at
|
||||
FROM daily_work_reports dwr
|
||||
LEFT JOIN workers w ON dwr.worker_id = w.worker_id
|
||||
LEFT JOIN workers w ON dwr.user_id = w.user_id
|
||||
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
||||
LEFT JOIN work_types wt ON dwr.work_type_id = wt.id
|
||||
LEFT JOIN tasks t ON dwr.work_type_id = t.task_id
|
||||
@@ -234,8 +234,8 @@ class WorkAnalysis {
|
||||
return results.map(row => ({
|
||||
id: row.id,
|
||||
report_date: row.report_date,
|
||||
worker_id: row.worker_id,
|
||||
worker_name: row.worker_name || `작업자 ${row.worker_id}`,
|
||||
user_id: row.user_id,
|
||||
worker_name: row.worker_name || `작업자 ${row.user_id}`,
|
||||
project_id: row.project_id,
|
||||
project_name: row.project_name || `프로젝트 ${row.project_id}`,
|
||||
job_no: row.job_no || 'N/A',
|
||||
@@ -274,7 +274,7 @@ class WorkAnalysis {
|
||||
SUM(work_hours) as total_hours,
|
||||
COUNT(*) as total_reports,
|
||||
ROUND(AVG(work_hours), 2) as avg_hours,
|
||||
COUNT(DISTINCT worker_id) as active_workers
|
||||
COUNT(DISTINCT user_id) as active_workers
|
||||
FROM daily_work_reports
|
||||
WHERE report_date BETWEEN ? AND ?
|
||||
GROUP BY DAYOFWEEK(report_date)
|
||||
@@ -306,7 +306,7 @@ class WorkAnalysis {
|
||||
irc.category_name as error_category_name,
|
||||
COUNT(*) as error_count,
|
||||
SUM(dwr.work_hours) as total_hours,
|
||||
COUNT(DISTINCT dwr.worker_id) as affected_workers,
|
||||
COUNT(DISTINCT dwr.user_id) as affected_workers,
|
||||
COUNT(DISTINCT dwr.project_id) as affected_projects
|
||||
FROM daily_work_reports dwr
|
||||
LEFT JOIN issue_report_items iri ON dwr.error_type_id = iri.item_id
|
||||
@@ -341,7 +341,7 @@ class WorkAnalysis {
|
||||
MONTHNAME(report_date) as month_name,
|
||||
SUM(work_hours) as total_hours,
|
||||
COUNT(*) as total_reports,
|
||||
COUNT(DISTINCT worker_id) as active_workers,
|
||||
COUNT(DISTINCT user_id) as active_workers,
|
||||
COUNT(DISTINCT project_id) as active_projects,
|
||||
SUM(CASE WHEN work_status_id = 2 THEN 1 ELSE 0 END) as error_count
|
||||
FROM daily_work_reports
|
||||
@@ -371,7 +371,7 @@ class WorkAnalysis {
|
||||
async getWorkerSpecialization(startDate, endDate) {
|
||||
const query = `
|
||||
SELECT
|
||||
dwr.worker_id,
|
||||
dwr.user_id,
|
||||
w.worker_name,
|
||||
dwr.work_type_id,
|
||||
wt.name as work_type_name,
|
||||
@@ -382,24 +382,24 @@ class WorkAnalysis {
|
||||
ROUND((SUM(dwr.work_hours) / (
|
||||
SELECT SUM(work_hours)
|
||||
FROM daily_work_reports
|
||||
WHERE worker_id = dwr.worker_id
|
||||
WHERE user_id = dwr.user_id
|
||||
AND report_date BETWEEN ? AND ?
|
||||
)) * 100, 2) as percentage
|
||||
FROM daily_work_reports dwr
|
||||
LEFT JOIN workers w ON dwr.worker_id = w.worker_id
|
||||
LEFT JOIN workers w ON dwr.user_id = w.user_id
|
||||
LEFT JOIN work_types wt ON dwr.work_type_id = wt.id
|
||||
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
||||
WHERE dwr.report_date BETWEEN ? AND ?
|
||||
GROUP BY dwr.worker_id, w.worker_name, dwr.work_type_id, wt.name, dwr.project_id, p.project_name
|
||||
GROUP BY dwr.user_id, w.worker_name, dwr.work_type_id, wt.name, dwr.project_id, p.project_name
|
||||
HAVING totalHours > 0
|
||||
ORDER BY dwr.worker_id, totalHours DESC
|
||||
ORDER BY dwr.user_id, totalHours DESC
|
||||
`;
|
||||
|
||||
try {
|
||||
const [results] = await this.db.execute(query, [startDate, endDate, startDate, endDate]);
|
||||
return results.map(row => ({
|
||||
worker_id: row.worker_id,
|
||||
worker_name: row.worker_name || `작업자 ${row.worker_id}`,
|
||||
user_id: row.user_id,
|
||||
worker_name: row.worker_name || `작업자 ${row.user_id}`,
|
||||
work_type_id: row.work_type_id,
|
||||
work_type_name: row.work_type_name || `작업유형 ${row.work_type_id}`,
|
||||
project_id: row.project_id,
|
||||
|
||||
@@ -26,7 +26,7 @@ const getAnalysis = async (startDate, endDate) => {
|
||||
const summarySql = `
|
||||
SELECT
|
||||
COUNT(DISTINCT dwr.project_id) as totalProjects,
|
||||
COUNT(DISTINCT dwr.worker_id) as totalworkers,
|
||||
COUNT(DISTINCT dwr.user_id) as totalworkers,
|
||||
COUNT(DISTINCT dwr.task_id) as totalTasks,
|
||||
SUM(${workHoursCalc}) as totalHours
|
||||
FROM DailyWorkReports dwr
|
||||
@@ -35,7 +35,7 @@ const getAnalysis = async (startDate, endDate) => {
|
||||
|
||||
// 2. 프로젝트별 집계 쿼리
|
||||
const byProjectSql = `
|
||||
SELECT p.project_name as name, SUM(${workHoursCalc}) as hours, COUNT(DISTINCT dwr.worker_id) as participants
|
||||
SELECT p.project_name as name, SUM(${workHoursCalc}) as hours, COUNT(DISTINCT dwr.user_id) as participants
|
||||
FROM DailyWorkReports dwr
|
||||
JOIN projects p ON dwr.project_id = p.project_id
|
||||
${whereClause}
|
||||
@@ -48,7 +48,7 @@ const getAnalysis = async (startDate, endDate) => {
|
||||
const byWorkerSql = `
|
||||
SELECT w.worker_name as name, SUM(${workHoursCalc}) as hours, COUNT(DISTINCT dwr.project_id) as participants
|
||||
FROM DailyWorkReports dwr
|
||||
JOIN workers w ON dwr.worker_id = w.worker_id
|
||||
JOIN workers w ON dwr.user_id = w.user_id
|
||||
${whereClause}
|
||||
GROUP BY w.worker_name
|
||||
HAVING hours > 0
|
||||
@@ -57,7 +57,7 @@ const getAnalysis = async (startDate, endDate) => {
|
||||
|
||||
// 4. 작업별 집계 쿼리
|
||||
const byTaskSql = `
|
||||
SELECT t.category as name, SUM(${workHoursCalc}) as hours, COUNT(DISTINCT dwr.worker_id) as participants
|
||||
SELECT t.category as name, SUM(${workHoursCalc}) as hours, COUNT(DISTINCT dwr.user_id) as participants
|
||||
FROM DailyWorkReports dwr
|
||||
JOIN Tasks t ON dwr.task_id = t.task_id
|
||||
${whereClause}
|
||||
@@ -74,7 +74,7 @@ const getAnalysis = async (startDate, endDate) => {
|
||||
(${workHoursCalc}) as work_hours, dwr.memo
|
||||
FROM DailyWorkReports dwr
|
||||
JOIN projects p ON dwr.project_id = p.project_id
|
||||
JOIN workers w ON dwr.worker_id = w.worker_id
|
||||
JOIN workers w ON dwr.user_id = w.user_id
|
||||
JOIN Tasks t ON dwr.task_id = t.task_id
|
||||
${whereClause}
|
||||
HAVING work_hours > 0
|
||||
|
||||
@@ -2,7 +2,7 @@ const { getDb } = require('../dbPool');
|
||||
|
||||
class AttendanceModel {
|
||||
// 일일 근태 기록 조회
|
||||
static async getDailyAttendanceRecords(date, workerId = null) {
|
||||
static async getDailyAttendanceRecords(date, userId = null) {
|
||||
const db = await getDb();
|
||||
let query = `
|
||||
SELECT
|
||||
@@ -15,7 +15,7 @@ class AttendanceModel {
|
||||
vt.type_code as vacation_type_code,
|
||||
vt.deduct_days as vacation_days
|
||||
FROM daily_attendance_records dar
|
||||
LEFT JOIN workers w ON dar.worker_id = w.worker_id
|
||||
LEFT JOIN workers w ON dar.user_id = w.user_id
|
||||
LEFT JOIN work_attendance_types wat ON dar.attendance_type_id = wat.id
|
||||
LEFT JOIN vacation_types vt ON dar.vacation_type_id = vt.id
|
||||
WHERE dar.record_date = ?
|
||||
@@ -23,9 +23,9 @@ class AttendanceModel {
|
||||
|
||||
const params = [date];
|
||||
|
||||
if (workerId) {
|
||||
query += ' AND dar.worker_id = ?';
|
||||
params.push(workerId);
|
||||
if (userId) {
|
||||
query += ' AND dar.user_id = ?';
|
||||
params.push(userId);
|
||||
}
|
||||
|
||||
query += ' ORDER BY w.worker_name';
|
||||
@@ -35,7 +35,7 @@ class AttendanceModel {
|
||||
}
|
||||
|
||||
// 기간별 근태 기록 조회 (월별 조회용)
|
||||
static async getDailyRecords(startDate, endDate, workerId = null) {
|
||||
static async getDailyRecords(startDate, endDate, userId = null) {
|
||||
const db = await getDb();
|
||||
let query = `
|
||||
SELECT
|
||||
@@ -48,7 +48,7 @@ class AttendanceModel {
|
||||
vt.type_code as vacation_type_code,
|
||||
vt.deduct_days as vacation_days
|
||||
FROM daily_attendance_records dar
|
||||
LEFT JOIN workers w ON dar.worker_id = w.worker_id
|
||||
LEFT JOIN workers w ON dar.user_id = w.user_id
|
||||
LEFT JOIN work_attendance_types wat ON dar.attendance_type_id = wat.id
|
||||
LEFT JOIN vacation_types vt ON dar.vacation_type_id = vt.id
|
||||
WHERE dar.record_date BETWEEN ? AND ?
|
||||
@@ -56,9 +56,9 @@ class AttendanceModel {
|
||||
|
||||
const params = [startDate, endDate];
|
||||
|
||||
if (workerId) {
|
||||
query += ' AND dar.worker_id = ?';
|
||||
params.push(workerId);
|
||||
if (userId) {
|
||||
query += ' AND dar.user_id = ?';
|
||||
params.push(userId);
|
||||
}
|
||||
|
||||
query += ' ORDER BY dar.record_date ASC';
|
||||
@@ -68,17 +68,17 @@ class AttendanceModel {
|
||||
}
|
||||
|
||||
// 작업 보고서와 근태 기록 동기화 (시간 합산 및 상태 업데이트)
|
||||
static async syncWithWorkReports(workerId, date) {
|
||||
static async syncWithWorkReports(userId, date) {
|
||||
const db = await getDb();
|
||||
|
||||
// 1. 해당 날짜의 총 작업 시간 계산
|
||||
const [reportStats] = await db.execute(`
|
||||
SELECT
|
||||
SELECT
|
||||
COALESCE(SUM(work_hours), 0) as total_hours,
|
||||
COUNT(*) as report_count
|
||||
FROM daily_work_reports
|
||||
WHERE worker_id = ? AND report_date = ?
|
||||
`, [workerId, date]);
|
||||
WHERE user_id = ? AND report_date = ?
|
||||
`, [userId, date]);
|
||||
|
||||
const totalHours = parseFloat(reportStats[0].total_hours || 0);
|
||||
const reportCount = reportStats[0].report_count;
|
||||
@@ -110,8 +110,8 @@ class AttendanceModel {
|
||||
// 3. 기록 업데이트 (휴가 정보는 유지)
|
||||
// 기존 기록 조회
|
||||
const [existing] = await db.execute(
|
||||
'SELECT id, vacation_type_id FROM daily_attendance_records WHERE worker_id = ? AND record_date = ?',
|
||||
[workerId, date]
|
||||
'SELECT id, vacation_type_id FROM daily_attendance_records WHERE user_id = ? AND record_date = ?',
|
||||
[userId, date]
|
||||
);
|
||||
|
||||
if (existing.length > 0) {
|
||||
@@ -138,9 +138,9 @@ class AttendanceModel {
|
||||
// 생성자가 명확하지 않으므로 시스템(1) 또는 알 수 없음 처리
|
||||
await db.execute(`
|
||||
INSERT INTO daily_attendance_records
|
||||
(record_date, worker_id, total_work_hours, attendance_type_id, status, created_by)
|
||||
(record_date, user_id, total_work_hours, attendance_type_id, status, created_by)
|
||||
VALUES (?, ?, ?, ?, ?, 1)
|
||||
`, [date, workerId, totalHours, typeId, status]);
|
||||
`, [date, userId, totalHours, typeId, status]);
|
||||
|
||||
return { synced: true, totalHours, status, created: true };
|
||||
}
|
||||
@@ -152,14 +152,14 @@ class AttendanceModel {
|
||||
|
||||
// 1. 활성 작업자 조회
|
||||
const [workers] = await db.execute(
|
||||
'SELECT worker_id FROM workers WHERE status = "active"' // is_active check not needed as status covers it based on previous fix? Wait, previous fix used status='active'.
|
||||
'SELECT user_id FROM workers WHERE status = "active" AND user_id IS NOT NULL'
|
||||
);
|
||||
|
||||
if (workers.length === 0) return { inserted: 0 };
|
||||
|
||||
// 2. 일일 근태 레코드 일괄 생성 (이미 존재하면 무시)
|
||||
// VALUES (...), (...), ...
|
||||
const values = workers.map(w => [date, w.worker_id, 'incomplete', createdBy]);
|
||||
const values = workers.map(w => [date, w.user_id, 'incomplete', createdBy]);
|
||||
|
||||
// Bulk INSERT IGNORE
|
||||
// Note: mysql2 execute doesn't support nested arrays for bulk insert easily with placeholder ?
|
||||
@@ -175,10 +175,10 @@ class AttendanceModel {
|
||||
|
||||
for (const w of workers) {
|
||||
const [result] = await conn.execute(`
|
||||
INSERT IGNORE INTO daily_attendance_records
|
||||
(record_date, worker_id, status, created_by)
|
||||
INSERT IGNORE INTO daily_attendance_records
|
||||
(record_date, user_id, status, created_by)
|
||||
VALUES (?, ?, 'incomplete', ?)
|
||||
`, [date, w.worker_id, createdBy]);
|
||||
`, [date, w.user_id, createdBy]);
|
||||
|
||||
insertedCount += result.affectedRows;
|
||||
}
|
||||
@@ -200,7 +200,7 @@ class AttendanceModel {
|
||||
|
||||
const {
|
||||
record_date,
|
||||
worker_id,
|
||||
user_id,
|
||||
total_work_hours = 8,
|
||||
work_attendance_type_id = 1,
|
||||
vacation_type_id = null,
|
||||
@@ -212,8 +212,8 @@ class AttendanceModel {
|
||||
|
||||
// 기존 기록 확인
|
||||
const [existing] = await db.execute(
|
||||
'SELECT id FROM daily_attendance_records WHERE worker_id = ? AND record_date = ?',
|
||||
[worker_id, record_date]
|
||||
'SELECT id FROM daily_attendance_records WHERE user_id = ? AND record_date = ?',
|
||||
[user_id, record_date]
|
||||
);
|
||||
|
||||
if (existing.length > 0) {
|
||||
@@ -240,12 +240,12 @@ class AttendanceModel {
|
||||
// 생성
|
||||
const [result] = await db.execute(`
|
||||
INSERT INTO daily_attendance_records (
|
||||
record_date, worker_id, total_work_hours, attendance_type_id,
|
||||
record_date, user_id, total_work_hours, attendance_type_id,
|
||||
vacation_type_id, is_overtime_approved, created_by
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
`, [
|
||||
record_date,
|
||||
worker_id,
|
||||
user_id,
|
||||
total_work_hours,
|
||||
attendance_type_id,
|
||||
vacation_type_id,
|
||||
@@ -263,8 +263,8 @@ class AttendanceModel {
|
||||
|
||||
// 모든 작업자와 해당 날짜의 근태 기록을 조회
|
||||
const [rows] = await db.execute(`
|
||||
SELECT
|
||||
w.worker_id,
|
||||
SELECT
|
||||
w.user_id,
|
||||
w.worker_name,
|
||||
w.job_type,
|
||||
COALESCE(dar.total_work_hours, 0) as total_work_hours,
|
||||
@@ -277,16 +277,16 @@ class AttendanceModel {
|
||||
vt.type_code as vacation_type_code,
|
||||
dar.notes,
|
||||
-- 작업 건수 계산
|
||||
(SELECT COUNT(*) FROM daily_work_reports dwr
|
||||
WHERE dwr.worker_id = w.worker_id AND dwr.report_date = ?) as work_count,
|
||||
(SELECT COUNT(*) FROM daily_work_reports dwr
|
||||
WHERE dwr.user_id = w.user_id AND dwr.report_date = ?) as work_count,
|
||||
-- 오류 건수 계산
|
||||
(SELECT COUNT(*) FROM daily_work_reports dwr
|
||||
WHERE dwr.worker_id = w.worker_id AND dwr.report_date = ? AND dwr.work_status_id = 2) as error_count
|
||||
(SELECT COUNT(*) FROM daily_work_reports dwr
|
||||
WHERE dwr.user_id = w.user_id AND dwr.report_date = ? AND dwr.work_status_id = 2) as error_count
|
||||
FROM workers w
|
||||
LEFT JOIN daily_attendance_records dar ON w.worker_id = dar.worker_id AND dar.record_date = ?
|
||||
LEFT JOIN daily_attendance_records dar ON w.user_id = dar.user_id AND dar.record_date = ?
|
||||
LEFT JOIN work_attendance_types wat ON dar.attendance_type_id = wat.id
|
||||
LEFT JOIN vacation_types vt ON dar.vacation_type_id = vt.id
|
||||
WHERE w.is_active = TRUE
|
||||
WHERE w.status = 'active' AND w.user_id IS NOT NULL
|
||||
ORDER BY w.worker_name
|
||||
`, [date, date, date]);
|
||||
|
||||
@@ -294,7 +294,7 @@ class AttendanceModel {
|
||||
}
|
||||
|
||||
// 휴가 처리
|
||||
static async processVacation(workerId, date, vacationType, createdBy) {
|
||||
static async processVacation(userId, date, vacationType, createdBy) {
|
||||
const db = await getDb();
|
||||
|
||||
// 휴가 유형 정보 조회
|
||||
@@ -312,9 +312,9 @@ class AttendanceModel {
|
||||
// 현재 작업 시간 조회
|
||||
const [workHours] = await db.execute(`
|
||||
SELECT COALESCE(SUM(work_hours), 0) as total_hours
|
||||
FROM daily_work_reports
|
||||
WHERE worker_id = ? AND report_date = ?
|
||||
`, [workerId, date]);
|
||||
FROM daily_work_reports
|
||||
WHERE user_id = ? AND report_date = ?
|
||||
`, [userId, date]);
|
||||
|
||||
const currentHours = parseFloat(workHours[0].total_hours);
|
||||
// deduct_days를 시간으로 변환 (1일 = 8시간)
|
||||
@@ -338,12 +338,12 @@ class AttendanceModel {
|
||||
// 휴가 작업 기록 생성 (프로젝트 ID 13 = "연차/휴무", work_type_id 1 = 기본)
|
||||
await db.execute(`
|
||||
INSERT INTO daily_work_reports (
|
||||
report_date, worker_id, project_id, work_type_id, work_status_id,
|
||||
report_date, user_id, project_id, work_type_id, work_status_id,
|
||||
work_hours, description, created_by
|
||||
) VALUES (?, ?, 13, 1, 1, ?, ?, ?)
|
||||
`, [
|
||||
date,
|
||||
workerId,
|
||||
userId,
|
||||
vacationHours,
|
||||
`${vacationTypeInfo.type_name} 처리`,
|
||||
createdBy
|
||||
@@ -352,7 +352,7 @@ class AttendanceModel {
|
||||
// 근태 기록 업데이트
|
||||
const attendanceData = {
|
||||
record_date: date,
|
||||
worker_id: workerId,
|
||||
user_id: userId,
|
||||
total_work_hours: totalHours,
|
||||
work_attendance_type_id: attendanceTypes[0]?.id,
|
||||
vacation_type_id: vacationTypeInfo.id,
|
||||
@@ -364,19 +364,19 @@ class AttendanceModel {
|
||||
}
|
||||
|
||||
// 초과근무 승인
|
||||
static async approveOvertime(workerId, date, approvedBy) {
|
||||
static async approveOvertime(userId, date, approvedBy) {
|
||||
const db = await getDb();
|
||||
|
||||
const [result] = await db.execute(`
|
||||
UPDATE daily_attendance_records
|
||||
SET
|
||||
UPDATE daily_attendance_records
|
||||
SET
|
||||
overtime_approved = TRUE,
|
||||
overtime_approved_by = ?,
|
||||
overtime_approved_at = CURRENT_TIMESTAMP,
|
||||
updated_by = ?,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE worker_id = ? AND record_date = ?
|
||||
`, [approvedBy, approvedBy, workerId, date]);
|
||||
WHERE user_id = ? AND record_date = ?
|
||||
`, [approvedBy, approvedBy, userId, date]);
|
||||
|
||||
return result.affectedRows > 0;
|
||||
}
|
||||
@@ -400,24 +400,24 @@ class AttendanceModel {
|
||||
}
|
||||
|
||||
// 작업자 휴가 잔여 조회
|
||||
static async getWorkerVacationBalance(workerId, year = null) {
|
||||
static async getWorkerVacationBalance(userId, year = null) {
|
||||
const db = await getDb();
|
||||
const currentYear = year || new Date().getFullYear();
|
||||
|
||||
const [rows] = await db.execute(`
|
||||
SELECT id, worker_id, year, total_annual_leave, used_annual_leave, notes, created_at, updated_at FROM worker_vacation_balance
|
||||
WHERE worker_id = ? AND year = ?
|
||||
`, [workerId, currentYear]);
|
||||
SELECT id, user_id, year, total_annual_leave, used_annual_leave, notes, created_at, updated_at FROM worker_vacation_balance
|
||||
WHERE user_id = ? AND year = ?
|
||||
`, [userId, currentYear]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
// 기본 연차 생성 (15일)
|
||||
await db.execute(`
|
||||
INSERT INTO worker_vacation_balance (worker_id, year, total_annual_leave)
|
||||
INSERT INTO worker_vacation_balance (user_id, year, total_annual_leave)
|
||||
VALUES (?, ?, 15.0)
|
||||
`, [workerId, currentYear]);
|
||||
`, [userId, currentYear]);
|
||||
|
||||
return {
|
||||
worker_id: workerId,
|
||||
user_id: userId,
|
||||
year: currentYear,
|
||||
total_annual_leave: 15.0,
|
||||
used_annual_leave: 0,
|
||||
@@ -429,14 +429,14 @@ class AttendanceModel {
|
||||
}
|
||||
|
||||
// 월별 근태 통계
|
||||
static async getMonthlyAttendanceStats(year, month, workerId = null) {
|
||||
static async getMonthlyAttendanceStats(year, month, userId = null) {
|
||||
const db = await getDb();
|
||||
|
||||
// work_attendance_types: 1=NORMAL, 2=LATE, 3=EARLY_LEAVE, 4=ABSENT, 5=VACATION
|
||||
// vacation_types: 1=ANNUAL(연차), 2=HALF_ANNUAL(반차), 3=SICK(병가), 4=SPECIAL(경조사)
|
||||
let query = `
|
||||
SELECT
|
||||
w.worker_id,
|
||||
w.user_id,
|
||||
w.worker_name,
|
||||
COUNT(CASE WHEN dar.attendance_type_id = 1 AND (dar.is_overtime_approved = 0 OR dar.is_overtime_approved IS NULL) THEN 1 END) as regular_days,
|
||||
COUNT(CASE WHEN dar.is_overtime_approved = 1 OR dar.total_work_hours > 8 THEN 1 END) as overtime_days,
|
||||
@@ -446,19 +446,19 @@ class AttendanceModel {
|
||||
COALESCE(SUM(dar.total_work_hours), 0) as total_work_hours,
|
||||
COALESCE(AVG(dar.total_work_hours), 0) as avg_work_hours
|
||||
FROM workers w
|
||||
LEFT JOIN daily_attendance_records dar ON w.worker_id = dar.worker_id
|
||||
LEFT JOIN daily_attendance_records dar ON w.user_id = dar.user_id
|
||||
AND YEAR(dar.record_date) = ? AND MONTH(dar.record_date) = ?
|
||||
WHERE w.employment_status = 'employed'
|
||||
`;
|
||||
|
||||
const params = [year, month];
|
||||
|
||||
if (workerId) {
|
||||
query += ' AND w.worker_id = ?';
|
||||
params.push(workerId);
|
||||
if (userId) {
|
||||
query += ' AND w.user_id = ?';
|
||||
params.push(userId);
|
||||
}
|
||||
|
||||
query += ' GROUP BY w.worker_id, w.worker_name ORDER BY w.worker_name';
|
||||
query += ' GROUP BY w.user_id, w.worker_name ORDER BY w.worker_name';
|
||||
|
||||
const [rows] = await db.execute(query, params);
|
||||
return rows;
|
||||
@@ -467,12 +467,12 @@ class AttendanceModel {
|
||||
// 출근 체크 기록 생성 또는 업데이트
|
||||
static async upsertCheckin(checkinData) {
|
||||
const db = await getDb();
|
||||
const { worker_id, record_date, is_present } = checkinData;
|
||||
const { user_id, record_date, is_present } = checkinData;
|
||||
|
||||
// 해당 날짜에 기록이 있는지 확인
|
||||
const [existing] = await db.execute(
|
||||
'SELECT id FROM daily_attendance_records WHERE worker_id = ? AND record_date = ?',
|
||||
[worker_id, record_date]
|
||||
'SELECT id FROM daily_attendance_records WHERE user_id = ? AND record_date = ?',
|
||||
[user_id, record_date]
|
||||
);
|
||||
|
||||
if (existing.length > 0) {
|
||||
@@ -486,9 +486,9 @@ class AttendanceModel {
|
||||
// 새로 생성 (기본값으로)
|
||||
const [result] = await db.execute(
|
||||
`INSERT INTO daily_attendance_records
|
||||
(worker_id, record_date, is_present, attendance_type_id, created_by)
|
||||
(user_id, record_date, is_present, attendance_type_id, created_by)
|
||||
VALUES (?, ?, ?, 1, 1)`,
|
||||
[worker_id, record_date, is_present]
|
||||
[user_id, record_date, is_present]
|
||||
);
|
||||
return result.insertId;
|
||||
}
|
||||
@@ -499,7 +499,7 @@ class AttendanceModel {
|
||||
const db = await getDb();
|
||||
const query = `
|
||||
SELECT
|
||||
w.worker_id,
|
||||
w.user_id,
|
||||
w.worker_name,
|
||||
w.job_type,
|
||||
w.employment_status,
|
||||
@@ -512,9 +512,9 @@ class AttendanceModel {
|
||||
vr.days_used as vacation_days
|
||||
FROM workers w
|
||||
LEFT JOIN daily_attendance_records dar
|
||||
ON w.worker_id = dar.worker_id AND dar.record_date = ?
|
||||
ON w.user_id = dar.user_id AND dar.record_date = ?
|
||||
LEFT JOIN vacation_requests vr
|
||||
ON w.worker_id = vr.worker_id
|
||||
ON w.user_id = vr.user_id
|
||||
AND ? BETWEEN vr.start_date AND vr.end_date
|
||||
AND vr.status = 'approved'
|
||||
LEFT JOIN vacation_types vt ON vr.vacation_type_id = vt.id
|
||||
|
||||
@@ -12,13 +12,13 @@ const createMany = async (reports) => {
|
||||
const insertedIds = [];
|
||||
const sql = `
|
||||
INSERT INTO DailyIssueReports
|
||||
(date, worker_id, project_id, start_time, end_time, issue_type_id)
|
||||
(date, user_id, project_id, start_time, end_time, issue_type_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
`;
|
||||
|
||||
for (const report of reports) {
|
||||
const { date, worker_id, project_id, start_time, end_time, issue_type_id } = report;
|
||||
const [result] = await conn.query(sql, [date, worker_id, project_id, start_time, end_time, issue_type_id]);
|
||||
const { date, user_id, project_id, start_time, end_time, issue_type_id } = report;
|
||||
const [result] = await conn.query(sql, [date, user_id, project_id, start_time, end_time, issue_type_id]);
|
||||
insertedIds.push(result.insertId);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ const getAllByDate = async (date) => {
|
||||
d.id, d.date, w.worker_name, p.project_name, d.start_time, d.end_time,
|
||||
t.category, t.subcategory, d.description
|
||||
FROM DailyIssueReports d
|
||||
LEFT JOIN workers w ON d.worker_id = w.worker_id
|
||||
LEFT JOIN workers w ON d.user_id = w.user_id
|
||||
LEFT JOIN projects p ON d.project_id = p.project_id
|
||||
LEFT JOIN IssueTypes t ON d.issue_type_id = t.issue_type_id
|
||||
WHERE d.date = ?
|
||||
@@ -58,7 +58,7 @@ const getAllByDate = async (date) => {
|
||||
*/
|
||||
const getById = async (id) => {
|
||||
const db = await getDb();
|
||||
const [rows] = await db.query(`SELECT id, date, worker_id, project_id, issue_type_id, description, created_at, start_time, end_time FROM DailyIssueReports WHERE id = ?`, [id]);
|
||||
const [rows] = await db.query(`SELECT id, date, user_id, project_id, issue_type_id, description, created_at, start_time, end_time FROM DailyIssueReports WHERE id = ?`, [id]);
|
||||
return rows[0];
|
||||
};
|
||||
|
||||
|
||||
@@ -39,22 +39,22 @@ const getAllErrorTypes = async () => {
|
||||
* 누적 추가 전용 함수 (createDailyReport 대체) - 절대 삭제 안함!
|
||||
*/
|
||||
const createDailyReport = async (reportData) => {
|
||||
const { report_date, worker_id, work_entries, created_by, created_by_name, total_hours } = reportData;
|
||||
const { report_date, user_id, work_entries, created_by, created_by_name, total_hours } = reportData;
|
||||
const db = await getDb();
|
||||
const conn = await db.getConnection();
|
||||
|
||||
try {
|
||||
await conn.beginTransaction();
|
||||
|
||||
console.log(`${created_by_name}이 ${report_date} ${worker_id}번 작업자에게 데이터 추가 중...`);
|
||||
console.log(`${created_by_name}이 ${report_date} ${user_id}번 작업자에게 데이터 추가 중...`);
|
||||
|
||||
const [existingReports] = await conn.query(
|
||||
`SELECT dwr.created_by, u.name as created_by_name, COUNT(*) as count, SUM(dwr.work_hours) as total_hours
|
||||
FROM daily_work_reports dwr
|
||||
LEFT JOIN users u ON dwr.created_by = u.user_id
|
||||
WHERE dwr.report_date = ? AND dwr.worker_id = ?
|
||||
LEFT JOIN sso_users u ON dwr.created_by = u.user_id
|
||||
WHERE dwr.report_date = ? AND dwr.user_id = ?
|
||||
GROUP BY dwr.created_by`,
|
||||
[report_date, worker_id]
|
||||
[report_date, user_id]
|
||||
);
|
||||
|
||||
console.log('기존 데이터 (삭제하지 않음):', existingReports);
|
||||
@@ -66,9 +66,9 @@ const createDailyReport = async (reportData) => {
|
||||
|
||||
const [insertResult] = await conn.query(
|
||||
`INSERT INTO daily_work_reports
|
||||
(report_date, worker_id, project_id, work_type_id, work_status_id, error_type_id, work_hours, created_by, created_at)
|
||||
(report_date, user_id, project_id, work_type_id, work_status_id, error_type_id, work_hours, created_by, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW())`,
|
||||
[report_date, worker_id, project_id, work_type_id, work_status_id || 1, error_type_id || null, work_hours, created_by]
|
||||
[report_date, user_id, project_id, work_type_id, work_status_id || 1, error_type_id || null, work_hours, created_by]
|
||||
);
|
||||
|
||||
insertedIds.push(insertResult.insertId);
|
||||
@@ -77,10 +77,10 @@ const createDailyReport = async (reportData) => {
|
||||
const [finalReports] = await conn.query(
|
||||
`SELECT dwr.created_by, u.name as created_by_name, COUNT(*) as count, SUM(dwr.work_hours) as total_hours
|
||||
FROM daily_work_reports dwr
|
||||
LEFT JOIN users u ON dwr.created_by = u.user_id
|
||||
WHERE dwr.report_date = ? AND dwr.worker_id = ?
|
||||
LEFT JOIN sso_users u ON dwr.created_by = u.user_id
|
||||
WHERE dwr.report_date = ? AND dwr.user_id = ?
|
||||
GROUP BY dwr.created_by`,
|
||||
[report_date, worker_id]
|
||||
[report_date, user_id]
|
||||
);
|
||||
|
||||
const grandTotal = finalReports.reduce((sum, report) => sum + parseFloat(report.total_hours || 0), 0);
|
||||
@@ -103,7 +103,7 @@ const createDailyReport = async (reportData) => {
|
||||
insertedIds[0] || null,
|
||||
JSON.stringify({
|
||||
report_date,
|
||||
worker_id,
|
||||
user_id,
|
||||
work_entries_count: work_entries.length,
|
||||
added_hours: total_hours,
|
||||
my_total: myTotal,
|
||||
@@ -123,7 +123,7 @@ const createDailyReport = async (reportData) => {
|
||||
// 근태 기록 동기화
|
||||
try {
|
||||
const AttendanceModel = require('./attendanceModel');
|
||||
await AttendanceModel.syncWithWorkReports(worker_id, report_date);
|
||||
await AttendanceModel.syncWithWorkReports(user_id, report_date);
|
||||
} catch (syncErr) {
|
||||
console.error('근태 기록 동기화 실패:', syncErr);
|
||||
}
|
||||
@@ -153,7 +153,7 @@ const createDailyReport = async (reportData) => {
|
||||
/**
|
||||
* 특정 날짜 + 작업자 + 작성자의 누적 현황 조회
|
||||
*/
|
||||
const getMyAccumulatedHours = async (date, worker_id, created_by) => {
|
||||
const getMyAccumulatedHours = async (date, user_id, created_by) => {
|
||||
const db = await getDb();
|
||||
|
||||
const sql = `
|
||||
@@ -166,32 +166,32 @@ const getMyAccumulatedHours = async (date, worker_id, created_by) => {
|
||||
) as my_entries
|
||||
FROM daily_work_reports dwr
|
||||
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
||||
WHERE dwr.report_date = ? AND dwr.worker_id = ? AND dwr.created_by = ?
|
||||
WHERE dwr.report_date = ? AND dwr.user_id = ? AND dwr.created_by = ?
|
||||
`;
|
||||
|
||||
const [rows] = await db.query(sql, [date, worker_id, created_by]);
|
||||
const [rows] = await db.query(sql, [date, user_id, created_by]);
|
||||
return rows[0] || { my_total_hours: 0, my_entry_count: 0, my_entries: null };
|
||||
};
|
||||
|
||||
/**
|
||||
* 누적 현황 조회 - 날짜+작업자별 (모든 기여자)
|
||||
*/
|
||||
const getAccumulatedReportsByDate = async (date, worker_id) => {
|
||||
const getAccumulatedReportsByDate = async (date, user_id) => {
|
||||
const db = await getDb();
|
||||
|
||||
const sql = getSelectQuery() + `
|
||||
WHERE dwr.report_date = ? AND dwr.worker_id = ?
|
||||
WHERE dwr.report_date = ? AND dwr.user_id = ?
|
||||
ORDER BY dwr.created_by, dwr.created_at ASC
|
||||
`;
|
||||
|
||||
const [rows] = await db.query(sql, [date, worker_id]);
|
||||
const [rows] = await db.query(sql, [date, user_id]);
|
||||
return rows;
|
||||
};
|
||||
|
||||
/**
|
||||
* 기여자별 요약 조회
|
||||
*/
|
||||
const getContributorsByDate = async (date, worker_id) => {
|
||||
const getContributorsByDate = async (date, user_id) => {
|
||||
const db = await getDb();
|
||||
|
||||
const sql = `
|
||||
@@ -207,14 +207,14 @@ const getContributorsByDate = async (date, worker_id) => {
|
||||
ORDER BY dwr.created_at SEPARATOR ', '
|
||||
) as entry_details
|
||||
FROM daily_work_reports dwr
|
||||
LEFT JOIN users u ON dwr.created_by = u.user_id
|
||||
LEFT JOIN sso_users u ON dwr.created_by = u.user_id
|
||||
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
||||
WHERE dwr.report_date = ? AND dwr.worker_id = ?
|
||||
WHERE dwr.report_date = ? AND dwr.user_id = ?
|
||||
GROUP BY dwr.created_by
|
||||
ORDER BY total_hours DESC, first_entry ASC
|
||||
`;
|
||||
|
||||
const [rows] = await db.query(sql, [date, worker_id]);
|
||||
const [rows] = await db.query(sql, [date, user_id]);
|
||||
return rows;
|
||||
};
|
||||
|
||||
@@ -232,9 +232,9 @@ const removeSpecificEntry = async (entry_id, deleted_by) => {
|
||||
const [entryInfo] = await conn.query(
|
||||
`SELECT dwr.*, w.worker_name, p.project_name, u.name as created_by_name
|
||||
FROM daily_work_reports dwr
|
||||
LEFT JOIN workers w ON dwr.worker_id = w.worker_id
|
||||
LEFT JOIN workers w ON dwr.user_id = w.user_id
|
||||
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
||||
LEFT JOIN users u ON dwr.created_by = u.user_id
|
||||
LEFT JOIN sso_users u ON dwr.created_by = u.user_id
|
||||
WHERE dwr.id = ?`,
|
||||
[entry_id]
|
||||
);
|
||||
@@ -282,7 +282,7 @@ const getSelectQuery = () => `
|
||||
SELECT
|
||||
dwr.id,
|
||||
dwr.report_date,
|
||||
dwr.worker_id,
|
||||
dwr.user_id,
|
||||
dwr.project_id,
|
||||
dwr.work_type_id,
|
||||
dwr.work_status_id,
|
||||
@@ -299,13 +299,13 @@ const getSelectQuery = () => `
|
||||
dwr.created_at,
|
||||
dwr.updated_at
|
||||
FROM daily_work_reports dwr
|
||||
LEFT JOIN workers w ON dwr.worker_id = w.worker_id
|
||||
LEFT JOIN workers w ON dwr.user_id = w.user_id
|
||||
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
||||
LEFT JOIN work_types wt ON dwr.work_type_id = wt.id
|
||||
LEFT JOIN work_status_types wst ON dwr.work_status_id = wst.id
|
||||
LEFT JOIN issue_report_items iri ON dwr.error_type_id = iri.item_id
|
||||
LEFT JOIN issue_report_categories irc ON iri.category_id = irc.category_id
|
||||
LEFT JOIN users u ON dwr.created_by = u.user_id
|
||||
LEFT JOIN sso_users u ON dwr.created_by = u.user_id
|
||||
`;
|
||||
|
||||
/**
|
||||
@@ -347,26 +347,26 @@ const getByDateAndCreator = async (date, created_by) => {
|
||||
/**
|
||||
* 10. 일일 작업보고서 조회 (작업자별)
|
||||
*/
|
||||
const getByWorker = async (worker_id) => {
|
||||
const getByWorker = async (user_id) => {
|
||||
const db = await getDb();
|
||||
const sql = getSelectQuery() + `
|
||||
WHERE dwr.worker_id = ?
|
||||
WHERE dwr.user_id = ?
|
||||
ORDER BY dwr.report_date DESC, dwr.id ASC
|
||||
`;
|
||||
const [rows] = await db.query(sql, [worker_id]);
|
||||
const [rows] = await db.query(sql, [user_id]);
|
||||
return rows;
|
||||
};
|
||||
|
||||
/**
|
||||
* 11. 일일 작업보고서 조회 (날짜 + 작업자)
|
||||
*/
|
||||
const getByDateAndWorker = async (date, worker_id) => {
|
||||
const getByDateAndWorker = async (date, user_id) => {
|
||||
const db = await getDb();
|
||||
const sql = getSelectQuery() + `
|
||||
WHERE dwr.report_date = ? AND dwr.worker_id = ?
|
||||
WHERE dwr.report_date = ? AND dwr.user_id = ?
|
||||
ORDER BY dwr.id ASC
|
||||
`;
|
||||
const [rows] = await db.query(sql, [date, worker_id]);
|
||||
const [rows] = await db.query(sql, [date, user_id]);
|
||||
return rows;
|
||||
};
|
||||
|
||||
@@ -387,7 +387,7 @@ const getByRange = async (start_date, end_date) => {
|
||||
* 13. 상세 검색 (페이지네이션 포함)
|
||||
*/
|
||||
const searchWithDetails = async (params) => {
|
||||
const { start_date, end_date, worker_id, project_id, work_status_id, created_by, page, limit } = params;
|
||||
const { start_date, end_date, user_id, project_id, work_status_id, created_by, page, limit } = params;
|
||||
|
||||
const db = await getDb();
|
||||
|
||||
@@ -395,9 +395,9 @@ const searchWithDetails = async (params) => {
|
||||
let whereConditions = ['dwr.report_date BETWEEN ? AND ?'];
|
||||
let queryParams = [start_date, end_date];
|
||||
|
||||
if (worker_id) {
|
||||
whereConditions.push('dwr.worker_id = ?');
|
||||
queryParams.push(worker_id);
|
||||
if (user_id) {
|
||||
whereConditions.push('dwr.user_id = ?');
|
||||
queryParams.push(user_id);
|
||||
}
|
||||
|
||||
if (project_id) {
|
||||
@@ -448,16 +448,16 @@ const getSummaryByDate = async (date) => {
|
||||
|
||||
const sql = `
|
||||
SELECT
|
||||
dwr.worker_id,
|
||||
dwr.user_id,
|
||||
w.worker_name,
|
||||
dwr.report_date,
|
||||
SUM(dwr.work_hours) as total_hours,
|
||||
COUNT(*) as work_entries_count,
|
||||
SUM(CASE WHEN dwr.work_status_id = 2 THEN 1 ELSE 0 END) as error_count
|
||||
FROM daily_work_reports dwr
|
||||
LEFT JOIN workers w ON dwr.worker_id = w.worker_id
|
||||
LEFT JOIN workers w ON dwr.user_id = w.user_id
|
||||
WHERE dwr.report_date = ?
|
||||
GROUP BY dwr.worker_id, dwr.report_date
|
||||
GROUP BY dwr.user_id, dwr.report_date
|
||||
ORDER BY w.worker_name ASC
|
||||
`;
|
||||
const [rows] = await db.query(sql, [date]);
|
||||
@@ -467,24 +467,24 @@ const getSummaryByDate = async (date) => {
|
||||
/**
|
||||
* 15. 일일 근무 요약 조회 (작업자별)
|
||||
*/
|
||||
const getSummaryByWorker = async (worker_id) => {
|
||||
const getSummaryByWorker = async (user_id) => {
|
||||
const db = await getDb();
|
||||
|
||||
const sql = `
|
||||
SELECT
|
||||
dwr.report_date,
|
||||
dwr.worker_id,
|
||||
dwr.user_id,
|
||||
w.worker_name,
|
||||
SUM(dwr.work_hours) as total_hours,
|
||||
COUNT(*) as work_entries_count,
|
||||
SUM(CASE WHEN dwr.work_status_id = 2 THEN 1 ELSE 0 END) as error_count
|
||||
FROM daily_work_reports dwr
|
||||
LEFT JOIN workers w ON dwr.worker_id = w.worker_id
|
||||
WHERE dwr.worker_id = ?
|
||||
GROUP BY dwr.report_date, dwr.worker_id
|
||||
LEFT JOIN workers w ON dwr.user_id = w.user_id
|
||||
WHERE dwr.user_id = ?
|
||||
GROUP BY dwr.report_date, dwr.user_id
|
||||
ORDER BY dwr.report_date DESC
|
||||
`;
|
||||
const [rows] = await db.query(sql, [worker_id]);
|
||||
const [rows] = await db.query(sql, [user_id]);
|
||||
return rows;
|
||||
};
|
||||
|
||||
@@ -499,7 +499,7 @@ const getMonthlySummary = async (year, month) => {
|
||||
const sql = `
|
||||
SELECT
|
||||
dwr.report_date,
|
||||
dwr.worker_id,
|
||||
dwr.user_id,
|
||||
w.worker_name,
|
||||
SUM(dwr.work_hours) as total_work_hours,
|
||||
COUNT(DISTINCT dwr.project_id) as project_count,
|
||||
@@ -508,11 +508,11 @@ const getMonthlySummary = async (year, month) => {
|
||||
GROUP_CONCAT(DISTINCT p.project_name ORDER BY p.project_name) as projects,
|
||||
GROUP_CONCAT(DISTINCT wt.name ORDER BY wt.name) as work_types
|
||||
FROM daily_work_reports dwr
|
||||
LEFT JOIN workers w ON dwr.worker_id = w.worker_id
|
||||
LEFT JOIN workers w ON dwr.user_id = w.user_id
|
||||
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
||||
LEFT JOIN work_types wt ON dwr.work_type_id = wt.id
|
||||
WHERE dwr.report_date BETWEEN ? AND ?
|
||||
GROUP BY dwr.report_date, dwr.worker_id
|
||||
GROUP BY dwr.report_date, dwr.user_id
|
||||
ORDER BY dwr.report_date DESC, w.worker_name ASC
|
||||
`;
|
||||
const [rows] = await db.query(sql, [start, end]);
|
||||
@@ -567,11 +567,11 @@ const updateById = async (id, updateData) => {
|
||||
|
||||
// [Sync] 근태 기록 동기화
|
||||
try {
|
||||
const [targetReport] = await db.query('SELECT worker_id, report_date FROM daily_work_reports WHERE id = ?', [id]);
|
||||
const [targetReport] = await db.query('SELECT user_id, report_date FROM daily_work_reports WHERE id = ?', [id]);
|
||||
if (targetReport.length > 0) {
|
||||
const { worker_id, report_date } = targetReport[0];
|
||||
const { user_id, report_date } = targetReport[0];
|
||||
const AttendanceModel = require('./attendanceModel');
|
||||
await AttendanceModel.syncWithWorkReports(worker_id, report_date);
|
||||
await AttendanceModel.syncWithWorkReports(user_id, report_date);
|
||||
}
|
||||
} catch (syncErr) {
|
||||
console.error('근태 기록 동기화 실패 (Update):', syncErr);
|
||||
@@ -615,9 +615,9 @@ const removeById = async (id, deletedBy) => {
|
||||
// [Sync] 근태 기록 동기화
|
||||
if (reportInfo.length > 0) {
|
||||
try {
|
||||
const { worker_id, report_date } = reportInfo[0];
|
||||
const { user_id, report_date } = reportInfo[0];
|
||||
const AttendanceModel = require('./attendanceModel');
|
||||
await AttendanceModel.syncWithWorkReports(worker_id, report_date);
|
||||
await AttendanceModel.syncWithWorkReports(user_id, report_date);
|
||||
} catch (syncErr) {
|
||||
console.error('근태 기록 동기화 실패 (Delete):', syncErr);
|
||||
}
|
||||
@@ -635,7 +635,7 @@ const removeById = async (id, deletedBy) => {
|
||||
/**
|
||||
* 19. 작업자의 특정 날짜 전체 삭제
|
||||
*/
|
||||
const removeByDateAndWorker = async (date, worker_id, deletedBy) => {
|
||||
const removeByDateAndWorker = async (date, user_id, deletedBy) => {
|
||||
const db = await getDb();
|
||||
const conn = await db.getConnection();
|
||||
|
||||
@@ -644,14 +644,14 @@ const removeByDateAndWorker = async (date, worker_id, deletedBy) => {
|
||||
|
||||
// 삭제 전 정보 저장 (감사 로그용)
|
||||
const [reportInfos] = await conn.query(
|
||||
'SELECT id, report_date, worker_id, project_id, work_type_id, work_status_id, error_type_id, work_hours, created_at, updated_at, created_by, updated_by FROM daily_work_reports WHERE report_date = ? AND worker_id = ?',
|
||||
[date, worker_id]
|
||||
'SELECT id, report_date, user_id, project_id, work_type_id, work_status_id, error_type_id, work_hours, created_at, updated_at, created_by, updated_by FROM daily_work_reports WHERE report_date = ? AND user_id = ?',
|
||||
[date, user_id]
|
||||
);
|
||||
|
||||
// 작업보고서 삭제
|
||||
const [result] = await conn.query(
|
||||
'DELETE FROM daily_work_reports WHERE report_date = ? AND worker_id = ?',
|
||||
[date, worker_id]
|
||||
'DELETE FROM daily_work_reports WHERE report_date = ? AND user_id = ?',
|
||||
[date, user_id]
|
||||
);
|
||||
|
||||
// 감사 로그 추가
|
||||
@@ -673,7 +673,7 @@ const removeByDateAndWorker = async (date, worker_id, deletedBy) => {
|
||||
// [Sync] 근태 기록 동기화
|
||||
try {
|
||||
const AttendanceModel = require('./attendanceModel');
|
||||
await AttendanceModel.syncWithWorkReports(worker_id, date);
|
||||
await AttendanceModel.syncWithWorkReports(user_id, date);
|
||||
} catch (syncErr) {
|
||||
console.error('근태 기록 동기화 실패 (Batch Delete):', syncErr);
|
||||
}
|
||||
@@ -697,7 +697,7 @@ const getStatistics = async (start_date, end_date) => {
|
||||
SELECT
|
||||
COUNT(*) as total_reports,
|
||||
SUM(work_hours) as total_hours,
|
||||
COUNT(DISTINCT worker_id) as unique_workers,
|
||||
COUNT(DISTINCT user_id) as unique_workers,
|
||||
COUNT(DISTINCT project_id) as unique_projects
|
||||
FROM daily_work_reports
|
||||
WHERE report_date BETWEEN ? AND ?
|
||||
@@ -708,7 +708,7 @@ const getStatistics = async (start_date, end_date) => {
|
||||
SELECT
|
||||
report_date,
|
||||
SUM(work_hours) as daily_hours,
|
||||
COUNT(DISTINCT worker_id) as daily_workers
|
||||
COUNT(DISTINCT user_id) as daily_workers
|
||||
FROM daily_work_reports
|
||||
WHERE report_date BETWEEN ? AND ?
|
||||
GROUP BY report_date
|
||||
@@ -727,7 +727,7 @@ const getStatistics = async (start_date, end_date) => {
|
||||
* @param {object} modelData - 서비스 레이어에서 전달된 데이터
|
||||
* @returns {Promise<object>} 삽입된 항목의 ID 배열과 개수
|
||||
*/
|
||||
const createReportEntries = async ({ report_date, worker_id, entries }) => {
|
||||
const createReportEntries = async ({ report_date, user_id, entries }) => {
|
||||
const db = await getDb();
|
||||
const conn = await db.getConnection();
|
||||
try {
|
||||
@@ -736,7 +736,7 @@ const createReportEntries = async ({ report_date, worker_id, entries }) => {
|
||||
const insertedIds = [];
|
||||
const sql = `
|
||||
INSERT INTO daily_work_reports
|
||||
(report_date, worker_id, project_id, work_type_id, work_hours, work_status_id, error_type_id, created_by)
|
||||
(report_date, user_id, project_id, work_type_id, work_hours, work_status_id, error_type_id, created_by)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`;
|
||||
|
||||
@@ -744,7 +744,7 @@ const createReportEntries = async ({ report_date, worker_id, entries }) => {
|
||||
const { project_id, work_type_id, work_hours, work_status_id, error_type_id, created_by } = entry;
|
||||
const [result] = await conn.query(sql, [
|
||||
report_date,
|
||||
worker_id,
|
||||
user_id,
|
||||
project_id,
|
||||
work_type_id,
|
||||
work_hours,
|
||||
@@ -760,7 +760,7 @@ const createReportEntries = async ({ report_date, worker_id, entries }) => {
|
||||
// [Sync] 근태 기록 동기화
|
||||
try {
|
||||
const AttendanceModel = require('./attendanceModel');
|
||||
await AttendanceModel.syncWithWorkReports(worker_id, report_date);
|
||||
await AttendanceModel.syncWithWorkReports(user_id, report_date);
|
||||
} catch (syncErr) {
|
||||
console.error('근태 기록 동기화 실패 (V2 Create):', syncErr);
|
||||
}
|
||||
@@ -788,7 +788,7 @@ const getSelectQueryV2 = () => `
|
||||
SELECT
|
||||
dwr.id,
|
||||
dwr.report_date,
|
||||
dwr.worker_id,
|
||||
dwr.user_id,
|
||||
dwr.project_id,
|
||||
dwr.work_type_id,
|
||||
dwr.work_status_id,
|
||||
@@ -805,19 +805,19 @@ const getSelectQueryV2 = () => `
|
||||
u.name as created_by_name,
|
||||
dwr.created_at
|
||||
FROM daily_work_reports dwr
|
||||
LEFT JOIN workers w ON dwr.worker_id = w.worker_id
|
||||
LEFT JOIN workers w ON dwr.user_id = w.user_id
|
||||
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
||||
LEFT JOIN tasks t ON dwr.work_type_id = t.task_id
|
||||
LEFT JOIN work_types wt ON t.work_type_id = wt.id
|
||||
LEFT JOIN work_status_types wst ON dwr.work_status_id = wst.id
|
||||
LEFT JOIN issue_report_items iri ON dwr.error_type_id = iri.item_id
|
||||
LEFT JOIN issue_report_categories irc ON iri.category_id = irc.category_id
|
||||
LEFT JOIN users u ON dwr.created_by = u.user_id
|
||||
LEFT JOIN sso_users u ON dwr.created_by = u.user_id
|
||||
`;
|
||||
|
||||
/**
|
||||
* [V2] 옵션 기반으로 작업 보고서를 조회합니다.
|
||||
* @param {object} options - 조회 조건 (date, worker_id, created_by_user_id 등)
|
||||
* @param {object} options - 조회 조건 (date, user_id, created_by_user_id 등)
|
||||
* @returns {Promise<Array>} 조회된 작업 보고서 배열
|
||||
*/
|
||||
const getReportsWithOptions = async (options) => {
|
||||
@@ -834,9 +834,9 @@ const getReportsWithOptions = async (options) => {
|
||||
queryParams.push(options.start_date, options.end_date);
|
||||
}
|
||||
|
||||
if (options.worker_id) {
|
||||
whereConditions.push('dwr.worker_id = ?');
|
||||
queryParams.push(options.worker_id);
|
||||
if (options.user_id) {
|
||||
whereConditions.push('dwr.user_id = ?');
|
||||
queryParams.push(options.user_id);
|
||||
}
|
||||
if (options.created_by_user_id) {
|
||||
whereConditions.push('dwr.created_by = ?');
|
||||
@@ -890,7 +890,7 @@ const updateReportById = async (reportId, updateData) => {
|
||||
// [Sync] 업데이트 전 정보 조회 (동기화를 위해)
|
||||
let targetInfo = null;
|
||||
try {
|
||||
const [rows] = await db.query('SELECT worker_id, report_date FROM daily_work_reports WHERE id = ?', [reportId]);
|
||||
const [rows] = await db.query('SELECT user_id, report_date FROM daily_work_reports WHERE id = ?', [reportId]);
|
||||
if (rows.length > 0) targetInfo = rows[0];
|
||||
} catch (e) { console.warn('Sync fetch failed', e); }
|
||||
|
||||
@@ -902,7 +902,7 @@ const updateReportById = async (reportId, updateData) => {
|
||||
if (targetInfo) {
|
||||
try {
|
||||
const AttendanceModel = require('./attendanceModel');
|
||||
await AttendanceModel.syncWithWorkReports(targetInfo.worker_id, targetInfo.report_date);
|
||||
await AttendanceModel.syncWithWorkReports(targetInfo.user_id, targetInfo.report_date);
|
||||
} catch (syncErr) {
|
||||
console.error('근태 기록 동기화 실패 (V2 Update):', syncErr);
|
||||
}
|
||||
@@ -925,7 +925,7 @@ const removeReportById = async (reportId, deletedByUserId) => {
|
||||
await conn.beginTransaction();
|
||||
|
||||
// 감사 로그를 위해 삭제 전 정보 조회
|
||||
const [reportInfo] = await conn.query('SELECT id, report_date, worker_id, project_id, work_type_id, work_status_id, error_type_id, work_hours, created_at, updated_at, created_by, updated_by FROM daily_work_reports WHERE id = ?', [reportId]);
|
||||
const [reportInfo] = await conn.query('SELECT id, report_date, user_id, project_id, work_type_id, work_status_id, error_type_id, work_hours, created_at, updated_at, created_by, updated_by FROM daily_work_reports WHERE id = ?', [reportId]);
|
||||
|
||||
// 실제 삭제 작업
|
||||
const [result] = await conn.query('DELETE FROM daily_work_reports WHERE id = ?', [reportId]);
|
||||
@@ -940,9 +940,9 @@ const removeReportById = async (reportId, deletedByUserId) => {
|
||||
// [Sync] 근태 기록 동기화
|
||||
if (reportInfo.length > 0) {
|
||||
try {
|
||||
const { worker_id, report_date } = reportInfo[0];
|
||||
const { user_id, report_date } = reportInfo[0];
|
||||
const AttendanceModel = require('./attendanceModel');
|
||||
await AttendanceModel.syncWithWorkReports(worker_id, report_date);
|
||||
await AttendanceModel.syncWithWorkReports(user_id, report_date);
|
||||
} catch (syncErr) {
|
||||
console.error('근태 기록 동기화 실패 (V2 Delete):', syncErr);
|
||||
}
|
||||
@@ -1075,7 +1075,7 @@ const createFromTbmAssignment = async (reportData) => {
|
||||
const {
|
||||
tbm_assignment_id,
|
||||
tbm_session_id,
|
||||
worker_id,
|
||||
user_id,
|
||||
project_id,
|
||||
work_type_id,
|
||||
report_date,
|
||||
@@ -1098,7 +1098,7 @@ const createFromTbmAssignment = async (reportData) => {
|
||||
// 1. 작업보고서 생성
|
||||
const sql = `
|
||||
INSERT INTO daily_work_reports
|
||||
(tbm_session_id, tbm_assignment_id, report_date, worker_id, project_id, work_type_id,
|
||||
(tbm_session_id, tbm_assignment_id, report_date, user_id, project_id, work_type_id,
|
||||
start_time, end_time, work_hours, total_hours, regular_hours, error_hours,
|
||||
work_status_id, error_type_id, created_by, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())
|
||||
@@ -1108,7 +1108,7 @@ const createFromTbmAssignment = async (reportData) => {
|
||||
tbm_session_id,
|
||||
tbm_assignment_id,
|
||||
report_date,
|
||||
worker_id,
|
||||
user_id,
|
||||
project_id,
|
||||
work_type_id,
|
||||
start_time || null,
|
||||
@@ -1150,7 +1150,7 @@ const createFromTbmAssignment = async (reportData) => {
|
||||
// 4. 근태 기록 동기화
|
||||
try {
|
||||
const AttendanceModel = require('./attendanceModel');
|
||||
await AttendanceModel.syncWithWorkReports(worker_id, report_date);
|
||||
await AttendanceModel.syncWithWorkReports(user_id, report_date);
|
||||
} catch (syncErr) {
|
||||
console.error('근태 기록 동기화 실패 (TBM Report):', syncErr);
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ const departmentModel = {
|
||||
SELECT w.*, d.department_name, u.user_id, u.username
|
||||
FROM workers w
|
||||
LEFT JOIN departments d ON w.department_id = d.department_id
|
||||
LEFT JOIN users u ON u.worker_id = w.worker_id
|
||||
LEFT JOIN users u ON u.user_id = w.user_id
|
||||
WHERE w.department_id = ?
|
||||
ORDER BY w.worker_name
|
||||
`, [departmentId]);
|
||||
@@ -99,20 +99,20 @@ const departmentModel = {
|
||||
},
|
||||
|
||||
// 작업자 부서 변경
|
||||
async moveWorker(workerId, departmentId) {
|
||||
async moveWorker(userId, departmentId) {
|
||||
const db = await getDb();
|
||||
const [result] = await db.query(`
|
||||
UPDATE workers SET department_id = ? WHERE worker_id = ?
|
||||
`, [departmentId, workerId]);
|
||||
UPDATE workers SET department_id = ? WHERE user_id = ?
|
||||
`, [departmentId, userId]);
|
||||
return result.affectedRows > 0;
|
||||
},
|
||||
|
||||
// 여러 작업자 부서 일괄 변경
|
||||
async moveWorkers(workerIds, departmentId) {
|
||||
async moveWorkers(userIds, departmentId) {
|
||||
const db = await getDb();
|
||||
const [result] = await db.query(`
|
||||
UPDATE workers SET department_id = ? WHERE worker_id IN (?)
|
||||
`, [departmentId, workerIds]);
|
||||
UPDATE workers SET department_id = ? WHERE user_id IN (?)
|
||||
`, [departmentId, userIds]);
|
||||
return result.affectedRows;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -49,7 +49,7 @@ class MonthlyStatusModel {
|
||||
// daily_work_reports에서 직접 집계하여 조회 (중복 없음 보장)
|
||||
const [rows] = await db.query(`
|
||||
SELECT
|
||||
w.worker_id,
|
||||
w.user_id,
|
||||
w.worker_name,
|
||||
w.job_type,
|
||||
YEAR(?) as year,
|
||||
@@ -77,9 +77,9 @@ class MonthlyStatusModel {
|
||||
END as has_issues,
|
||||
MAX(dwr.created_at) as last_updated
|
||||
FROM workers w
|
||||
LEFT JOIN daily_work_reports dwr ON w.worker_id = dwr.worker_id AND dwr.report_date = ?
|
||||
LEFT JOIN daily_work_reports dwr ON w.user_id = dwr.user_id AND dwr.report_date = ?
|
||||
WHERE w.status = 'active'
|
||||
GROUP BY w.worker_id, w.worker_name, w.job_type
|
||||
GROUP BY w.user_id, w.worker_name, w.job_type
|
||||
ORDER BY w.worker_name ASC
|
||||
`, [date, date, date, date]);
|
||||
|
||||
@@ -97,15 +97,15 @@ class MonthlyStatusModel {
|
||||
try {
|
||||
// 해당 월의 모든 날짜와 작업자 조합을 찾아서 재계산
|
||||
const [workDates] = await db.execute(`
|
||||
SELECT DISTINCT report_date, worker_id
|
||||
FROM daily_work_reports
|
||||
SELECT DISTINCT report_date, user_id
|
||||
FROM daily_work_reports
|
||||
WHERE YEAR(report_date) = ? AND MONTH(report_date) = ?
|
||||
`, [year, month]);
|
||||
|
||||
let updatedCount = 0;
|
||||
|
||||
for (const { report_date, worker_id } of workDates) {
|
||||
await db.execute('CALL UpdateMonthlyWorkerStatus(?, ?)', [report_date, worker_id]);
|
||||
for (const { report_date, user_id } of workDates) {
|
||||
await db.execute('CALL UpdateMonthlyWorkerStatus(?, ?)', [report_date, user_id]);
|
||||
updatedCount++;
|
||||
}
|
||||
|
||||
@@ -119,23 +119,23 @@ class MonthlyStatusModel {
|
||||
}
|
||||
|
||||
// 특정 날짜 집계 강제 업데이트
|
||||
static async updateDateSummary(date, workerId = null) {
|
||||
static async updateDateSummary(date, userId = null) {
|
||||
const db = await getDb();
|
||||
|
||||
try {
|
||||
if (workerId) {
|
||||
if (userId) {
|
||||
// 특정 작업자만 업데이트
|
||||
await db.execute('CALL UpdateMonthlyWorkerStatus(?, ?)', [date, workerId]);
|
||||
await db.execute('CALL UpdateMonthlyWorkerStatus(?, ?)', [date, userId]);
|
||||
} else {
|
||||
// 해당 날짜의 모든 작업자 업데이트
|
||||
const [workers] = await db.execute(`
|
||||
SELECT DISTINCT worker_id
|
||||
FROM daily_work_reports
|
||||
SELECT DISTINCT user_id
|
||||
FROM daily_work_reports
|
||||
WHERE report_date = ?
|
||||
`, [date]);
|
||||
|
||||
for (const { worker_id } of workers) {
|
||||
await db.execute('CALL UpdateMonthlyWorkerStatus(?, ?)', [date, worker_id]);
|
||||
for (const { user_id } of workers) {
|
||||
await db.execute('CALL UpdateMonthlyWorkerStatus(?, ?)', [date, user_id]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ class MonthlyStatusModel {
|
||||
const [workerStatusCount] = await db.execute(`
|
||||
SELECT
|
||||
COUNT(*) as total_records,
|
||||
COUNT(DISTINCT worker_id) as unique_workers,
|
||||
COUNT(DISTINCT user_id) as unique_workers,
|
||||
COUNT(DISTINCT date) as unique_dates,
|
||||
MAX(last_updated) as last_update
|
||||
FROM monthly_worker_status
|
||||
|
||||
@@ -139,13 +139,13 @@ const PageAccessModel = {
|
||||
u.name,
|
||||
u.role_id,
|
||||
r.name as role_name,
|
||||
u.worker_id,
|
||||
u.user_id as worker_user_id,
|
||||
w.worker_name,
|
||||
w.job_type,
|
||||
COUNT(upa.page_id) as granted_pages_count
|
||||
FROM users u
|
||||
LEFT JOIN roles r ON u.role_id = r.id
|
||||
LEFT JOIN workers w ON u.worker_id = w.worker_id
|
||||
LEFT JOIN workers w ON u.user_id = w.user_id
|
||||
LEFT JOIN user_page_access upa ON u.user_id = upa.user_id AND upa.can_access = 1
|
||||
WHERE u.is_active = 1
|
||||
AND u.role_id IN (4, 5)
|
||||
|
||||
@@ -8,11 +8,11 @@ const TbmModel = {
|
||||
const db = await getDb();
|
||||
const [result] = await db.query(
|
||||
`INSERT INTO tbm_sessions
|
||||
(session_date, leader_id, project_id, work_type_id, task_id, work_location, created_by)
|
||||
(session_date, leader_user_id, project_id, work_type_id, task_id, work_location, created_by)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
||||
[
|
||||
sessionData.session_date,
|
||||
sessionData.leader_id,
|
||||
sessionData.leader_user_id,
|
||||
sessionData.project_id || null,
|
||||
sessionData.work_type_id || null,
|
||||
sessionData.task_id || null,
|
||||
@@ -32,7 +32,7 @@ const TbmModel = {
|
||||
w.job_type as leader_job_type,
|
||||
u.username as created_by_username,
|
||||
u.name as created_by_name,
|
||||
COUNT(DISTINCT ta.worker_id) as team_member_count,
|
||||
COUNT(DISTINCT ta.user_id) as team_member_count,
|
||||
GROUP_CONCAT(DISTINCT w2.worker_name ORDER BY ta.assignment_id SEPARATOR ', ') as team_member_names,
|
||||
(SELECT COUNT(*) FROM tbm_transfers tf
|
||||
WHERE (tf.source_session_id = s.session_id OR tf.dest_session_id = s.session_id)
|
||||
@@ -46,10 +46,10 @@ const TbmModel = {
|
||||
first_t.task_name,
|
||||
first_wp.workplace_name as work_location
|
||||
FROM tbm_sessions s
|
||||
LEFT JOIN workers w ON s.leader_id = w.worker_id
|
||||
LEFT JOIN workers w ON s.leader_user_id = w.user_id
|
||||
LEFT JOIN sso_users u ON s.created_by = u.user_id
|
||||
LEFT JOIN tbm_team_assignments ta ON s.session_id = ta.session_id
|
||||
LEFT JOIN workers w2 ON ta.worker_id = w2.worker_id
|
||||
LEFT JOIN workers w2 ON ta.user_id = w2.user_id
|
||||
LEFT JOIN (
|
||||
SELECT * FROM tbm_team_assignments
|
||||
WHERE (session_id, assignment_id) IN (
|
||||
@@ -80,7 +80,7 @@ const TbmModel = {
|
||||
w.phone_number as leader_phone,
|
||||
u.username as created_by_username,
|
||||
u.name as created_by_name,
|
||||
COUNT(DISTINCT ta.worker_id) as team_member_count,
|
||||
COUNT(DISTINCT ta.user_id) as team_member_count,
|
||||
first_p.project_name,
|
||||
first_p.job_no,
|
||||
first_wt.name as work_type_name,
|
||||
@@ -90,7 +90,7 @@ const TbmModel = {
|
||||
first_wp.workplace_name as work_location,
|
||||
first_wc.category_name as workplace_category_name
|
||||
FROM tbm_sessions s
|
||||
LEFT JOIN workers w ON s.leader_id = w.worker_id
|
||||
LEFT JOIN workers w ON s.leader_user_id = w.user_id
|
||||
LEFT JOIN sso_users u ON s.created_by = u.user_id
|
||||
LEFT JOIN tbm_team_assignments ta ON s.session_id = ta.session_id
|
||||
LEFT JOIN (
|
||||
@@ -165,8 +165,8 @@ const TbmModel = {
|
||||
await conn.query(
|
||||
`UPDATE tbm_team_assignments
|
||||
SET attendance_type = ?, attendance_hours = ?
|
||||
WHERE session_id = ? AND worker_id = ?`,
|
||||
[item.attendance_type, item.attendance_hours || null, sessionId, item.worker_id]
|
||||
WHERE session_id = ? AND user_id = ?`,
|
||||
[item.attendance_type, item.attendance_hours || null, sessionId, item.user_id]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -174,8 +174,8 @@ const TbmModel = {
|
||||
const annualWorkers = attendanceData.filter(a => a.attendance_type === 'annual');
|
||||
for (const aw of annualWorkers) {
|
||||
const [assignRows] = await conn.query(
|
||||
'SELECT assignment_id FROM tbm_team_assignments WHERE session_id = ? AND worker_id = ?',
|
||||
[sessionId, aw.worker_id]
|
||||
'SELECT assignment_id FROM tbm_team_assignments WHERE session_id = ? AND user_id = ?',
|
||||
[sessionId, aw.user_id]
|
||||
);
|
||||
if (assignRows.length > 0) {
|
||||
const [existingReport] = await conn.query(
|
||||
@@ -185,9 +185,9 @@ const TbmModel = {
|
||||
if (existingReport.length === 0) {
|
||||
await conn.query(
|
||||
`INSERT INTO daily_work_reports
|
||||
(report_date, worker_id, project_id, work_hours, work_status_id, created_by, tbm_assignment_id, created_at)
|
||||
(report_date, user_id, project_id, work_hours, work_status_id, created_by, tbm_assignment_id, created_at)
|
||||
VALUES (?, ?, 13, 8, 1, ?, ?, NOW())`,
|
||||
[reportDate, aw.worker_id, createdBy, assignRows[0].assignment_id]
|
||||
[reportDate, aw.user_id, createdBy, assignRows[0].assignment_id]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -207,7 +207,7 @@ const TbmModel = {
|
||||
for (const aw of annualWorkers) {
|
||||
try {
|
||||
const AttendanceModel = require('./attendanceModel');
|
||||
await AttendanceModel.syncWithWorkReports(aw.worker_id, reportDate);
|
||||
await AttendanceModel.syncWithWorkReports(aw.user_id, reportDate);
|
||||
} catch (syncErr) {
|
||||
// 근태 동기화 오류 (무시됨)
|
||||
}
|
||||
@@ -237,7 +237,7 @@ const TbmModel = {
|
||||
const db = await getDb();
|
||||
const [result] = await db.query(
|
||||
`INSERT INTO tbm_team_assignments
|
||||
(session_id, worker_id, split_seq, assigned_role, work_detail, is_present, absence_reason,
|
||||
(session_id, user_id, split_seq, assigned_role, work_detail, is_present, absence_reason,
|
||||
project_id, work_type_id, task_id, workplace_category_id, workplace_id, work_hours)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
@@ -253,7 +253,7 @@ const TbmModel = {
|
||||
work_hours = COALESCE(VALUES(work_hours), work_hours)`,
|
||||
[
|
||||
assignmentData.session_id,
|
||||
assignmentData.worker_id,
|
||||
assignmentData.user_id,
|
||||
assignmentData.split_seq || 0,
|
||||
assignmentData.assigned_role,
|
||||
assignmentData.work_detail,
|
||||
@@ -273,19 +273,19 @@ const TbmModel = {
|
||||
addSplitAssignment: async (assignmentData) => {
|
||||
const db = await getDb();
|
||||
const [maxRows] = await db.query(
|
||||
'SELECT COALESCE(MAX(split_seq), -1) as max_seq FROM tbm_team_assignments WHERE session_id = ? AND worker_id = ?',
|
||||
[assignmentData.session_id, assignmentData.worker_id]
|
||||
'SELECT COALESCE(MAX(split_seq), -1) as max_seq FROM tbm_team_assignments WHERE session_id = ? AND user_id = ?',
|
||||
[assignmentData.session_id, assignmentData.user_id]
|
||||
);
|
||||
const nextSeq = (maxRows[0].max_seq || 0) + 1;
|
||||
|
||||
const [result] = await db.query(
|
||||
`INSERT INTO tbm_team_assignments
|
||||
(session_id, worker_id, split_seq, work_hours, project_id, work_type_id,
|
||||
(session_id, user_id, split_seq, work_hours, project_id, work_type_id,
|
||||
task_id, workplace_category_id, workplace_id, is_present)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1)`,
|
||||
[
|
||||
assignmentData.session_id,
|
||||
assignmentData.worker_id,
|
||||
assignmentData.user_id,
|
||||
nextSeq,
|
||||
assignmentData.work_hours,
|
||||
assignmentData.project_id || null,
|
||||
@@ -306,7 +306,7 @@ const TbmModel = {
|
||||
const db = await getDb();
|
||||
const values = members.map(m => [
|
||||
sessionId,
|
||||
m.worker_id,
|
||||
m.user_id,
|
||||
m.assigned_role || null,
|
||||
m.work_detail || null,
|
||||
m.is_present !== undefined ? m.is_present : true,
|
||||
@@ -320,7 +320,7 @@ const TbmModel = {
|
||||
|
||||
const [result] = await db.query(
|
||||
`INSERT INTO tbm_team_assignments
|
||||
(session_id, worker_id, assigned_role, work_detail, is_present, absence_reason,
|
||||
(session_id, user_id, assigned_role, work_detail, is_present, absence_reason,
|
||||
project_id, work_type_id, task_id, workplace_category_id, workplace_id)
|
||||
VALUES ?`,
|
||||
[values]
|
||||
@@ -343,7 +343,7 @@ const TbmModel = {
|
||||
wc.category_name AS workplace_category_name,
|
||||
wp.workplace_name
|
||||
FROM tbm_team_assignments ta
|
||||
INNER JOIN workers w ON ta.worker_id = w.worker_id
|
||||
INNER JOIN workers w ON ta.user_id = w.user_id
|
||||
LEFT JOIN projects p ON ta.project_id = p.project_id
|
||||
LEFT JOIN work_types wt ON ta.work_type_id = wt.id
|
||||
LEFT JOIN tasks t ON ta.task_id = t.task_id
|
||||
@@ -359,7 +359,7 @@ const TbmModel = {
|
||||
removeTeamMember: async (sessionId, workerId) => {
|
||||
const db = await getDb();
|
||||
const [result] = await db.query(
|
||||
`DELETE FROM tbm_team_assignments WHERE session_id = ? AND worker_id = ?`,
|
||||
`DELETE FROM tbm_team_assignments WHERE session_id = ? AND user_id = ?`,
|
||||
[sessionId, workerId]
|
||||
);
|
||||
return result;
|
||||
@@ -464,13 +464,13 @@ const TbmModel = {
|
||||
const db = await getDb();
|
||||
const [result] = await db.query(
|
||||
`INSERT INTO team_handovers
|
||||
(session_id, from_leader_id, to_leader_id, handover_date, handover_time,
|
||||
(session_id, from_leader_user_id, to_leader_user_id, handover_date, handover_time,
|
||||
reason, handover_notes, worker_ids)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
[
|
||||
handoverData.session_id,
|
||||
handoverData.from_leader_id,
|
||||
handoverData.to_leader_id,
|
||||
handoverData.from_leader_user_id,
|
||||
handoverData.to_leader_user_id,
|
||||
handoverData.handover_date,
|
||||
handoverData.handover_time,
|
||||
handoverData.reason,
|
||||
@@ -502,8 +502,8 @@ const TbmModel = {
|
||||
u.username as confirmed_by_username,
|
||||
u.name as confirmed_by_name
|
||||
FROM team_handovers h
|
||||
INNER JOIN workers w1 ON h.from_leader_id = w1.worker_id
|
||||
INNER JOIN workers w2 ON h.to_leader_id = w2.worker_id
|
||||
INNER JOIN workers w1 ON h.from_leader_user_id = w1.user_id
|
||||
INNER JOIN workers w2 ON h.to_leader_user_id = w2.user_id
|
||||
LEFT JOIN sso_users u ON h.confirmed_by = u.user_id
|
||||
WHERE h.handover_date = ?
|
||||
ORDER BY h.handover_time DESC`,
|
||||
@@ -521,9 +521,9 @@ const TbmModel = {
|
||||
w1.phone_number as from_leader_phone,
|
||||
s.work_location
|
||||
FROM team_handovers h
|
||||
INNER JOIN workers w1 ON h.from_leader_id = w1.worker_id
|
||||
INNER JOIN workers w1 ON h.from_leader_user_id = w1.user_id
|
||||
LEFT JOIN tbm_sessions s ON h.session_id = s.session_id
|
||||
WHERE h.to_leader_id = ? AND h.is_confirmed = 0
|
||||
WHERE h.to_leader_user_id = ? AND h.is_confirmed = 0
|
||||
ORDER BY h.handover_date DESC, h.handover_time DESC`,
|
||||
[toLeaderId]
|
||||
);
|
||||
@@ -538,7 +538,7 @@ const TbmModel = {
|
||||
`SELECT
|
||||
DATE(session_date) as date,
|
||||
COUNT(DISTINCT session_id) as session_count,
|
||||
COUNT(DISTINCT leader_id) as leader_count,
|
||||
COUNT(DISTINCT leader_user_id) as leader_count,
|
||||
SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed_count
|
||||
FROM tbm_sessions
|
||||
WHERE session_date BETWEEN ? AND ?
|
||||
@@ -553,16 +553,16 @@ const TbmModel = {
|
||||
const db = await getDb();
|
||||
const [rows] = await db.query(
|
||||
`SELECT
|
||||
s.leader_id,
|
||||
s.leader_user_id,
|
||||
w.worker_name as leader_name,
|
||||
COUNT(DISTINCT s.session_id) as total_sessions,
|
||||
SUM(CASE WHEN s.status = 'completed' THEN 1 ELSE 0 END) as completed_sessions,
|
||||
COUNT(DISTINCT ta.worker_id) as total_team_members
|
||||
COUNT(DISTINCT ta.user_id) as total_team_members
|
||||
FROM tbm_sessions s
|
||||
INNER JOIN workers w ON s.leader_id = w.worker_id
|
||||
INNER JOIN workers w ON s.leader_user_id = w.user_id
|
||||
LEFT JOIN tbm_team_assignments ta ON s.session_id = ta.session_id
|
||||
WHERE s.session_date BETWEEN ? AND ?
|
||||
GROUP BY s.leader_id
|
||||
GROUP BY s.leader_user_id
|
||||
ORDER BY total_sessions DESC`,
|
||||
[startDate, endDate]
|
||||
);
|
||||
@@ -597,7 +597,7 @@ const TbmModel = {
|
||||
`SELECT
|
||||
ta.assignment_id,
|
||||
ta.session_id,
|
||||
ta.worker_id,
|
||||
ta.user_id,
|
||||
ta.project_id,
|
||||
ta.work_type_id,
|
||||
ta.task_id,
|
||||
@@ -620,9 +620,9 @@ const TbmModel = {
|
||||
lw.worker_name as leader_name
|
||||
FROM tbm_team_assignments ta
|
||||
INNER JOIN tbm_sessions s ON ta.session_id = s.session_id
|
||||
INNER JOIN workers w ON ta.worker_id = w.worker_id
|
||||
INNER JOIN workers w ON ta.user_id = w.user_id
|
||||
LEFT JOIN sso_users creator ON s.created_by = creator.user_id
|
||||
LEFT JOIN workers lw ON s.leader_id = lw.worker_id
|
||||
LEFT JOIN workers lw ON s.leader_user_id = lw.user_id
|
||||
LEFT JOIN projects p ON ta.project_id = p.project_id
|
||||
LEFT JOIN work_types wt ON ta.work_type_id = wt.id
|
||||
LEFT JOIN tasks t ON ta.task_id = t.task_id
|
||||
|
||||
@@ -13,15 +13,15 @@ const TbmTransferModel = {
|
||||
await conn.beginTransaction();
|
||||
|
||||
const {
|
||||
transfer_type, worker_id, source_session_id, dest_session_id,
|
||||
transfer_type, user_id, source_session_id, dest_session_id,
|
||||
hours, initiated_by, transfer_date,
|
||||
project_id, work_type_id, task_id, workplace_category_id, workplace_id
|
||||
} = transferData;
|
||||
|
||||
// 1. source 세션에서 해당 작업자의 work_hours 업데이트
|
||||
const [sourceRows] = await conn.query(
|
||||
'SELECT assignment_id, work_hours FROM tbm_team_assignments WHERE session_id = ? AND worker_id = ?',
|
||||
[source_session_id, worker_id]
|
||||
'SELECT assignment_id, work_hours FROM tbm_team_assignments WHERE session_id = ? AND user_id = ?',
|
||||
[source_session_id, user_id]
|
||||
);
|
||||
|
||||
if (sourceRows.length === 0) {
|
||||
@@ -38,28 +38,28 @@ const TbmTransferModel = {
|
||||
}
|
||||
|
||||
await conn.query(
|
||||
'UPDATE tbm_team_assignments SET work_hours = ? WHERE session_id = ? AND worker_id = ?',
|
||||
[newSourceHours, source_session_id, worker_id]
|
||||
'UPDATE tbm_team_assignments SET work_hours = ? WHERE session_id = ? AND user_id = ?',
|
||||
[newSourceHours, source_session_id, user_id]
|
||||
);
|
||||
|
||||
// 2. dest 세션에 작업자 INSERT (이미 있으면 work_hours 증가)
|
||||
const [destRows] = await conn.query(
|
||||
'SELECT assignment_id, work_hours FROM tbm_team_assignments WHERE session_id = ? AND worker_id = ?',
|
||||
[dest_session_id, worker_id]
|
||||
'SELECT assignment_id, work_hours FROM tbm_team_assignments WHERE session_id = ? AND user_id = ?',
|
||||
[dest_session_id, user_id]
|
||||
);
|
||||
|
||||
if (destRows.length > 0) {
|
||||
const existingHours = destRows[0].work_hours === null ? 8 : parseFloat(destRows[0].work_hours);
|
||||
await conn.query(
|
||||
'UPDATE tbm_team_assignments SET work_hours = ? WHERE session_id = ? AND worker_id = ?',
|
||||
[existingHours + parseFloat(hours), dest_session_id, worker_id]
|
||||
'UPDATE tbm_team_assignments SET work_hours = ? WHERE session_id = ? AND user_id = ?',
|
||||
[existingHours + parseFloat(hours), dest_session_id, user_id]
|
||||
);
|
||||
} else {
|
||||
await conn.query(
|
||||
`INSERT INTO tbm_team_assignments
|
||||
(session_id, worker_id, work_hours, project_id, work_type_id, task_id, workplace_category_id, workplace_id, is_present)
|
||||
(session_id, user_id, work_hours, project_id, work_type_id, task_id, workplace_category_id, workplace_id, is_present)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1)`,
|
||||
[dest_session_id, worker_id, parseFloat(hours),
|
||||
[dest_session_id, user_id, parseFloat(hours),
|
||||
project_id || null, work_type_id || null, task_id || null,
|
||||
workplace_category_id || null, workplace_id || null]
|
||||
);
|
||||
@@ -68,18 +68,18 @@ const TbmTransferModel = {
|
||||
// 3. tbm_transfers에 로그 INSERT
|
||||
const [logResult] = await conn.query(
|
||||
`INSERT INTO tbm_transfers
|
||||
(transfer_date, worker_id, source_session_id, dest_session_id, hours, transfer_type, initiated_by)
|
||||
(transfer_date, user_id, source_session_id, dest_session_id, hours, transfer_type, initiated_by)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
||||
[transfer_date, worker_id, source_session_id, dest_session_id, parseFloat(hours), transfer_type, initiated_by]
|
||||
[transfer_date, user_id, source_session_id, dest_session_id, parseFloat(hours), transfer_type, initiated_by]
|
||||
);
|
||||
|
||||
// 4. 합계 시간 검증 (경고만, 차단 안함)
|
||||
const [totalRows] = await conn.query(
|
||||
`SELECT SUM(COALESCE(work_hours, 8)) as total_hours
|
||||
FROM tbm_team_assignments
|
||||
WHERE worker_id = ?
|
||||
WHERE user_id = ?
|
||||
AND session_id IN (SELECT session_id FROM tbm_sessions WHERE session_date = ?)`,
|
||||
[worker_id, transfer_date]
|
||||
[user_id, transfer_date]
|
||||
);
|
||||
const totalHours = totalRows[0] ? parseFloat(totalRows[0].total_hours) : 0;
|
||||
|
||||
@@ -128,8 +128,8 @@ const TbmTransferModel = {
|
||||
|
||||
// 2. dest 세션에서 작업자 work_hours 감소 (또는 삭제)
|
||||
const [destRows] = await conn.query(
|
||||
'SELECT assignment_id, work_hours FROM tbm_team_assignments WHERE session_id = ? AND worker_id = ?',
|
||||
[t.dest_session_id, t.worker_id]
|
||||
'SELECT assignment_id, work_hours FROM tbm_team_assignments WHERE session_id = ? AND user_id = ?',
|
||||
[t.dest_session_id, t.user_id]
|
||||
);
|
||||
|
||||
if (destRows.length > 0) {
|
||||
@@ -138,29 +138,29 @@ const TbmTransferModel = {
|
||||
|
||||
if (newDestHours <= 0) {
|
||||
await conn.query(
|
||||
'DELETE FROM tbm_team_assignments WHERE session_id = ? AND worker_id = ?',
|
||||
[t.dest_session_id, t.worker_id]
|
||||
'DELETE FROM tbm_team_assignments WHERE session_id = ? AND user_id = ?',
|
||||
[t.dest_session_id, t.user_id]
|
||||
);
|
||||
} else {
|
||||
await conn.query(
|
||||
'UPDATE tbm_team_assignments SET work_hours = ? WHERE session_id = ? AND worker_id = ?',
|
||||
[newDestHours, t.dest_session_id, t.worker_id]
|
||||
'UPDATE tbm_team_assignments SET work_hours = ? WHERE session_id = ? AND user_id = ?',
|
||||
[newDestHours, t.dest_session_id, t.user_id]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. source 세션에서 작업자 work_hours 복원
|
||||
const [sourceRows] = await conn.query(
|
||||
'SELECT assignment_id, work_hours FROM tbm_team_assignments WHERE session_id = ? AND worker_id = ?',
|
||||
[t.source_session_id, t.worker_id]
|
||||
'SELECT assignment_id, work_hours FROM tbm_team_assignments WHERE session_id = ? AND user_id = ?',
|
||||
[t.source_session_id, t.user_id]
|
||||
);
|
||||
|
||||
if (sourceRows.length > 0) {
|
||||
const sourceHours = sourceRows[0].work_hours === null ? 8 : parseFloat(sourceRows[0].work_hours);
|
||||
const restoredHours = sourceHours + parseFloat(t.hours);
|
||||
await conn.query(
|
||||
'UPDATE tbm_team_assignments SET work_hours = ? WHERE session_id = ? AND worker_id = ?',
|
||||
[restoredHours >= 8 ? null : restoredHours, t.source_session_id, t.worker_id]
|
||||
'UPDATE tbm_team_assignments SET work_hours = ? WHERE session_id = ? AND user_id = ?',
|
||||
[restoredHours >= 8 ? null : restoredHours, t.source_session_id, t.user_id]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -191,11 +191,11 @@ const TbmTransferModel = {
|
||||
dl.worker_name as dest_leader_name,
|
||||
u.name as initiated_by_name
|
||||
FROM tbm_transfers t
|
||||
INNER JOIN workers w ON t.worker_id = w.worker_id
|
||||
INNER JOIN workers w ON t.user_id = w.user_id
|
||||
LEFT JOIN tbm_sessions ss ON t.source_session_id = ss.session_id
|
||||
LEFT JOIN workers sl ON ss.leader_id = sl.worker_id
|
||||
LEFT JOIN workers sl ON ss.leader_id = sl.user_id
|
||||
LEFT JOIN tbm_sessions ds ON t.dest_session_id = ds.session_id
|
||||
LEFT JOIN workers dl ON ds.leader_id = dl.worker_id
|
||||
LEFT JOIN workers dl ON ds.leader_id = dl.user_id
|
||||
LEFT JOIN sso_users u ON t.initiated_by = u.user_id
|
||||
WHERE t.transfer_date = ?
|
||||
ORDER BY t.created_at DESC
|
||||
@@ -213,7 +213,7 @@ const TbmTransferModel = {
|
||||
// 1. 해당 날짜의 모든 배정 가져오기
|
||||
const [assignments] = await db.query(`
|
||||
SELECT
|
||||
ta.worker_id,
|
||||
ta.user_id,
|
||||
ta.session_id,
|
||||
ta.work_hours,
|
||||
w.worker_name,
|
||||
@@ -223,22 +223,22 @@ const TbmTransferModel = {
|
||||
s.status as session_status
|
||||
FROM tbm_team_assignments ta
|
||||
INNER JOIN tbm_sessions s ON ta.session_id = s.session_id
|
||||
INNER JOIN workers w ON ta.worker_id = w.worker_id
|
||||
LEFT JOIN workers lw ON s.leader_id = lw.worker_id
|
||||
INNER JOIN workers w ON ta.user_id = w.user_id
|
||||
LEFT JOIN workers lw ON s.leader_id = lw.user_id
|
||||
WHERE s.session_date = ?
|
||||
ORDER BY w.worker_name
|
||||
`, [date]);
|
||||
|
||||
// 2. 모든 작업자 가져오기 (배정 안 된 사람도 포함)
|
||||
const [allWorkers] = await db.query(
|
||||
"SELECT worker_id, worker_name, job_type FROM workers WHERE status = 'active' AND department = '생산' ORDER BY worker_name"
|
||||
"SELECT user_id, worker_name, job_type FROM workers WHERE status = 'active' AND department = '생산' ORDER BY worker_name"
|
||||
);
|
||||
|
||||
// 3. 작업자별 배정 현황 구성
|
||||
const workerMap = {};
|
||||
allWorkers.forEach(w => {
|
||||
workerMap[w.worker_id] = {
|
||||
worker_id: w.worker_id,
|
||||
workerMap[w.user_id] = {
|
||||
user_id: w.user_id,
|
||||
worker_name: w.worker_name,
|
||||
job_type: w.job_type,
|
||||
sessions: [],
|
||||
@@ -249,14 +249,14 @@ const TbmTransferModel = {
|
||||
|
||||
assignments.forEach(a => {
|
||||
const hours = a.work_hours === null ? 8 : parseFloat(a.work_hours);
|
||||
if (workerMap[a.worker_id]) {
|
||||
workerMap[a.worker_id].sessions.push({
|
||||
if (workerMap[a.user_id]) {
|
||||
workerMap[a.user_id].sessions.push({
|
||||
session_id: a.session_id,
|
||||
leader_name: a.leader_name,
|
||||
work_hours: hours,
|
||||
session_status: a.session_status
|
||||
});
|
||||
workerMap[a.worker_id].total_hours += hours;
|
||||
workerMap[a.user_id].total_hours += hours;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ const findByUsername = async (username) => {
|
||||
const [rows] = await db.query(
|
||||
`SELECT u.user_id, u.username, u.password, u.name, u.email,
|
||||
u.role_id, r.name as role_name,
|
||||
u._access_level_old as access_level, u.worker_id, u.is_active,
|
||||
u._access_level_old as access_level, u.is_active,
|
||||
u.last_login_at, u.password_changed_at, u.failed_login_attempts,
|
||||
u.locked_until, u.created_at, u.updated_at
|
||||
FROM users u
|
||||
|
||||
@@ -9,7 +9,7 @@ const vacationBalanceModel = {
|
||||
/**
|
||||
* 특정 작업자의 모든 휴가 잔액 조회 (특정 연도)
|
||||
*/
|
||||
async getByWorkerAndYear(workerId, year) {
|
||||
async getByWorkerAndYear(userId, year) {
|
||||
const db = await getDb();
|
||||
const [rows] = await db.query(`
|
||||
SELECT
|
||||
@@ -20,16 +20,16 @@ const vacationBalanceModel = {
|
||||
vt.is_special
|
||||
FROM vacation_balance_details vbd
|
||||
INNER JOIN vacation_types vt ON vbd.vacation_type_id = vt.id
|
||||
WHERE vbd.worker_id = ? AND vbd.year = ?
|
||||
WHERE vbd.user_id = ? AND vbd.year = ?
|
||||
ORDER BY vt.priority ASC, vt.type_name ASC
|
||||
`, [workerId, year]);
|
||||
`, [userId, year]);
|
||||
return rows;
|
||||
},
|
||||
|
||||
/**
|
||||
* 특정 작업자의 특정 휴가 유형 잔액 조회
|
||||
*/
|
||||
async getByWorkerTypeYear(workerId, vacationTypeId, year) {
|
||||
async getByWorkerTypeYear(userId, vacationTypeId, year) {
|
||||
const db = await getDb();
|
||||
const [rows] = await db.query(`
|
||||
SELECT
|
||||
@@ -38,10 +38,10 @@ const vacationBalanceModel = {
|
||||
vt.type_code
|
||||
FROM vacation_balance_details vbd
|
||||
INNER JOIN vacation_types vt ON vbd.vacation_type_id = vt.id
|
||||
WHERE vbd.worker_id = ?
|
||||
WHERE vbd.user_id = ?
|
||||
AND vbd.vacation_type_id = ?
|
||||
AND vbd.year = ?
|
||||
`, [workerId, vacationTypeId, year]);
|
||||
`, [userId, vacationTypeId, year]);
|
||||
return rows;
|
||||
},
|
||||
|
||||
@@ -59,7 +59,7 @@ const vacationBalanceModel = {
|
||||
vt.type_code,
|
||||
vt.priority
|
||||
FROM vacation_balance_details vbd
|
||||
INNER JOIN workers w ON vbd.worker_id = w.worker_id
|
||||
INNER JOIN workers w ON vbd.user_id = w.user_id
|
||||
INNER JOIN vacation_types vt ON vbd.vacation_type_id = vt.id
|
||||
WHERE vbd.year = ?
|
||||
AND w.employment_status = 'employed'
|
||||
@@ -98,39 +98,39 @@ const vacationBalanceModel = {
|
||||
/**
|
||||
* 작업자의 휴가 사용 일수 업데이트 (차감)
|
||||
*/
|
||||
async deductDays(workerId, vacationTypeId, year, daysToDeduct) {
|
||||
async deductDays(userId, vacationTypeId, year, daysToDeduct) {
|
||||
const db = await getDb();
|
||||
const [result] = await db.query(`
|
||||
UPDATE vacation_balance_details
|
||||
SET used_days = used_days + ?,
|
||||
updated_at = NOW()
|
||||
WHERE worker_id = ?
|
||||
WHERE user_id = ?
|
||||
AND vacation_type_id = ?
|
||||
AND year = ?
|
||||
`, [daysToDeduct, workerId, vacationTypeId, year]);
|
||||
`, [daysToDeduct, userId, vacationTypeId, year]);
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* 작업자의 휴가 사용 일수 복구 (취소)
|
||||
*/
|
||||
async restoreDays(workerId, vacationTypeId, year, daysToRestore) {
|
||||
async restoreDays(userId, vacationTypeId, year, daysToRestore) {
|
||||
const db = await getDb();
|
||||
const [result] = await db.query(`
|
||||
UPDATE vacation_balance_details
|
||||
SET used_days = GREATEST(0, used_days - ?),
|
||||
updated_at = NOW()
|
||||
WHERE worker_id = ?
|
||||
WHERE user_id = ?
|
||||
AND vacation_type_id = ?
|
||||
AND year = ?
|
||||
`, [daysToRestore, workerId, vacationTypeId, year]);
|
||||
`, [daysToRestore, userId, vacationTypeId, year]);
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* 특정 작업자의 사용 가능한 휴가 일수 확인
|
||||
*/
|
||||
async getAvailableVacationDays(workerId, year) {
|
||||
async getAvailableVacationDays(userId, year) {
|
||||
const db = await getDb();
|
||||
const [rows] = await db.query(`
|
||||
SELECT
|
||||
@@ -144,11 +144,11 @@ const vacationBalanceModel = {
|
||||
vbd.remaining_days
|
||||
FROM vacation_balance_details vbd
|
||||
INNER JOIN vacation_types vt ON vbd.vacation_type_id = vt.id
|
||||
WHERE vbd.worker_id = ?
|
||||
WHERE vbd.user_id = ?
|
||||
AND vbd.year = ?
|
||||
AND vbd.remaining_days > 0
|
||||
ORDER BY vt.priority ASC
|
||||
`, [workerId, year]);
|
||||
`, [userId, year]);
|
||||
return rows;
|
||||
},
|
||||
|
||||
@@ -162,11 +162,11 @@ const vacationBalanceModel = {
|
||||
|
||||
const db = await getDb();
|
||||
const query = `INSERT INTO vacation_balance_details
|
||||
(worker_id, vacation_type_id, year, total_days, used_days, notes, created_by)
|
||||
(user_id, vacation_type_id, year, total_days, used_days, notes, created_by)
|
||||
VALUES ?`;
|
||||
|
||||
const values = balances.map(b => [
|
||||
b.worker_id,
|
||||
b.user_id,
|
||||
b.vacation_type_id,
|
||||
b.year,
|
||||
b.total_days || 0,
|
||||
@@ -202,7 +202,7 @@ const vacationBalanceModel = {
|
||||
/**
|
||||
* 휴가 사용 시 우선순위에 따라 잔액에서 차감
|
||||
*/
|
||||
async deductByPriority(workerId, year, daysToDeduct) {
|
||||
async deductByPriority(userId, year, daysToDeduct) {
|
||||
const db = await getDb();
|
||||
|
||||
const [balances] = await db.query(`
|
||||
@@ -211,13 +211,13 @@ const vacationBalanceModel = {
|
||||
vt.type_code, vt.type_name, vt.priority
|
||||
FROM vacation_balance_details vbd
|
||||
INNER JOIN vacation_types vt ON vbd.vacation_type_id = vt.id
|
||||
WHERE vbd.worker_id = ? AND vbd.year = ?
|
||||
WHERE vbd.user_id = ? AND vbd.year = ?
|
||||
AND (vbd.total_days - vbd.used_days) > 0
|
||||
ORDER BY vt.priority ASC
|
||||
`, [workerId, year]);
|
||||
`, [userId, year]);
|
||||
|
||||
if (balances.length === 0) {
|
||||
console.warn(`[VacationBalance] 작업자 ${workerId}의 ${year}년 휴가 잔액이 없습니다`);
|
||||
console.warn(`[VacationBalance] 작업자 ${userId}의 ${year}년 휴가 잔액이 없습니다`);
|
||||
return { success: false, message: '휴가 잔액이 없습니다', deducted: 0 };
|
||||
}
|
||||
|
||||
@@ -248,14 +248,14 @@ const vacationBalanceModel = {
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[VacationBalance] 작업자 ${workerId}: ${daysToDeduct}일 차감 완료`, deductions);
|
||||
console.log(`[VacationBalance] 작업자 ${userId}: ${daysToDeduct}일 차감 완료`, deductions);
|
||||
return { success: true, deductions, totalDeducted: daysToDeduct - remaining };
|
||||
},
|
||||
|
||||
/**
|
||||
* 휴가 취소 시 우선순위 역순으로 복구
|
||||
*/
|
||||
async restoreByPriority(workerId, year, daysToRestore) {
|
||||
async restoreByPriority(userId, year, daysToRestore) {
|
||||
const db = await getDb();
|
||||
|
||||
const [balances] = await db.query(`
|
||||
@@ -263,10 +263,10 @@ const vacationBalanceModel = {
|
||||
vt.type_code, vt.type_name, vt.priority
|
||||
FROM vacation_balance_details vbd
|
||||
INNER JOIN vacation_types vt ON vbd.vacation_type_id = vt.id
|
||||
WHERE vbd.worker_id = ? AND vbd.year = ?
|
||||
WHERE vbd.user_id = ? AND vbd.year = ?
|
||||
AND vbd.used_days > 0
|
||||
ORDER BY vt.priority DESC
|
||||
`, [workerId, year]);
|
||||
`, [userId, year]);
|
||||
|
||||
let remaining = daysToRestore;
|
||||
const restorations = [];
|
||||
@@ -295,7 +295,7 @@ const vacationBalanceModel = {
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[VacationBalance] 작업자 ${workerId}: ${daysToRestore}일 복구 완료`, restorations);
|
||||
console.log(`[VacationBalance] 작업자 ${userId}: ${daysToRestore}일 복구 완료`, restorations);
|
||||
return { success: true, restorations, totalRestored: daysToRestore - remaining };
|
||||
},
|
||||
|
||||
@@ -311,7 +311,7 @@ const vacationBalanceModel = {
|
||||
vt.type_name,
|
||||
vt.type_code
|
||||
FROM vacation_balance_details vbd
|
||||
INNER JOIN workers w ON vbd.worker_id = w.worker_id
|
||||
INNER JOIN workers w ON vbd.user_id = w.user_id
|
||||
INNER JOIN vacation_types vt ON vbd.vacation_type_id = vt.id
|
||||
WHERE vbd.id = ?
|
||||
`, [id]);
|
||||
|
||||
@@ -30,7 +30,7 @@ const vacationRequestModel = {
|
||||
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 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
|
||||
@@ -39,9 +39,9 @@ const vacationRequestModel = {
|
||||
|
||||
const params = [];
|
||||
|
||||
if (filters.worker_id) {
|
||||
query += ` AND vr.worker_id = ?`;
|
||||
params.push(filters.worker_id);
|
||||
if (filters.user_id) {
|
||||
query += ` AND vr.user_id = ?`;
|
||||
params.push(filters.user_id);
|
||||
}
|
||||
if (filters.status) {
|
||||
query += ` AND vr.status = ?`;
|
||||
@@ -85,7 +85,7 @@ const vacationRequestModel = {
|
||||
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 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
|
||||
@@ -128,35 +128,35 @@ const vacationRequestModel = {
|
||||
/**
|
||||
* 특정 작업자의 대기 중인 휴가 신청 수
|
||||
*/
|
||||
async getPendingCount(workerId) {
|
||||
async getPendingCount(userId) {
|
||||
const db = await getDb();
|
||||
const [rows] = await db.query(`
|
||||
SELECT COUNT(*) as count FROM vacation_requests
|
||||
WHERE worker_id = ? AND status = 'pending'
|
||||
`, [workerId]);
|
||||
WHERE user_id = ? AND status = 'pending'
|
||||
`, [userId]);
|
||||
return rows;
|
||||
},
|
||||
|
||||
/**
|
||||
* 특정 작업자의 승인된 휴가 일수 합계 (특정 기간)
|
||||
*/
|
||||
async getApprovedDaysInPeriod(workerId, startDate, endDate) {
|
||||
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 worker_id = ? AND status = 'approved' AND start_date >= ? AND end_date <= ?
|
||||
`, [workerId, startDate, endDate]);
|
||||
WHERE user_id = ? AND status = 'approved' AND start_date >= ? AND end_date <= ?
|
||||
`, [userId, startDate, endDate]);
|
||||
return rows;
|
||||
},
|
||||
|
||||
/**
|
||||
* 휴가 기간 중복 체크
|
||||
*/
|
||||
async checkOverlap(workerId, startDate, endDate, excludeRequestId = null) {
|
||||
async checkOverlap(userId, startDate, endDate, excludeRequestId = null) {
|
||||
const db = await getDb();
|
||||
let query = `
|
||||
SELECT COUNT(*) as count FROM vacation_requests
|
||||
WHERE worker_id = ?
|
||||
WHERE user_id = ?
|
||||
AND status IN ('pending', 'approved')
|
||||
AND (
|
||||
(start_date <= ? AND end_date >= ?) OR
|
||||
@@ -164,7 +164,7 @@ const vacationRequestModel = {
|
||||
(start_date >= ? AND end_date <= ?)
|
||||
)
|
||||
`;
|
||||
const params = [workerId, startDate, startDate, endDate, endDate, startDate, endDate];
|
||||
const params = [userId, startDate, startDate, endDate, endDate, startDate, endDate];
|
||||
|
||||
if (excludeRequestId) {
|
||||
query += ` AND request_id != ?`;
|
||||
@@ -187,7 +187,7 @@ const vacationRequestModel = {
|
||||
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 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'
|
||||
|
||||
@@ -12,14 +12,14 @@ const createBatch = async (reports) => {
|
||||
|
||||
const sql = `
|
||||
INSERT INTO WorkReports
|
||||
(\`date\`, worker_id, project_id, task_id, overtime_hours, work_details, memo)
|
||||
(\`date\`, user_id, project_id, task_id, overtime_hours, work_details, memo)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
`;
|
||||
|
||||
for (const rpt of reports) {
|
||||
const params = [
|
||||
rpt.date,
|
||||
rpt.worker_id,
|
||||
rpt.user_id,
|
||||
rpt.project_id,
|
||||
rpt.task_id || null,
|
||||
rpt.overtime_hours || null,
|
||||
@@ -44,18 +44,18 @@ const createBatch = async (reports) => {
|
||||
const create = async (report) => {
|
||||
const db = await getDb();
|
||||
const {
|
||||
date, worker_id, project_id,
|
||||
date, user_id, project_id,
|
||||
task_id, overtime_hours,
|
||||
work_details, memo
|
||||
} = report;
|
||||
|
||||
const [result] = await db.query(
|
||||
`INSERT INTO WorkReports
|
||||
(\`date\`, worker_id, project_id, task_id, overtime_hours, work_details, memo)
|
||||
(\`date\`, user_id, project_id, task_id, overtime_hours, work_details, memo)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
||||
[
|
||||
date,
|
||||
worker_id,
|
||||
user_id,
|
||||
project_id,
|
||||
task_id || null,
|
||||
overtime_hours || null,
|
||||
@@ -74,7 +74,7 @@ const getAllByDate = async (date) => {
|
||||
const db = await getDb();
|
||||
const sql = `
|
||||
SELECT
|
||||
wr.worker_id,
|
||||
wr.user_id,
|
||||
wr.id,
|
||||
wr.\`date\`,
|
||||
w.worker_name,
|
||||
@@ -84,7 +84,7 @@ const getAllByDate = async (date) => {
|
||||
wr.work_details,
|
||||
wr.memo
|
||||
FROM WorkReports wr
|
||||
LEFT JOIN workers w ON wr.worker_id = w.worker_id
|
||||
LEFT JOIN workers w ON wr.user_id = w.user_id
|
||||
LEFT JOIN projects p ON wr.project_id = p.project_id
|
||||
LEFT JOIN Tasks t ON wr.task_id = t.task_id
|
||||
WHERE wr.\`date\` = ?
|
||||
@@ -100,7 +100,7 @@ const getAllByDate = async (date) => {
|
||||
const getByRange = async (start, end) => {
|
||||
const db = await getDb();
|
||||
const [rows] = await db.query(
|
||||
`SELECT id, \`date\`, worker_id, project_id, morning_task_id, afternoon_task_id, overtime_hours, overtime_task_id, work_details, note, memo, created_at, updated_at, morning_project_id, afternoon_project_id, overtime_project_id, task_id FROM WorkReports
|
||||
`SELECT id, \`date\`, user_id, project_id, morning_task_id, afternoon_task_id, overtime_hours, overtime_task_id, work_details, note, memo, created_at, updated_at, morning_project_id, afternoon_project_id, overtime_project_id, task_id FROM WorkReports
|
||||
WHERE \`date\` BETWEEN ? AND ?
|
||||
ORDER BY \`date\` ASC`,
|
||||
[start, end]
|
||||
@@ -114,7 +114,7 @@ const getByRange = async (start, end) => {
|
||||
const getById = async (id) => {
|
||||
const db = await getDb();
|
||||
const [rows] = await db.query(
|
||||
`SELECT id, \`date\`, worker_id, project_id, morning_task_id, afternoon_task_id, overtime_hours, overtime_task_id, work_details, note, memo, created_at, updated_at, morning_project_id, afternoon_project_id, overtime_project_id, task_id FROM WorkReports WHERE id = ?`,
|
||||
`SELECT id, \`date\`, user_id, project_id, morning_task_id, afternoon_task_id, overtime_hours, overtime_task_id, work_details, note, memo, created_at, updated_at, morning_project_id, afternoon_project_id, overtime_project_id, task_id FROM WorkReports WHERE id = ?`,
|
||||
[id]
|
||||
);
|
||||
return rows[0];
|
||||
@@ -126,7 +126,7 @@ const getById = async (id) => {
|
||||
const update = async (id, report) => {
|
||||
const db = await getDb();
|
||||
const {
|
||||
date, worker_id, project_id,
|
||||
date, user_id, project_id,
|
||||
task_id, overtime_hours,
|
||||
work_details, memo
|
||||
} = report;
|
||||
@@ -134,7 +134,7 @@ const update = async (id, report) => {
|
||||
const [result] = await db.query(
|
||||
`UPDATE WorkReports
|
||||
SET \`date\` = ?,
|
||||
worker_id = ?,
|
||||
user_id = ?,
|
||||
project_id = ?,
|
||||
task_id = ?,
|
||||
overtime_hours = ?,
|
||||
@@ -144,7 +144,7 @@ const update = async (id, report) => {
|
||||
WHERE id = ?`,
|
||||
[
|
||||
date,
|
||||
worker_id,
|
||||
user_id,
|
||||
project_id,
|
||||
task_id || null,
|
||||
overtime_hours || null,
|
||||
@@ -172,11 +172,11 @@ const remove = async (id) => {
|
||||
/**
|
||||
* 8. 중복 확인
|
||||
*/
|
||||
const existsByDateAndWorker = async (date, worker_id) => {
|
||||
const existsByDateAndWorker = async (date, user_id) => {
|
||||
const db = await getDb();
|
||||
const [rows] = await db.query(
|
||||
`SELECT 1 FROM WorkReports WHERE \`date\` = ? AND worker_id = ? LIMIT 1`,
|
||||
[date, worker_id]
|
||||
`SELECT 1 FROM WorkReports WHERE \`date\` = ? AND user_id = ? LIMIT 1`,
|
||||
[date, user_id]
|
||||
);
|
||||
return rows.length > 0;
|
||||
};
|
||||
|
||||
@@ -39,39 +39,60 @@ const getAll = async () => {
|
||||
const [rows] = await db.query(`
|
||||
SELECT
|
||||
w.*,
|
||||
w.user_id,
|
||||
CASE WHEN w.status = 'active' THEN 1 ELSE 0 END AS is_active,
|
||||
u.user_id,
|
||||
su.username,
|
||||
d.department_name
|
||||
FROM workers w
|
||||
LEFT JOIN users u ON w.worker_id = u.worker_id
|
||||
LEFT JOIN sso_users su ON w.user_id = su.user_id
|
||||
LEFT JOIN departments d ON w.department_id = d.department_id
|
||||
ORDER BY w.worker_id DESC
|
||||
ORDER BY w.worker_name ASC
|
||||
`);
|
||||
return rows;
|
||||
};
|
||||
|
||||
// 3. 단일 조회
|
||||
// 3. 단일 조회 (worker_id 기준 - 하위 호환성 유지)
|
||||
const getById = async (worker_id) => {
|
||||
const db = await getDb();
|
||||
const [rows] = await db.query(`
|
||||
SELECT
|
||||
w.*,
|
||||
w.user_id,
|
||||
CASE WHEN w.status = 'active' THEN 1 ELSE 0 END AS is_active,
|
||||
u.user_id,
|
||||
su.username,
|
||||
d.department_name
|
||||
FROM workers w
|
||||
LEFT JOIN users u ON w.worker_id = u.worker_id
|
||||
LEFT JOIN sso_users su ON w.user_id = su.user_id
|
||||
LEFT JOIN departments d ON w.department_id = d.department_id
|
||||
WHERE w.worker_id = ?
|
||||
`, [worker_id]);
|
||||
return rows[0];
|
||||
};
|
||||
|
||||
// 4. 작업자 수정
|
||||
// 3-1. 단일 조회 (user_id 기준)
|
||||
const getByUserId = async (userId) => {
|
||||
const db = await getDb();
|
||||
const [rows] = await db.query(`
|
||||
SELECT
|
||||
w.*,
|
||||
w.user_id,
|
||||
CASE WHEN w.status = 'active' THEN 1 ELSE 0 END AS is_active,
|
||||
su.username,
|
||||
d.department_name
|
||||
FROM workers w
|
||||
LEFT JOIN sso_users su ON w.user_id = su.user_id
|
||||
LEFT JOIN departments d ON w.department_id = d.department_id
|
||||
WHERE w.user_id = ?
|
||||
`, [userId]);
|
||||
return rows[0];
|
||||
};
|
||||
|
||||
// 4. 작업자 수정 (worker_id 또는 user_id 기준)
|
||||
const update = async (worker) => {
|
||||
const db = await getDb();
|
||||
const {
|
||||
worker_id,
|
||||
user_id,
|
||||
worker_name,
|
||||
job_type,
|
||||
status,
|
||||
@@ -123,12 +144,22 @@ const update = async (worker) => {
|
||||
throw new Error('업데이트할 필드가 없습니다');
|
||||
}
|
||||
|
||||
values.push(worker_id); // WHERE 조건용
|
||||
// WHERE 조건: user_id 우선, 없으면 worker_id 사용
|
||||
let whereClause;
|
||||
if (user_id !== undefined) {
|
||||
whereClause = 'user_id = ?';
|
||||
values.push(user_id);
|
||||
} else if (worker_id !== undefined) {
|
||||
whereClause = 'worker_id = ?';
|
||||
values.push(worker_id);
|
||||
} else {
|
||||
throw new Error('worker_id 또는 user_id가 필요합니다');
|
||||
}
|
||||
|
||||
const query = `UPDATE workers SET ${updates.join(', ')} WHERE worker_id = ?`;
|
||||
const query = `UPDATE workers SET ${updates.join(', ')} WHERE ${whereClause}`;
|
||||
|
||||
console.log('🔍 실행할 SQL:', query);
|
||||
console.log('🔍 SQL 파라미터:', values);
|
||||
console.log('실행할 SQL:', query);
|
||||
console.log('SQL 파라미터:', values);
|
||||
|
||||
const [result] = await db.query(query, values);
|
||||
|
||||
@@ -192,6 +223,7 @@ module.exports = {
|
||||
create,
|
||||
getAll,
|
||||
getById,
|
||||
getByUserId,
|
||||
update,
|
||||
remove
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user