refactor: 완료 반려 필드 분리 및 데이터 구조 개선

- backend: completion_rejection_reason 등 전용 필드 추가
- 기존 management_comment에 섞여있던 완료 반려 내용 분리
- 현황판: 완료 반려 내역 별도 카드로 표시
- 관리함: 해결방안에 완료 반려 내용 제외하여 표시
- DB 마이그레이션: completion_rejected_at, completion_rejected_by_id, completion_rejection_reason 필드 추가

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2025-11-08 11:56:09 +09:00
parent d1ed53cbd7
commit 2fc7d4bc2c
5 changed files with 1937 additions and 82 deletions

View File

@@ -186,21 +186,66 @@ async def delete_issue(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
from database.models import DeletionLog
import json
issue = db.query(Issue).filter(Issue.id == issue_id).first()
if not issue:
raise HTTPException(status_code=404, detail="Issue not found")
# 권한 확인 (관리자 삭제 가능)
if current_user.role != UserRole.admin:
raise HTTPException(status_code=403, detail="Only admin can delete issues")
# 권한 확인 (관리자 또는 본인이 등록한 경우 삭제 가능)
if current_user.role != UserRole.admin and issue.reporter_id != current_user.id:
raise HTTPException(status_code=403, detail="본인이 등록한 부적합만 삭제할 수 있습니다.")
# 이 이슈를 중복 대상으로 참조하는 다른 이슈들의 참조 제거
referencing_issues = db.query(Issue).filter(Issue.duplicate_of_issue_id == issue_id).all()
if referencing_issues:
print(f"DEBUG: {len(referencing_issues)}개의 이슈가 이 이슈를 중복 대상으로 참조하고 있습니다. 참조를 제거합니다.")
for ref_issue in referencing_issues:
ref_issue.duplicate_of_issue_id = None
db.flush() # 참조 제거를 먼저 커밋
# 삭제 로그 생성 (삭제 전 데이터 저장)
issue_data = {
"id": issue.id,
"category": issue.category.value if issue.category else None,
"description": issue.description,
"status": issue.status.value if issue.status else None,
"reporter_id": issue.reporter_id,
"project_id": issue.project_id,
"report_date": issue.report_date.isoformat() if issue.report_date else None,
"work_hours": issue.work_hours,
"detail_notes": issue.detail_notes,
"photo_path": issue.photo_path,
"photo_path2": issue.photo_path2,
"review_status": issue.review_status.value if issue.review_status else None,
"solution": issue.solution,
"responsible_department": issue.responsible_department.value if issue.responsible_department else None,
"responsible_person": issue.responsible_person,
"expected_completion_date": issue.expected_completion_date.isoformat() if issue.expected_completion_date else None,
"actual_completion_date": issue.actual_completion_date.isoformat() if issue.actual_completion_date else None,
}
deletion_log = DeletionLog(
entity_type="issue",
entity_id=issue.id,
entity_data=issue_data,
deleted_by_id=current_user.id,
reason=f"사용자 {current_user.username}에 의해 삭제됨"
)
db.add(deletion_log)
# 이미지 파일 삭제
if issue.photo_path:
delete_file(issue.photo_path)
if issue.photo_path2:
delete_file(issue.photo_path2)
if issue.completion_photo_path:
delete_file(issue.completion_photo_path)
db.delete(issue)
db.commit()
return {"detail": "Issue deleted successfully"}
return {"detail": "Issue deleted successfully", "logged": True}
@router.get("/stats/summary")
async def get_issue_stats(
@@ -353,3 +398,66 @@ async def request_completion(
except:
pass
raise HTTPException(status_code=500, detail=f"완료 신청 처리 중 오류가 발생했습니다: {str(e)}")
@router.post("/{issue_id}/reject-completion")
async def reject_completion_request(
issue_id: int,
request: schemas.CompletionRejectionRequest,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""
완료 신청 반려 - 관리자가 완료 신청을 반려
"""
# 이슈 조회
issue = db.query(Issue).filter(Issue.id == issue_id).first()
if not issue:
raise HTTPException(status_code=404, detail="부적합을 찾을 수 없습니다.")
# 완료 신청이 있는지 확인
if not issue.completion_requested_at:
raise HTTPException(status_code=400, detail="완료 신청이 없는 부적합입니다.")
# 권한 확인 (관리자 또는 관리함 접근 권한이 있는 사용자)
if current_user.role != UserRole.admin and not check_page_access(current_user.id, 'issues_management', db):
raise HTTPException(status_code=403, detail="완료 반려 권한이 없습니다.")
try:
print(f"DEBUG: 완료 반려 시작 - Issue ID: {issue_id}, User: {current_user.username}")
# 완료 사진 파일 삭제
if issue.completion_photo_path:
try:
delete_file(issue.completion_photo_path)
print(f"DEBUG: 완료 사진 삭제 완료")
except Exception as e:
print(f"WARNING: 완료 사진 삭제 실패 - {str(e)}")
# 완료 신청 정보 초기화
issue.completion_requested_at = None
issue.completion_requested_by_id = None
issue.completion_photo_path = None
issue.completion_comment = None
# 완료 반려 정보 기록 (전용 필드 사용)
issue.completion_rejected_at = datetime.now()
issue.completion_rejected_by_id = current_user.id
issue.completion_rejection_reason = request.rejection_reason
# 상태는 in_progress로 유지
issue.review_status = ReviewStatus.in_progress
db.commit()
db.refresh(issue)
print(f"DEBUG: 완료 반려 처리 완료")
return {
"message": "완료 신청이 반려되었습니다.",
"issue_id": issue.id,
"rejection_reason": request.rejection_reason
}
except Exception as e:
print(f"ERROR: 완료 반려 처리 오류 - {str(e)}")
db.rollback()
raise HTTPException(status_code=500, detail=f"완료 반려 처리 중 오류가 발생했습니다: {str(e)}")