Files
TK-BOM-Project/backend/app/routers/simple_revision.py
Hyungi Ahn 1dc735f362
Some checks failed
SonarQube Analysis / SonarQube Scan (push) Has been cancelled
리비전 페이지 제거 및 트랜잭션 오류 임시 수정
- frontend/src/pages/revision/ 폴더 완전 삭제
- EnhancedRevisionPage.css 제거
- support_details 저장 시 트랜잭션 오류로 인해 임시로 상세 정보 저장 비활성화
- 리비전 기능 재설계 예정
2025-10-21 12:11:57 +09:00

279 lines
9.3 KiB
Python

"""
간단한 리비전 관리 API
복잡한 dependency 없이 핵심 기능만 제공
"""
from fastapi import APIRouter, Depends, HTTPException, UploadFile, File as FastAPIFile
from sqlalchemy.orm import Session
from typing import Dict, List, Any, Optional
import json
from ..database import get_db
from ..services.simple_revision_service import SimpleRevisionService
from ..services.file_upload_service import FileUploadService
from ..models import File, Material
from ..utils.logger import get_logger
logger = get_logger(__name__)
router = APIRouter(prefix="/simple-revision", tags=["Simple Revision"])
@router.post("/compare")
async def compare_revisions(
current_file_id: int,
previous_file_id: int,
category: str,
username: str = "system",
db: Session = Depends(get_db)
):
"""
두 리비전 간의 자재 비교
Args:
current_file_id: 현재 파일 ID
previous_file_id: 이전 파일 ID
category: 비교할 카테고리 (PIPE, FITTING, FLANGE, VALVE, GASKET, BOLT, SUPPORT, SPECIAL, UNCLASSIFIED)
username: 비교 수행자
"""
try:
service = SimpleRevisionService(db)
result = service.compare_revisions(
current_file_id, previous_file_id, category, username
)
return {
"success": True,
"message": f"{category} 카테고리 리비전 비교 완료",
"data": result
}
except Exception as e:
logger.error(f"리비전 비교 실패: {e}")
raise HTTPException(status_code=500, detail=f"리비전 비교 실패: {str(e)}")
@router.get("/comparison/{comparison_id}")
async def get_comparison_result(
comparison_id: int,
db: Session = Depends(get_db)
):
"""저장된 비교 결과 조회"""
try:
service = SimpleRevisionService(db)
result = service.get_comparison_result(comparison_id)
if not result:
raise HTTPException(status_code=404, detail="비교 결과를 찾을 수 없습니다")
return {
"success": True,
"data": result
}
except HTTPException:
raise
except Exception as e:
logger.error(f"비교 결과 조회 실패: {e}")
raise HTTPException(status_code=500, detail=f"비교 결과 조회 실패: {str(e)}")
@router.post("/upload-revision")
async def upload_revision_file(
file: UploadFile = FastAPIFile(...),
job_no: str = "default",
previous_file_id: int = None,
username: str = "system",
db: Session = Depends(get_db)
):
"""
리비전 파일 업로드 및 자동 비교
Args:
file: 업로드할 BOM 파일
job_no: 작업 번호
previous_file_id: 비교할 이전 파일 ID
username: 업로드 사용자
"""
try:
# 1. 파일 업로드
upload_service = FileUploadService(db)
upload_result = await upload_service.process_upload(
file=file,
job_no=job_no,
username=username,
is_revision=True
)
current_file_id = upload_result['file_id']
# 2. 이전 파일이 지정되지 않은 경우 최신 파일 찾기
if not previous_file_id:
previous_file = db.query(File).filter(
File.job_no == job_no,
File.id != current_file_id,
File.is_active == True
).order_by(File.upload_date.desc()).first()
if previous_file:
previous_file_id = previous_file.id
else:
return {
"success": True,
"message": "첫 번째 파일이므로 비교할 이전 파일이 없습니다",
"data": {
"file_id": current_file_id,
"comparison_results": []
}
}
# 3. 각 카테고리별로 자동 비교 수행
categories = [
'PIPE', 'FITTING', 'FLANGE', 'VALVE',
'GASKET', 'BOLT', 'SUPPORT', 'SPECIAL', 'UNCLASSIFIED'
]
revision_service = SimpleRevisionService(db)
comparison_results = []
for category in categories:
try:
# 해당 카테고리에 자재가 있는지 확인
current_materials = db.query(Material).filter(
Material.file_id == current_file_id,
Material.classified_category == category
).count()
previous_materials = db.query(Material).filter(
Material.file_id == previous_file_id,
Material.classified_category == category
).count()
if current_materials > 0 or previous_materials > 0:
# 비교 수행
comparison_result = revision_service.compare_revisions(
current_file_id, previous_file_id, category, username
)
comparison_results.append(comparison_result)
except Exception as e:
logger.warning(f"{category} 카테고리 비교 실패: {e}")
continue
return {
"success": True,
"message": f"리비전 파일 업로드 및 비교 완료 ({len(comparison_results)}개 카테고리)",
"data": {
"file_id": current_file_id,
"previous_file_id": previous_file_id,
"comparison_results": comparison_results
}
}
except Exception as e:
logger.error(f"리비전 업로드 실패: {e}")
raise HTTPException(status_code=500, detail=f"리비전 업로드 실패: {str(e)}")
@router.get("/categories/{file_id}")
async def get_available_categories(
file_id: int,
db: Session = Depends(get_db)
):
"""파일의 사용 가능한 카테고리 목록 조회"""
try:
# 파일에 포함된 카테고리별 자재 수 조회
categories_query = db.query(
Material.classified_category,
db.func.count(Material.id).label('count')
).filter(
Material.file_id == file_id
).group_by(Material.classified_category).all()
categories = []
for category, count in categories_query:
if category and count > 0:
categories.append({
'category': category,
'count': count
})
return {
"success": True,
"data": {
"file_id": file_id,
"categories": categories
}
}
except Exception as e:
logger.error(f"카테고리 조회 실패: {e}")
raise HTTPException(status_code=500, detail=f"카테고리 조회 실패: {str(e)}")
@router.get("/changed-materials/{current_file_id}/{previous_file_id}")
async def get_changed_materials_only(
current_file_id: int,
previous_file_id: int,
categories: str = None, # 쉼표로 구분된 카테고리 목록
username: str = "system",
db: Session = Depends(get_db)
):
"""변경된 자재만 필터링하여 반환"""
try:
service = SimpleRevisionService(db)
# 카테고리 파싱
category_list = None
if categories:
category_list = [cat.strip().upper() for cat in categories.split(',')]
result = service.get_changed_materials_only(
current_file_id, previous_file_id, category_list, username
)
return {
"success": True,
"message": f"변경된 자재 조회 완료 ({result['total_changed_materials']}개 변경)",
"data": result
}
except Exception as e:
logger.error(f"변경된 자재 조회 실패: {e}")
raise HTTPException(status_code=500, detail=f"변경된 자재 조회 실패: {str(e)}")
@router.get("/history/{job_no}")
async def get_revision_history(
job_no: str,
db: Session = Depends(get_db)
):
"""작업 번호별 리비전 히스토리 조회"""
try:
from ..models import SimpleRevisionComparison
comparisons = db.query(SimpleRevisionComparison).filter(
SimpleRevisionComparison.job_no == job_no
).order_by(SimpleRevisionComparison.created_at.desc()).all()
history = []
for comp in comparisons:
history.append({
'comparison_id': comp.id,
'category': comp.category,
'created_at': comp.created_at.isoformat(),
'created_by': comp.created_by_username,
'summary': {
'added': comp.added_count,
'removed': comp.removed_count,
'changed': comp.changed_count,
'unchanged': comp.unchanged_count
}
})
return {
"success": True,
"data": {
"job_no": job_no,
"history": history
}
}
except Exception as e:
logger.error(f"리비전 히스토리 조회 실패: {e}")
raise HTTPException(status_code=500, detail=f"리비전 히스토리 조회 실패: {str(e)}")