봄 등록, csv 적용, 모품번 없이 저장 기능 개발, 엑셀 새로 업로드 기능 추가

This commit is contained in:
2025-10-24 17:47:21 +09:00
parent 23ebcd3b88
commit 709f2b4d4b
4 changed files with 313 additions and 28 deletions

View File

@@ -1,7 +1,9 @@
package com.pms.service;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.sql.Clob;
import java.util.ArrayList;
import java.util.HashMap;
@@ -3149,6 +3151,231 @@ public class PartMngService extends BaseService {
}
/**
* CSV 파일 파싱 (엑셀과 동일한 형식으로 반환)
* 첫 번째 열이 "수준"인 경우 계층 구조를 자동으로 파악
*/
private ArrayList parsingCsvFile(String path, String fileName, SqlSession sqlSession) throws Exception {
ArrayList resultList = new ArrayList();
BufferedReader br = null;
try {
File csvFile = new File(path + "\\" + fileName);
br = new BufferedReader(new InputStreamReader(new FileInputStream(csvFile), "UTF-8"));
String line;
int rowIndex = 0;
// 모든 자품번 수집 및 수준별 품번 매핑
Set<String> allPartNumbers = new HashSet<>();
List<String[]> allRows = new ArrayList<>();
Map<String, String> levelToPartNoMap = new HashMap<>(); // 수준 -> 품번 매핑
Map<Integer, String> depthToPartNoMap = new HashMap<>(); // 깊이 -> 품번 매핑 (숫자만 있는 경우)
while ((line = br.readLine()) != null) {
String[] values = line.split(",");
allRows.add(values);
// 헤더가 아닌 경우 품번 수집
if (rowIndex > 0 && values.length > 1) {
String level = values[0].trim(); // 수준
String partNo = values[1].trim(); // 품번
// CSV 큰따옴표 제거
if (level.startsWith("\"") && level.endsWith("\"") && level.length() > 1) {
level = level.substring(1, level.length() - 1);
}
if (partNo.startsWith("\"") && partNo.endsWith("\"") && partNo.length() > 1) {
partNo = partNo.substring(1, partNo.length() - 1);
}
if (!StringUtils.isBlank(partNo)) {
allPartNumbers.add(partNo);
if (!StringUtils.isBlank(level)) {
levelToPartNoMap.put(level, partNo);
// 숫자만 있는 경우를 위한 깊이 매핑
try {
int depth = Integer.parseInt(level);
depthToPartNoMap.put(depth, partNo);
} catch (NumberFormatException e) {
// 숫자가 아니면 무시 (1.1, 1.4.1 같은 형식)
}
}
}
}
rowIndex++;
}
// 데이터 파싱
rowIndex = 0;
Map<Integer, String> currentDepthPartNoMap = new HashMap<>(); // 현재 처리 중인 각 깊이별 최신 품번
for (String[] values : allRows) {
if (rowIndex == 0) { // 헤더 건너뛰기
rowIndex++;
continue;
}
if (values.length < 11) { // 최소 11개 컬럼 필요 (수준 포함)
rowIndex++;
continue;
}
Map partMap = new HashMap();
AtomicInteger emptyColCnt = new AtomicInteger(0);
String noteMsg = "";
int colIndex = 0;
// 각 컬럼 파싱 (CSV: 수준, 품번, 품명, 수량, ...)
String level = getCsvValue(values, colIndex++, emptyColCnt); // 0: 수준
String partNo = getCsvValue(values, colIndex++, emptyColCnt); // 1: 품번
String partName = getCsvValue(values, colIndex++, emptyColCnt); // 2: 품명
String qty = getCsvValue(values, colIndex++, emptyColCnt); // 3: 수량
String itemQty = getCsvValue(values, colIndex++, emptyColCnt); // 4: 항목수량
String material = getCsvValue(values, colIndex++, emptyColCnt); // 5: 재료
String heatTreatmentHardness = getCsvValue(values, colIndex++, emptyColCnt); // 6: 열처리경도
String heatTreatmentMethod = getCsvValue(values, colIndex++, emptyColCnt); // 7: 열처리방법
String surfaceTreatment = getCsvValue(values, colIndex++, emptyColCnt); // 8: 표면처리
String supplier = getCsvValue(values, colIndex++, emptyColCnt); // 9: 공급업체
String partType = getCsvValue(values, colIndex++, emptyColCnt); // 10: 범주이름
// 수준으로부터 부모 품번 찾기
String parentPartNo = "";
if (!StringUtils.isBlank(level)) {
// 숫자만 있는 경우 (1, 2, 3, 4 등)
try {
int currentDepth = Integer.parseInt(level);
// 현재 깊이의 품번 저장 (다음 행에서 참조할 수 있도록)
if (!StringUtils.isBlank(partNo)) {
currentDepthPartNoMap.put(currentDepth, partNo);
}
// 부모 찾기: 바로 이전 깊이의 최신 품번
if (currentDepth > 1) {
int parentDepth = currentDepth - 1;
if (currentDepthPartNoMap.containsKey(parentDepth)) {
parentPartNo = currentDepthPartNoMap.get(parentDepth);
}
}
} catch (NumberFormatException e) {
// 숫자가 아닌 경우 (1.1, 1.4.1 등) - 기존 로직 사용
String parentLevel = getParentLevel(level);
if (!StringUtils.isBlank(parentLevel) && levelToPartNoMap.containsKey(parentLevel)) {
parentPartNo = levelToPartNoMap.get(parentLevel);
}
}
}
// 유효성 검증
if(!StringUtils.isBlank(parentPartNo) && rowIndex > 2) {
if(!allPartNumbers.contains(parentPartNo)) {
noteMsg += "모품번 미존재:" + parentPartNo + ";";
}
}
// PART_TYPE 코드 조회
String partTypeCode = "";
if(!StringUtils.isBlank(partType) && rowIndex > 2) {
Map sqlParamMap = new HashMap();
sqlParamMap.put("CODE_NAME", partType);
String partNoForCheck = CommonUtils.checkNull(partNo);
sqlParamMap.put("partNo", partNoForCheck);
Map partTypeMap = sqlSession.selectOne("partMng.parttypeInfo", sqlParamMap);
if(null != partTypeMap && !StringUtils.isBlank((String)partTypeMap.get("code_id"))){
partTypeCode = (String)partTypeMap.get("code_id");
} else {
noteMsg += "부품유형 확인:" + partType + ";";
}
} else if(!StringUtils.isBlank(partType) && rowIndex <= 2) {
Map sqlParamMap = new HashMap();
sqlParamMap.put("CODE_NAME", partType);
Map partTypeMap = sqlSession.selectOne("partMng.parttypeInfo", sqlParamMap);
if(null != partTypeMap && !StringUtils.isBlank((String)partTypeMap.get("code_id"))){
partTypeCode = (String)partTypeMap.get("code_id");
}
}
// Map에 데이터 저장
partMap.put("LEVEL", level); // 수준 값 (화면 표시용)
partMap.put("PARENT_PART_NO", parentPartNo); // 실제 부모 품번 (저장용)
partMap.put("PART_NO", partNo);
partMap.put("PART_NAME", partName);
partMap.put("QTY", qty);
partMap.put("ITEM_QTY", itemQty);
partMap.put("MATERIAL", material);
partMap.put("HEAT_TREATMENT_HARDNESS", heatTreatmentHardness);
partMap.put("HEAT_TREATMENT_METHOD", heatTreatmentMethod);
partMap.put("SURFACE_TREATMENT", surfaceTreatment);
partMap.put("SUPPLIER", supplier);
partMap.put("PART_TYPE", partTypeCode);
partMap.put("NOTE", noteMsg);
if(!StringUtils.isBlank(noteMsg) || emptyColCnt.intValue() < 9) {
resultList.add(partMap);
}
rowIndex++;
}
} catch (Exception e) {
e.printStackTrace();
throw e;
} finally {
if (br != null) {
try {
br.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return resultList;
}
/**
* CSV 값 추출 헬퍼 메서드
*/
private String getCsvValue(String[] values, int index, AtomicInteger emptyColCnt) {
if (index >= values.length) {
emptyColCnt.incrementAndGet();
return "";
}
String value = values[index].trim();
// CSV 큰따옴표 제거
if (value.startsWith("\"") && value.endsWith("\"") && value.length() > 1) {
value = value.substring(1, value.length() - 1);
}
if (StringUtils.isBlank(value)) {
emptyColCnt.incrementAndGet();
}
return value;
}
/**
* 수준으로부터 부모 수준 찾기
* 예: "1.4.1" -> "1.4", "1.8" -> "1", "1" -> ""
*/
private String getParentLevel(String level) {
if (StringUtils.isBlank(level)) {
return "";
}
// 마지막 점(.)의 위치 찾기
int lastDotIndex = level.lastIndexOf('.');
if (lastDotIndex > 0) {
// 마지막 점 이전까지가 부모 수준
return level.substring(0, lastDotIndex);
}
// 점이 없으면 최상위 레벨이므로 부모 없음
return "";
}
/**
* BOM 복사를 위한 데이터 조회 (엑셀 파싱 형식과 동일하게 반환)
*/
@@ -3250,6 +3477,19 @@ public class PartMngService extends BaseService {
String path = CommonUtils.checkNull(fileMap.get("FILE_PATH"));
String fileName = CommonUtils.checkNull(fileMap.get("SAVED_FILE_NAME"));
// CSV 파일인 경우 (수준 기반 계층 구조)
if (fileName.endsWith(".csv") || fileName.endsWith(".CSV")) {
resultList = parsingCsvFile(path, fileName, sqlSession);
// CSV 파일임을 표시
for(int i = 0; i < resultList.size(); i++) {
Map partMap = (Map)resultList.get(i);
partMap.put("IS_CSV", "Y");
}
sqlSession.close();
return resultList;
}
// Excel 파일인 경우
FileInputStream fis = new FileInputStream(path+"\\"+fileName);
Workbook workBook = null;
@@ -3983,14 +4223,27 @@ public class PartMngService extends BaseService {
SqlSession sqlSession = null;
Map sqlMap = new HashMap();
try{
List<Map<String, Object>> gridDataList = JsonUtil.JsonToList(CommonUtils.checkNull(paramMap.get("jqGrid")));
sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
String objid = CommonUtils.checkNull(paramMap.get("importPopObjid"));
String bomobjid = CommonUtils.checkNull(paramMap.get("BOM_REPORT_OBJID"));
if(!"".equals(bomobjid)){
objid = bomobjid;
}
String masterObjid = objid;
List<Map<String, Object>> gridDataList = JsonUtil.JsonToList(CommonUtils.checkNull(paramMap.get("jqGrid")));
sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
// 기존 BOM이 있으면 해당 BOM을 수정, 없으면 새로 생성
String objid = CommonUtils.checkNull(paramMap.get("importPopObjid"));
String bomobjid = CommonUtils.checkNull(paramMap.get("BOM_REPORT_OBJID"));
if(!"".equals(bomobjid)){
// 기존 BOM 수정: 기존 파트 데이터 삭제
objid = bomobjid;
Map deleteParam = new HashMap();
deleteParam.put("BOM_REPORT_OBJID", objid);
sqlSession.delete("partMng.deleteBomPartQtyByBomObjid", deleteParam);
// BOM 상태 초기화
Map resetParam = new HashMap();
resetParam.put("OBJID", objid);
sqlSession.update("partMng.resetBomReportStatus", resetParam);
}
String masterObjid = objid;
// BOM부터 만들고 프로젝트에 연결하도록 변경 - 프로젝트 유닛 정보 조회 주석처리
/*
@@ -4219,8 +4472,10 @@ public class PartMngService extends BaseService {
String parent_objid ="";
partobjMap.put("PART_NO", CommonUtils.checkNull((String)insertMap.get("PARENT_PART_NO")));
partobjMap.put("BOM_REPORT_OBJID", objid);
resultMap = (HashMap)sqlSession.selectOne("partMng.getBomPartQtyObjid", partobjMap);
if(null!=resultMap){
// selectList로 변경 (중복 품번 대응)
List<Map> resultList = sqlSession.selectList("partMng.getBomPartQtyObjid", partobjMap);
if(resultList != null && resultList.size() > 0){
resultMap = (HashMap)resultList.get(0); // 첫 번째 결과 사용
parent_objid = CommonUtils.checkNull((String)resultMap.get("child_objid"));
}
@@ -4234,13 +4489,7 @@ public class PartMngService extends BaseService {
System.out.println(" insertMap--->"+insertMap);
//BOM저장
//BOM에 구조 추가할경우 상태값 변경
if(!"".equals(bomobjid)){
insertMap.put("STATUS", "deploy");
insertMap.put("LAST_PART_OBJID", part_no);
insertMap.put("DEPLOY_USER_ID", "addBom");
insertMap.put("DEPLOY_DATE", "Y");
}
// 기존 BOM 수정 시 deploy 상태는 설정하지 않음 (초기화된 상태 유지)
sqlSession.insert("partMng.relatePartInfo", insertMap);
}//end of gridDataList