- workerModel: remove()를 user_id 기반 cascading delete로 전환 - workerController: 계정 생성/해제를 workers.user_id 연결 방식으로 변경 - userController: JOIN 방향 전환 (u.worker_id→w.worker_id 에서 w.user_id→u.user_id) - authController, systemController, authRoutes: 모든 CRUD에서 worker_id 참조 제거 - DB: UNIQUE KEY 5개 교체, FK 7개 삭제, daily_worker_summary user_id 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
232 lines
6.9 KiB
JavaScript
232 lines
6.9 KiB
JavaScript
const { getDb } = require('../dbPool');
|
|
|
|
// 날짜 형식 변환 헬퍼 함수 (ISO 8601 -> MySQL DATE)
|
|
const formatDate = (dateStr) => {
|
|
if (!dateStr) return null;
|
|
if (typeof dateStr === 'string' && dateStr.includes('T')) {
|
|
return dateStr.split('T')[0]; // ISO 8601 -> YYYY-MM-DD
|
|
}
|
|
return dateStr;
|
|
};
|
|
|
|
// 1. 작업자 생성
|
|
const create = async (worker) => {
|
|
const db = await getDb();
|
|
const {
|
|
worker_name,
|
|
job_type = null,
|
|
join_date = null,
|
|
salary = null,
|
|
annual_leave = null,
|
|
status = 'active',
|
|
employment_status = 'employed',
|
|
department_id = null
|
|
} = worker;
|
|
|
|
const [result] = await db.query(
|
|
`INSERT INTO workers
|
|
(worker_name, job_type, join_date, salary, annual_leave, status, employment_status, department_id)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
[worker_name, job_type, formatDate(join_date), salary, annual_leave, status, employment_status, department_id]
|
|
);
|
|
|
|
return result.insertId;
|
|
};
|
|
|
|
// 2. 전체 조회
|
|
const getAll = async () => {
|
|
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
|
|
ORDER BY w.worker_name ASC
|
|
`);
|
|
return rows;
|
|
};
|
|
|
|
// 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,
|
|
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.worker_id = ?
|
|
`, [worker_id]);
|
|
return rows[0];
|
|
};
|
|
|
|
// 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,
|
|
join_date,
|
|
salary,
|
|
annual_leave,
|
|
employment_status,
|
|
department_id
|
|
} = worker;
|
|
|
|
// 업데이트할 필드만 동적으로 구성
|
|
const updates = [];
|
|
const values = [];
|
|
|
|
if (worker_name !== undefined) {
|
|
updates.push('worker_name = ?');
|
|
values.push(worker_name);
|
|
}
|
|
if (job_type !== undefined) {
|
|
updates.push('job_type = ?');
|
|
values.push(job_type);
|
|
}
|
|
if (status !== undefined) {
|
|
updates.push('status = ?');
|
|
values.push(status);
|
|
}
|
|
if (join_date !== undefined) {
|
|
updates.push('join_date = ?');
|
|
values.push(formatDate(join_date));
|
|
}
|
|
if (salary !== undefined) {
|
|
updates.push('salary = ?');
|
|
values.push(salary);
|
|
}
|
|
if (annual_leave !== undefined) {
|
|
updates.push('annual_leave = ?');
|
|
values.push(annual_leave);
|
|
}
|
|
if (employment_status !== undefined) {
|
|
updates.push('employment_status = ?');
|
|
values.push(employment_status);
|
|
}
|
|
if (department_id !== undefined) {
|
|
updates.push('department_id = ?');
|
|
values.push(department_id);
|
|
}
|
|
|
|
if (updates.length === 0) {
|
|
throw new Error('업데이트할 필드가 없습니다');
|
|
}
|
|
|
|
// 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 ${whereClause}`;
|
|
|
|
console.log('실행할 SQL:', query);
|
|
console.log('SQL 파라미터:', values);
|
|
|
|
const [result] = await db.query(query, values);
|
|
|
|
return result.affectedRows;
|
|
};
|
|
|
|
// 5. 삭제 (user_id 기반 - 외래키 제약조건 처리)
|
|
const remove = async (userId) => {
|
|
const db = await getDb();
|
|
const conn = await db.getConnection();
|
|
|
|
try {
|
|
await conn.beginTransaction();
|
|
|
|
console.log(`🗑️ 작업자 삭제 시작: user_id=${userId}`);
|
|
|
|
// 안전한 삭제: 각 테이블을 개별적으로 처리하고 오류가 발생해도 계속 진행
|
|
const tables = [
|
|
{ name: 'DailyIssueReports', query: 'DELETE FROM DailyIssueReports WHERE user_id = ?', action: '삭제' },
|
|
{ name: 'WorkReports', query: 'DELETE FROM WorkReports WHERE user_id = ?', action: '삭제' },
|
|
{ name: 'daily_work_reports', query: 'DELETE FROM daily_work_reports WHERE user_id = ?', action: '삭제' },
|
|
{ name: 'daily_attendance_records', query: 'DELETE FROM daily_attendance_records WHERE user_id = ?', action: '삭제' },
|
|
{ name: 'daily_worker_summary', query: 'DELETE FROM daily_worker_summary WHERE user_id = ?', action: '삭제' },
|
|
{ name: 'tbm_team_assignments', query: 'DELETE FROM tbm_team_assignments WHERE user_id = ?', action: '삭제' },
|
|
{ name: 'tbm_transfers', query: 'DELETE FROM tbm_transfers WHERE user_id = ?', action: '삭제' },
|
|
{ name: 'vacation_requests', query: 'DELETE FROM vacation_requests WHERE user_id = ?', action: '삭제' },
|
|
{ name: 'vacation_balance_details', query: 'DELETE FROM vacation_balance_details WHERE user_id = ?', action: '삭제' },
|
|
{ name: 'worker_vacation_balance', query: 'DELETE FROM worker_vacation_balance WHERE user_id = ?', action: '삭제' },
|
|
{ name: 'worker_groups', query: 'DELETE FROM worker_groups WHERE user_id = ?', action: '삭제' }
|
|
];
|
|
|
|
for (const table of tables) {
|
|
try {
|
|
const [result] = await conn.query(table.query, [userId]);
|
|
if (result.affectedRows > 0) {
|
|
console.log(`✅ ${table.name} 테이블 ${table.action}: ${result.affectedRows}건`);
|
|
}
|
|
} catch (tableError) {
|
|
console.log(`⚠️ ${table.name} 테이블 ${table.action} 실패 (무시): ${tableError.message}`);
|
|
}
|
|
}
|
|
|
|
// 마지막으로 작업자 삭제
|
|
const [result] = await conn.query(
|
|
`DELETE FROM workers WHERE user_id = ?`,
|
|
[userId]
|
|
);
|
|
console.log(`✅ 작업자 삭제 완료: ${result.affectedRows}건`);
|
|
|
|
await conn.commit();
|
|
return result.affectedRows;
|
|
|
|
} catch (err) {
|
|
await conn.rollback();
|
|
console.error(`❌ 작업자 삭제 오류 (user_id: ${userId}):`, err);
|
|
throw new Error(`작업자 삭제 중 오류가 발생했습니다: ${err.message}`);
|
|
} finally {
|
|
conn.release();
|
|
}
|
|
};
|
|
|
|
module.exports = {
|
|
create,
|
|
getAll,
|
|
getById,
|
|
getByUserId,
|
|
update,
|
|
remove
|
|
};
|