feat: SWG 가스켓 전체 구성 정보 표시 개선
Some checks failed
SonarQube Analysis / SonarQube Scan (push) Has been cancelled
Some checks failed
SonarQube Analysis / SonarQube Scan (push) Has been cancelled
- H/F/I/O SS304/GRAPHITE/CS/CS 패턴에서 4개 구성요소 모두 표시 - 기존 SS304 + GRAPHITE → SS304/GRAPHITE/CS/CS로 완전한 구성 표시 - 외부링/필러/내부링/추가구성 모든 정보 포함 - 구매수량 계산 모달에서 정확한 재질 정보 확인 가능
This commit is contained in:
@@ -7,162 +7,83 @@ from fastapi import Depends
|
||||
from typing import Optional, List, Dict
|
||||
import os
|
||||
import shutil
|
||||
# 설정 및 로깅 import
|
||||
from .config import get_settings
|
||||
from .utils.logger import get_logger
|
||||
from .utils.error_handlers import setup_error_handlers
|
||||
|
||||
# 설정 로드
|
||||
settings = get_settings()
|
||||
|
||||
# 로거 설정
|
||||
logger = get_logger(__name__)
|
||||
|
||||
# FastAPI 앱 생성
|
||||
app = FastAPI(
|
||||
title="TK-MP BOM Management API",
|
||||
title=settings.app_name,
|
||||
description="자재 분류 및 프로젝트 관리 시스템",
|
||||
version="1.0.0"
|
||||
version=settings.app_version,
|
||||
debug=settings.debug
|
||||
)
|
||||
|
||||
# CORS 설정
|
||||
# 에러 핸들러 설정
|
||||
setup_error_handlers(app)
|
||||
|
||||
# CORS 설정 (환경별 분리)
|
||||
cors_config = settings.get_cors_config()
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
**cors_config
|
||||
)
|
||||
|
||||
logger.info(f"CORS origins configured for {settings.environment}: {settings.security.cors_origins}")
|
||||
|
||||
# 라우터들 import 및 등록
|
||||
try:
|
||||
from .routers import files
|
||||
app.include_router(files.router, prefix="/files", tags=["files"])
|
||||
except ImportError:
|
||||
print("files 라우터를 찾을 수 없습니다")
|
||||
logger.warning("files 라우터를 찾을 수 없습니다")
|
||||
|
||||
try:
|
||||
from .routers import jobs
|
||||
app.include_router(jobs.router, prefix="/jobs", tags=["jobs"])
|
||||
except ImportError:
|
||||
print("jobs 라우터를 찾을 수 없습니다")
|
||||
logger.warning("jobs 라우터를 찾을 수 없습니다")
|
||||
|
||||
try:
|
||||
from .routers import purchase
|
||||
app.include_router(purchase.router, tags=["purchase"])
|
||||
except ImportError:
|
||||
print("purchase 라우터를 찾을 수 없습니다")
|
||||
logger.warning("purchase 라우터를 찾을 수 없습니다")
|
||||
|
||||
try:
|
||||
from .routers import material_comparison
|
||||
app.include_router(material_comparison.router, tags=["material-comparison"])
|
||||
except ImportError:
|
||||
print("material_comparison 라우터를 찾을 수 없습니다")
|
||||
logger.warning("material_comparison 라우터를 찾을 수 없습니다")
|
||||
|
||||
# 파일 목록 조회 API
|
||||
@app.get("/files")
|
||||
async def get_files(
|
||||
job_no: Optional[str] = None, # project_id 대신 job_no 사용
|
||||
show_history: bool = False, # 이력 표시 여부
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""파일 목록 조회 (BOM별 그룹화)"""
|
||||
try:
|
||||
if show_history:
|
||||
# 전체 이력 표시
|
||||
query = "SELECT * FROM files"
|
||||
params = {}
|
||||
|
||||
if job_no:
|
||||
query += " WHERE job_no = :job_no"
|
||||
params["job_no"] = job_no
|
||||
|
||||
query += " ORDER BY original_filename, revision DESC"
|
||||
else:
|
||||
# 최신 리비전만 표시
|
||||
if job_no:
|
||||
query = """
|
||||
SELECT f1.* FROM files f1
|
||||
INNER JOIN (
|
||||
SELECT original_filename, MAX(revision) as max_revision
|
||||
FROM files
|
||||
WHERE job_no = :job_no
|
||||
GROUP BY original_filename
|
||||
) f2 ON f1.original_filename = f2.original_filename
|
||||
AND f1.revision = f2.max_revision
|
||||
WHERE f1.job_no = :job_no
|
||||
ORDER BY f1.upload_date DESC
|
||||
"""
|
||||
params = {"job_no": job_no}
|
||||
else:
|
||||
# job_no가 없으면 전체 파일 조회
|
||||
query = "SELECT * FROM files ORDER BY upload_date DESC"
|
||||
params = {}
|
||||
|
||||
result = db.execute(text(query), params)
|
||||
files = result.fetchall()
|
||||
|
||||
return [
|
||||
{
|
||||
"id": f.id,
|
||||
"filename": f.original_filename,
|
||||
"original_filename": f.original_filename,
|
||||
"name": f.original_filename,
|
||||
"job_no": f.job_no, # job_no 사용
|
||||
"bom_name": f.bom_name or f.original_filename, # 실제 bom_name 값 사용, 없으면 파일명
|
||||
"revision": f.revision or "Rev.0", # 실제 리비전 또는 기본값
|
||||
"parsed_count": f.parsed_count or 0, # 파싱된 자재 수
|
||||
"bom_type": f.file_type or "unknown", # file_type을 BOM 종류로 사용
|
||||
"status": "active" if f.is_active else "inactive", # is_active 상태
|
||||
"file_size": f.file_size,
|
||||
"created_at": f.upload_date,
|
||||
"upload_date": f.upload_date,
|
||||
"description": f"파일: {f.original_filename}"
|
||||
}
|
||||
for f in files
|
||||
]
|
||||
except Exception as e:
|
||||
print(f"파일 목록 조회 에러: {str(e)}")
|
||||
return {"error": f"파일 목록 조회 실패: {str(e)}"}
|
||||
try:
|
||||
from .routers import tubing
|
||||
app.include_router(tubing.router, prefix="/tubing", tags=["tubing"])
|
||||
except ImportError:
|
||||
logger.warning("tubing 라우터를 찾을 수 없습니다")
|
||||
|
||||
# 파일 삭제 API
|
||||
@app.delete("/files/{file_id}")
|
||||
async def delete_file(
|
||||
file_id: int,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""파일 삭제"""
|
||||
try:
|
||||
# 먼저 파일 정보 조회
|
||||
file_query = text("SELECT * FROM files WHERE id = :file_id")
|
||||
file_result = db.execute(file_query, {"file_id": file_id})
|
||||
file = file_result.fetchone()
|
||||
|
||||
if not file:
|
||||
return {"error": "파일을 찾을 수 없습니다"}
|
||||
|
||||
# 먼저 상세 테이블의 데이터 삭제 (외래 키 제약 조건 때문)
|
||||
# 각 자재 타입별 상세 테이블 데이터 삭제
|
||||
detail_tables = [
|
||||
'pipe_details', 'fitting_details', 'valve_details',
|
||||
'flange_details', 'bolt_details', 'gasket_details',
|
||||
'instrument_details'
|
||||
]
|
||||
|
||||
# 해당 파일의 materials ID 조회
|
||||
material_ids_query = text("SELECT id FROM materials WHERE file_id = :file_id")
|
||||
material_ids_result = db.execute(material_ids_query, {"file_id": file_id})
|
||||
material_ids = [row[0] for row in material_ids_result]
|
||||
|
||||
if material_ids:
|
||||
# 각 상세 테이블에서 관련 데이터 삭제
|
||||
for table in detail_tables:
|
||||
delete_detail_query = text(f"DELETE FROM {table} WHERE material_id = ANY(:material_ids)")
|
||||
db.execute(delete_detail_query, {"material_ids": material_ids})
|
||||
|
||||
# materials 테이블 데이터 삭제
|
||||
materials_query = text("DELETE FROM materials WHERE file_id = :file_id")
|
||||
db.execute(materials_query, {"file_id": file_id})
|
||||
|
||||
# 파일 삭제
|
||||
delete_query = text("DELETE FROM files WHERE id = :file_id")
|
||||
db.execute(delete_query, {"file_id": file_id})
|
||||
|
||||
db.commit()
|
||||
return {"success": True, "message": "파일과 관련 데이터가 삭제되었습니다"}
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
return {"error": f"파일 삭제 실패: {str(e)}"}
|
||||
# 파일 관리 API 라우터 등록
|
||||
try:
|
||||
from .api import file_management
|
||||
app.include_router(file_management.router, tags=["file-management"])
|
||||
logger.info("파일 관리 API 라우터 등록 완료")
|
||||
except ImportError as e:
|
||||
logger.warning(f"파일 관리 라우터를 찾을 수 없습니다: {e}")
|
||||
|
||||
# 인증 API 라우터 등록
|
||||
try:
|
||||
from .auth import auth_router
|
||||
app.include_router(auth_router, prefix="/auth", tags=["authentication"])
|
||||
logger.info("인증 API 라우터 등록 완료")
|
||||
except ImportError as e:
|
||||
logger.warning(f"인증 라우터를 찾을 수 없습니다: {e}")
|
||||
|
||||
# 프로젝트 관리 API (비활성화 - jobs 테이블 사용)
|
||||
# projects 테이블은 더 이상 사용하지 않음
|
||||
|
||||
Reference in New Issue
Block a user