🔧 자재 분류기 개선 및 ELL 키워드 분류 문제 해결 (테스트 필요 - 안되는거 같음)
분류기 개선사항: 1. ELL-O-LET vs 일반 엘보 분류 개선 - OLET 우선순위 확인 로직 추가 - ELL 키워드 충돌 문제 해결 2. 엘보 서브타입 강화 - 90DEG_LONG_RADIUS, 90DEG_SHORT_RADIUS 등 조합형 추가 - 더 구체적인 키워드 패턴 지원 3. 레듀스 플랜지 분류 개선 - REDUCING FLANGE가 FITTING이 아닌 FLANGE로 분류되도록 수정 - 특별 우선순위 로직 추가 4. 90 ELL SW 분류 문제 해결 - fitting_keywords에 ELL 키워드 추가 - ELBOW description_keywords에 ELL, 90 ELL, 45 ELL 추가 기술적 개선: - 키워드 우선순위 체계 강화 - 구체적인 패턴 매칭 개선 - 분류 신뢰도 향상 플랜지 카테고리 개선: - 타입 풀네임 표시 (WN → WELD NECK FLANGE) - 끝단처리 별도 컬럼 추가 (RF → RAISED FACE) - 엑셀 내보내기 구조 개선 (P열 납기일, 관리항목 4개)
This commit is contained in:
@@ -9,8 +9,16 @@ DATABASE_URL = os.getenv(
|
||||
"postgresql://tkmp_user:tkmp_password_2025@postgres:5432/tk_mp_bom"
|
||||
)
|
||||
|
||||
# SQLAlchemy 엔진 생성
|
||||
engine = create_engine(DATABASE_URL)
|
||||
# SQLAlchemy 엔진 생성 (UTF-8 인코딩 설정)
|
||||
engine = create_engine(
|
||||
DATABASE_URL,
|
||||
connect_args={
|
||||
"client_encoding": "utf8",
|
||||
"options": "-c client_encoding=utf8 -c timezone=UTC"
|
||||
},
|
||||
pool_pre_ping=True,
|
||||
echo=False
|
||||
)
|
||||
|
||||
# 세션 팩토리 생성
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
|
||||
@@ -194,7 +194,7 @@ async def get_purchase_requests(
|
||||
u.name as requested_by,
|
||||
f.original_filename,
|
||||
j.job_name,
|
||||
COUNT(pri.id) as item_count
|
||||
COUNT(pri.item_id) as item_count
|
||||
FROM purchase_requests pr
|
||||
LEFT JOIN users u ON pr.requested_by = u.user_id
|
||||
LEFT JOIN files f ON pr.file_id = f.id
|
||||
@@ -271,9 +271,13 @@ async def get_request_materials(
|
||||
if info_result and info_result.excel_file_path:
|
||||
json_path = os.path.join(EXCEL_DIR, info_result.excel_file_path)
|
||||
if os.path.exists(json_path):
|
||||
with open(json_path, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
grouped_materials = data.get("grouped_materials", [])
|
||||
try:
|
||||
with open(json_path, 'r', encoding='utf-8', errors='ignore') as f:
|
||||
data = json.load(f)
|
||||
grouped_materials = data.get("grouped_materials", [])
|
||||
except Exception as e:
|
||||
print(f"⚠️ JSON 파일 읽기 오류 (무시): {e}")
|
||||
grouped_materials = []
|
||||
|
||||
# 개별 자재 정보 조회 (기존 코드)
|
||||
query = text("""
|
||||
@@ -316,76 +320,106 @@ async def get_request_materials(
|
||||
ORDER BY m.classified_category, m.original_description
|
||||
""")
|
||||
|
||||
# 🎯 데이터베이스 쿼리 실행
|
||||
results = db.execute(query, {"request_id": request_id}).fetchall()
|
||||
|
||||
materials = []
|
||||
for row in results:
|
||||
# quantity를 정수로 변환 (소수점 제거)
|
||||
qty = row.requested_quantity or row.original_quantity
|
||||
|
||||
# 🎯 안전한 문자열 변환 함수
|
||||
def safe_str(value):
|
||||
if value is None:
|
||||
return ''
|
||||
try:
|
||||
qty_int = int(float(qty)) if qty else 0
|
||||
except (ValueError, TypeError):
|
||||
if isinstance(value, bytes):
|
||||
return value.decode('utf-8', errors='ignore')
|
||||
return str(value)
|
||||
except Exception:
|
||||
return str(value) if value else ''
|
||||
|
||||
for row in results:
|
||||
try:
|
||||
# quantity를 정수로 변환 (소수점 제거)
|
||||
qty = row.requested_quantity or row.original_quantity
|
||||
try:
|
||||
qty_int = int(float(qty)) if qty else 0
|
||||
except (ValueError, TypeError):
|
||||
qty_int = 0
|
||||
|
||||
# 안전한 문자열 변환
|
||||
original_description = safe_str(row.original_description)
|
||||
size_spec = safe_str(row.size_spec)
|
||||
material_grade = safe_str(row.material_grade)
|
||||
full_material_grade = safe_str(row.full_material_grade)
|
||||
user_requirement = safe_str(row.user_requirement)
|
||||
|
||||
except Exception as e:
|
||||
# 오류 발생 시 기본값 사용
|
||||
qty_int = 0
|
||||
original_description = ''
|
||||
size_spec = ''
|
||||
material_grade = ''
|
||||
full_material_grade = ''
|
||||
user_requirement = ''
|
||||
|
||||
# BOM 페이지와 동일한 형식으로 데이터 구성
|
||||
material_dict = {
|
||||
"item_id": row.item_id,
|
||||
"material_id": row.material_id,
|
||||
"id": row.material_id,
|
||||
"original_description": row.original_description,
|
||||
"classified_category": row.classified_category,
|
||||
"size_spec": row.size_spec,
|
||||
"size_inch": row.main_nom,
|
||||
"main_nom": row.main_nom,
|
||||
"red_nom": row.red_nom,
|
||||
"schedule": row.schedule,
|
||||
"material_grade": row.material_grade,
|
||||
"full_material_grade": row.full_material_grade,
|
||||
"original_description": original_description,
|
||||
"classified_category": safe_str(row.classified_category),
|
||||
"size_spec": size_spec,
|
||||
"size_inch": safe_str(row.main_nom),
|
||||
"main_nom": safe_str(row.main_nom),
|
||||
"red_nom": safe_str(row.red_nom),
|
||||
"schedule": safe_str(row.schedule),
|
||||
"material_grade": material_grade,
|
||||
"full_material_grade": full_material_grade,
|
||||
"quantity": qty_int,
|
||||
"unit": row.requested_unit or row.original_unit,
|
||||
"user_requirement": row.user_requirement,
|
||||
"unit": safe_str(row.requested_unit or row.original_unit),
|
||||
"user_requirement": user_requirement,
|
||||
"is_ordered": row.is_ordered,
|
||||
"is_received": row.is_received,
|
||||
"classification_details": row.classification_details
|
||||
"classification_details": safe_str(row.classification_details)
|
||||
}
|
||||
|
||||
# 카테고리별 상세 정보 추가
|
||||
# 카테고리별 상세 정보 추가 (안전한 문자열 처리)
|
||||
if row.classified_category == 'PIPE' and row.manufacturing_method:
|
||||
material_dict["pipe_details"] = {
|
||||
"manufacturing_method": row.manufacturing_method,
|
||||
"schedule": row.pipe_schedule,
|
||||
"material_spec": row.material_spec,
|
||||
"end_preparation": row.end_preparation,
|
||||
"manufacturing_method": safe_str(row.manufacturing_method),
|
||||
"schedule": safe_str(row.pipe_schedule),
|
||||
"material_spec": safe_str(row.material_spec),
|
||||
"end_preparation": safe_str(row.end_preparation),
|
||||
"length_mm": row.length_mm
|
||||
}
|
||||
elif row.classified_category == 'FITTING' and row.fitting_type:
|
||||
material_dict["fitting_details"] = {
|
||||
"fitting_type": row.fitting_type,
|
||||
"fitting_subtype": row.fitting_subtype,
|
||||
"connection_method": row.fitting_connection,
|
||||
"pressure_rating": row.fitting_pressure,
|
||||
"schedule": row.fitting_schedule
|
||||
"fitting_type": safe_str(row.fitting_type),
|
||||
"fitting_subtype": safe_str(row.fitting_subtype),
|
||||
"connection_method": safe_str(row.fitting_connection),
|
||||
"pressure_rating": safe_str(row.fitting_pressure),
|
||||
"schedule": safe_str(row.fitting_schedule)
|
||||
}
|
||||
elif row.classified_category == 'FLANGE' and row.flange_type:
|
||||
material_dict["flange_details"] = {
|
||||
"flange_type": row.flange_type,
|
||||
"facing_type": row.facing_type,
|
||||
"pressure_rating": row.flange_pressure
|
||||
"flange_type": safe_str(row.flange_type),
|
||||
"facing_type": safe_str(row.facing_type),
|
||||
"pressure_rating": safe_str(row.flange_pressure)
|
||||
}
|
||||
elif row.classified_category == 'GASKET' and row.gasket_type:
|
||||
material_dict["gasket_details"] = {
|
||||
"gasket_type": row.gasket_type,
|
||||
"gasket_subtype": row.gasket_subtype,
|
||||
"material_type": row.gasket_material,
|
||||
"filler_material": row.filler_material,
|
||||
"pressure_rating": row.gasket_pressure,
|
||||
"thickness": row.gasket_thickness
|
||||
"gasket_type": safe_str(row.gasket_type),
|
||||
"gasket_subtype": safe_str(row.gasket_subtype),
|
||||
"material_type": safe_str(row.gasket_material),
|
||||
"filler_material": safe_str(row.filler_material),
|
||||
"pressure_rating": safe_str(row.gasket_pressure),
|
||||
"thickness": safe_str(row.gasket_thickness)
|
||||
}
|
||||
elif row.classified_category == 'BOLT' and row.bolt_type:
|
||||
material_dict["bolt_details"] = {
|
||||
"bolt_type": row.bolt_type,
|
||||
"material_standard": row.bolt_material,
|
||||
"length": row.bolt_length
|
||||
"bolt_type": safe_str(row.bolt_type),
|
||||
"material_standard": safe_str(row.bolt_material),
|
||||
"length": safe_str(row.bolt_length)
|
||||
}
|
||||
|
||||
materials.append(material_dict)
|
||||
@@ -521,10 +555,11 @@ def create_excel_file(materials_data: List[Dict], file_path: str, request_no: st
|
||||
|
||||
ws = wb.create_sheet(title=category)
|
||||
|
||||
# 헤더 정의
|
||||
# 헤더 정의 (P열에 납기일, 관리항목 통일)
|
||||
headers = ['TAGNO', '품목명', '수량', '통화구분', '단가', '크기', '압력등급', '스케줄',
|
||||
'재질', '상세내역', '사용자요구', '관리항목1', '관리항목7', '관리항목8',
|
||||
'관리항목9', '관리항목10', '납기일(YYYY-MM-DD)']
|
||||
'재질', '상세내역', '사용자요구', '관리항목1', '관리항목2', '관리항목3',
|
||||
'관리항목4', '납기일(YYYY-MM-DD)', '관리항목5', '관리항목6', '관리항목7',
|
||||
'관리항목8', '관리항목9', '관리항목10']
|
||||
|
||||
# 헤더 작성
|
||||
for col, header in enumerate(headers, 1):
|
||||
|
||||
@@ -11,8 +11,12 @@ from .material_classifier import classify_material, get_manufacturing_method_fro
|
||||
FITTING_TYPES = {
|
||||
"ELBOW": {
|
||||
"dat_file_patterns": ["90L_", "45L_", "ELL_", "ELBOW_"],
|
||||
"description_keywords": ["ELBOW", "ELL", "엘보"],
|
||||
"description_keywords": ["ELBOW", "ELL", "엘보", "90 ELBOW", "45 ELBOW", "LR ELBOW", "SR ELBOW", "90 ELL", "45 ELL"],
|
||||
"subtypes": {
|
||||
"90DEG_LONG_RADIUS": ["90 LR", "90° LR", "90DEG LR", "90도 장반경", "90 LONG RADIUS", "LR 90"],
|
||||
"90DEG_SHORT_RADIUS": ["90 SR", "90° SR", "90DEG SR", "90도 단반경", "90 SHORT RADIUS", "SR 90"],
|
||||
"45DEG_LONG_RADIUS": ["45 LR", "45° LR", "45DEG LR", "45도 장반경", "45 LONG RADIUS", "LR 45"],
|
||||
"45DEG_SHORT_RADIUS": ["45 SR", "45° SR", "45DEG SR", "45도 단반경", "45 SHORT RADIUS", "SR 45"],
|
||||
"90DEG": ["90", "90°", "90DEG", "90도"],
|
||||
"45DEG": ["45", "45°", "45DEG", "45도"],
|
||||
"LONG_RADIUS": ["LR", "LONG RADIUS", "장반경"],
|
||||
@@ -98,11 +102,12 @@ FITTING_TYPES = {
|
||||
},
|
||||
|
||||
"OLET": {
|
||||
"dat_file_patterns": ["SOL_", "WOL_", "TOL_", "OLET_", "SOCK-O-LET", "WELD-O-LET"],
|
||||
"description_keywords": ["OLET", "올렛", "O-LET", "SOCK-O-LET", "WELD-O-LET", "SOCKOLET", "WELDOLET", "THREAD-O-LET", "THREADOLET", "SOCKLET", "SOCKET"],
|
||||
"dat_file_patterns": ["SOL_", "WOL_", "TOL_", "EOL_", "NOL_", "COL_", "OLET_", "SOCK-O-LET", "WELD-O-LET", "ELL-O-LET", "THREAD-O-LET", "ELB-O-LET", "NIP-O-LET", "COUP-O-LET"],
|
||||
"description_keywords": ["SOCK-O-LET", "WELD-O-LET", "ELL-O-LET", "THREAD-O-LET", "ELB-O-LET", "NIP-O-LET", "COUP-O-LET", "SOCKOLET", "WELDOLET", "ELLOLET", "THREADOLET", "ELBOLET", "NIPOLET", "COUPOLET", "OLET", "올렛", "O-LET", "SOCKLET"],
|
||||
"subtypes": {
|
||||
"SOCKOLET": ["SOCK-O-LET", "SOCKOLET", "SOL", "SOCK O-LET", "SOCKET-O-LET", "SOCKLET"],
|
||||
"WELDOLET": ["WELD-O-LET", "WELDOLET", "WOL", "WELD O-LET", "WELDING-O-LET"],
|
||||
"ELLOLET": ["ELL-O-LET", "ELLOLET", "EOL", "ELL O-LET", "ELBOW-O-LET"],
|
||||
"THREADOLET": ["THREAD-O-LET", "THREADOLET", "TOL", "THREADED-O-LET"],
|
||||
"ELBOLET": ["ELB-O-LET", "ELBOLET", "EOL", "ELBOW-O-LET"],
|
||||
"NIPOLET": ["NIP-O-LET", "NIPOLET", "NOL", "NIPPLE-O-LET"],
|
||||
@@ -203,7 +208,11 @@ def classify_fitting(dat_file: str, description: str, main_nom: str,
|
||||
dat_upper = dat_file.upper()
|
||||
|
||||
# 1. 피팅 키워드 확인 (재질만 있어도 통합 분류기가 이미 피팅으로 분류했으므로 진행)
|
||||
fitting_keywords = ['ELBOW', 'ELL', 'TEE', 'REDUCER', 'RED', 'CAP', 'NIPPLE', 'SWAGE', 'OLET', 'COUPLING', 'PLUG', 'SOCKLET', 'SOCKET', '엘보', '티', '리듀서', '캡', '니플', '스웨지', '올렛', '커플링', '플러그', 'SOCK-O-LET', 'WELD-O-LET', 'SOCKOLET', 'WELDOLET']
|
||||
# OLET 키워드를 우선 확인하여 정확한 분류 수행
|
||||
olet_keywords = ['SOCK-O-LET', 'WELD-O-LET', 'ELL-O-LET', 'THREAD-O-LET', 'ELB-O-LET', 'NIP-O-LET', 'COUP-O-LET', 'SOCKOLET', 'WELDOLET', 'ELLOLET', 'THREADOLET', 'ELBOLET', 'NIPOLET', 'COUPOLET', 'OLET', 'O-LET', 'SOCKLET']
|
||||
has_olet_keyword = any(keyword in desc_upper or keyword in dat_upper for keyword in olet_keywords)
|
||||
|
||||
fitting_keywords = ['ELBOW', 'ELL', 'TEE', 'REDUCER', 'RED', 'CAP', 'NIPPLE', 'SWAGE', 'COUPLING', 'PLUG', '엘보', '티', '리듀서', '캡', '니플', '스웨지', '올렛', '커플링', '플러그'] + olet_keywords
|
||||
has_fitting_keyword = any(keyword in desc_upper or keyword in dat_upper for keyword in fitting_keywords)
|
||||
|
||||
# 피팅 재질 확인 (A234, A403, A420)
|
||||
@@ -301,6 +310,14 @@ def classify_fitting(dat_file: str, description: str, main_nom: str,
|
||||
"fitting_type": fitting_type_result.get('confidence', 0),
|
||||
"connection": connection_result.get('confidence', 0),
|
||||
"pressure": pressure_result.get('confidence', 0)
|
||||
}),
|
||||
|
||||
# 통합분류기 호환성을 위한 confidence 필드
|
||||
"confidence": calculate_fitting_confidence({
|
||||
"material": material_result.get('confidence', 0),
|
||||
"fitting_type": fitting_type_result.get('confidence', 0),
|
||||
"connection": connection_result.get('confidence', 0),
|
||||
"pressure": pressure_result.get('confidence', 0)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -428,12 +445,28 @@ def classify_fitting_type(dat_file: str, description: str,
|
||||
dat_upper = dat_file.upper()
|
||||
desc_upper = description.upper()
|
||||
|
||||
# 0. 사이즈 패턴 분석으로 TEE vs REDUCER 구분 (최우선)
|
||||
# 0. OLET 우선 확인 (ELL과의 혼동 방지)
|
||||
olet_specific_keywords = ['SOCK-O-LET', 'WELD-O-LET', 'ELL-O-LET', 'THREAD-O-LET', 'ELB-O-LET', 'NIP-O-LET', 'COUP-O-LET', 'SOCKOLET', 'WELDOLET', 'ELLOLET', 'THREADOLET', 'ELBOLET', 'NIPOLET', 'COUPOLET', 'O-LET', 'SOCKLET']
|
||||
for keyword in olet_specific_keywords:
|
||||
if keyword in desc_upper or keyword in dat_upper:
|
||||
subtype_result = classify_fitting_subtype(
|
||||
"OLET", desc_upper, main_nom, red_nom, FITTING_TYPES["OLET"]
|
||||
)
|
||||
return {
|
||||
"type": "OLET",
|
||||
"subtype": subtype_result["subtype"],
|
||||
"confidence": 0.95,
|
||||
"evidence": [f"OLET_PRIORITY_KEYWORD: {keyword}"],
|
||||
"subtype_confidence": subtype_result["confidence"],
|
||||
"requires_two_sizes": FITTING_TYPES["OLET"].get("requires_two_sizes", False)
|
||||
}
|
||||
|
||||
# 1. 사이즈 패턴 분석으로 TEE vs REDUCER 구분
|
||||
size_pattern_result = analyze_size_pattern_for_fitting_type(desc_upper, main_nom, red_nom)
|
||||
if size_pattern_result.get("confidence", 0) > 0.85:
|
||||
return size_pattern_result
|
||||
|
||||
# 1. DAT_FILE 패턴으로 1차 분류 (가장 신뢰도 높음)
|
||||
# 2. DAT_FILE 패턴으로 1차 분류 (가장 신뢰도 높음)
|
||||
for fitting_type, type_data in FITTING_TYPES.items():
|
||||
for pattern in type_data["dat_file_patterns"]:
|
||||
if pattern in dat_upper:
|
||||
@@ -450,7 +483,7 @@ def classify_fitting_type(dat_file: str, description: str,
|
||||
"requires_two_sizes": type_data.get("requires_two_sizes", False)
|
||||
}
|
||||
|
||||
# 2. DESCRIPTION 키워드로 2차 분류
|
||||
# 3. DESCRIPTION 키워드로 2차 분류
|
||||
for fitting_type, type_data in FITTING_TYPES.items():
|
||||
for keyword in type_data["description_keywords"]:
|
||||
if keyword in desc_upper:
|
||||
@@ -467,7 +500,7 @@ def classify_fitting_type(dat_file: str, description: str,
|
||||
"requires_two_sizes": type_data.get("requires_two_sizes", False)
|
||||
}
|
||||
|
||||
# 3. 분류 실패
|
||||
# 4. 분류 실패
|
||||
return {
|
||||
"type": "UNKNOWN",
|
||||
"subtype": "UNKNOWN",
|
||||
|
||||
@@ -11,9 +11,9 @@ from .fitting_classifier import classify_fitting
|
||||
LEVEL1_TYPE_KEYWORDS = {
|
||||
"BOLT": ["FLANGE BOLT", "U-BOLT", "U BOLT", "BOLT", "STUD", "NUT", "SCREW", "WASHER", "볼트", "너트", "스터드", "나사", "와셔", "유볼트"],
|
||||
"VALVE": ["VALVE", "GATE", "BALL", "GLOBE", "CHECK", "BUTTERFLY", "NEEDLE", "RELIEF", "밸브", "게이트", "볼", "글로브", "체크", "버터플라이", "니들", "릴리프"],
|
||||
"FLANGE": ["FLG", "FLANGE", "플랜지", "프랜지", "ORIFICE", "SPECTACLE", "PADDLE", "SPACER", "BLIND"],
|
||||
"FLANGE": ["FLG", "FLANGE", "플랜지", "프랜지", "ORIFICE", "SPECTACLE", "PADDLE", "SPACER", "BLIND", "REDUCING FLANGE", "RED FLANGE"],
|
||||
"PIPE": ["PIPE", "TUBE", "파이프", "배관", "SMLS", "SEAMLESS"],
|
||||
"FITTING": ["ELBOW", "ELL", "TEE", "REDUCER", "RED", "CAP", "COUPLING", "NIPPLE", "SWAGE", "OLET", "PLUG", "엘보", "티", "리듀서", "캡", "니플", "커플링", "플러그", "CONC", "ECC", "SOCK-O-LET", "WELD-O-LET", "SOCKOLET", "WELDOLET", "THREADOLET"],
|
||||
"FITTING": ["SOCK-O-LET", "WELD-O-LET", "ELL-O-LET", "THREAD-O-LET", "ELB-O-LET", "NIP-O-LET", "COUP-O-LET", "SOCKOLET", "WELDOLET", "ELLOLET", "THREADOLET", "ELBOLET", "NIPOLET", "COUPOLET", "OLET", "ELBOW", "ELL", "TEE", "REDUCER", "RED", "CAP", "COUPLING", "NIPPLE", "SWAGE", "PLUG", "엘보", "티", "리듀서", "캡", "니플", "커플링", "플러그", "CONC", "ECC"],
|
||||
"GASKET": ["GASKET", "GASK", "가스켓", "SWG", "SPIRAL"],
|
||||
"INSTRUMENT": ["GAUGE", "TRANSMITTER", "SENSOR", "THERMOMETER", "계기", "게이지", "트랜스미터", "센서"],
|
||||
"SUPPORT": ["URETHANE BLOCK", "URETHANE", "BLOCK SHOE", "CLAMP", "SUPPORT", "HANGER", "SPRING", "우레탄", "블록", "클램프", "서포트", "행거", "스프링"]
|
||||
@@ -128,24 +128,29 @@ def classify_material_integrated(description: str, main_nom: str = "",
|
||||
|
||||
# 1단계: Level 1 키워드로 타입 식별
|
||||
detected_types = []
|
||||
for material_type, keywords in LEVEL1_TYPE_KEYWORDS.items():
|
||||
type_found = False
|
||||
# 긴 키워드부터 확인 (FLANGE BOLT가 FLANGE보다 먼저 매칭되도록)
|
||||
sorted_keywords = sorted(keywords, key=len, reverse=True)
|
||||
for keyword in sorted_keywords:
|
||||
# 전체 문자열에서 찾기
|
||||
if keyword in desc_upper:
|
||||
detected_types.append((material_type, keyword))
|
||||
type_found = True
|
||||
break
|
||||
# 각 부분에서도 정확히 매칭되는지 확인
|
||||
for part in desc_parts:
|
||||
if keyword == part or keyword in part:
|
||||
|
||||
# 특별 우선순위: REDUCING FLANGE 먼저 확인
|
||||
if "REDUCING FLANGE" in desc_upper or "RED FLANGE" in desc_upper:
|
||||
detected_types.append(("FLANGE", "REDUCING FLANGE"))
|
||||
else:
|
||||
for material_type, keywords in LEVEL1_TYPE_KEYWORDS.items():
|
||||
type_found = False
|
||||
# 긴 키워드부터 확인 (FLANGE BOLT가 FLANGE보다 먼저 매칭되도록)
|
||||
sorted_keywords = sorted(keywords, key=len, reverse=True)
|
||||
for keyword in sorted_keywords:
|
||||
# 전체 문자열에서 찾기
|
||||
if keyword in desc_upper:
|
||||
detected_types.append((material_type, keyword))
|
||||
type_found = True
|
||||
break
|
||||
if type_found:
|
||||
break
|
||||
# 각 부분에서도 정확히 매칭되는지 확인
|
||||
for part in desc_parts:
|
||||
if keyword == part or keyword in part:
|
||||
detected_types.append((material_type, keyword))
|
||||
type_found = True
|
||||
break
|
||||
if type_found:
|
||||
break
|
||||
|
||||
# 2단계: 복수 타입 감지 시 Level 2로 구체화
|
||||
if len(detected_types) > 1:
|
||||
|
||||
1744
backend/exports/PR-20251015-001.json
Normal file
1744
backend/exports/PR-20251015-001.json
Normal file
File diff suppressed because it is too large
Load Diff
BIN
backend/exports/PR-20251015-001.xlsx
Normal file
BIN
backend/exports/PR-20251015-001.xlsx
Normal file
Binary file not shown.
745
backend/exports/PR-20251015-002.json
Normal file
745
backend/exports/PR-20251015-002.json
Normal file
@@ -0,0 +1,745 @@
|
||||
{
|
||||
"request_no": "PR-20251015-002",
|
||||
"job_no": "TKG-20000P",
|
||||
"created_at": "2025-10-15T05:53:13.449375",
|
||||
"materials": [
|
||||
{
|
||||
"material_id": 76366,
|
||||
"description": "FLG WELD NECK RF SCH 40S, 150LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "10\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 5,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76371,
|
||||
"description": "FLG WELD NECK RF SCH 40S, 150LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "12\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 1,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76372,
|
||||
"description": "FLG WELD NECK RF SCH 40, 150LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "2\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 36,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76408,
|
||||
"description": "FLG WELD NECK RF SCH 40, 300LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "2\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 6,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76414,
|
||||
"description": "FLG WELD NECK RF SCH 40S, 150LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "2\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 7,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76422,
|
||||
"description": "FLG WELD NECK RF SCH 40, 600LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "3\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 8,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76427,
|
||||
"description": "FLG WELD NECK RF SCH 40S, 600LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "3\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 2,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76429,
|
||||
"description": "FLG WELD NECK RF SCH 40, 150LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "3\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 12,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76441,
|
||||
"description": "FLG WELD NECK RF SCH 40, 300LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "3\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 2,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76446,
|
||||
"description": "FLG WELD NECK RF SCH 40S, 150LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "3\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 9,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76455,
|
||||
"description": "FLG WELD NECK RF SCH 40, 300LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "4\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 3,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76458,
|
||||
"description": "FLG WELD NECK RF SCH 40, 150LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "6\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 10,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76468,
|
||||
"description": "FLG SWRF SCH 40S, 150LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "1/2\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 14,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76480,
|
||||
"description": "FLG SWRF SCH 80, 150LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "3/4\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 15,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76484,
|
||||
"description": "FLG SWRF SCH 40S, 150LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "1\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 9,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76485,
|
||||
"description": "FLG SWRF SCH 80, 150LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "1\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 66,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76489,
|
||||
"description": "FLG SWRF SCH 80, 600LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "1\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 6,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76491,
|
||||
"description": "FLG SWRF SCH 40S, 150LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "1 1/2\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 8,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76499,
|
||||
"description": "FLG SWRF SCH 80, 150LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "1 1/2\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 40,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76535,
|
||||
"description": "FLG SWRF SCH 80, 600LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "1 1/2\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 5,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76540,
|
||||
"description": "RED. FLG SWRF SCH 40S, 150LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "1 1/2\" x 3/4\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 2,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76542,
|
||||
"description": "RED. FLG SWRF SCH 80, 150LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "1 1/2\" x 3/4\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 4,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76546,
|
||||
"description": "RED. FLG SWRF SCH 80, 600LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "1 1/2\" x 3/4\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 2,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76556,
|
||||
"description": "FLG SWRF SCH 40S, 600LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "1\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 1,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76624,
|
||||
"description": "RED. FLG SWRF SCH 80, 150LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "1\" x 3/4\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 1,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76629,
|
||||
"description": "FLG SWRF SCH 80, 300LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "1 1/2\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 3,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76634,
|
||||
"description": "FLG SWRF SCH 80, 150LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "1/2\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 57,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76691,
|
||||
"description": "FLG SWRF SCH 40S, 150LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "3/4\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 7,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76698,
|
||||
"description": "FLG SWRF SCH 40S, 300LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "3/4\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 1,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76699,
|
||||
"description": "FLG SWRF SCH 40S, 600LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "3/4\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 1,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76711,
|
||||
"description": "FLG SWRF SCH 80, 300LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "3/4\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 2,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"material_id": 76713,
|
||||
"description": "FLG SWRF SCH 80, 600LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "3/4\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 5,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
}
|
||||
],
|
||||
"grouped_materials": [
|
||||
{
|
||||
"group_key": "FLG WELD NECK RF SCH 40S, 150LB, ASTM A182 F304|10\"|undefined|ASTM A182 F304",
|
||||
"material_ids": [
|
||||
76366
|
||||
],
|
||||
"description": "FLG WELD NECK RF SCH 40S, 150LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "10\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 5,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG WELD NECK RF SCH 40S, 150LB, ASTM A182 F304|12\"|undefined|ASTM A182 F304",
|
||||
"material_ids": [
|
||||
76371
|
||||
],
|
||||
"description": "FLG WELD NECK RF SCH 40S, 150LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "12\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 1,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG WELD NECK RF SCH 40, 150LB, ASTM A105|2\"|undefined|ASTM A105",
|
||||
"material_ids": [
|
||||
76372
|
||||
],
|
||||
"description": "FLG WELD NECK RF SCH 40, 150LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "2\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 36,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG WELD NECK RF SCH 40, 300LB, ASTM A105|2\"|undefined|ASTM A105",
|
||||
"material_ids": [
|
||||
76408
|
||||
],
|
||||
"description": "FLG WELD NECK RF SCH 40, 300LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "2\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 6,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG WELD NECK RF SCH 40S, 150LB, ASTM A182 F304|2\"|undefined|ASTM A182 F304",
|
||||
"material_ids": [
|
||||
76414
|
||||
],
|
||||
"description": "FLG WELD NECK RF SCH 40S, 150LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "2\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 7,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG WELD NECK RF SCH 40, 600LB, ASTM A105|3\"|undefined|ASTM A105",
|
||||
"material_ids": [
|
||||
76422
|
||||
],
|
||||
"description": "FLG WELD NECK RF SCH 40, 600LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "3\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 8,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG WELD NECK RF SCH 40S, 600LB, ASTM A182 F304|3\"|undefined|ASTM A182 F304",
|
||||
"material_ids": [
|
||||
76427
|
||||
],
|
||||
"description": "FLG WELD NECK RF SCH 40S, 600LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "3\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 2,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG WELD NECK RF SCH 40, 150LB, ASTM A105|3\"|undefined|ASTM A105",
|
||||
"material_ids": [
|
||||
76429
|
||||
],
|
||||
"description": "FLG WELD NECK RF SCH 40, 150LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "3\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 12,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG WELD NECK RF SCH 40, 300LB, ASTM A105|3\"|undefined|ASTM A105",
|
||||
"material_ids": [
|
||||
76441
|
||||
],
|
||||
"description": "FLG WELD NECK RF SCH 40, 300LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "3\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 2,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG WELD NECK RF SCH 40S, 150LB, ASTM A182 F304|3\"|undefined|ASTM A182 F304",
|
||||
"material_ids": [
|
||||
76446
|
||||
],
|
||||
"description": "FLG WELD NECK RF SCH 40S, 150LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "3\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 9,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG WELD NECK RF SCH 40, 300LB, ASTM A105|4\"|undefined|ASTM A105",
|
||||
"material_ids": [
|
||||
76455
|
||||
],
|
||||
"description": "FLG WELD NECK RF SCH 40, 300LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "4\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 3,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG WELD NECK RF SCH 40, 150LB, ASTM A105|6\"|undefined|ASTM A105",
|
||||
"material_ids": [
|
||||
76458
|
||||
],
|
||||
"description": "FLG WELD NECK RF SCH 40, 150LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "6\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 10,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG SWRF SCH 40S, 150LB, ASTM A182 F304|1/2\"|undefined|ASTM A182 F304",
|
||||
"material_ids": [
|
||||
76468
|
||||
],
|
||||
"description": "FLG SWRF SCH 40S, 150LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "1/2\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 14,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG SWRF SCH 80, 150LB, ASTM A105|3/4\"|undefined|ASTM A105",
|
||||
"material_ids": [
|
||||
76480
|
||||
],
|
||||
"description": "FLG SWRF SCH 80, 150LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "3/4\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 15,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG SWRF SCH 40S, 150LB, ASTM A182 F304|1\"|undefined|ASTM A182 F304",
|
||||
"material_ids": [
|
||||
76484
|
||||
],
|
||||
"description": "FLG SWRF SCH 40S, 150LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "1\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 9,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG SWRF SCH 80, 150LB, ASTM A105|1\"|undefined|ASTM A105",
|
||||
"material_ids": [
|
||||
76485
|
||||
],
|
||||
"description": "FLG SWRF SCH 80, 150LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "1\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 66,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG SWRF SCH 80, 600LB, ASTM A105|1\"|undefined|ASTM A105",
|
||||
"material_ids": [
|
||||
76489
|
||||
],
|
||||
"description": "FLG SWRF SCH 80, 600LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "1\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 6,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG SWRF SCH 40S, 150LB, ASTM A182 F304|1 1/2\"|undefined|ASTM A182 F304",
|
||||
"material_ids": [
|
||||
76491
|
||||
],
|
||||
"description": "FLG SWRF SCH 40S, 150LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "1 1/2\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 8,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG SWRF SCH 80, 150LB, ASTM A105|1 1/2\"|undefined|ASTM A105",
|
||||
"material_ids": [
|
||||
76499
|
||||
],
|
||||
"description": "FLG SWRF SCH 80, 150LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "1 1/2\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 40,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG SWRF SCH 80, 600LB, ASTM A105|1 1/2\"|undefined|ASTM A105",
|
||||
"material_ids": [
|
||||
76535
|
||||
],
|
||||
"description": "FLG SWRF SCH 80, 600LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "1 1/2\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 5,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "RED. FLG SWRF SCH 40S, 150LB, ASTM A182 F304|1 1/2\" x 3/4\"|undefined|ASTM A182 F304",
|
||||
"material_ids": [
|
||||
76540
|
||||
],
|
||||
"description": "RED. FLG SWRF SCH 40S, 150LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "1 1/2\" x 3/4\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 2,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "RED. FLG SWRF SCH 80, 150LB, ASTM A105|1 1/2\" x 3/4\"|undefined|ASTM A105",
|
||||
"material_ids": [
|
||||
76542
|
||||
],
|
||||
"description": "RED. FLG SWRF SCH 80, 150LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "1 1/2\" x 3/4\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 4,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "RED. FLG SWRF SCH 80, 600LB, ASTM A105|1 1/2\" x 3/4\"|undefined|ASTM A105",
|
||||
"material_ids": [
|
||||
76546
|
||||
],
|
||||
"description": "RED. FLG SWRF SCH 80, 600LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "1 1/2\" x 3/4\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 2,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG SWRF SCH 40S, 600LB, ASTM A182 F304|1\"|undefined|ASTM A182 F304",
|
||||
"material_ids": [
|
||||
76556
|
||||
],
|
||||
"description": "FLG SWRF SCH 40S, 600LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "1\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 1,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "RED. FLG SWRF SCH 80, 150LB, ASTM A105|1\" x 3/4\"|undefined|ASTM A105",
|
||||
"material_ids": [
|
||||
76624
|
||||
],
|
||||
"description": "RED. FLG SWRF SCH 80, 150LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "1\" x 3/4\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 1,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG SWRF SCH 80, 300LB, ASTM A105|1 1/2\"|undefined|ASTM A105",
|
||||
"material_ids": [
|
||||
76629
|
||||
],
|
||||
"description": "FLG SWRF SCH 80, 300LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "1 1/2\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 3,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG SWRF SCH 80, 150LB, ASTM A105|1/2\"|undefined|ASTM A105",
|
||||
"material_ids": [
|
||||
76634
|
||||
],
|
||||
"description": "FLG SWRF SCH 80, 150LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "1/2\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 57,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG SWRF SCH 40S, 150LB, ASTM A182 F304|3/4\"|undefined|ASTM A182 F304",
|
||||
"material_ids": [
|
||||
76691
|
||||
],
|
||||
"description": "FLG SWRF SCH 40S, 150LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "3/4\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 7,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG SWRF SCH 40S, 300LB, ASTM A182 F304|3/4\"|undefined|ASTM A182 F304",
|
||||
"material_ids": [
|
||||
76698
|
||||
],
|
||||
"description": "FLG SWRF SCH 40S, 300LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "3/4\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 1,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG SWRF SCH 40S, 600LB, ASTM A182 F304|3/4\"|undefined|ASTM A182 F304",
|
||||
"material_ids": [
|
||||
76699
|
||||
],
|
||||
"description": "FLG SWRF SCH 40S, 600LB, ASTM A182 F304",
|
||||
"category": "FLANGE",
|
||||
"size": "3/4\"",
|
||||
"material_grade": "ASTM A182 F304",
|
||||
"quantity": 1,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG SWRF SCH 80, 300LB, ASTM A105|3/4\"|undefined|ASTM A105",
|
||||
"material_ids": [
|
||||
76711
|
||||
],
|
||||
"description": "FLG SWRF SCH 80, 300LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "3/4\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 2,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
},
|
||||
{
|
||||
"group_key": "FLG SWRF SCH 80, 600LB, ASTM A105|3/4\"|undefined|ASTM A105",
|
||||
"material_ids": [
|
||||
76713
|
||||
],
|
||||
"description": "FLG SWRF SCH 80, 600LB, ASTM A105",
|
||||
"category": "FLANGE",
|
||||
"size": "3/4\"",
|
||||
"material_grade": "ASTM A105",
|
||||
"quantity": 5,
|
||||
"unit": "EA",
|
||||
"user_requirement": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
backend/exports/PR-20251015-002.xlsx
Normal file
BIN
backend/exports/PR-20251015-002.xlsx
Normal file
Binary file not shown.
Reference in New Issue
Block a user