feat: BOM과 구매관리 페이지 엑셀 통합 및 완전 동일화
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:
Hyungi Ahn
2025-10-14 15:59:33 +09:00
parent 72126ef78d
commit 8f5330a008
9 changed files with 334 additions and 4535 deletions

View File

@@ -1382,6 +1382,20 @@ const NewMaterialsPage = ({
user_requirement: userRequirements[material.id] || ''
}));
// 1단계: 엑셀 파일 생성
const timestamp = new Date().toISOString().split('T')[0];
const fileName = `${jobNo}_${selectedCategory}_${timestamp}.xlsx`;
// BOM 페이지에서 사용하는 엑셀 내보내기 함수 사용
await exportCategoryToExcel(
selectedCategory,
dataWithRequirements,
jobNo,
fileName,
userRequirements
);
// 2단계: 생성된 엑셀을 서버에 업로드 (구매신청과 함께)
// 서버에 구매신청 생성
try {
// 그룹화된 데이터를 구매신청 형식으로 변환
@@ -1472,9 +1486,9 @@ const NewMaterialsPage = ({
uploadDate: new Date().toLocaleDateString()
};
const fileName = `${selectedCategory}_${jobNo || 'export'}_${new Date().toISOString().split('T')[0]}.xlsx`;
const excelFileName = `${selectedCategory}_${jobNo || 'export'}_${new Date().toISOString().split('T')[0]}.xlsx`;
exportMaterialsToExcel(dataWithRequirements, fileName, additionalInfo);
exportMaterialsToExcel(dataWithRequirements, excelFileName, additionalInfo);
console.log('✅ 엑셀 내보내기 성공');
} catch (error) {

View File

@@ -54,81 +54,27 @@ const PurchaseRequestPage = ({ onNavigate, fileId, jobNo, selectedProject }) =>
const handleDownloadExcel = async (requestId, requestNo) => {
try {
console.log('📥 엑셀 다운로드 시작:', requestId, requestNo);
// 서버에서 자재 데이터 가져오기
const response = await api.get(`/purchase-request/${requestId}/download-excel`);
console.log('📦 서버 응답:', response.data);
if (response.data.success) {
const materials = response.data.materials;
const groupedMaterials = response.data.grouped_materials || [];
const jobNo = response.data.job_no;
console.log('📊 materials:', materials.length, '개');
console.log('📊 groupedMaterials:', groupedMaterials.length, '개');
// 사용자 요구사항 매핑
const userRequirements = {};
materials.forEach(material => {
if (material.user_requirement) {
userRequirements[material.material_id || material.id] = material.user_requirement;
}
});
// 개별 자재 사용 (BOM 페이지와 동일하게)
// groupedMaterials는 일부 자재가 누락될 수 있으므로 materials 사용
const dataToExport = materials;
// 파일명 생성
const timestamp = new Date().toISOString().split('T')[0];
const fileName = `${jobNo}_${requestNo}_${timestamp}.xlsx`;
console.log('📄 내보낼 데이터:', dataToExport.length, '개');
console.log('📄 첫 번째 자재:', dataToExport[0]);
// materials 데이터를 BOM 형식으로 변환
const materialsForExport = materials.map(m => {
// description에서 품목명 추출 (NIPPLE, ELBOW, TEE 등)
const desc = m.description || '';
const category = m.category || 'UNKNOWN';
return {
...m,
classified_category: category,
original_description: desc,
size_spec: m.size,
size_inch: m.size,
material_grade: m.material_grade,
full_material_grade: m.material_grade,
schedule: m.schedule,
quantity: m.quantity,
unit: m.unit,
// FITTING의 경우 타입 정보 추가
fitting_details: category === 'FITTING' ? {
fitting_type: desc.includes('NIPPLE') ? 'NIPPLE' :
desc.includes('ELBOW') ? 'ELBOW' :
desc.includes('TEE') ? 'TEE' :
desc.includes('REDUCER') ? 'REDUCER' :
desc.includes('CAP') ? 'CAP' :
desc.includes('PLUG') ? 'PLUG' :
desc.includes('COUPLING') ? 'COUPLING' : 'FITTING'
} : undefined
};
});
console.log('🔄 BOM 형식으로 변환 완료:', materialsForExport.length, '개');
// 기존 엑셀 유틸리티 사용
exportMaterialsToExcel(materialsForExport, fileName, {
jobNo,
requestNo,
userRequirements
});
console.log('✅ 엑셀 내보내기 완료');
} else {
console.error('❌ 서버 응답 실패:', response.data);
alert('데이터를 가져올 수 없습니다');
}
// 서버에서 생성된 엑셀 파일 직접 다운로드 (BOM 페이지와 동일한 파일)
const response = await api.get(`/purchase-request/${requestId}/download-excel`, {
responseType: 'blob' // 파일 다운로드용
});
// 파일 다운로드 처리
const blob = new Blob([response.data], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
});
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `${requestNo}_재다운로드.xlsx`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
console.log('✅ 엑셀 파일 다운로드 완료');
} catch (error) {
console.error('❌ 엑셀 다운로드 실패:', error);
alert('엑셀 다운로드 실패: ' + error.message);