Files
TK-BOM-Project/backend/app/services/exclude_classifier.py
hyungi e0ad21bfad
Some checks failed
SonarQube Analysis / SonarQube Scan (push) Has been cancelled
feat: SPECIAL/UNCLASSIFIED 카테고리 추가 및 WELD GAP 자동 제외
주요 변경사항:
- SPECIAL 카테고리 추가: 특수 제작 품목 관리 (Type, Drawing, Detail1-4)
- UNCLASSIFIED 카테고리 추가: 미분류 자재 원본 그대로 표시
- UNKNOWN → UNCLASSIFIED 통합: 기존 UNKNOWN 카테고리 제거
- WELD GAP 자동 제외: BOM 업로드 시 WELD GAP 항목 자동 필터링

백엔드:
- integrated_classifier.py: UNKNOWN → UNCLASSIFIED 변경, SPECIAL 우선순위 분류
- files.py: parse_dataframe에서 WELD GAP 필터링, UNKNOWN 참조 제거
- exclude_classifier.py: WELD GAP 제외 로직 유지

프론트엔드:
- SpecialMaterialsView.jsx: 특수 제작 품목 관리 컴포넌트
- UnclassifiedMaterialsView.jsx: 미분류 자재 관리 컴포넌트
- BOMManagementPage.jsx: 새 카테고리 추가 및 라우팅
- excelExport.js: SPECIAL/UNCLASSIFIED 엑셀 내보내기 지원
- 모든 UNKNOWN 참조를 UNCLASSIFIED로 변경

기능 개선:
- 저장 기능: 모든 카테고리에 추가요청사항 저장/편집 기능
- P열 납기일 규칙: 모든 카테고리 엑셀 내보내기 통일
- UI 개선: Detail1-4 컬럼명으로 혼동 방지
- 데이터 정리: 모든 프로젝트 및 BOM 데이터 초기화
2025-10-17 13:48:48 +09:00

80 lines
2.6 KiB
Python

"""
EXCLUDE 분류 시스템
실제 자재가 아닌 계산용/제외 항목들 분류
"""
import re
from typing import Dict, List, Optional
# ========== 제외 대상 타입 ==========
EXCLUDE_TYPES = {
"CUTTING_LOSS": {
"description_keywords": ["CUTTING LOSS", "CUT LOSS", "절단로스", "컷팅로스"],
"characteristics": "절단 시 손실 고려용 계산 항목",
"reason": "실제 자재 아님 - 절단 로스 계산용"
},
"SPARE_ALLOWANCE": {
"description_keywords": ["SPARE", "ALLOWANCE", "여유분", "스페어"],
"characteristics": "예비품/여유분 계산 항목",
"reason": "실제 자재 아님 - 여유분 계산용"
},
"THICKNESS_NOTE": {
"description_keywords": ["THK", "THICK", "두께", "THICKNESS"],
"characteristics": "두께 표기용 항목",
"reason": "실제 자재 아님 - 두께 정보"
},
"CALCULATION_ITEM": {
"description_keywords": ["CALC", "CALCULATION", "계산", "산정"],
"characteristics": "기타 계산용 항목",
"reason": "실제 자재 아님 - 계산 목적"
}
}
def classify_exclude(dat_file: str, description: str, main_nom: str = "") -> Dict:
"""
제외 대상 분류
Args:
dat_file: DAT_FILE 필드
description: DESCRIPTION 필드
main_nom: MAIN_NOM 필드
Returns:
제외 분류 결과
"""
desc_upper = description.upper()
# 제외 대상 키워드 확인
for exclude_type, type_data in EXCLUDE_TYPES.items():
for keyword in type_data["description_keywords"]:
if keyword in desc_upper:
return {
"category": "EXCLUDE",
"exclude_type": exclude_type,
"characteristics": type_data["characteristics"],
"reason": type_data["reason"],
"overall_confidence": 0.95,
"evidence": [f"EXCLUDE_KEYWORD: {keyword}"],
"recommendation": "BOM에서 제외 권장"
}
# 제외 대상 아님
return {
"category": "UNKNOWN",
"overall_confidence": 0.0,
"reason": "제외 대상 키워드 없음"
}
def is_exclude_item(description: str) -> bool:
"""간단한 제외 대상 체크"""
desc_upper = description.upper()
exclude_keywords = [
"WELD GAP", "WELDING GAP", "GAP",
"CUTTING LOSS", "CUT LOSS",
"SPARE", "ALLOWANCE",
"THK", "THICK"
]
return any(keyword in desc_upper for keyword in exclude_keywords)