// models/tbmModel.js - TBM 시스템 모델 const { getDb } = require('../dbPool'); const TbmModel = { // ==================== TBM 세션 관련 ==================== createSession: async (sessionData) => { 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) VALUES (?, ?, ?, ?, ?, ?, ?)`, [ sessionData.session_date, sessionData.leader_id, sessionData.project_id || null, sessionData.work_type_id || null, sessionData.task_id || null, sessionData.work_location || null, sessionData.created_by ] ); return result; }, getSessionsByDate: async (date) => { const db = await getDb(); const [rows] = await db.query( `SELECT s.*, w.worker_name as leader_name, 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, 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) AND tf.transfer_date = s.session_date) as transfer_count, first_ta.project_id, first_ta.work_type_id, first_ta.task_id, first_ta.workplace_id, first_p.project_name, first_wt.name as work_type_name, 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 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 ( SELECT * FROM tbm_team_assignments WHERE (session_id, assignment_id) IN ( SELECT session_id, MIN(assignment_id) FROM tbm_team_assignments GROUP BY session_id ) ) first_ta ON s.session_id = first_ta.session_id LEFT JOIN projects first_p ON first_ta.project_id = first_p.project_id LEFT JOIN work_types first_wt ON first_ta.work_type_id = first_wt.id LEFT JOIN tasks first_t ON first_ta.task_id = first_t.task_id LEFT JOIN workplaces first_wp ON first_ta.workplace_id = first_wp.workplace_id WHERE s.session_date = ? GROUP BY s.session_id ORDER BY s.session_id DESC`, [date] ); return rows; }, getSessionById: async (sessionId) => { const db = await getDb(); const [rows] = await db.query( `SELECT s.*, w.worker_name as leader_name, w.job_type as leader_job_type, 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, first_p.project_name, first_p.job_no, first_wt.name as work_type_name, first_wt.category as work_type_category, first_t.task_name, first_t.description as task_description, 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 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 ( SELECT * FROM tbm_team_assignments WHERE (session_id, assignment_id) IN ( SELECT session_id, MIN(assignment_id) FROM tbm_team_assignments GROUP BY session_id ) ) first_ta ON s.session_id = first_ta.session_id LEFT JOIN projects first_p ON first_ta.project_id = first_p.project_id LEFT JOIN work_types first_wt ON first_ta.work_type_id = first_wt.id LEFT JOIN tasks first_t ON first_ta.task_id = first_t.task_id LEFT JOIN workplaces first_wp ON first_ta.workplace_id = first_wp.workplace_id LEFT JOIN workplace_categories first_wc ON first_ta.workplace_category_id = first_wc.category_id WHERE s.session_id = ? GROUP BY s.session_id`, [sessionId] ); return rows; }, updateSession: async (sessionId, sessionData) => { const db = await getDb(); const [result] = await db.query( `UPDATE tbm_sessions SET project_id = ?, work_location = ?, status = ?, updated_at = NOW() WHERE session_id = ?`, [sessionData.project_id, sessionData.work_location, sessionData.status, sessionId] ); return result; }, completeSession: async (sessionId, endTime) => { const db = await getDb(); const [result] = await db.query( `UPDATE tbm_sessions SET status = 'completed', end_time = ?, updated_at = NOW() WHERE session_id = ?`, [endTime, sessionId] ); return result; }, completeSessionWithAttendance: async (sessionId, endTime, attendanceData, createdBy) => { const db = await getDb(); const conn = await db.getConnection(); try { await conn.beginTransaction(); // 1. 세션 정보 조회 const [sessionRows] = await conn.query( 'SELECT session_date FROM tbm_sessions WHERE session_id = ?', [sessionId] ); if (sessionRows.length === 0) { await conn.commit(); return { affectedRows: 0 }; } const sessionDate = sessionRows[0].session_date; let reportDate; if (sessionDate instanceof Date) { reportDate = sessionDate.toISOString().split('T')[0]; } else if (typeof sessionDate === 'string') { reportDate = sessionDate.split('T')[0]; } else { reportDate = new Date(sessionDate).toISOString().split('T')[0]; } // 2. 각 작업자의 근태 유형 업데이트 for (const item of attendanceData) { 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] ); } // 3. 연차 작업자 → 작업보고서 자동 생성 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] ); if (assignRows.length > 0) { const [existingReport] = await conn.query( 'SELECT id FROM daily_work_reports WHERE tbm_assignment_id = ?', [assignRows[0].assignment_id] ); 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) VALUES (?, ?, 13, 8, 1, ?, ?, NOW())`, [reportDate, aw.worker_id, createdBy, assignRows[0].assignment_id] ); } } } // 4. 세션 완료 처리 await conn.query( `UPDATE tbm_sessions SET status = 'completed', end_time = ?, updated_at = NOW() WHERE session_id = ?`, [endTime, sessionId] ); await conn.commit(); // 5. 연차 작업자 근태 동기화 for (const aw of annualWorkers) { try { const AttendanceModel = require('./attendanceModel'); await AttendanceModel.syncWithWorkReports(aw.worker_id, reportDate); } catch (syncErr) { // 근태 동기화 오류 (무시됨) } } return { affectedRows: 1 }; } catch (err) { try { await conn.rollback(); } catch (e) {} throw err; } finally { conn.release(); } }, deleteSession: async (sessionId) => { const db = await getDb(); const [result] = await db.query( `DELETE FROM tbm_sessions WHERE session_id = ? AND status = 'draft'`, [sessionId] ); return result; }, // ==================== 팀 구성 관련 ==================== addTeamMember: async (assignmentData) => { 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, project_id, work_type_id, task_id, workplace_category_id, workplace_id, work_hours) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE assigned_role = VALUES(assigned_role), work_detail = VALUES(work_detail), is_present = VALUES(is_present), absence_reason = VALUES(absence_reason), project_id = VALUES(project_id), work_type_id = VALUES(work_type_id), task_id = VALUES(task_id), workplace_category_id = VALUES(workplace_category_id), workplace_id = VALUES(workplace_id), work_hours = COALESCE(VALUES(work_hours), work_hours)`, [ assignmentData.session_id, assignmentData.worker_id, assignmentData.split_seq || 0, assignmentData.assigned_role, assignmentData.work_detail, assignmentData.is_present !== undefined ? assignmentData.is_present : true, assignmentData.absence_reason, assignmentData.project_id || null, assignmentData.work_type_id || null, assignmentData.task_id || null, assignmentData.workplace_category_id || null, assignmentData.workplace_id || null, assignmentData.work_hours !== undefined ? assignmentData.work_hours : null ] ); return result; }, 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] ); 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, task_id, workplace_category_id, workplace_id, is_present) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1)`, [ assignmentData.session_id, assignmentData.worker_id, nextSeq, assignmentData.work_hours, assignmentData.project_id || null, assignmentData.work_type_id || null, assignmentData.task_id || null, assignmentData.workplace_category_id || null, assignmentData.workplace_id || null ] ); return { assignment_id: result.insertId, split_seq: nextSeq }; }, addTeamMembers: async (sessionId, members) => { if (!members || members.length === 0) { return { affectedRows: 0 }; } const db = await getDb(); const values = members.map(m => [ sessionId, m.worker_id, m.assigned_role || null, m.work_detail || null, m.is_present !== undefined ? m.is_present : true, m.absence_reason || null, m.project_id || null, m.work_type_id || null, m.task_id || null, m.workplace_category_id || null, m.workplace_id || null ]); const [result] = await db.query( `INSERT INTO tbm_team_assignments (session_id, worker_id, assigned_role, work_detail, is_present, absence_reason, project_id, work_type_id, task_id, workplace_category_id, workplace_id) VALUES ?`, [values] ); return result; }, getTeamMembers: async (sessionId) => { const db = await getDb(); const [rows] = await db.query( `SELECT ta.*, w.worker_name, w.job_type, w.phone_number, w.department, p.project_name, wt.name as work_type_name, t.task_name, 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 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 LEFT JOIN workplace_categories wc ON ta.workplace_category_id = wc.category_id LEFT JOIN workplaces wp ON ta.workplace_id = wp.workplace_id WHERE ta.session_id = ? ORDER BY ta.assigned_at DESC`, [sessionId] ); return rows; }, removeTeamMember: async (sessionId, workerId) => { const db = await getDb(); const [result] = await db.query( `DELETE FROM tbm_team_assignments WHERE session_id = ? AND worker_id = ?`, [sessionId, workerId] ); return result; }, clearAllTeamMembers: async (sessionId) => { const db = await getDb(); const [result] = await db.query( `DELETE FROM tbm_team_assignments WHERE session_id = ?`, [sessionId] ); return result; }, // ==================== 안전 체크리스트 관련 ==================== getAllSafetyChecks: async () => { const db = await getDb(); const [rows] = await db.query( `SELECT * FROM tbm_safety_checks WHERE is_active = 1 ORDER BY check_category, display_order` ); return rows; }, getSafetyChecksByCategory: async (category) => { const db = await getDb(); const [rows] = await db.query( `SELECT * FROM tbm_safety_checks WHERE check_category = ? AND is_active = 1 ORDER BY display_order`, [category] ); return rows; }, getSafetyRecords: async (sessionId) => { const db = await getDb(); const [rows] = await db.query( `SELECT sr.*, sc.check_category, sc.check_item, sc.description, sc.is_required, u.username as checked_by_username, u.name as checked_by_name FROM tbm_safety_records sr INNER JOIN tbm_safety_checks sc ON sr.check_id = sc.check_id LEFT JOIN sso_users u ON sr.checked_by = u.user_id WHERE sr.session_id = ? ORDER BY sc.check_category, sc.display_order`, [sessionId] ); return rows; }, saveSafetyRecord: async (recordData) => { const db = await getDb(); const [result] = await db.query( `INSERT INTO tbm_safety_records (session_id, check_id, is_checked, notes, checked_by, checked_at) VALUES (?, ?, ?, ?, ?, NOW()) ON DUPLICATE KEY UPDATE is_checked = VALUES(is_checked), notes = VALUES(notes), checked_by = VALUES(checked_by), checked_at = NOW()`, [recordData.session_id, recordData.check_id, recordData.is_checked, recordData.notes, recordData.checked_by] ); return result; }, saveSafetyRecords: async (sessionId, records, checkedBy) => { if (!records || records.length === 0) { return { affectedRows: 0 }; } const db = await getDb(); const values = records.map(r => [ sessionId, r.check_id, r.is_checked, r.notes || null, checkedBy ]); const [result] = await db.query( `INSERT INTO tbm_safety_records (session_id, check_id, is_checked, notes, checked_by, checked_at) VALUES ? ON DUPLICATE KEY UPDATE is_checked = VALUES(is_checked), notes = VALUES(notes), checked_by = VALUES(checked_by), checked_at = NOW()`, [values] ); return result; }, // ==================== 작업 인계 관련 ==================== createHandover: async (handoverData) => { 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, reason, handover_notes, worker_ids) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [ handoverData.session_id, handoverData.from_leader_id, handoverData.to_leader_id, handoverData.handover_date, handoverData.handover_time, handoverData.reason, handoverData.handover_notes, JSON.stringify(handoverData.worker_ids || []) ] ); return result; }, confirmHandover: async (handoverId, confirmedBy) => { const db = await getDb(); const [result] = await db.query( `UPDATE team_handovers SET is_confirmed = 1, confirmed_at = NOW(), confirmed_by = ? WHERE handover_id = ?`, [confirmedBy, handoverId] ); return result; }, getHandoversByDate: async (date) => { const db = await getDb(); const [rows] = await db.query( `SELECT h.*, w1.worker_name as from_leader_name, w2.worker_name as to_leader_name, 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 LEFT JOIN sso_users u ON h.confirmed_by = u.user_id WHERE h.handover_date = ? ORDER BY h.handover_time DESC`, [date] ); return rows; }, getPendingHandovers: async (toLeaderId) => { const db = await getDb(); const [rows] = await db.query( `SELECT h.*, w1.worker_name as from_leader_name, 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 LEFT JOIN tbm_sessions s ON h.session_id = s.session_id WHERE h.to_leader_id = ? AND h.is_confirmed = 0 ORDER BY h.handover_date DESC, h.handover_time DESC`, [toLeaderId] ); return rows; }, // ==================== 통계 및 리포트 ==================== getTbmStatistics: async (startDate, endDate) => { const db = await getDb(); const [rows] = await db.query( `SELECT DATE(session_date) as date, COUNT(DISTINCT session_id) as session_count, COUNT(DISTINCT leader_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 ? GROUP BY DATE(session_date) ORDER BY date DESC`, [startDate, endDate] ); return rows; }, getLeaderStatistics: async (startDate, endDate) => { const db = await getDb(); const [rows] = await db.query( `SELECT s.leader_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 FROM tbm_sessions s INNER JOIN workers w ON s.leader_id = w.worker_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 ORDER BY total_sessions DESC`, [startDate, endDate] ); return rows; }, getIncompleteWorkReports: async (userId) => { const db = await getDb(); let whereClause = ` WHERE dwr.id IS NULL AND s.status = 'completed' AND (ta.attendance_type IS NULL OR ta.attendance_type != 'annual') AND ta.task_id IS NOT NULL AND ta.workplace_id IS NOT NULL `; const params = []; if (userId !== null && userId !== undefined) { whereClause = ` WHERE s.created_by = ? AND dwr.id IS NULL AND s.status = 'completed' AND (ta.attendance_type IS NULL OR ta.attendance_type != 'annual') AND ta.task_id IS NOT NULL AND ta.workplace_id IS NOT NULL `; params.push(userId); } const [rows] = await db.query( `SELECT ta.assignment_id, ta.session_id, ta.worker_id, ta.project_id, ta.work_type_id, ta.task_id, ta.workplace_category_id, ta.workplace_id, ta.attendance_type, ta.attendance_hours, ta.work_hours, s.session_date, s.status as session_status, s.created_by, w.worker_name, w.job_type, p.project_name, wt.name as work_type_name, t.task_name, wp.workplace_name, wc.category_name, creator.name as created_by_name, 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 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 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 LEFT JOIN workplaces wp ON ta.workplace_id = wp.workplace_id LEFT JOIN workplace_categories wc ON ta.workplace_category_id = wc.category_id LEFT JOIN daily_work_reports dwr ON ta.assignment_id = dwr.tbm_assignment_id ${whereClause} ORDER BY s.session_date DESC, ta.assignment_id ASC`, params ); return rows; }, // ========== 안전 체크리스트 확장 메서드 ========== getSafetyChecksByType: async (checkType, options = {}) => { const db = await getDb(); let sql = ` SELECT sc.*, wc.condition_name as weather_condition_name, wc.icon as weather_icon, t.task_name FROM tbm_safety_checks sc LEFT JOIN weather_conditions wc ON sc.weather_condition = wc.condition_code LEFT JOIN tasks t ON sc.task_id = t.task_id WHERE sc.is_active = 1 AND sc.check_type = ? `; const params = [checkType]; if (checkType === 'weather' && options.weatherCondition) { sql += ' AND sc.weather_condition = ?'; params.push(options.weatherCondition); } if (checkType === 'task' && options.taskId) { sql += ' AND sc.task_id = ?'; params.push(options.taskId); } sql += ' ORDER BY sc.check_category, sc.display_order'; const [rows] = await db.query(sql, params); return rows; }, getSafetyChecksByWeather: async (conditions) => { if (!conditions || conditions.length === 0) { return []; } const db = await getDb(); const placeholders = conditions.map(() => '?').join(','); const [rows] = await db.query( `SELECT sc.*, wc.condition_name as weather_condition_name, wc.icon as weather_icon FROM tbm_safety_checks sc LEFT JOIN weather_conditions wc ON sc.weather_condition = wc.condition_code WHERE sc.is_active = 1 AND sc.check_type = 'weather' AND sc.weather_condition IN (${placeholders}) ORDER BY sc.weather_condition, sc.display_order`, conditions ); return rows; }, getSafetyChecksByTasks: async (taskIds) => { if (!taskIds || taskIds.length === 0) { return []; } const db = await getDb(); const placeholders = taskIds.map(() => '?').join(','); const [rows] = await db.query( `SELECT sc.*, t.task_name, wt.name as work_type_name FROM tbm_safety_checks sc LEFT JOIN tasks t ON sc.task_id = t.task_id LEFT JOIN work_types wt ON t.work_type_id = wt.id WHERE sc.is_active = 1 AND sc.check_type = 'task' AND sc.task_id IN (${placeholders}) ORDER BY sc.task_id, sc.display_order`, taskIds ); return rows; }, getFilteredSafetyChecks: async (sessionId, weatherConditions = []) => { const db = await getDb(); // 1. 세션 작업 ID 목록 const [assignments] = await db.query( `SELECT DISTINCT task_id FROM tbm_team_assignments WHERE session_id = ? AND task_id IS NOT NULL`, [sessionId] ); const taskIds = assignments.map(a => a.task_id); // 2. 기본 체크항목 const [basicChecks] = await db.query( `SELECT sc.*, 'basic' as section_type FROM tbm_safety_checks sc WHERE sc.is_active = 1 AND sc.check_type = 'basic' ORDER BY sc.check_category, sc.display_order` ); // 3. 날씨별 체크항목 let weatherChecks = []; if (weatherConditions && weatherConditions.length > 0) { const wcPlaceholders = weatherConditions.map(() => '?').join(','); const [rows] = await db.query( `SELECT sc.*, wc.condition_name as weather_condition_name, wc.icon as weather_icon, 'weather' as section_type FROM tbm_safety_checks sc LEFT JOIN weather_conditions wc ON sc.weather_condition = wc.condition_code WHERE sc.is_active = 1 AND sc.check_type = 'weather' AND sc.weather_condition IN (${wcPlaceholders}) ORDER BY sc.weather_condition, sc.display_order`, weatherConditions ); weatherChecks = rows; } // 4. 작업별 체크항목 let taskChecks = []; if (taskIds.length > 0) { const taskPlaceholders = taskIds.map(() => '?').join(','); const [rows] = await db.query( `SELECT sc.*, t.task_name, wt.name as work_type_name, 'task' as section_type FROM tbm_safety_checks sc LEFT JOIN tasks t ON sc.task_id = t.task_id LEFT JOIN work_types wt ON t.work_type_id = wt.id WHERE sc.is_active = 1 AND sc.check_type = 'task' AND sc.task_id IN (${taskPlaceholders}) ORDER BY sc.task_id, sc.display_order`, taskIds ); taskChecks = rows; } // 5. 기존 체크 기록 const [existingRecords] = await db.query( `SELECT check_id, is_checked, notes FROM tbm_safety_records WHERE session_id = ?`, [sessionId] ); const recordMap = {}; existingRecords.forEach(r => { recordMap[r.check_id] = { is_checked: r.is_checked, notes: r.notes }; }); // 6. 기록 병합 const mergeWithRecords = (checks) => { return checks.map(check => ({ ...check, is_checked: recordMap[check.check_id]?.is_checked || false, notes: recordMap[check.check_id]?.notes || null })); }; return { basic: mergeWithRecords(basicChecks), weather: mergeWithRecords(weatherChecks), task: mergeWithRecords(taskChecks), totalCount: basicChecks.length + weatherChecks.length + taskChecks.length, weatherConditions: weatherConditions }; }, createSafetyCheck: async (checkData) => { const db = await getDb(); const [result] = await db.query( `INSERT INTO tbm_safety_checks (check_category, check_type, weather_condition, task_id, check_item, description, is_required, display_order) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [ checkData.check_category, checkData.check_type || 'basic', checkData.weather_condition || null, checkData.task_id || null, checkData.check_item, checkData.description || null, checkData.is_required !== false, checkData.display_order || 0 ] ); return { insertId: result.insertId }; }, updateSafetyCheck: async (checkId, checkData) => { const db = await getDb(); const [result] = await db.query( `UPDATE tbm_safety_checks SET check_category = ?, check_type = ?, weather_condition = ?, task_id = ?, check_item = ?, description = ?, is_required = ?, display_order = ?, is_active = ?, updated_at = NOW() WHERE check_id = ?`, [ checkData.check_category, checkData.check_type || 'basic', checkData.weather_condition || null, checkData.task_id || null, checkData.check_item, checkData.description || null, checkData.is_required !== false, checkData.display_order || 0, checkData.is_active !== false, checkId ] ); return { affectedRows: result.affectedRows }; }, deleteSafetyCheck: async (checkId) => { const db = await getDb(); const [result] = await db.query( `UPDATE tbm_safety_checks SET is_active = 0 WHERE check_id = ?`, [checkId] ); return { affectedRows: result.affectedRows }; } }; module.exports = TbmModel;