diff --git a/backend/app/database.py b/backend/app/database.py index 0435325..91cbad7 100644 --- a/backend/app/database.py +++ b/backend/app/database.py @@ -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) diff --git a/backend/app/routers/purchase_request.py b/backend/app/routers/purchase_request.py index 39d0d92..a94962f 100644 --- a/backend/app/routers/purchase_request.py +++ b/backend/app/routers/purchase_request.py @@ -34,7 +34,7 @@ class PurchaseRequestCreate(BaseModel): @router.post("/create") async def create_purchase_request( request_data: PurchaseRequestCreate, - # current_user: dict = Depends(get_current_user), + current_user: dict = Depends(get_current_user), db: Session = Depends(get_db) ): """ @@ -81,7 +81,7 @@ async def create_purchase_request( material_count, excel_file_path, requested_by ) VALUES ( :request_no, :file_id, :job_no, :category, - :material_count, :excel_path, :requested_by + :material_count, :excel_file_path, :requested_by ) RETURNING request_id """) @@ -91,8 +91,8 @@ async def create_purchase_request( "job_no": request_data.job_no, "category": request_data.category, "material_count": len(request_data.material_ids), - "excel_path": excel_filename, # 엑셀 파일명 저장 (JSON 대신) - "requested_by": 1 # current_user.get("user_id") + "excel_file_path": excel_filename, # 엑셀 파일명 저장 (JSON 대신) + "requested_by": current_user.get("user_id") }) request_id = result.fetchone().request_id @@ -163,7 +163,7 @@ async def create_purchase_request( db.rollback() logger.error(f"Failed to create purchase request: {str(e)}") raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=500, detail=f"구매신청 생성 실패: {str(e)}" ) @@ -244,7 +244,7 @@ async def get_purchase_requests( except Exception as e: logger.error(f"Failed to get purchase requests: {str(e)}") raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=500, detail=f"구매신청 목록 조회 실패: {str(e)}" ) @@ -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) @@ -400,7 +434,7 @@ async def get_request_materials( except Exception as e: logger.error(f"Failed to get request materials: {str(e)}") raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=500, detail=f"구매신청 자재 조회 실패: {str(e)}" ) @@ -451,7 +485,7 @@ async def download_request_excel( except Exception as e: logger.error(f"Failed to download request excel: {str(e)}") raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=500, detail=f"엑셀 다운로드 실패: {str(e)}" ) @@ -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): diff --git a/backend/app/services/fitting_classifier.py b/backend/app/services/fitting_classifier.py index 7c192df..6e75112 100644 --- a/backend/app/services/fitting_classifier.py +++ b/backend/app/services/fitting_classifier.py @@ -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", diff --git a/backend/app/services/integrated_classifier.py b/backend/app/services/integrated_classifier.py index fafd339..6c9ce44 100644 --- a/backend/app/services/integrated_classifier.py +++ b/backend/app/services/integrated_classifier.py @@ -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: diff --git a/backend/exports/PR-20251014-001.json b/backend/exports/PR-20251014-001.json index 7889920..3b7cb69 100644 --- a/backend/exports/PR-20251014-001.json +++ b/backend/exports/PR-20251014-001.json @@ -1,100 +1,575 @@ { "request_no": "PR-20251014-001", "job_no": "테스트용", - "created_at": "2025-10-14T06:47:25.065166", + "created_at": "2025-10-14T22:16:10.998006", "materials": [ { - "material_id": 2013, - "description": "SIGHT GLASS, FLG, 150LB", - "category": "FLANGE", - "size": "1\"", - "material_grade": "SS", - "quantity": 6, - "unit": "EA", - "user_requirement": "" - }, - { - "material_id": 2019, - "description": "SIGHT GLASS, FLG, 150LB", - "category": "FLANGE", + "material_id": 60768, + "description": "PIPE, SMLS, SCH 40S, ASTM A312 TP304", + "category": "PIPE", "size": "1/2\"", - "material_grade": "SS", - "quantity": 5, + "material_grade": "ASTM A312 TP304", + "quantity": 11, "unit": "EA", "user_requirement": "" }, { - "material_id": 2024, - "description": "SIGHT GLASS, FLG, 150LB", - "category": "FLANGE", - "size": "2\"", - "material_grade": "SS", - "quantity": 2, - "unit": "EA", - "user_requirement": "" - }, - { - "material_id": 2027, - "description": "STRAINER, FLG, 150LB", - "category": "FLANGE", - "size": "2\"", - "material_grade": "-", - "quantity": 1, + "material_id": 60776, + "description": "PIPE, SMLS, SCH 80, ASTM A106 B", + "category": "PIPE", + "size": "3/4\"", + "material_grade": "ASTM A106 B", + "quantity": 92, "unit": "EA", "user_requirement": "" } ], "grouped_materials": [ { - "group_key": "SIGHT GLASS, FLG, 150LB|1\"|undefined|SS", + "group_key": "PIPE, SMLS, SCH 40S, ASTM A312 TP304|1/2\"|undefined|ASTM A312 TP304", "material_ids": [ - 2013 + 60768 ], - "description": "SIGHT GLASS, FLG, 150LB", - "category": "FLANGE", - "size": "1\"", - "material_grade": "SS", - "quantity": 6, - "unit": "EA", - "user_requirement": "" - }, - { - "group_key": "SIGHT GLASS, FLG, 150LB|1/2\"|undefined|SS", - "material_ids": [ - 2019 - ], - "description": "SIGHT GLASS, FLG, 150LB", - "category": "FLANGE", + "description": "PIPE, SMLS, SCH 40S, ASTM A312 TP304", + "category": "PIPE", "size": "1/2\"", - "material_grade": "SS", - "quantity": 5, - "unit": "EA", + "material_grade": "ASTM A312 TP304", + "quantity": 11, + "unit": "m", + "total_length": 1395.1, + "pipe_lengths": [ + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 155, + "quantity": 1, + "totalLength": 155 + }, + { + "length": 155, + "quantity": 1, + "totalLength": 155 + }, + { + "length": 200, + "quantity": 1, + "totalLength": 200 + }, + { + "length": 245.1, + "quantity": 1, + "totalLength": 245.1 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + } + ], "user_requirement": "" }, { - "group_key": "SIGHT GLASS, FLG, 150LB|2\"|undefined|SS", + "group_key": "PIPE, SMLS, SCH 80, ASTM A106 B|3/4\"|undefined|ASTM A106 B", "material_ids": [ - 2024 + 60776 ], - "description": "SIGHT GLASS, FLG, 150LB", - "category": "FLANGE", - "size": "2\"", - "material_grade": "SS", - "quantity": 2, - "unit": "EA", - "user_requirement": "" - }, - { - "group_key": "STRAINER, FLG, 150LB|2\"|undefined|-", - "material_ids": [ - 2027 + "description": "PIPE, SMLS, SCH 80, ASTM A106 B", + "category": "PIPE", + "size": "3/4\"", + "material_grade": "ASTM A106 B", + "quantity": 92, + "unit": "m", + "total_length": 7920.2, + "pipe_lengths": [ + { + "length": 60, + "quantity": 1, + "totalLength": 60 + }, + { + "length": 60, + "quantity": 1, + "totalLength": 60 + }, + { + "length": 60, + "quantity": 1, + "totalLength": 60 + }, + { + "length": 60, + "quantity": 1, + "totalLength": 60 + }, + { + "length": 43.3, + "quantity": 1, + "totalLength": 43.3 + }, + { + "length": 43.3, + "quantity": 1, + "totalLength": 43.3 + }, + { + "length": 43.3, + "quantity": 1, + "totalLength": 43.3 + }, + { + "length": 43.3, + "quantity": 1, + "totalLength": 43.3 + }, + { + "length": 43.3, + "quantity": 1, + "totalLength": 43.3 + }, + { + "length": 43.3, + "quantity": 1, + "totalLength": 43.3 + }, + { + "length": 50, + "quantity": 1, + "totalLength": 50 + }, + { + "length": 50, + "quantity": 1, + "totalLength": 50 + }, + { + "length": 50, + "quantity": 1, + "totalLength": 50 + }, + { + "length": 50, + "quantity": 1, + "totalLength": 50 + }, + { + "length": 50, + "quantity": 1, + "totalLength": 50 + }, + { + "length": 50, + "quantity": 1, + "totalLength": 50 + }, + { + "length": 50, + "quantity": 1, + "totalLength": 50 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 76.2, + "quantity": 1, + "totalLength": 76.2 + }, + { + "length": 76.2, + "quantity": 1, + "totalLength": 76.2 + }, + { + "length": 76.2, + "quantity": 1, + "totalLength": 76.2 + }, + { + "length": 76.2, + "quantity": 1, + "totalLength": 76.2 + }, + { + "length": 76.2, + "quantity": 1, + "totalLength": 76.2 + }, + { + "length": 76.2, + "quantity": 1, + "totalLength": 76.2 + }, + { + "length": 77.6, + "quantity": 1, + "totalLength": 77.6 + }, + { + "length": 77.6, + "quantity": 1, + "totalLength": 77.6 + }, + { + "length": 77.6, + "quantity": 1, + "totalLength": 77.6 + }, + { + "length": 77.6, + "quantity": 1, + "totalLength": 77.6 + }, + { + "length": 77.6, + "quantity": 1, + "totalLength": 77.6 + }, + { + "length": 77.6, + "quantity": 1, + "totalLength": 77.6 + }, + { + "length": 80, + "quantity": 1, + "totalLength": 80 + }, + { + "length": 80, + "quantity": 1, + "totalLength": 80 + }, + { + "length": 80, + "quantity": 1, + "totalLength": 80 + }, + { + "length": 80, + "quantity": 1, + "totalLength": 80 + }, + { + "length": 80, + "quantity": 1, + "totalLength": 80 + }, + { + "length": 80, + "quantity": 1, + "totalLength": 80 + }, + { + "length": 80, + "quantity": 1, + "totalLength": 80 + }, + { + "length": 80, + "quantity": 1, + "totalLength": 80 + }, + { + "length": 80, + "quantity": 1, + "totalLength": 80 + }, + { + "length": 88.6, + "quantity": 1, + "totalLength": 88.6 + }, + { + "length": 88.6, + "quantity": 1, + "totalLength": 88.6 + }, + { + "length": 98.4, + "quantity": 1, + "totalLength": 98.4 + }, + { + "length": 98.4, + "quantity": 1, + "totalLength": 98.4 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 120, + "quantity": 1, + "totalLength": 120 + }, + { + "length": 120, + "quantity": 1, + "totalLength": 120 + }, + { + "length": 150, + "quantity": 1, + "totalLength": 150 + }, + { + "length": 150, + "quantity": 1, + "totalLength": 150 + }, + { + "length": 150, + "quantity": 1, + "totalLength": 150 + }, + { + "length": 150, + "quantity": 1, + "totalLength": 150 + }, + { + "length": 150, + "quantity": 1, + "totalLength": 150 + }, + { + "length": 223.6, + "quantity": 1, + "totalLength": 223.6 + } ], - "description": "STRAINER, FLG, 150LB", - "category": "FLANGE", - "size": "2\"", - "material_grade": "-", - "quantity": 1, - "unit": "EA", "user_requirement": "" } ] diff --git a/backend/exports/PR-20251015-001.json b/backend/exports/PR-20251015-001.json new file mode 100644 index 0000000..a1dcfa5 --- /dev/null +++ b/backend/exports/PR-20251015-001.json @@ -0,0 +1,1744 @@ +{ + "request_no": "PR-20251015-001", + "job_no": "TKG-20000P", + "created_at": "2025-10-15T04:57:30.133259", + "materials": [ + { + "material_id": 75644, + "description": "HALF NIPPLE, SMLS, SCH 80S, ASTM A312 TP304 SW X NPT", + "category": "FITTING", + "size": "1/2\"", + "material_grade": "ASTM A312 TP304", + "quantity": 3, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 75646, + "description": "HALF NIPPLE, SMLS, SCH 80S, ASTM A312 TP304 SW X NPT", + "category": "FITTING", + "size": "1/2\"", + "material_grade": "ASTM A312 TP304", + "quantity": 3, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 75786, + "description": "HALF NIPPLE, SMLS, SCH 160, ASTM A106 B SW * NPT", + "category": "FITTING", + "size": "1\"", + "material_grade": "ASTM A106 B", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 75935, + "description": "HALF NIPPLE, SMLS, SCH 160, ASTM A106 B SW X NPT", + "category": "FITTING", + "size": "1/2\"", + "material_grade": "ASTM A106 B", + "quantity": 9, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 75939, + "description": "HALF NIPPLE, SMLS, SCH 160, ASTM A106 B SW X NPT", + "category": "FITTING", + "size": "1/2\"", + "material_grade": "ASTM A106 B", + "quantity": 9, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 75942, + "description": "HALF NIPPLE, SMLS, SCH 160, ASTM A106 B SW X NPT", + "category": "FITTING", + "size": "1/2\"", + "material_grade": "ASTM A106 B", + "quantity": 9, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 75944, + "description": "NIPPLE, SMLS, SCH 160, ASTM A106 B", + "category": "FITTING", + "size": "1/2\"", + "material_grade": "ASTM A106 B", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76255, + "description": "90 LR ELL, SMLS, SCH 40S, ASTM A403 WP304", + "category": "FITTING", + "size": "10\"", + "material_grade": "ASTM A403 WP304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76256, + "description": "90 LR ELL, SMLS, SCH 40, ASTM A234 WPB", + "category": "FITTING", + "size": "2\"", + "material_grade": "ASTM A234 WPB", + "quantity": 25, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76281, + "description": "90 LR ELL, SMLS, SCH 40S, ASTM A403 WP304", + "category": "FITTING", + "size": "2\"", + "material_grade": "ASTM A403 WP304", + "quantity": 6, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76287, + "description": "90 LR ELL, SMLS, SCH 40, ASTM A234 WPB", + "category": "FITTING", + "size": "3\"", + "material_grade": "ASTM A234 WPB", + "quantity": 12, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76299, + "description": "90 LR ELL, SMLS, SCH 40S, ASTM A403 WP304", + "category": "FITTING", + "size": "3\"", + "material_grade": "ASTM A403 WP304", + "quantity": 4, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76303, + "description": "90 LR ELL, SMLS, SCH 40, ASTM A234 WPB", + "category": "FITTING", + "size": "4\"", + "material_grade": "ASTM A234 WPB", + "quantity": 7, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76310, + "description": "90 SR ELL, SMLS, SCH 40, ASTM A234 WPB", + "category": "FITTING", + "size": "4\"", + "material_grade": "ASTM A234 WPB", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76311, + "description": "90 LR ELL, SMLS, SCH 40, ASTM A234 WPB", + "category": "FITTING", + "size": "6\"", + "material_grade": "ASTM A234 WPB", + "quantity": 7, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76318, + "description": "45 ELL, SMLS, SCH 40, ASTM A234 WPB", + "category": "FITTING", + "size": "6\"", + "material_grade": "ASTM A234 WPB", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76320, + "description": "TEE, SMLS, SCH 40, ASTM A234 WPB", + "category": "FITTING", + "size": "2\"", + "material_grade": "ASTM A234 WPB", + "quantity": 4, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76324, + "description": "TEE, SMLS, SCH 40S, ASTM A403 WP304", + "category": "FITTING", + "size": "2\"", + "material_grade": "ASTM A403 WP304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76325, + "description": "TEE, SMLS, SCH 40, ASTM A234 WPB", + "category": "FITTING", + "size": "3\"", + "material_grade": "ASTM A234 WPB", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76326, + "description": "TEE, SMLS, SCH 40S, ASTM A403 WP304", + "category": "FITTING", + "size": "3\"", + "material_grade": "ASTM A403 WP304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76327, + "description": "TEE RED, SMLS, SCH 40 X SCH 80, ASTM A234 WPB", + "category": "FITTING", + "size": "2\" x 1 1/2\"", + "material_grade": "ASTM A234 WPB", + "quantity": 3, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76330, + "description": "TEE RED, SMLS, SCH 40S X SCH 40S, ASTM A403 WP304", + "category": "FITTING", + "size": "2\" x 1 1/2\"", + "material_grade": "ASTM A403 WP304", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76332, + "description": "TEE RED, SMLS, SCH 40 X SCH 80, ASTM A234 WPB", + "category": "FITTING", + "size": "3\" x 1 1/2\"", + "material_grade": "ASTM A234 WPB", + "quantity": 3, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76335, + "description": "TEE RED, SMLS, SCH 40 X SCH 80, ASTM A234 WPB", + "category": "FITTING", + "size": "4\" x 1 1/2\"", + "material_grade": "ASTM A234 WPB", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76337, + "description": "RED CONC, SMLS, SCH 80 X SCH 80, ASTM A234 WPB", + "category": "FITTING", + "size": "1 1/2\" x 1\"", + "material_grade": "ASTM A234 WPB", + "quantity": 5, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76342, + "description": "RED CONC, SMLS, SCH 80 X SCH 80, ASTM A234 WPB", + "category": "FITTING", + "size": "1 1/2\" x 3/4\"", + "material_grade": "ASTM A234 WPB", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76344, + "description": "RED CONC, SMLS, SCH 80 X SCH 80, ASTM A234 WPB", + "category": "FITTING", + "size": "1\" x 3/4\"", + "material_grade": "ASTM A234 WPB", + "quantity": 5, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76349, + "description": "RED CONC, SMLS, SCH 40S X SCH 40S, ASTM A403 WP304", + "category": "FITTING", + "size": "12\" x 10\"", + "material_grade": "ASTM A403 WP304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76350, + "description": "RED CONC, SMLS, SCH 40 X SCH 80, ASTM A234 WPB", + "category": "FITTING", + "size": "2\" x 1 1/2\"", + "material_grade": "ASTM A234 WPB", + "quantity": 6, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76356, + "description": "RED CONC, SMLS, SCH 40S X SCH 40S, ASTM A403 WP304", + "category": "FITTING", + "size": "2\" x 1 1/2\"", + "material_grade": "ASTM A403 WP304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76357, + "description": "RED CONC, SMLS, SCH 40 X SCH 80, ASTM A234 WPB", + "category": "FITTING", + "size": "2\" x 1\"", + "material_grade": "ASTM A234 WPB", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76358, + "description": "RED CONC, SMLS, SCH 40 X SCH 80, ASTM A234 WPB", + "category": "FITTING", + "size": "3\" x 1 1/2\"", + "material_grade": "ASTM A234 WPB", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76360, + "description": "RED CONC, SMLS, SCH 40S X SCH 40S, ASTM A403 WP304", + "category": "FITTING", + "size": "3\" x 1\"", + "material_grade": "ASTM A403 WP304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76361, + "description": "RED CONC, SMLS, SCH 40 X SCH 40, ASTM A234 WPB", + "category": "FITTING", + "size": "3\" x 2\"", + "material_grade": "ASTM A234 WPB", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76362, + "description": "RED CONC, SMLS, SCH 40S X SCH 40S, ASTM A403 WP304", + "category": "FITTING", + "size": "3\" x 2\"", + "material_grade": "ASTM A403 WP304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 76363, + "description": "RED CONC, SMLS, SCH 80 X SCH 80, ASTM A234 WPB", + "category": "FITTING", + "size": "3/4\" x 1/2\"", + "material_grade": "ASTM A234 WPB", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77240, + "description": "90 ELL, SW, 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "1/2\"", + "material_grade": "ASTM A182 F304", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77242, + "description": "90 ELL, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1\"", + "material_grade": "ASTM A105", + "quantity": 57, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77246, + "description": "90 ELL, SW, 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "1\"", + "material_grade": "ASTM A182 F304", + "quantity": 9, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77250, + "description": "90 ELL, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1 1/2\"", + "material_grade": "ASTM A105", + "quantity": 32, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77282, + "description": "90 ELL, SW, 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "1 1/2\"", + "material_grade": "ASTM A182 F304", + "quantity": 9, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77349, + "description": "90 ELL, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1/2\"", + "material_grade": "ASTM A105", + "quantity": 32, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77381, + "description": "90 ELL, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "3/4\"", + "material_grade": "ASTM A105", + "quantity": 24, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77405, + "description": "TEE, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1 1/2\"", + "material_grade": "ASTM A105", + "quantity": 7, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77412, + "description": "TEE, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1\"", + "material_grade": "ASTM A105", + "quantity": 15, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77427, + "description": "TEE, SW, 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "1\"", + "material_grade": "ASTM A182 F304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77428, + "description": "TEE, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1/2\"", + "material_grade": "ASTM A105", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77430, + "description": "TEE RED, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1 1/2\" x 1\"", + "material_grade": "ASTM A105", + "quantity": 5, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77435, + "description": "TEE RED, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1 1/2\" x 1/2\"", + "material_grade": "ASTM A105", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77437, + "description": "TEE RED, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1 1/2\" x 3/4\"", + "material_grade": "ASTM A105", + "quantity": 6, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77443, + "description": "TEE RED, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1\" x 1/2\"", + "material_grade": "ASTM A105", + "quantity": 7, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77450, + "description": "TEE RED, SW, 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "1\" x 1/2\"", + "material_grade": "ASTM A182 F304", + "quantity": 6, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77453, + "description": "TEE RED, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1\" x 3/4\"", + "material_grade": "ASTM A105", + "quantity": 3, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77459, + "description": "TEE RED, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "2\" x 1\"", + "material_grade": "ASTM A105", + "quantity": 4, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77463, + "description": "TEE RED, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "3/4\" x 1/2\"", + "material_grade": "ASTM A105", + "quantity": 5, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77468, + "description": "CAP, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1 1/2\"", + "material_grade": "ASTM A105", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77469, + "description": "SOLID HEX. PLUG, NPT(M), 3000LB, ASTM A105", + "category": "FITTING", + "size": "1 1/2\"", + "material_grade": "ASTM A105", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77470, + "description": "CAP, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1\"", + "material_grade": "ASTM A105", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77471, + "description": "CAP, SW, 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "1\"", + "material_grade": "ASTM A182 F304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77472, + "description": "SOLID HEX. PLUG, NPT(M), 3000LB, ASTM A105", + "category": "FITTING", + "size": "1/2\"", + "material_grade": "ASTM A105", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77474, + "description": "SOLID HEX. PLUG, NPT(M), 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "1/2\"", + "material_grade": "ASTM A182 F304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77475, + "description": "CAP, SMLS, SCH 40, BW, ASTM A234 WPB", + "category": "FITTING", + "size": "2\"", + "material_grade": "ASTM A234 WPB", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77476, + "description": "CAP, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "3/4\"", + "material_grade": "ASTM A105", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77477, + "description": "SOLID HEX. PLUG, NPT(M), 3000LB, ASTM A105", + "category": "FITTING", + "size": "3/4\"", + "material_grade": "ASTM A105", + "quantity": 36, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77513, + "description": "SOLID HEX. PLUG, NPT(M), 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "3/4\"", + "material_grade": "ASTM A182 F304", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77530, + "description": "SOCK O LET, SW, 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "10\" x 1 1/2\"", + "material_grade": "ASTM A182 F304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77531, + "description": "SOCK O LET, SW, 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "10\" x 1\"", + "material_grade": "ASTM A182 F304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77532, + "description": "SOCK O LET, SW, 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "10\" x 3/4\"", + "material_grade": "ASTM A182 F304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77533, + "description": "SOCK O LET, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "2\" x 1/2\"", + "material_grade": "ASTM A105", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77535, + "description": "ELL O LET, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "2\" x 3/4\"", + "material_grade": "ASTM A105", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77536, + "description": "ELL O LET, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "3\" x 3/4\"", + "material_grade": "ASTM A105", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77537, + "description": "SOCK O LET, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "3\" x 3/4\"", + "material_grade": "ASTM A105", + "quantity": 9, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77546, + "description": "SOCK O LET, SW, 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "3\" x 3/4\"", + "material_grade": "ASTM A182 F304", + "quantity": 3, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77549, + "description": "SOCK O LET, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "3\" x 1\"", + "material_grade": "ASTM A105", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77550, + "description": "SOCK O LET, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "4\" x 3/4\"", + "material_grade": "ASTM A105", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77551, + "description": "SOCK O LET, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "6\" x 1 1/2\"", + "material_grade": "ASTM A105", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "material_id": 77553, + "description": "SOCK O LET, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "6\" x 3/4\"", + "material_grade": "ASTM A105", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + } + ], + "grouped_materials": [ + { + "group_key": "HALF NIPPLE, SMLS, SCH 80S, ASTM A312 TP304 SW X NPT|1/2\"|undefined|ASTM A312 TP304", + "material_ids": [ + 75644, + 75646 + ], + "description": "HALF NIPPLE, SMLS, SCH 80S, ASTM A312 TP304 SW X NPT", + "category": "FITTING", + "size": "1/2\"", + "material_grade": "ASTM A312 TP304", + "quantity": 3, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "HALF NIPPLE, SMLS, SCH 160, ASTM A106 B SW * NPT|1\"|undefined|ASTM A106 B", + "material_ids": [ + 75786 + ], + "description": "HALF NIPPLE, SMLS, SCH 160, ASTM A106 B SW * NPT", + "category": "FITTING", + "size": "1\"", + "material_grade": "ASTM A106 B", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "HALF NIPPLE, SMLS, SCH 160, ASTM A106 B SW X NPT|1/2\"|undefined|ASTM A106 B", + "material_ids": [ + 75935, + 75939, + 75942 + ], + "description": "HALF NIPPLE, SMLS, SCH 160, ASTM A106 B SW X NPT", + "category": "FITTING", + "size": "1/2\"", + "material_grade": "ASTM A106 B", + "quantity": 9, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "NIPPLE, SMLS, SCH 160, ASTM A106 B|1/2\"|undefined|ASTM A106 B", + "material_ids": [ + 75944 + ], + "description": "NIPPLE, SMLS, SCH 160, ASTM A106 B", + "category": "FITTING", + "size": "1/2\"", + "material_grade": "ASTM A106 B", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "90 LR ELL, SMLS, SCH 40S, ASTM A403 WP304|10\"|undefined|ASTM A403 WP304", + "material_ids": [ + 76255 + ], + "description": "90 LR ELL, SMLS, SCH 40S, ASTM A403 WP304", + "category": "FITTING", + "size": "10\"", + "material_grade": "ASTM A403 WP304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "90 LR ELL, SMLS, SCH 40, ASTM A234 WPB|2\"|undefined|ASTM A234 WPB", + "material_ids": [ + 76256 + ], + "description": "90 LR ELL, SMLS, SCH 40, ASTM A234 WPB", + "category": "FITTING", + "size": "2\"", + "material_grade": "ASTM A234 WPB", + "quantity": 25, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "90 LR ELL, SMLS, SCH 40S, ASTM A403 WP304|2\"|undefined|ASTM A403 WP304", + "material_ids": [ + 76281 + ], + "description": "90 LR ELL, SMLS, SCH 40S, ASTM A403 WP304", + "category": "FITTING", + "size": "2\"", + "material_grade": "ASTM A403 WP304", + "quantity": 6, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "90 LR ELL, SMLS, SCH 40, ASTM A234 WPB|3\"|undefined|ASTM A234 WPB", + "material_ids": [ + 76287 + ], + "description": "90 LR ELL, SMLS, SCH 40, ASTM A234 WPB", + "category": "FITTING", + "size": "3\"", + "material_grade": "ASTM A234 WPB", + "quantity": 12, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "90 LR ELL, SMLS, SCH 40S, ASTM A403 WP304|3\"|undefined|ASTM A403 WP304", + "material_ids": [ + 76299 + ], + "description": "90 LR ELL, SMLS, SCH 40S, ASTM A403 WP304", + "category": "FITTING", + "size": "3\"", + "material_grade": "ASTM A403 WP304", + "quantity": 4, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "90 LR ELL, SMLS, SCH 40, ASTM A234 WPB|4\"|undefined|ASTM A234 WPB", + "material_ids": [ + 76303 + ], + "description": "90 LR ELL, SMLS, SCH 40, ASTM A234 WPB", + "category": "FITTING", + "size": "4\"", + "material_grade": "ASTM A234 WPB", + "quantity": 7, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "90 SR ELL, SMLS, SCH 40, ASTM A234 WPB|4\"|undefined|ASTM A234 WPB", + "material_ids": [ + 76310 + ], + "description": "90 SR ELL, SMLS, SCH 40, ASTM A234 WPB", + "category": "FITTING", + "size": "4\"", + "material_grade": "ASTM A234 WPB", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "90 LR ELL, SMLS, SCH 40, ASTM A234 WPB|6\"|undefined|ASTM A234 WPB", + "material_ids": [ + 76311 + ], + "description": "90 LR ELL, SMLS, SCH 40, ASTM A234 WPB", + "category": "FITTING", + "size": "6\"", + "material_grade": "ASTM A234 WPB", + "quantity": 7, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "45 ELL, SMLS, SCH 40, ASTM A234 WPB|6\"|undefined|ASTM A234 WPB", + "material_ids": [ + 76318 + ], + "description": "45 ELL, SMLS, SCH 40, ASTM A234 WPB", + "category": "FITTING", + "size": "6\"", + "material_grade": "ASTM A234 WPB", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "TEE, SMLS, SCH 40, ASTM A234 WPB|2\"|undefined|ASTM A234 WPB", + "material_ids": [ + 76320 + ], + "description": "TEE, SMLS, SCH 40, ASTM A234 WPB", + "category": "FITTING", + "size": "2\"", + "material_grade": "ASTM A234 WPB", + "quantity": 4, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "TEE, SMLS, SCH 40S, ASTM A403 WP304|2\"|undefined|ASTM A403 WP304", + "material_ids": [ + 76324 + ], + "description": "TEE, SMLS, SCH 40S, ASTM A403 WP304", + "category": "FITTING", + "size": "2\"", + "material_grade": "ASTM A403 WP304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "TEE, SMLS, SCH 40, ASTM A234 WPB|3\"|undefined|ASTM A234 WPB", + "material_ids": [ + 76325 + ], + "description": "TEE, SMLS, SCH 40, ASTM A234 WPB", + "category": "FITTING", + "size": "3\"", + "material_grade": "ASTM A234 WPB", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "TEE, SMLS, SCH 40S, ASTM A403 WP304|3\"|undefined|ASTM A403 WP304", + "material_ids": [ + 76326 + ], + "description": "TEE, SMLS, SCH 40S, ASTM A403 WP304", + "category": "FITTING", + "size": "3\"", + "material_grade": "ASTM A403 WP304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "TEE RED, SMLS, SCH 40 X SCH 80, ASTM A234 WPB|2\" x 1 1/2\"|undefined|ASTM A234 WPB", + "material_ids": [ + 76327 + ], + "description": "TEE RED, SMLS, SCH 40 X SCH 80, ASTM A234 WPB", + "category": "FITTING", + "size": "2\" x 1 1/2\"", + "material_grade": "ASTM A234 WPB", + "quantity": 3, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "TEE RED, SMLS, SCH 40S X SCH 40S, ASTM A403 WP304|2\" x 1 1/2\"|undefined|ASTM A403 WP304", + "material_ids": [ + 76330 + ], + "description": "TEE RED, SMLS, SCH 40S X SCH 40S, ASTM A403 WP304", + "category": "FITTING", + "size": "2\" x 1 1/2\"", + "material_grade": "ASTM A403 WP304", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "TEE RED, SMLS, SCH 40 X SCH 80, ASTM A234 WPB|3\" x 1 1/2\"|undefined|ASTM A234 WPB", + "material_ids": [ + 76332 + ], + "description": "TEE RED, SMLS, SCH 40 X SCH 80, ASTM A234 WPB", + "category": "FITTING", + "size": "3\" x 1 1/2\"", + "material_grade": "ASTM A234 WPB", + "quantity": 3, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "TEE RED, SMLS, SCH 40 X SCH 80, ASTM A234 WPB|4\" x 1 1/2\"|undefined|ASTM A234 WPB", + "material_ids": [ + 76335 + ], + "description": "TEE RED, SMLS, SCH 40 X SCH 80, ASTM A234 WPB", + "category": "FITTING", + "size": "4\" x 1 1/2\"", + "material_grade": "ASTM A234 WPB", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "RED CONC, SMLS, SCH 80 X SCH 80, ASTM A234 WPB|1 1/2\" x 1\"|undefined|ASTM A234 WPB", + "material_ids": [ + 76337 + ], + "description": "RED CONC, SMLS, SCH 80 X SCH 80, ASTM A234 WPB", + "category": "FITTING", + "size": "1 1/2\" x 1\"", + "material_grade": "ASTM A234 WPB", + "quantity": 5, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "RED CONC, SMLS, SCH 80 X SCH 80, ASTM A234 WPB|1 1/2\" x 3/4\"|undefined|ASTM A234 WPB", + "material_ids": [ + 76342 + ], + "description": "RED CONC, SMLS, SCH 80 X SCH 80, ASTM A234 WPB", + "category": "FITTING", + "size": "1 1/2\" x 3/4\"", + "material_grade": "ASTM A234 WPB", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "RED CONC, SMLS, SCH 80 X SCH 80, ASTM A234 WPB|1\" x 3/4\"|undefined|ASTM A234 WPB", + "material_ids": [ + 76344 + ], + "description": "RED CONC, SMLS, SCH 80 X SCH 80, ASTM A234 WPB", + "category": "FITTING", + "size": "1\" x 3/4\"", + "material_grade": "ASTM A234 WPB", + "quantity": 5, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "RED CONC, SMLS, SCH 40S X SCH 40S, ASTM A403 WP304|12\" x 10\"|undefined|ASTM A403 WP304", + "material_ids": [ + 76349 + ], + "description": "RED CONC, SMLS, SCH 40S X SCH 40S, ASTM A403 WP304", + "category": "FITTING", + "size": "12\" x 10\"", + "material_grade": "ASTM A403 WP304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "RED CONC, SMLS, SCH 40 X SCH 80, ASTM A234 WPB|2\" x 1 1/2\"|undefined|ASTM A234 WPB", + "material_ids": [ + 76350 + ], + "description": "RED CONC, SMLS, SCH 40 X SCH 80, ASTM A234 WPB", + "category": "FITTING", + "size": "2\" x 1 1/2\"", + "material_grade": "ASTM A234 WPB", + "quantity": 6, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "RED CONC, SMLS, SCH 40S X SCH 40S, ASTM A403 WP304|2\" x 1 1/2\"|undefined|ASTM A403 WP304", + "material_ids": [ + 76356 + ], + "description": "RED CONC, SMLS, SCH 40S X SCH 40S, ASTM A403 WP304", + "category": "FITTING", + "size": "2\" x 1 1/2\"", + "material_grade": "ASTM A403 WP304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "RED CONC, SMLS, SCH 40 X SCH 80, ASTM A234 WPB|2\" x 1\"|undefined|ASTM A234 WPB", + "material_ids": [ + 76357 + ], + "description": "RED CONC, SMLS, SCH 40 X SCH 80, ASTM A234 WPB", + "category": "FITTING", + "size": "2\" x 1\"", + "material_grade": "ASTM A234 WPB", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "RED CONC, SMLS, SCH 40 X SCH 80, ASTM A234 WPB|3\" x 1 1/2\"|undefined|ASTM A234 WPB", + "material_ids": [ + 76358 + ], + "description": "RED CONC, SMLS, SCH 40 X SCH 80, ASTM A234 WPB", + "category": "FITTING", + "size": "3\" x 1 1/2\"", + "material_grade": "ASTM A234 WPB", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "RED CONC, SMLS, SCH 40S X SCH 40S, ASTM A403 WP304|3\" x 1\"|undefined|ASTM A403 WP304", + "material_ids": [ + 76360 + ], + "description": "RED CONC, SMLS, SCH 40S X SCH 40S, ASTM A403 WP304", + "category": "FITTING", + "size": "3\" x 1\"", + "material_grade": "ASTM A403 WP304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "RED CONC, SMLS, SCH 40 X SCH 40, ASTM A234 WPB|3\" x 2\"|undefined|ASTM A234 WPB", + "material_ids": [ + 76361 + ], + "description": "RED CONC, SMLS, SCH 40 X SCH 40, ASTM A234 WPB", + "category": "FITTING", + "size": "3\" x 2\"", + "material_grade": "ASTM A234 WPB", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "RED CONC, SMLS, SCH 40S X SCH 40S, ASTM A403 WP304|3\" x 2\"|undefined|ASTM A403 WP304", + "material_ids": [ + 76362 + ], + "description": "RED CONC, SMLS, SCH 40S X SCH 40S, ASTM A403 WP304", + "category": "FITTING", + "size": "3\" x 2\"", + "material_grade": "ASTM A403 WP304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "RED CONC, SMLS, SCH 80 X SCH 80, ASTM A234 WPB|3/4\" x 1/2\"|undefined|ASTM A234 WPB", + "material_ids": [ + 76363 + ], + "description": "RED CONC, SMLS, SCH 80 X SCH 80, ASTM A234 WPB", + "category": "FITTING", + "size": "3/4\" x 1/2\"", + "material_grade": "ASTM A234 WPB", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "90 ELL, SW, 3000LB, ASTM A182 F304|1/2\"|undefined|ASTM A182 F304", + "material_ids": [ + 77240 + ], + "description": "90 ELL, SW, 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "1/2\"", + "material_grade": "ASTM A182 F304", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "90 ELL, SW, 3000LB, ASTM A105|1\"|undefined|ASTM A105", + "material_ids": [ + 77242 + ], + "description": "90 ELL, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1\"", + "material_grade": "ASTM A105", + "quantity": 57, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "90 ELL, SW, 3000LB, ASTM A182 F304|1\"|undefined|ASTM A182 F304", + "material_ids": [ + 77246 + ], + "description": "90 ELL, SW, 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "1\"", + "material_grade": "ASTM A182 F304", + "quantity": 9, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "90 ELL, SW, 3000LB, ASTM A105|1 1/2\"|undefined|ASTM A105", + "material_ids": [ + 77250 + ], + "description": "90 ELL, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1 1/2\"", + "material_grade": "ASTM A105", + "quantity": 32, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "90 ELL, SW, 3000LB, ASTM A182 F304|1 1/2\"|undefined|ASTM A182 F304", + "material_ids": [ + 77282 + ], + "description": "90 ELL, SW, 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "1 1/2\"", + "material_grade": "ASTM A182 F304", + "quantity": 9, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "90 ELL, SW, 3000LB, ASTM A105|1/2\"|undefined|ASTM A105", + "material_ids": [ + 77349 + ], + "description": "90 ELL, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1/2\"", + "material_grade": "ASTM A105", + "quantity": 32, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "90 ELL, SW, 3000LB, ASTM A105|3/4\"|undefined|ASTM A105", + "material_ids": [ + 77381 + ], + "description": "90 ELL, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "3/4\"", + "material_grade": "ASTM A105", + "quantity": 24, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "TEE, SW, 3000LB, ASTM A105|1 1/2\"|undefined|ASTM A105", + "material_ids": [ + 77405 + ], + "description": "TEE, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1 1/2\"", + "material_grade": "ASTM A105", + "quantity": 7, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "TEE, SW, 3000LB, ASTM A105|1\"|undefined|ASTM A105", + "material_ids": [ + 77412 + ], + "description": "TEE, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1\"", + "material_grade": "ASTM A105", + "quantity": 15, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "TEE, SW, 3000LB, ASTM A182 F304|1\"|undefined|ASTM A182 F304", + "material_ids": [ + 77427 + ], + "description": "TEE, SW, 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "1\"", + "material_grade": "ASTM A182 F304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "TEE, SW, 3000LB, ASTM A105|1/2\"|undefined|ASTM A105", + "material_ids": [ + 77428 + ], + "description": "TEE, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1/2\"", + "material_grade": "ASTM A105", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "TEE RED, SW, 3000LB, ASTM A105|1 1/2\" x 1\"|undefined|ASTM A105", + "material_ids": [ + 77430 + ], + "description": "TEE RED, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1 1/2\" x 1\"", + "material_grade": "ASTM A105", + "quantity": 5, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "TEE RED, SW, 3000LB, ASTM A105|1 1/2\" x 1/2\"|undefined|ASTM A105", + "material_ids": [ + 77435 + ], + "description": "TEE RED, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1 1/2\" x 1/2\"", + "material_grade": "ASTM A105", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "TEE RED, SW, 3000LB, ASTM A105|1 1/2\" x 3/4\"|undefined|ASTM A105", + "material_ids": [ + 77437 + ], + "description": "TEE RED, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1 1/2\" x 3/4\"", + "material_grade": "ASTM A105", + "quantity": 6, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "TEE RED, SW, 3000LB, ASTM A105|1\" x 1/2\"|undefined|ASTM A105", + "material_ids": [ + 77443 + ], + "description": "TEE RED, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1\" x 1/2\"", + "material_grade": "ASTM A105", + "quantity": 7, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "TEE RED, SW, 3000LB, ASTM A182 F304|1\" x 1/2\"|undefined|ASTM A182 F304", + "material_ids": [ + 77450 + ], + "description": "TEE RED, SW, 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "1\" x 1/2\"", + "material_grade": "ASTM A182 F304", + "quantity": 6, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "TEE RED, SW, 3000LB, ASTM A105|1\" x 3/4\"|undefined|ASTM A105", + "material_ids": [ + 77453 + ], + "description": "TEE RED, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1\" x 3/4\"", + "material_grade": "ASTM A105", + "quantity": 3, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "TEE RED, SW, 3000LB, ASTM A105|2\" x 1\"|undefined|ASTM A105", + "material_ids": [ + 77459 + ], + "description": "TEE RED, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "2\" x 1\"", + "material_grade": "ASTM A105", + "quantity": 4, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "TEE RED, SW, 3000LB, ASTM A105|3/4\" x 1/2\"|undefined|ASTM A105", + "material_ids": [ + 77463 + ], + "description": "TEE RED, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "3/4\" x 1/2\"", + "material_grade": "ASTM A105", + "quantity": 5, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "CAP, SW, 3000LB, ASTM A105|1 1/2\"|undefined|ASTM A105", + "material_ids": [ + 77468 + ], + "description": "CAP, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1 1/2\"", + "material_grade": "ASTM A105", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "SOLID HEX. PLUG, NPT(M), 3000LB, ASTM A105|1 1/2\"|undefined|ASTM A105", + "material_ids": [ + 77469 + ], + "description": "SOLID HEX. PLUG, NPT(M), 3000LB, ASTM A105", + "category": "FITTING", + "size": "1 1/2\"", + "material_grade": "ASTM A105", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "CAP, SW, 3000LB, ASTM A105|1\"|undefined|ASTM A105", + "material_ids": [ + 77470 + ], + "description": "CAP, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "1\"", + "material_grade": "ASTM A105", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "CAP, SW, 3000LB, ASTM A182 F304|1\"|undefined|ASTM A182 F304", + "material_ids": [ + 77471 + ], + "description": "CAP, SW, 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "1\"", + "material_grade": "ASTM A182 F304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "SOLID HEX. PLUG, NPT(M), 3000LB, ASTM A105|1/2\"|undefined|ASTM A105", + "material_ids": [ + 77472 + ], + "description": "SOLID HEX. PLUG, NPT(M), 3000LB, ASTM A105", + "category": "FITTING", + "size": "1/2\"", + "material_grade": "ASTM A105", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "SOLID HEX. PLUG, NPT(M), 3000LB, ASTM A182 F304|1/2\"|undefined|ASTM A182 F304", + "material_ids": [ + 77474 + ], + "description": "SOLID HEX. PLUG, NPT(M), 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "1/2\"", + "material_grade": "ASTM A182 F304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "CAP, SMLS, SCH 40, BW, ASTM A234 WPB|2\"|undefined|ASTM A234 WPB", + "material_ids": [ + 77475 + ], + "description": "CAP, SMLS, SCH 40, BW, ASTM A234 WPB", + "category": "FITTING", + "size": "2\"", + "material_grade": "ASTM A234 WPB", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "CAP, SW, 3000LB, ASTM A105|3/4\"|undefined|ASTM A105", + "material_ids": [ + 77476 + ], + "description": "CAP, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "3/4\"", + "material_grade": "ASTM A105", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "SOLID HEX. PLUG, NPT(M), 3000LB, ASTM A105|3/4\"|undefined|ASTM A105", + "material_ids": [ + 77477 + ], + "description": "SOLID HEX. PLUG, NPT(M), 3000LB, ASTM A105", + "category": "FITTING", + "size": "3/4\"", + "material_grade": "ASTM A105", + "quantity": 36, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "SOLID HEX. PLUG, NPT(M), 3000LB, ASTM A182 F304|3/4\"|undefined|ASTM A182 F304", + "material_ids": [ + 77513 + ], + "description": "SOLID HEX. PLUG, NPT(M), 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "3/4\"", + "material_grade": "ASTM A182 F304", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "SOCK O LET, SW, 3000LB, ASTM A182 F304|10\" x 1 1/2\"|undefined|ASTM A182 F304", + "material_ids": [ + 77530 + ], + "description": "SOCK O LET, SW, 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "10\" x 1 1/2\"", + "material_grade": "ASTM A182 F304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "SOCK O LET, SW, 3000LB, ASTM A182 F304|10\" x 1\"|undefined|ASTM A182 F304", + "material_ids": [ + 77531 + ], + "description": "SOCK O LET, SW, 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "10\" x 1\"", + "material_grade": "ASTM A182 F304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "SOCK O LET, SW, 3000LB, ASTM A182 F304|10\" x 3/4\"|undefined|ASTM A182 F304", + "material_ids": [ + 77532 + ], + "description": "SOCK O LET, SW, 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "10\" x 3/4\"", + "material_grade": "ASTM A182 F304", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "SOCK O LET, SW, 3000LB, ASTM A105|2\" x 1/2\"|undefined|ASTM A105", + "material_ids": [ + 77533 + ], + "description": "SOCK O LET, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "2\" x 1/2\"", + "material_grade": "ASTM A105", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "ELL O LET, SW, 3000LB, ASTM A105|2\" x 3/4\"|undefined|ASTM A105", + "material_ids": [ + 77535 + ], + "description": "ELL O LET, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "2\" x 3/4\"", + "material_grade": "ASTM A105", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "ELL O LET, SW, 3000LB, ASTM A105|3\" x 3/4\"|undefined|ASTM A105", + "material_ids": [ + 77536 + ], + "description": "ELL O LET, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "3\" x 3/4\"", + "material_grade": "ASTM A105", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "SOCK O LET, SW, 3000LB, ASTM A105|3\" x 3/4\"|undefined|ASTM A105", + "material_ids": [ + 77537 + ], + "description": "SOCK O LET, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "3\" x 3/4\"", + "material_grade": "ASTM A105", + "quantity": 9, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "SOCK O LET, SW, 3000LB, ASTM A182 F304|3\" x 3/4\"|undefined|ASTM A182 F304", + "material_ids": [ + 77546 + ], + "description": "SOCK O LET, SW, 3000LB, ASTM A182 F304", + "category": "FITTING", + "size": "3\" x 3/4\"", + "material_grade": "ASTM A182 F304", + "quantity": 3, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "SOCK O LET, SW, 3000LB, ASTM A105|3\" x 1\"|undefined|ASTM A105", + "material_ids": [ + 77549 + ], + "description": "SOCK O LET, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "3\" x 1\"", + "material_grade": "ASTM A105", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "SOCK O LET, SW, 3000LB, ASTM A105|4\" x 3/4\"|undefined|ASTM A105", + "material_ids": [ + 77550 + ], + "description": "SOCK O LET, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "4\" x 3/4\"", + "material_grade": "ASTM A105", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "SOCK O LET, SW, 3000LB, ASTM A105|6\" x 1 1/2\"|undefined|ASTM A105", + "material_ids": [ + 77551 + ], + "description": "SOCK O LET, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "6\" x 1 1/2\"", + "material_grade": "ASTM A105", + "quantity": 2, + "unit": "EA", + "user_requirement": "" + }, + { + "group_key": "SOCK O LET, SW, 3000LB, ASTM A105|6\" x 3/4\"|undefined|ASTM A105", + "material_ids": [ + 77553 + ], + "description": "SOCK O LET, SW, 3000LB, ASTM A105", + "category": "FITTING", + "size": "6\" x 3/4\"", + "material_grade": "ASTM A105", + "quantity": 1, + "unit": "EA", + "user_requirement": "" + } + ] +} \ No newline at end of file diff --git a/backend/exports/PR-20251015-001.xlsx b/backend/exports/PR-20251015-001.xlsx new file mode 100644 index 0000000..102a4e0 Binary files /dev/null and b/backend/exports/PR-20251015-001.xlsx differ diff --git a/backend/exports/PR-20251015-002.json b/backend/exports/PR-20251015-002.json new file mode 100644 index 0000000..2195c36 --- /dev/null +++ b/backend/exports/PR-20251015-002.json @@ -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": "" + } + ] +} \ No newline at end of file diff --git a/backend/exports/PR-20251015-002.xlsx b/backend/exports/PR-20251015-002.xlsx new file mode 100644 index 0000000..3eb8388 Binary files /dev/null and b/backend/exports/PR-20251015-002.xlsx differ diff --git a/docker-compose.proxy.yml b/docker-compose.proxy.yml index b46bbf5..921b60f 100644 --- a/docker-compose.proxy.yml +++ b/docker-compose.proxy.yml @@ -4,7 +4,7 @@ services: container_name: tk-mp-nginx-proxy restart: unless-stopped ports: - - "80:80" + - "8808:80" volumes: - ./nginx-proxy.conf:/etc/nginx/conf.d/default.conf networks: diff --git a/docker-compose.yml b/docker-compose.yml index 4af1f7b..db032d4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -78,13 +78,13 @@ services: context: ./frontend dockerfile: Dockerfile args: - - VITE_API_URL=${VITE_API_URL:-http://localhost:18000} + - VITE_API_URL=${VITE_API_URL:-/api} container_name: tk-mp-frontend restart: unless-stopped ports: - - "${FRONTEND_PORT:-13000}:5173" + - "${FRONTEND_PORT:-13000}:3000" environment: - - VITE_API_URL=${VITE_API_URL:-http://localhost:18000} + - VITE_API_URL=${VITE_API_URL:-/api} depends_on: - backend networks: diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index d6d98ba..6492c61 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -229,9 +229,11 @@ function App() { console.log('getAdminFeatures - Current user:', user); console.log('getAdminFeatures - User role:', user?.role); console.log('getAdminFeatures - Pending count:', pendingSignupCount); + console.log('getAdminFeatures - Role check result:', user?.role === 'system' || user?.role === 'admin'); - // 시스템 관리자 기능 (admin role이 시스템 관리자) - if (user?.role === 'admin') { + // 시스템 관리자 기능 (system role이 최고 권한) + if (user?.role === 'system' || user?.role === 'admin') { + console.log('✅ 시스템 관리자 기능 추가 중...'); features.push( { id: 'user-management', @@ -937,7 +939,7 @@ function App() { - )} {/* adminFeatures 조건문 닫기 */} + )} ); diff --git a/frontend/src/pages/NewMaterialsPage.jsx b/frontend/src/pages/NewMaterialsPage.jsx index 2b027a6..7b7759d 100644 --- a/frontend/src/pages/NewMaterialsPage.jsx +++ b/frontend/src/pages/NewMaterialsPage.jsx @@ -638,6 +638,38 @@ const NewMaterialsPage = ({ // 스웨이지: 타입 명시 const swageType = fittingSubtype || ''; displayType = `SWAGE ${swageType}`.trim(); + } else if (fittingType === 'OLET') { + // OLET: 풀네임으로 표시 + const oletSubtype = fittingSubtype || ''; + let oletDisplayName = ''; + + switch (oletSubtype) { + case 'SOCKOLET': + oletDisplayName = 'SOCK-O-LET'; + break; + case 'WELDOLET': + oletDisplayName = 'WELD-O-LET'; + break; + case 'ELLOLET': + oletDisplayName = 'ELL-O-LET'; + break; + case 'THREADOLET': + oletDisplayName = 'THREAD-O-LET'; + break; + case 'ELBOLET': + oletDisplayName = 'ELB-O-LET'; + break; + case 'NIPOLET': + oletDisplayName = 'NIP-O-LET'; + break; + case 'COUPOLET': + oletDisplayName = 'COUP-O-LET'; + break; + default: + oletDisplayName = 'OLET'; + } + + displayType = oletDisplayName; } else if (!displayType) { // 기타 피팅 타입 displayType = fittingType || 'FITTING'; @@ -738,9 +770,83 @@ const NewMaterialsPage = ({ }; } else if (category === 'FLANGE') { const description = material.original_description || ''; + const flangeDetails = material.flange_details || {}; - // 백엔드에서 개선된 플랜지 타입 제공 (WN RF, SO FF 등) - const displayType = material.flange_details?.flange_type || '-'; + // 플랜지 타입 풀네임 매핑 (영어) + const flangeTypeMap = { + 'WN': 'WELD NECK FLANGE', + 'WELD_NECK': 'WELD NECK FLANGE', + 'SO': 'SLIP ON FLANGE', + 'SLIP_ON': 'SLIP ON FLANGE', + 'SW': 'SOCKET WELD FLANGE', + 'SOCKET_WELD': 'SOCKET WELD FLANGE', + 'BL': 'BLIND FLANGE', + 'BLIND': 'BLIND FLANGE', + 'RED': 'REDUCING FLANGE', + 'REDUCING': 'REDUCING FLANGE', + 'ORIFICE': 'ORIFICE FLANGE', + 'SPECTACLE': 'SPECTACLE BLIND', + 'PADDLE': 'PADDLE BLIND', + 'SPACER': 'SPACER' + }; + + // 끝단처리 풀네임 매핑 (영어) + const facingTypeMap = { + 'RF': 'RAISED FACE', + 'RAISED_FACE': 'RAISED FACE', + 'FF': 'FULL FACE', + 'FULL_FACE': 'FULL FACE', + 'RTJ': 'RING JOINT', + 'RING_JOINT': 'RING JOINT', + 'MALE': 'MALE', + 'FEMALE': 'FEMALE' + }; + + // 백엔드에서 제공된 타입 정보 + const rawFlangeType = flangeDetails.flange_type || ''; + const rawFacingType = flangeDetails.facing_type || ''; + + // 풀네임으로 변환 + let displayType = flangeTypeMap[rawFlangeType] || rawFlangeType || '-'; + let facingType = facingTypeMap[rawFacingType] || rawFacingType || '-'; + + // 백엔드 데이터가 없으면 description에서 추출 + if (displayType === '-') { + const upperDesc = description.toUpperCase(); + if (upperDesc.includes('WN') || upperDesc.includes('WELD NECK')) { + displayType = 'WELD NECK FLANGE'; + } else if (upperDesc.includes('SO') || upperDesc.includes('SLIP ON')) { + displayType = 'SLIP ON FLANGE'; + } else if (upperDesc.includes('SW') || upperDesc.includes('SOCKET')) { + displayType = 'SOCKET WELD FLANGE'; + } else if (upperDesc.includes('BLIND') || upperDesc.includes('BL')) { + displayType = 'BLIND FLANGE'; + } else if (upperDesc.includes('REDUCING') || upperDesc.includes('RED')) { + displayType = 'REDUCING FLANGE'; + } else if (upperDesc.includes('ORIFICE')) { + displayType = 'ORIFICE FLANGE'; + } else if (upperDesc.includes('SPECTACLE')) { + displayType = 'SPECTACLE BLIND'; + } else if (upperDesc.includes('PADDLE')) { + displayType = 'PADDLE BLIND'; + } else if (upperDesc.includes('SPACER')) { + displayType = 'SPACER'; + } else { + displayType = 'FLANGE'; + } + } + + // 끝단처리 정보가 없으면 description에서 추출 + if (facingType === '-') { + const upperDesc = description.toUpperCase(); + if (upperDesc.includes(' RF') || upperDesc.includes('RAISED')) { + facingType = 'RAISED FACE'; + } else if (upperDesc.includes(' FF') || upperDesc.includes('FULL FACE')) { + facingType = 'FULL FACE'; + } else if (upperDesc.includes('RTJ') || upperDesc.includes('RING')) { + facingType = 'RING JOINT'; + } + } // 원본 설명에서 스케줄 추출 let schedule = '-'; @@ -756,11 +862,12 @@ const NewMaterialsPage = ({ return { type: 'FLANGE', - subtype: displayType, // 백엔드에서 개선된 타입 정보 제공 (WN RF, SO FF 등) + subtype: displayType, // 풀네임 플랜지 타입 + facing: facingType, // 새로 추가: 끝단처리 정보 size: material.size_spec || '-', - pressure: material.flange_details?.pressure_rating || '-', + pressure: flangeDetails.pressure_rating || '-', schedule: schedule, - grade: material.full_material_grade || material.material_grade || '-', // 전체 재질명 우선 사용 + grade: material.full_material_grade || material.material_grade || '-', quantity: Math.round(material.quantity || 0), unit: '개', isFlange: true // 플랜지 구분용 플래그 @@ -1386,11 +1493,9 @@ const NewMaterialsPage = ({ const timestamp = new Date().toISOString().split('T')[0]; const fileName = `${jobNo}_${selectedCategory}_${timestamp}.xlsx`; - // BOM 페이지에서 사용하는 엑셀 내보내기 함수 사용 - await exportCategoryToExcel( - selectedCategory, + // 기존 엑셀 내보내기 함수 사용 + await exportMaterialsToExcel( dataWithRequirements, - jobNo, fileName, userRequirements ); @@ -1736,6 +1841,7 @@ const NewMaterialsPage = ({