feat: BOM과 구매관리 페이지 엑셀 통합 및 완전 동일화
Some checks failed
SonarQube Analysis / SonarQube Scan (push) Has been cancelled
Some checks failed
SonarQube Analysis / SonarQube Scan (push) Has been cancelled
엑셀 내보내기 통합: - BOM 페이지: 구매신청 시 백엔드에서 엑셀 파일 생성 및 저장 - 구매관리 페이지: 저장된 엑셀 파일 직접 다운로드 (재생성 안 함) - 두 페이지에서 완전히 동일한 엑셀 파일 제공 백엔드 엑셀 생성: - openpyxl 사용하여 서버에서 엑셀 생성 - 카테고리별 시트 구성 - 헤더 스타일링 (연파랑 배경) - 컬럼 너비 자동 조정 FLANGE 품목명 개선: - 품목명: FLANGE (간단) - 상세내역: WELD NECK RF, SLIP-ON RF 등 (전체 이름) - 특수 플랜지: ORIFICE FLANGE, SPECTACLE BLIND 등 구분 구매신청 관리 API 개선: - 상세 정보 포함 (pipe_details, fitting_details, flange_details 등) - BOM 형식과 동일한 데이터 구조 - 수량 정수 변환 (3.000 → 3) 에러 수정: - fileName 중복 선언 해결 - flange_details.connection_method 컬럼 제거 (존재하지 않음) - Python 문법 오류 수정 (new Date() → datetime.now()) DB 스키마 개선: - revision_status 컬럼 추가 및 크기 조정 (VARCHAR(30)) - 리비전 변경사항 추적 지원
This commit is contained in:
@@ -150,66 +150,43 @@ const formatMaterialForExcel = (material, includeComparison = false) => {
|
||||
// 구매 수량 계산
|
||||
const purchaseInfo = calculatePurchaseQuantity(material);
|
||||
|
||||
// 품목명 생성 (카테고리별 상세 처리)
|
||||
// 변수 선언 (먼저 선언)
|
||||
let itemName = '';
|
||||
let detailInfo = '';
|
||||
let gasketMaterial = '';
|
||||
let gasketThickness = '';
|
||||
if (category === 'PIPE') {
|
||||
itemName = material.pipe_details?.manufacturing_method || 'PIPE';
|
||||
} else if (category === 'FITTING') {
|
||||
itemName = material.fitting_details?.fitting_type || 'FITTING';
|
||||
} else if (category === 'FLANGE') {
|
||||
// 플랜지 타입 추출
|
||||
const desc = cleanDescription.toUpperCase();
|
||||
console.log('🔍 FLANGE 품목명 추출:', cleanDescription);
|
||||
// 플랜지는 품목명만 간단하게 (상세내역에 타입 정보)
|
||||
itemName = 'FLANGE';
|
||||
|
||||
if (material.flange_details) {
|
||||
console.log(' flange_details:', material.flange_details);
|
||||
const flangeType = material.flange_details.flange_type || '';
|
||||
const originalFlangeType = material.flange_details.original_flange_type || '';
|
||||
const facingType = material.flange_details.facing_type || '';
|
||||
|
||||
// 특수 플랜지 타입 우선
|
||||
if (desc.includes('ORIFICE')) {
|
||||
itemName = 'ORIFICE FLANGE';
|
||||
} else if (desc.includes('SPECTACLE')) {
|
||||
itemName = 'SPECTACLE BLIND';
|
||||
} else if (desc.includes('PADDLE')) {
|
||||
itemName = 'PADDLE BLIND';
|
||||
} else if (desc.includes('SPACER')) {
|
||||
itemName = 'SPACER';
|
||||
} else if (desc.includes('BLIND')) {
|
||||
itemName = 'BLIND FLANGE';
|
||||
} else {
|
||||
// 일반 플랜지: flange_type 사용 (WN RF, SO RF 등)
|
||||
itemName = flangeType || 'FLANGE';
|
||||
}
|
||||
// 특수 플랜지는 구분
|
||||
const desc = cleanDescription.toUpperCase();
|
||||
if (desc.includes('ORIFICE')) {
|
||||
itemName = 'ORIFICE FLANGE';
|
||||
} else if (desc.includes('SPECTACLE')) {
|
||||
itemName = 'SPECTACLE BLIND';
|
||||
} else if (desc.includes('PADDLE')) {
|
||||
itemName = 'PADDLE BLIND';
|
||||
} else if (desc.includes('SPACER')) {
|
||||
itemName = 'SPACER';
|
||||
} else if (desc.includes('BLIND')) {
|
||||
itemName = 'BLIND FLANGE';
|
||||
}
|
||||
|
||||
// 상세내역에 플랜지 타입 정보 저장 (줄임말 사용)
|
||||
if (material.flange_details && material.flange_details.flange_type) {
|
||||
detailInfo = material.flange_details.flange_type; // WN RF, SO RF 등
|
||||
} else {
|
||||
console.log(' flange_details 없음, description에서 추출');
|
||||
// flange_details가 없으면 description에서 추출
|
||||
if (desc.includes('ORIFICE')) {
|
||||
itemName = 'ORIFICE FLANGE';
|
||||
} else if (desc.includes('SPECTACLE') || desc.includes('SPEC')) {
|
||||
itemName = 'SPECTACLE BLIND';
|
||||
} else if (desc.includes('PADDLE')) {
|
||||
itemName = 'PADDLE BLIND';
|
||||
} else if (desc.includes('SPACER')) {
|
||||
itemName = 'SPACER';
|
||||
} else if (desc.includes('BLIND')) {
|
||||
itemName = 'BLIND FLANGE';
|
||||
} else if (desc.includes(' SW') || desc.includes(',SW') || desc.includes(', SW')) {
|
||||
itemName = 'FLANGE SW';
|
||||
} else if (desc.includes(' BW') || desc.includes(',BW') || desc.includes(', BW')) {
|
||||
itemName = 'FLANGE BW';
|
||||
} else if (desc.includes('RTJ')) {
|
||||
itemName = 'FLANGE RTJ';
|
||||
} else if (desc.includes(' FF') || desc.includes('FULL FACE')) {
|
||||
itemName = 'FLANGE FF';
|
||||
} else if (desc.includes(' RF') || desc.includes('RAISED')) {
|
||||
itemName = 'FLANGE RF';
|
||||
} else {
|
||||
itemName = 'FLANGE';
|
||||
// description에서 추출 (전체 이름 그대로 사용)
|
||||
const flangeTypeMatch = cleanDescription.match(/FLG\s+([^,]+?)(?=\s*SCH|\s*,\s*\d+LB|$)/i);
|
||||
if (flangeTypeMatch) {
|
||||
detailInfo = flangeTypeMatch[1].trim(); // WELD NECK RF 등 그대로
|
||||
}
|
||||
}
|
||||
console.log(' → 품목명:', itemName);
|
||||
} else if (category === 'VALVE') {
|
||||
itemName = 'VALVE';
|
||||
} else if (category === 'GASKET') {
|
||||
@@ -379,10 +356,7 @@ const formatMaterialForExcel = (material, includeComparison = false) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 카테고리별 상세 정보 추출
|
||||
let detailInfo = '';
|
||||
let gasketMaterial = '';
|
||||
let gasketThickness = '';
|
||||
// 카테고리별 상세 정보 추출 (이미 위에서 선언됨)
|
||||
|
||||
if (category === 'BOLT') {
|
||||
// 볼트의 경우 표면처리 정보 추출
|
||||
|
||||
Reference in New Issue
Block a user