feat(proxy-input): 대리입력 리뉴얼 — 2단계 UI + UPSERT + 부적합
프론트엔드: - Step 1: 날짜 선택 → 전체 작업자 목록 (완료/미입력/휴가 구분) - Step 2: 선택 작업자 일괄 편집 (프로젝트/공종/시간/부적합/비고) - 연차=선택불가, 반차=4h, 반반차=6h 기본값 백엔드: - POST /api/proxy-input UPSERT 방식 (409 제거) - 신규: TBM 세션 자동 생성 + 작업보고서 INSERT - 기존: 작업보고서 UPDATE - 부적합: work_report_defects INSERT (기존 defect 있으면 SKIP) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -54,76 +54,98 @@ const ProxyInputController = {
|
||||
|
||||
const userIds = entries.map(e => e.user_id);
|
||||
|
||||
// 1. 중복 체크
|
||||
const duplicates = await ProxyInputModel.checkDuplicateAssignments(conn, session_date, userIds);
|
||||
if (duplicates.length > 0) {
|
||||
await conn.rollback();
|
||||
return res.status(409).json({
|
||||
success: false,
|
||||
message: `다음 작업자가 이미 해당 날짜에 TBM 배정되어 있습니다: ${duplicates.map(d => d.worker_name).join(', ')}`,
|
||||
data: { duplicate_workers: duplicates }
|
||||
// 1. 기존 보고서 확인 (UPSERT 분기)
|
||||
const [existingReports] = await conn.query(
|
||||
`SELECT id, user_id FROM daily_work_reports WHERE report_date = ? AND user_id IN (${userIds.map(() => '?').join(',')})`,
|
||||
[session_date, ...userIds]
|
||||
);
|
||||
const existingMap = {};
|
||||
existingReports.forEach(r => { existingMap[r.user_id] = r.id; });
|
||||
|
||||
// 2. 신규 작업자용 TBM 세션 생성 (기존 있으면 재사용)
|
||||
let sessionId = null;
|
||||
const newUserIds = userIds.filter(id => !existingMap[id]);
|
||||
if (newUserIds.length > 0) {
|
||||
const sessionResult = await ProxyInputModel.createProxySession(conn, {
|
||||
session_date,
|
||||
leader_id: leader_id || userId,
|
||||
proxy_input_by: userId,
|
||||
created_by: userId,
|
||||
safety_notes: safety_notes || '',
|
||||
work_location: work_location || ''
|
||||
});
|
||||
sessionId = sessionResult.insertId;
|
||||
}
|
||||
|
||||
// 2. 작업자 존재 체크
|
||||
const validWorkerIds = await ProxyInputModel.validateWorkers(conn, userIds);
|
||||
const invalidIds = userIds.filter(id => !validWorkerIds.includes(id));
|
||||
if (invalidIds.length > 0) {
|
||||
await conn.rollback();
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: `존재하지 않거나 비활성 작업자: ${invalidIds.join(', ')}`
|
||||
});
|
||||
}
|
||||
|
||||
// 3. TBM 세션 생성
|
||||
const sessionResult = await ProxyInputModel.createProxySession(conn, {
|
||||
session_date,
|
||||
leader_id: leader_id || userId,
|
||||
proxy_input_by: userId,
|
||||
created_by: userId,
|
||||
safety_notes: safety_notes || '',
|
||||
work_location: work_location || ''
|
||||
});
|
||||
const sessionId = sessionResult.insertId;
|
||||
|
||||
// 4. 각 entry 처리
|
||||
// 3. 각 entry 처리 (UPSERT)
|
||||
const createdWorkers = [];
|
||||
for (const entry of entries) {
|
||||
// 팀 배정
|
||||
const assignResult = await ProxyInputModel.createTeamAssignment(conn, {
|
||||
session_id: sessionId,
|
||||
user_id: entry.user_id,
|
||||
project_id: entry.project_id,
|
||||
work_type_id: entry.work_type_id,
|
||||
task_id: entry.task_id || null,
|
||||
workplace_id: entry.workplace_id || null,
|
||||
work_hours: entry.work_hours
|
||||
});
|
||||
const assignmentId = assignResult.insertId;
|
||||
const existingReportId = existingMap[entry.user_id];
|
||||
|
||||
// 작업보고서
|
||||
const reportResult = await ProxyInputModel.createWorkReport(conn, {
|
||||
report_date: session_date,
|
||||
user_id: entry.user_id,
|
||||
project_id: entry.project_id,
|
||||
work_type_id: entry.work_type_id,
|
||||
task_id: entry.task_id || null,
|
||||
work_status_id: entry.work_status_id || 1,
|
||||
work_hours: entry.work_hours,
|
||||
start_time: entry.start_time || null,
|
||||
end_time: entry.end_time || null,
|
||||
note: entry.note || '',
|
||||
tbm_session_id: sessionId,
|
||||
tbm_assignment_id: assignmentId,
|
||||
created_by: userId,
|
||||
created_by_name: req.user.name || req.user.username || ''
|
||||
});
|
||||
if (existingReportId) {
|
||||
// UPDATE 기존 보고서
|
||||
await conn.query(`
|
||||
UPDATE daily_work_reports SET
|
||||
project_id = ?, work_type_id = ?, work_hours = ?,
|
||||
work_status_id = ?, start_time = ?, end_time = ?, note = ?,
|
||||
updated_at = NOW()
|
||||
WHERE id = ?
|
||||
`, [entry.project_id, entry.work_type_id, entry.work_hours,
|
||||
entry.work_status_id || 1, entry.start_time || null, entry.end_time || null,
|
||||
entry.note || '', existingReportId]);
|
||||
|
||||
createdWorkers.push({
|
||||
user_id: entry.user_id,
|
||||
report_id: reportResult.insertId
|
||||
});
|
||||
createdWorkers.push({ user_id: entry.user_id, report_id: existingReportId, action: 'updated' });
|
||||
} else {
|
||||
// INSERT 신규 — TBM 배정 + 작업보고서
|
||||
const assignResult = await ProxyInputModel.createTeamAssignment(conn, {
|
||||
session_id: sessionId,
|
||||
user_id: entry.user_id,
|
||||
project_id: entry.project_id,
|
||||
work_type_id: entry.work_type_id,
|
||||
task_id: entry.task_id || null,
|
||||
workplace_id: entry.workplace_id || null,
|
||||
work_hours: entry.work_hours
|
||||
});
|
||||
const assignmentId = assignResult.insertId;
|
||||
|
||||
const reportResult = await ProxyInputModel.createWorkReport(conn, {
|
||||
report_date: session_date,
|
||||
user_id: entry.user_id,
|
||||
project_id: entry.project_id,
|
||||
work_type_id: entry.work_type_id,
|
||||
task_id: entry.task_id || null,
|
||||
work_status_id: entry.work_status_id || 1,
|
||||
work_hours: entry.work_hours,
|
||||
start_time: entry.start_time || null,
|
||||
end_time: entry.end_time || null,
|
||||
note: entry.note || '',
|
||||
tbm_session_id: sessionId,
|
||||
tbm_assignment_id: assignmentId,
|
||||
created_by: userId,
|
||||
created_by_name: req.user.name || req.user.username || ''
|
||||
});
|
||||
|
||||
createdWorkers.push({ user_id: entry.user_id, report_id: reportResult.insertId, action: 'created' });
|
||||
}
|
||||
|
||||
// 부적합 처리 (defect_hours > 0 && 기존 defect 없을 때만)
|
||||
const defectHours = parseFloat(entry.defect_hours) || 0;
|
||||
const reportId = existingReportId || createdWorkers[createdWorkers.length - 1].report_id;
|
||||
if (defectHours > 0) {
|
||||
const [existingDefects] = await conn.query(
|
||||
'SELECT defect_id FROM work_report_defects WHERE report_id = ?', [reportId]
|
||||
);
|
||||
if (existingDefects.length === 0) {
|
||||
await conn.query(
|
||||
`INSERT INTO work_report_defects (report_id, defect_hours, note) VALUES (?, ?, '대리입력')`,
|
||||
[reportId, defectHours]
|
||||
);
|
||||
await conn.query(
|
||||
'UPDATE daily_work_reports SET error_hours = ?, work_status_id = 2 WHERE id = ?',
|
||||
[defectHours, reportId]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await conn.commit();
|
||||
|
||||
Reference in New Issue
Block a user