diff --git a/api.hyungi.net/controllers/dailyWorkReportController.js b/api.hyungi.net/controllers/dailyWorkReportController.js index d807dc0..9c79629 100644 --- a/api.hyungi.net/controllers/dailyWorkReportController.js +++ b/api.hyungi.net/controllers/dailyWorkReportController.js @@ -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 = { // 📝 V2 핵심 CRUD 함수 @@ -834,7 +902,8 @@ module.exports = { getDailyWorkReports, updateWorkReport, removeDailyWorkReport, - + createFromTbm, + // 📊 V2 통계 및 요약 함수 getWorkReportStats, getDailySummary, @@ -851,7 +920,7 @@ module.exports = { getWorkTypes, getWorkStatusTypes, getErrorTypes, - + // 🔽 마스터 데이터 CRUD createWorkType, updateWorkType, diff --git a/api.hyungi.net/models/dailyWorkReportModel.js b/api.hyungi.net/models/dailyWorkReportModel.js index 39346e4..e087153 100644 --- a/api.hyungi.net/models/dailyWorkReportModel.js +++ b/api.hyungi.net/models/dailyWorkReportModel.js @@ -1209,6 +1209,113 @@ const deleteErrorType = async (id, callback) => { }; +/** + * TBM 기반 작업보고서 생성 및 TBM 세션 완료 처리 + * @param {object} reportData - TBM 작업보고서 데이터 + * @returns {Promise} 생성 결과 + */ +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 기반 함수 위주로 재구성) module.exports = { // 새로 추가된 V2 함수 (Promise 기반) @@ -1216,6 +1323,7 @@ module.exports = { getReportsWithOptions, updateReportById, removeReportById, + createFromTbmAssignment, // Promise 기반으로 리팩토링된 함수 getStatistics,