fix: TBM 작업보고서 저장 버그 수정
문제: 1. dailyWorkReportController에서 DailyWorkReportModel(대문자) 사용 → dailyWorkReportModel(소문자)로 수정 2. daily_work_reports INSERT 쿼리에 work_hours 필드 누락 3. 에러 로그에 스택 트레이스 추가 해결: - 변수명 통일 (dailyWorkReportModel 사용) - INSERT 쿼리에 work_hours 필드 추가 (TBM에서는 total_hours와 동일) - 에러 핸들링 개선 (스택 트레이스 로깅 추가) 영향받는 파일: - api.hyungi.net/controllers/dailyWorkReportController.js (line 878, 887-894) - api.hyungi.net/models/dailyWorkReportModel.js (line 1242-1266) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -827,6 +827,74 @@ const getAccumulatedReports = (req, res) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TBM 배정 기반 작업보고서 생성
|
||||||
|
*/
|
||||||
|
const createFromTbm = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const {
|
||||||
|
tbm_assignment_id,
|
||||||
|
tbm_session_id,
|
||||||
|
worker_id,
|
||||||
|
project_id,
|
||||||
|
work_type_id,
|
||||||
|
report_date,
|
||||||
|
start_time,
|
||||||
|
end_time,
|
||||||
|
total_hours,
|
||||||
|
error_hours,
|
||||||
|
error_type_id,
|
||||||
|
work_status_id
|
||||||
|
} = req.body;
|
||||||
|
|
||||||
|
// 필수 필드 검증
|
||||||
|
if (!tbm_assignment_id || !tbm_session_id || !worker_id || !report_date || !total_hours) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: '필수 필드가 누락되었습니다. (assignment_id, session_id, worker_id, report_date, total_hours)'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// regular_hours 계산
|
||||||
|
const regular_hours = total_hours - (error_hours || 0);
|
||||||
|
|
||||||
|
const reportData = {
|
||||||
|
tbm_assignment_id,
|
||||||
|
tbm_session_id,
|
||||||
|
worker_id,
|
||||||
|
project_id,
|
||||||
|
work_type_id,
|
||||||
|
report_date,
|
||||||
|
start_time,
|
||||||
|
end_time,
|
||||||
|
total_hours,
|
||||||
|
error_hours: error_hours || 0,
|
||||||
|
regular_hours,
|
||||||
|
work_status_id: work_status_id || (error_hours > 0 ? 2 : 1), // error_hours가 있으면 상태 2 (부적합)
|
||||||
|
error_type_id,
|
||||||
|
created_by: req.user.user_id
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await dailyWorkReportModel.createFromTbmAssignment(reportData);
|
||||||
|
|
||||||
|
res.status(201).json({
|
||||||
|
success: true,
|
||||||
|
message: '작업보고서가 생성되었습니다.',
|
||||||
|
data: result
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error('TBM 작업보고서 생성 오류:', err);
|
||||||
|
console.error('Error stack:', err.stack);
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: 'TBM 작업보고서 생성 중 오류가 발생했습니다.',
|
||||||
|
error: err.message,
|
||||||
|
stack: process.env.NODE_ENV === 'development' ? err.stack : undefined
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 모든 컨트롤러 함수 내보내기 (리팩토링된 함수 위주로 재구성)
|
// 모든 컨트롤러 함수 내보내기 (리팩토링된 함수 위주로 재구성)
|
||||||
module.exports = {
|
module.exports = {
|
||||||
// 📝 V2 핵심 CRUD 함수
|
// 📝 V2 핵심 CRUD 함수
|
||||||
@@ -834,7 +902,8 @@ module.exports = {
|
|||||||
getDailyWorkReports,
|
getDailyWorkReports,
|
||||||
updateWorkReport,
|
updateWorkReport,
|
||||||
removeDailyWorkReport,
|
removeDailyWorkReport,
|
||||||
|
createFromTbm,
|
||||||
|
|
||||||
// 📊 V2 통계 및 요약 함수
|
// 📊 V2 통계 및 요약 함수
|
||||||
getWorkReportStats,
|
getWorkReportStats,
|
||||||
getDailySummary,
|
getDailySummary,
|
||||||
@@ -851,7 +920,7 @@ module.exports = {
|
|||||||
getWorkTypes,
|
getWorkTypes,
|
||||||
getWorkStatusTypes,
|
getWorkStatusTypes,
|
||||||
getErrorTypes,
|
getErrorTypes,
|
||||||
|
|
||||||
// 🔽 마스터 데이터 CRUD
|
// 🔽 마스터 데이터 CRUD
|
||||||
createWorkType,
|
createWorkType,
|
||||||
updateWorkType,
|
updateWorkType,
|
||||||
|
|||||||
@@ -1209,6 +1209,113 @@ const deleteErrorType = async (id, callback) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TBM 기반 작업보고서 생성 및 TBM 세션 완료 처리
|
||||||
|
* @param {object} reportData - TBM 작업보고서 데이터
|
||||||
|
* @returns {Promise<object>} 생성 결과
|
||||||
|
*/
|
||||||
|
const createFromTbmAssignment = async (reportData) => {
|
||||||
|
const {
|
||||||
|
tbm_assignment_id,
|
||||||
|
tbm_session_id,
|
||||||
|
worker_id,
|
||||||
|
project_id,
|
||||||
|
work_type_id,
|
||||||
|
report_date,
|
||||||
|
start_time,
|
||||||
|
end_time,
|
||||||
|
total_hours,
|
||||||
|
error_hours,
|
||||||
|
regular_hours,
|
||||||
|
work_status_id,
|
||||||
|
error_type_id,
|
||||||
|
created_by
|
||||||
|
} = reportData;
|
||||||
|
|
||||||
|
const db = await getDb();
|
||||||
|
const conn = await db.getConnection();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await conn.beginTransaction();
|
||||||
|
|
||||||
|
// 1. 작업보고서 생성
|
||||||
|
const sql = `
|
||||||
|
INSERT INTO daily_work_reports
|
||||||
|
(tbm_session_id, tbm_assignment_id, report_date, worker_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())
|
||||||
|
`;
|
||||||
|
|
||||||
|
const [result] = await conn.query(sql, [
|
||||||
|
tbm_session_id,
|
||||||
|
tbm_assignment_id,
|
||||||
|
report_date,
|
||||||
|
worker_id,
|
||||||
|
project_id,
|
||||||
|
work_type_id,
|
||||||
|
start_time || null,
|
||||||
|
end_time || null,
|
||||||
|
total_hours, // work_hours는 TBM에서 total_hours와 동일
|
||||||
|
total_hours,
|
||||||
|
regular_hours,
|
||||||
|
error_hours || 0,
|
||||||
|
work_status_id || 1,
|
||||||
|
error_type_id || null,
|
||||||
|
created_by
|
||||||
|
]);
|
||||||
|
|
||||||
|
const reportId = result.insertId;
|
||||||
|
|
||||||
|
// 2. TBM 세션의 모든 팀 배정이 작업보고서를 제출했는지 확인
|
||||||
|
const [assignmentCheck] = await conn.query(`
|
||||||
|
SELECT
|
||||||
|
COUNT(*) as total_assignments,
|
||||||
|
COUNT(dwr.tbm_assignment_id) as completed_assignments
|
||||||
|
FROM tbm_team_assignments ta
|
||||||
|
LEFT JOIN daily_work_reports dwr ON ta.assignment_id = dwr.tbm_assignment_id
|
||||||
|
WHERE ta.session_id = ?
|
||||||
|
`, [tbm_session_id]);
|
||||||
|
|
||||||
|
const { total_assignments, completed_assignments } = assignmentCheck[0];
|
||||||
|
|
||||||
|
// 3. 모든 팀원이 작업보고서를 제출했으면 TBM 세션을 완료로 표시
|
||||||
|
if (total_assignments === completed_assignments) {
|
||||||
|
await conn.query(`
|
||||||
|
UPDATE tbm_sessions
|
||||||
|
SET status = 'completed', updated_at = NOW()
|
||||||
|
WHERE session_id = ?
|
||||||
|
`, [tbm_session_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
await conn.commit();
|
||||||
|
|
||||||
|
// 4. 근태 기록 동기화
|
||||||
|
try {
|
||||||
|
const AttendanceModel = require('./attendanceModel');
|
||||||
|
await AttendanceModel.syncWithWorkReports(worker_id, report_date);
|
||||||
|
} catch (syncErr) {
|
||||||
|
console.error('근태 기록 동기화 실패 (TBM Report):', syncErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`[Model] TBM 작업보고서 생성 완료: report_id=${reportId}, session=${tbm_session_id}, assignment=${tbm_assignment_id}`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
report_id: reportId,
|
||||||
|
tbm_completed: total_assignments === completed_assignments,
|
||||||
|
completion_status: `${completed_assignments}/${total_assignments} 작업 완료`
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
await conn.rollback();
|
||||||
|
console.error('[Model] TBM 작업보고서 생성 중 오류 발생:', err);
|
||||||
|
throw new Error('TBM 작업보고서 생성 중 오류가 발생했습니다.');
|
||||||
|
} finally {
|
||||||
|
conn.release();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 모든 함수 내보내기 (Promise 기반 함수 위주로 재구성)
|
// 모든 함수 내보내기 (Promise 기반 함수 위주로 재구성)
|
||||||
module.exports = {
|
module.exports = {
|
||||||
// 새로 추가된 V2 함수 (Promise 기반)
|
// 새로 추가된 V2 함수 (Promise 기반)
|
||||||
@@ -1216,6 +1323,7 @@ module.exports = {
|
|||||||
getReportsWithOptions,
|
getReportsWithOptions,
|
||||||
updateReportById,
|
updateReportById,
|
||||||
removeReportById,
|
removeReportById,
|
||||||
|
createFromTbmAssignment,
|
||||||
|
|
||||||
// Promise 기반으로 리팩토링된 함수
|
// Promise 기반으로 리팩토링된 함수
|
||||||
getStatistics,
|
getStatistics,
|
||||||
|
|||||||
Reference in New Issue
Block a user