Merge pull request 'V2025111901' (#74) from V2025111901 into main

Reviewed-on: #74
This commit was merged in pull request #74.
This commit is contained in:
2025-11-24 09:49:44 +00:00
12 changed files with 1811 additions and 467 deletions

View File

@@ -898,12 +898,26 @@ public class PartMngController {
public String structureBomCopyFormPopup(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
try {
String objId = CommonUtils.checkNull((String)paramMap.get("objId"));
String partNo = CommonUtils.checkNull((String)paramMap.get("partNo"));
String partName = CommonUtils.checkNull((String)paramMap.get("partName"));
System.out.println("========== structureBomCopyFormPopup ==========");
System.out.println("objId: " + objId);
System.out.println("partNo: " + partNo);
System.out.println("partName: " + partName);
// objId를 항상 설정 (음수 포함)
request.setAttribute("TARGET_OBJID", objId);
// URL 파라미터로 전달된 품번/품명이 있으면 우선 사용
if(!"".equals(partNo) && !"".equals(partName)) {
Map<String, Object> urlParamInfo = new HashMap<>();
urlParamInfo.put("PART_NO", partNo);
urlParamInfo.put("PART_NAME", partName);
request.setAttribute("urlParamInfo", urlParamInfo);
System.out.println("URL 파라미터 사용: " + partNo + " / " + partName);
}
// objId가 유효한 경우 프로젝트 정보 조회 (음수도 유효한 OBJID임)
if(!"".equals(objId) && !"-1".equals(objId)) {
try {
@@ -929,6 +943,13 @@ public class PartMngController {
Map code_map = new HashMap();
code_map.put("rev", commonService.bizMakeOptionList("", "", "common.getRevNoselect"));
code_map.put("product_code", commonService.bizMakeOptionList("", "", "common.getProductNoselect"));
// E-BOM 목록 (기존 getActiveBomList 사용)
code_map.put("ebom_list", commonService.bizMakeOptionList("", "", "partMng.getActiveBomList"));
// M-BOM 목록 (bizMakeOptionList 사용)
code_map.put("mbom_list", commonService.bizMakeOptionList("", "", "productionplanning.getMbomListForSelect2"));
request.setAttribute("code_map", code_map);
} catch(Exception e) {

View File

@@ -1084,17 +1084,63 @@ public class ProductionPlanningController extends BaseService {
if(projectInfo != null) {
System.out.println("BOM_REPORT_OBJID: " + projectInfo.get("BOM_REPORT_OBJID"));
System.out.println("SOURCE_BOM_TYPE: " + projectInfo.get("SOURCE_BOM_TYPE"));
System.out.println("SOURCE_EBOM_OBJID: " + projectInfo.get("SOURCE_EBOM_OBJID"));
System.out.println("SOURCE_MBOM_OBJID: " + projectInfo.get("SOURCE_MBOM_OBJID"));
System.out.println("MBOM_STATUS: " + projectInfo.get("MBOM_STATUS"));
// 1. 먼저 저장된 M-BOM 데이터가 있는지 확인
String bomReportObjid = CommonUtils.checkNull(projectInfo.get("BOM_REPORT_OBJID"));
if(!"".equals(bomReportObjid)) {
Map<String, Object> bomParam = new HashMap<>();
bomParam.put("bomReportObjId", bomReportObjid);
bomParam.put("search_type", "working");
String bomReportObjid = "";
boolean isSavedMbom = false;
// 1. 먼저 저장된 M-BOM이 있는지 확인 (MBOM_HEADER 테이블)
Map<String, Object> savedMbomParam = new HashMap<>();
savedMbomParam.put("projectObjId", objId);
Map<String, Object> savedMbom = commonService.selectOne("productionplanning.getLatestMbomByProjectId", request, savedMbomParam);
if(savedMbom != null && savedMbom.get("OBJID") != null) {
// 저장된 M-BOM이 있으면 해당 M-BOM 사용
bomReportObjid = CommonUtils.checkNull(savedMbom.get("OBJID"));
isSavedMbom = true;
System.out.println("저장된 M-BOM 사용: " + bomReportObjid);
} else {
// 저장된 M-BOM이 없으면 할당된 BOM 정보 사용
String sourceBomType = CommonUtils.checkNull(projectInfo.get("SOURCE_BOM_TYPE"));
String sourceEbomObjId = CommonUtils.checkNull(projectInfo.get("SOURCE_EBOM_OBJID"));
String sourceMbomObjId = CommonUtils.checkNull(projectInfo.get("SOURCE_MBOM_OBJID"));
List<Map<String, Object>> mbomDetailList = commonService.selectList("partMng.getBOMTreeList", request, bomParam);
System.out.println("mbomDetailList size: " + (mbomDetailList != null ? mbomDetailList.size() : 0));
if("EBOM".equals(sourceBomType) && !"".equals(sourceEbomObjId)) {
bomReportObjid = sourceEbomObjId;
System.out.println("할당된 E-BOM 사용: " + bomReportObjid);
} else if("MBOM".equals(sourceBomType) && !"".equals(sourceMbomObjId)) {
bomReportObjid = sourceMbomObjId;
System.out.println("할당된 M-BOM 사용: " + bomReportObjid);
} else {
bomReportObjid = CommonUtils.checkNull(projectInfo.get("BOM_REPORT_OBJID"));
System.out.println("기존 BOM_REPORT_OBJID 사용: " + bomReportObjid);
}
}
// 2. BOM 데이터 조회
List<Map<String, Object>> mbomDetailList = null;
if(!"".equals(bomReportObjid)) {
if(isSavedMbom) {
// 저장된 M-BOM: MBOM_DETAIL 테이블에서 조회
Map<String, Object> mbomParam = new HashMap<>();
mbomParam.put("mbomHeaderObjid", bomReportObjid);
List tempList = commonService.selectList("productionplanning.getSavedMbomTreeList", request, mbomParam);
// MyBatis resultType="map"은 소문자로 반환하므로 대문자로 변환 필요
mbomDetailList = (List<Map<String, Object>>) (List<?>) CommonUtils.keyChangeUpperList(tempList);
System.out.println("저장된 M-BOM 조회 - mbomDetailList size: " + (mbomDetailList != null ? mbomDetailList.size() : 0));
} else {
// 할당된 E-BOM/M-BOM: BOM_PART_QTY 테이블에서 조회
Map<String, Object> bomParam = new HashMap<>();
bomParam.put("bomReportObjId", bomReportObjid);
bomParam.put("search_type", "working");
mbomDetailList = commonService.selectList("partMng.getBOMTreeList", request, bomParam);
System.out.println("할당된 BOM 조회 - mbomDetailList size: " + (mbomDetailList != null ? mbomDetailList.size() : 0));
}
}
if(mbomDetailList != null && !mbomDetailList.isEmpty()) {
// 저장된 M-BOM 데이터가 있으면 이를 표시
@@ -1121,8 +1167,6 @@ public class ProductionPlanningController extends BaseService {
request.setAttribute("bomTreeListJson", gson.toJson(mbomDetailList));
return "/productionplanning/mBomPopupLeft";
}
}
}
}
} catch(Exception e) {
@@ -1196,49 +1240,6 @@ public class ProductionPlanningController extends BaseService {
return result;
}
/**
* M-BOM 저장
* @param request
* @param paramMap
* @return
*/
@ResponseBody
@RequestMapping("/productionplanning/saveMbom.do")
public Map<String, Object> saveMbom(HttpServletRequest request, @RequestBody Map<String, Object> paramMap) {
Map<String, Object> resultMap = new HashMap<>();
try {
// M-BOM 데이터 저장 로직
List<Map<String, Object>> mbomData = (List<Map<String, Object>>) paramMap.get("mbomData");
String partNo = CommonUtils.checkNull(paramMap.get("partNo"));
String partName = CommonUtils.checkNull(paramMap.get("partName"));
String mbomPartNo = CommonUtils.checkNull(paramMap.get("mbomPartNo")); // 기존 M-BOM 품번
boolean isUpdate = paramMap.get("isUpdate") != null && (Boolean)paramMap.get("isUpdate"); // 수정 여부
if(mbomData == null || mbomData.isEmpty()) {
resultMap.put("result", "fail");
resultMap.put("message", "저장할 데이터가 없습니다.");
return resultMap;
}
// M-BOM 저장 서비스 호출
// isUpdate가 true이면 기존 M-BOM 품번 유지, false이면 새로 생성
int saveResult = productionPlanningService.saveMbom(request, mbomData, partNo, partName, mbomPartNo, isUpdate);
if(saveResult > 0) {
resultMap.put("result", "success");
resultMap.put("message", isUpdate ? "M-BOM이 수정되었습니다." : "M-BOM이 저장되었습니다.");
} else {
resultMap.put("result", "fail");
resultMap.put("message", "저장에 실패했습니다.");
}
} catch(Exception e) {
e.printStackTrace();
resultMap.put("result", "fail");
resultMap.put("message", "오류가 발생했습니다: " + e.getMessage());
}
return resultMap;
}
/**
* 품번으로 최신 M-BOM 조회 (Machine 이외 제품용)
* @param request
@@ -1279,16 +1280,21 @@ public class ProductionPlanningController extends BaseService {
public Map<String, Object> getMbomHistory(HttpServletRequest request, @RequestParam Map<String, Object> paramMap) {
Map<String, Object> resultMap = new HashMap<>();
try {
String mbomPartNo = CommonUtils.checkNull(paramMap.get("mbomPartNo"));
String projectObjId = CommonUtils.checkNull(paramMap.get("projectObjId"));
if("".equals(mbomPartNo)) {
if("".equals(projectObjId)) {
resultMap.put("historyList", new ArrayList<>());
return resultMap;
}
// M-BOM 이력 조회 (PART_BOM_REPORT 테이블에서 동일 PART_NO로 조회)
System.out.println("========== getMbomHistory ==========");
System.out.println("projectObjId: " + projectObjId);
// M-BOM 이력 조회 (PROJECT_OBJID로 조회)
List<Map<String, Object>> historyList = commonService.selectList("productionplanning.getMbomHistory", request, paramMap);
System.out.println("조회된 이력 수: " + (historyList != null ? historyList.size() : 0));
resultMap.put("historyList", historyList != null ? historyList : new ArrayList<>());
} catch(Exception e) {
e.printStackTrace();
@@ -1357,4 +1363,170 @@ public class ProductionPlanningController extends BaseService {
}
return resultMap;
}
/**
* BOM 할당 정보 저장 (M-BOM 기준 설정)
* PROJECT_MGMT 테이블에 E-BOM 또는 M-BOM 할당 정보만 저장
* 실제 M-BOM 생성은 M-BOM 상세 팝업에서 수행
*/
@RequestMapping("/productionplanning/saveBomAssignment.do")
@ResponseBody
public Map<String, Object> saveBomAssignment(HttpServletRequest request, @RequestBody Map<String, Object> paramMap) {
Map<String, Object> resultMap = new HashMap<>();
try {
System.out.println("========== saveBomAssignment ==========");
System.out.println("projectObjId: " + paramMap.get("projectObjId"));
System.out.println("sourceBomType: " + paramMap.get("sourceBomType"));
System.out.println("sourceBomObjId: " + paramMap.get("sourceBomObjId"));
System.out.println("partNo: " + paramMap.get("partNo"));
System.out.println("partName: " + paramMap.get("partName"));
// PROJECT_MGMT 테이블 업데이트
boolean updateResult = productionPlanningService.saveBomAssignment(request, paramMap);
if(updateResult) {
resultMap.put("result", "success");
resultMap.put("message", "M-BOM 기준 정보가 저장되었습니다.");
} else {
resultMap.put("result", "fail");
resultMap.put("message", "저장에 실패했습니다.");
}
} catch(Exception e) {
e.printStackTrace();
resultMap.put("result", "error");
resultMap.put("message", "오류가 발생했습니다: " + e.getMessage());
}
return resultMap;
}
@RequestMapping("/productionplanning/getMbomAssignmentInfo.do")
@ResponseBody
public Map<String, Object> getMbomAssignmentInfo(HttpServletRequest request, @RequestParam Map<String, Object> paramMap) {
Map<String, Object> resultMap = new HashMap<>();
try {
String projectObjId = CommonUtils.checkNull((String)paramMap.get("projectObjId"));
System.out.println("========== getMbomAssignmentInfo ==========");
System.out.println("projectObjId: " + projectObjId);
// PROJECT_MGMT에서 BOM 할당 정보 조회
Map<String, Object> assignmentInfo = productionPlanningService.getMbomAssignment(projectObjId);
if(assignmentInfo != null && !assignmentInfo.isEmpty()) {
resultMap.putAll(assignmentInfo);
}
} catch(Exception e) {
e.printStackTrace();
resultMap.put("error", "오류가 발생했습니다: " + e.getMessage());
}
return resultMap;
}
/**
* 프로젝트별 최신 M-BOM 조회
*/
@RequestMapping("/productionplanning/getLatestMbomByProjectId.do")
@ResponseBody
public Map<String, Object> getLatestMbomByProjectId(HttpServletRequest request, @RequestParam Map<String, Object> paramMap) {
Map<String, Object> resultMap = new HashMap<>();
try {
String projectObjId = CommonUtils.checkNull((String)paramMap.get("projectObjId"));
paramMap.put("projectObjId", projectObjId);
// MBOM_HEADER에서 해당 프로젝트의 최신 M-BOM 조회
Map<String, Object> savedMbom = commonService.selectOne("productionplanning.getLatestMbomByProjectId", request, paramMap);
if(savedMbom != null && !savedMbom.isEmpty()) {
resultMap = (Map<String, Object>) CommonUtils.toUpperCaseMapKey(savedMbom);
}
} catch(Exception e) {
e.printStackTrace();
resultMap.put("error", "오류가 발생했습니다: " + e.getMessage());
}
return resultMap;
}
/**
* M-BOM 저장
* 최초 저장 시: M-BOM 품번 생성 + 데이터 저장
* 수정 저장 시: 동일 품번으로 업데이트 + 이력 저장
*/
@RequestMapping("/productionplanning/saveMbom.do")
@ResponseBody
public Map<String, Object> saveMbom(HttpServletRequest request, @RequestBody Map<String, Object> paramMap) {
Map<String, Object> resultMap = new HashMap<>();
try {
System.out.println("========== saveMbom ==========");
String projectObjId = CommonUtils.checkNull((String)paramMap.get("projectObjId"));
String mbomPartNo = CommonUtils.checkNull((String)paramMap.get("mbomPartNo"));
boolean isUpdate = "true".equals(String.valueOf(paramMap.get("isUpdate")));
System.out.println("projectObjId: " + projectObjId);
System.out.println("mbomPartNo: " + mbomPartNo);
System.out.println("isUpdate: " + isUpdate);
// PROJECT_MGMT에서 할당 정보 조회
Map<String, Object> assignment = (Map<String, Object>) commonService.selectOne("productionplanning.getMbomAssignment", request, paramMap);
if(assignment == null || assignment.isEmpty()) {
resultMap.put("result", "fail");
resultMap.put("message", "M-BOM 기준 정보가 없습니다. BOM 복사 팝업에서 먼저 기준을 설정해주세요.");
return resultMap;
}
String sourceBomType = CommonUtils.checkNull(assignment.get("SOURCE_BOM_TYPE"));
String sourceBomObjId = "";
String baseBomPartNo = "";
if("EBOM".equals(sourceBomType)) {
sourceBomObjId = CommonUtils.checkNull(assignment.get("SOURCE_EBOM_OBJID"));
baseBomPartNo = CommonUtils.checkNull(assignment.get("EBOM_PART_NO"));
} else if("MBOM".equals(sourceBomType)) {
sourceBomObjId = CommonUtils.checkNull(assignment.get("SOURCE_MBOM_OBJID"));
baseBomPartNo = CommonUtils.checkNull(assignment.get("MBOM_NO"));
}
if(sourceBomObjId.isEmpty()) {
resultMap.put("result", "fail");
resultMap.put("message", "기준 BOM 정보가 올바르지 않습니다.");
return resultMap;
}
// M-BOM 품번 생성 또는 사용
String finalMbomNo = "";
if(!isUpdate || mbomPartNo.isEmpty()) {
// 최초 저장: M-BOM 품번 생성
finalMbomNo = productionPlanningService.generateMbomNo(request, sourceBomType, baseBomPartNo);
System.out.println("생성된 M-BOM 품번: " + finalMbomNo);
} else {
// 수정 저장: 기존 품번 사용
finalMbomNo = mbomPartNo;
System.out.println("기존 M-BOM 품번 사용: " + finalMbomNo);
}
paramMap.put("mbomNo", finalMbomNo);
paramMap.put("sourceBomType", sourceBomType);
paramMap.put("sourceBomObjId", sourceBomObjId);
paramMap.put("isUpdate", isUpdate);
// M-BOM 저장
boolean saveResult = productionPlanningService.saveMbom(request, paramMap);
if(saveResult) {
resultMap.put("result", "success");
resultMap.put("message", isUpdate ? "M-BOM이 수정되었습니다." : "M-BOM이 생성되었습니다.");
resultMap.put("mbomNo", finalMbomNo);
} else {
resultMap.put("result", "fail");
resultMap.put("message", "M-BOM 저장에 실패했습니다.");
}
} catch(Exception e) {
e.printStackTrace();
resultMap.put("result", "error");
resultMap.put("message", "오류가 발생했습니다: " + e.getMessage());
}
return resultMap;
}
}

View File

@@ -8099,4 +8099,18 @@ SELECT PM.OBJID
)
</update>
<!-- E-BOM 목록 조회 (셀렉트박스용) -->
<select id="getEbomList" parameterType="map" resultType="map">
SELECT
OBJID,
PART_NO,
PART_NAME,
REV,
SPEC_NAME,
REGDATE
FROM PART_BOM_REPORT
WHERE STATUS = 'Y'
ORDER BY REGDATE DESC, PART_NO
</select>
</mapper>

View File

@@ -2944,29 +2944,47 @@
LIMIT 1),
''
) AS EBOM_REGDATE,
COALESCE(PM.MBOM_STATUS, '') AS MBOM_STATUS,
-- M-BOM 상태: 새 MBOM_HEADER 테이블에서 조회
COALESCE(
(SELECT PBR.PART_NO
FROM PART_BOM_REPORT PBR
WHERE PBR.OBJID::VARCHAR = PM.BOM_REPORT_OBJID
AND PM.MBOM_STATUS = 'Y'
LIMIT 1),
(SELECT
CASE
WHEN COUNT(*) > 0 THEN 'Y'
ELSE COALESCE(PM.MBOM_STATUS, '')
END
FROM MBOM_HEADER MH
WHERE MH.PROJECT_OBJID = PM.OBJID::VARCHAR
AND MH.STATUS = 'Y'
LIMIT 1),
COALESCE(PM.MBOM_STATUS, '')
) AS MBOM_STATUS,
-- M-BOM 품번: 새 MBOM_HEADER 테이블에서 조회
COALESCE(
(SELECT MH.MBOM_NO
FROM MBOM_HEADER MH
WHERE MH.PROJECT_OBJID = PM.OBJID::VARCHAR
AND MH.STATUS = 'Y'
ORDER BY MH.REGDATE DESC
LIMIT 1),
''
) AS MBOM_PART_NO,
'1.0' AS MBOM_VERSION,
-- M-BOM 저장일: 새 MBOM_HEADER 테이블에서 조회
COALESCE(
(SELECT TO_CHAR(PBR.REGDATE, 'YYYY-MM-DD')
FROM PART_BOM_REPORT PBR
WHERE PBR.OBJID::VARCHAR = PM.BOM_REPORT_OBJID
AND PM.MBOM_STATUS = 'Y'
LIMIT 1),
(SELECT TO_CHAR(MH.REGDATE, 'YYYY-MM-DD')
FROM MBOM_HEADER MH
WHERE MH.PROJECT_OBJID = PM.OBJID::VARCHAR
AND MH.STATUS = 'Y'
ORDER BY MH.REGDATE DESC
LIMIT 1),
TO_CHAR(PM.REGDATE, 'YYYY-MM-DD')
) AS MBOM_REGDATE
FROM
PROJECT_MGMT PM
LEFT JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
LEFT OUTER JOIN CONTRACT_ITEM CI ON PM.CONTRACT_OBJID = CI.CONTRACT_OBJID
AND PM.PART_OBJID = CI.PART_OBJID
-- CONTRACT_ITEM과 LEFT JOIN하여 품목별로 펼쳐서 보이기
LEFT JOIN CONTRACT_ITEM CI ON CM.OBJID::VARCHAR = CI.CONTRACT_OBJID
-- LEFT JOIN CONTRACT_ITEM CI ON CM.OBJID::VARCHAR = CI.CONTRACT_OBJID
AND CI.STATUS = 'ACTIVE'
WHERE 1=1
AND PM.PROJECT_NO IS NOT NULL
@@ -3024,6 +3042,10 @@
PM.BOM_REPORT_OBJID,
PM.PART_NO,
PM.PART_NAME,
PM.SOURCE_BOM_TYPE,
PM.SOURCE_EBOM_OBJID,
PM.SOURCE_MBOM_OBJID,
PM.QUANTITY,
COALESCE(
(SELECT PBR.PART_NO
FROM PART_BOM_REPORT PBR
@@ -3268,21 +3290,6 @@
BPQ.SEQ
</select>
<!-- M-BOM 품번 최대 순번 조회 (같은 날짜) -->
<select id="getMaxMbomSeqByDate" parameterType="map" resultType="int">
SELECT
COALESCE(MAX(
CAST(
SUBSTRING(PART_NO FROM '.+-([0-9]+)$') AS INTEGER
)
), 0) AS MAX_SEQ
FROM
PART_BOM_REPORT
WHERE
PART_NO LIKE #{prefix} || '%'
AND STATUS = 'Y'
</select>
<!-- 품번으로 최신 M-BOM 조회 (Machine 이외 제품용) -->
<select id="getLatestMbomByPartNo" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT
@@ -3314,85 +3321,26 @@
<!-- M-BOM 이력 조회 -->
<select id="getMbomHistory" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT
PBR.OBJID,
PBR.PART_NO AS MBOM_PART_NO,
TO_CHAR(PBR.REGDATE, 'YYYY-MM-DD HH24:MI:SS') AS REGDATE,
PBR.REGUSER,
COALESCE(PBR.REMARK, '') AS REMARK,
PBR.STATUS
MH.OBJID,
MH.MBOM_HEADER_OBJID,
MH.CHANGE_TYPE,
MH.CHANGE_DESCRIPTION,
MH.BEFORE_DATA,
MH.AFTER_DATA,
MH.CHANGE_USER,
TO_CHAR(MH.CHANGE_DATE, 'YYYY-MM-DD HH24:MI:SS') AS CHANGE_DATE,
-- MBOM_HEADER 정보 조인
MHD.MBOM_NO AS MBOM_PART_NO,
MHD.PROJECT_OBJID,
TO_CHAR(MHD.REGDATE, 'YYYY-MM-DD HH24:MI:SS') AS REGDATE
FROM
PART_BOM_REPORT PBR
MBOM_HISTORY MH
INNER JOIN MBOM_HEADER MHD ON MH.MBOM_HEADER_OBJID = MHD.OBJID
WHERE
PBR.PART_NO = #{mbomPartNo}
ORDER BY PBR.REGDATE DESC
MHD.PROJECT_OBJID = #{projectObjId}
ORDER BY MH.CHANGE_DATE DESC
</select>
<!-- M-BOM 헤더 저장 -->
<insert id="insertMbomHeader" parameterType="map">
<selectKey keyProperty="OBJID" resultType="string" order="BEFORE">
SELECT REPLACE(UUID(),'-','') FROM DUAL
</selectKey>
INSERT INTO MBOM_HEADER (
OBJID,
MBOM_NO,
PART_NO,
PART_NAME,
SAVE_DATE,
CREATE_USER,
CREATE_DATE,
UPDATE_USER,
UPDATE_DATE
) VALUES (
#{OBJID},
CONCAT('MBOM-', DATE_FORMAT(NOW(), '%Y%m%d%H%i%s')),
#{PART_NO},
#{PART_NAME},
NOW(),
#{CREATE_USER},
NOW(),
#{UPDATE_USER},
NOW()
)
</insert>
<!-- M-BOM 상세 저장 -->
<insert id="insertMbomDetail" parameterType="map">
<selectKey keyProperty="OBJID" resultType="string" order="BEFORE">
SELECT REPLACE(UUID(),'-','') FROM DUAL
</selectKey>
INSERT INTO MBOM_DETAIL (
OBJID,
MBOM_HEADER_OBJID,
PART_NO,
PART_NAME,
QTY,
LEVEL,
REVISION,
SPEC,
PRODUCT_NAME,
STATUS_NAME,
CREATE_USER,
CREATE_DATE,
UPDATE_USER,
UPDATE_DATE
) VALUES (
#{OBJID},
#{MBOM_HEADER_OBJID},
#{PART_NO},
#{PART_NAME},
#{QTY},
#{LEVEL},
#{REVISION},
#{SPEC},
#{PRODUCT_NAME},
#{STATUS_NAME},
#{CREATE_USER},
NOW(),
#{UPDATE_USER},
NOW()
)
</insert>
<!-- E-BOM을 M-BOM으로 복사 -->
<insert id="saveMbomFromEbom" parameterType="map">
/* productionplanning.saveMbomFromEbom - E-BOM을 M-BOM으로 복사 */
@@ -3463,4 +3411,312 @@
PART_NAME = #{PART_NAME}
WHERE OBJID::VARCHAR = #{PROJECT_OBJID}
</insert>
<!-- M-BOM 관련 쿼리 -->
<!-- BOM 할당 정보 저장 (M-BOM 기준 설정) -->
<update id="saveBomAssignment" parameterType="map">
UPDATE PROJECT_MGMT
SET
SOURCE_BOM_TYPE = #{sourceBomType},
SOURCE_EBOM_OBJID = CASE WHEN #{sourceBomType} = 'EBOM' THEN #{sourceBomObjId} ELSE NULL END,
SOURCE_MBOM_OBJID = CASE WHEN #{sourceBomType} = 'MBOM' THEN #{sourceBomObjId} ELSE NULL END
WHERE OBJID::VARCHAR = #{projectObjId}
</update>
<!-- 프로젝트의 최신 저장된 M-BOM 조회 -->
<select id="getLatestMbomByProjectId" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT
OBJID,
MBOM_NO,
SOURCE_BOM_TYPE,
SOURCE_EBOM_OBJID,
SOURCE_MBOM_OBJID,
PROJECT_OBJID,
STATUS,
REGDATE
FROM MBOM_HEADER
WHERE PROJECT_OBJID = #{projectObjId}
AND STATUS = 'Y'
ORDER BY REGDATE DESC
LIMIT 1
</select>
<!-- M-BOM 할당 정보 조회 -->
<select id="getMbomAssignment" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT
PM.OBJID,
PM.SOURCE_BOM_TYPE,
PM.SOURCE_EBOM_OBJID,
PM.SOURCE_MBOM_OBJID,
PM.PART_NO,
PM.PART_NAME,
PM.PRODUCT,
CODE_NAME(PM.PRODUCT) AS PRODUCT_NAME,
-- E-BOM 정보
CASE WHEN PM.SOURCE_BOM_TYPE = 'EBOM' THEN
(SELECT PART_NO FROM PART_BOM_REPORT WHERE OBJID = PM.SOURCE_EBOM_OBJID)
END AS EBOM_PART_NO,
CASE WHEN PM.SOURCE_BOM_TYPE = 'EBOM' THEN
(SELECT PART_NAME FROM PART_BOM_REPORT WHERE OBJID = PM.SOURCE_EBOM_OBJID)
END AS EBOM_PART_NAME,
-- M-BOM 정보
CASE WHEN PM.SOURCE_BOM_TYPE = 'MBOM' THEN
(SELECT MBOM_NO FROM MBOM_HEADER WHERE OBJID = PM.SOURCE_MBOM_OBJID)
END AS MBOM_NO,
CASE WHEN PM.SOURCE_BOM_TYPE = 'MBOM' THEN
(SELECT PART_NAME FROM MBOM_HEADER WHERE OBJID = PM.SOURCE_MBOM_OBJID)
END AS MBOM_PART_NAME
FROM PROJECT_MGMT PM
WHERE PM.OBJID::VARCHAR = #{projectObjId}
</select>
<!-- M-BOM 품번 생성 - 같은 날짜의 최대 순번 조회 -->
<select id="getMaxMbomSeqByDate" parameterType="map" resultType="int">
SELECT COALESCE(MAX(
CAST(
SUBSTRING(
MBOM_NO FROM LENGTH(MBOM_NO) - 1 FOR 2
) AS INTEGER
)
), 0) AS MAX_SEQ
FROM MBOM_HEADER
WHERE MBOM_NO LIKE #{mbomPrefix} || '%'
AND REGDATE::DATE = CURRENT_DATE
</select>
<!-- M-BOM 품번으로 조회 -->
<select id="getMbomByNo" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT * FROM MBOM_HEADER
WHERE PROJECT_OBJID = #{projectObjId}
ORDER BY REGDATE DESC
LIMIT 1
</select>
<!-- MBOM_HEADER 삽입 -->
<insert id="insertMbomHeader" parameterType="map">
INSERT INTO MBOM_HEADER (
OBJID, MBOM_NO, SOURCE_BOM_TYPE, SOURCE_EBOM_OBJID, SOURCE_MBOM_OBJID,
PROJECT_OBJID, PART_NO, PART_NAME, STATUS, MBOM_STATUS,
WRITER, REGDATE
) VALUES (
#{objid}, #{mbomNo}, #{sourceBomType}, #{sourceEbomObjid}, #{sourceMbomObjid},
#{projectObjId}, #{partNo}, #{partName}, 'Y', 'DRAFT',
#{sessionUserId}, NOW()
)
</insert>
<!-- MBOM_DETAIL 삽입 -->
<insert id="insertMbomDetail" parameterType="map">
INSERT INTO MBOM_DETAIL (
OBJID, MBOM_HEADER_OBJID, PARENT_OBJID, CHILD_OBJID, SEQ, LEVEL,
PART_OBJID, PART_NO, PART_NAME, QTY, UNIT,
SUPPLY_TYPE, MAKE_OR_BUY,
RAW_MATERIAL_PART_NO, RAW_MATERIAL_SPEC, RAW_MATERIAL, RAW_MATERIAL_SIZE,
PROCESSING_VENDOR, PROCESSING_DEADLINE, GRINDING_DEADLINE,
REQUIRED_QTY, ORDER_QTY, PRODUCTION_QTY, STOCK_QTY, SHORTAGE_QTY,
VENDOR, UNIT_PRICE, TOTAL_PRICE, CURRENCY, LEAD_TIME, MIN_ORDER_QTY,
STATUS, WRITER, REGDATE, REMARK
) VALUES (
#{objid}, #{mbomHeaderObjid}, #{parentObjid}, #{childObjid}, #{seq}, #{level},
#{partObjid}, #{partNo}, #{partName}, #{qty}, #{unit},
#{supplyType}, #{makeOrBuy},
#{rawMaterialPartNo}, #{rawMaterialSpec}, #{rawMaterial}, #{rawMaterialSize},
#{processingVendor}, #{processingDeadline}, #{grindingDeadline},
#{requiredQty}, #{orderQty}, #{productionQty}, #{stockQty}, #{shortageQty},
#{vendor}, #{unitPrice}, #{totalPrice}, #{currency}, #{leadTime}, #{minOrderQty},
'ACTIVE', #{sessionUserId}, NOW(), #{remark}
)
</insert>
<!-- MBOM_HEADER 업데이트 -->
<update id="updateMbomHeader" parameterType="map">
UPDATE MBOM_HEADER
SET
PART_NO = #{partNo},
PART_NAME = #{partName},
EDITER = #{sessionUserId},
EDIT_DATE = NOW()
WHERE OBJID = #{mbomHeaderObjid}
</update>
<!-- MBOM_DETAIL 삭제 (수정 시 기존 데이터 삭제 후 재삽입) -->
<delete id="deleteMbomDetail" parameterType="map">
DELETE FROM MBOM_DETAIL
WHERE MBOM_HEADER_OBJID = #{mbomHeaderObjid}
</delete>
<!-- MBOM_HISTORY 삽입 -->
<insert id="insertMbomHistory" parameterType="map">
INSERT INTO MBOM_HISTORY (
OBJID, MBOM_HEADER_OBJID, CHANGE_TYPE, CHANGE_DESCRIPTION,
BEFORE_DATA, AFTER_DATA, CHANGE_USER, CHANGE_DATE
) VALUES (
#{objid}, #{mbomHeaderObjid}, #{changeType}, #{changeDescription},
#{beforeData}::JSONB, #{afterData}::JSONB, #{sessionUserId}, NOW()
)
</insert>
<!-- PROJECT_MGMT MBOM_STATUS 업데이트 -->
<update id="updateProjectMbomStatus" parameterType="map">
UPDATE PROJECT_MGMT
SET
MBOM_STATUS = 'Y',
MBOM_WRITER = #{sessionUserId},
MBOM_REGDATE = NOW()
WHERE OBJID::VARCHAR = #{projectObjId}
</update>
<!-- M-BOM 목록 조회 (셀렉트박스용) -->
<select id="getMbomListForSelect" parameterType="map" resultType="map">
SELECT
OBJID,
MBOM_NO,
SOURCE_BOM_TYPE,
REGDATE,
STATUS
FROM MBOM_HEADER
WHERE STATUS = 'Y'
ORDER BY REGDATE DESC, MBOM_NO
</select>
<!-- M-BOM 목록 (bizMakeOptionList용) -->
<select id="getMbomListForSelect2" parameterType="map" resultType="map">
SELECT
OBJID AS CODE,
COALESCE(MBOM_NO, '') ||
CASE WHEN SOURCE_BOM_TYPE IS NOT NULL AND SOURCE_BOM_TYPE != '' THEN ' (' || SOURCE_BOM_TYPE || ')' ELSE '' END AS NAME
FROM MBOM_HEADER
WHERE STATUS = 'Y'
ORDER BY REGDATE DESC, MBOM_NO
</select>
<!-- M-BOM 상세 리스트 조회 (이력용) -->
<select id="getMbomDetailList" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT
OBJID,
MBOM_HEADER_OBJID,
PARENT_OBJID,
CHILD_OBJID,
SEQ,
LEVEL,
PART_OBJID,
PART_NO,
PART_NAME,
QTY,
UNIT,
SUPPLY_TYPE,
MAKE_OR_BUY,
RAW_MATERIAL_PART_NO,
RAW_MATERIAL_SPEC,
RAW_MATERIAL,
RAW_MATERIAL_SIZE,
PROCESSING_VENDOR,
PROCESSING_DEADLINE,
GRINDING_DEADLINE,
REQUIRED_QTY,
ORDER_QTY,
PRODUCTION_QTY,
STOCK_QTY,
SHORTAGE_QTY,
VENDOR,
UNIT_PRICE,
TOTAL_PRICE,
CURRENCY,
LEAD_TIME,
MIN_ORDER_QTY,
STATUS,
REMARK
FROM
MBOM_DETAIL
WHERE
MBOM_HEADER_OBJID = #{mbomHeaderObjid}
AND STATUS = 'ACTIVE'
ORDER BY SEQ
</select>
<!-- 저장된 M-BOM 트리 조회 (MBOM_DETAIL 테이블) -->
<select id="getSavedMbomTreeList" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT
MD.OBJID,
MD.MBOM_HEADER_OBJID AS BOM_REPORT_OBJID,
MD.PARENT_OBJID,
MD.CHILD_OBJID,
MD.SEQ,
MD.LEVEL,
MD.PART_OBJID,
MD.PART_NO,
MD.PART_NAME,
MD.QTY,
MD.QTY AS QTY_TEMP,
MD.QTY AS ITEM_QTY,
MD.UNIT,
-- 생산 정보
MD.SUPPLY_TYPE,
MD.MAKE_OR_BUY,
MD.RAW_MATERIAL_PART_NO AS RAW_MATERIAL_NO, -- JSP 그리드 필드명에 맞춤
MD.RAW_MATERIAL_SPEC,
MD.RAW_MATERIAL,
MD.RAW_MATERIAL_SIZE AS SIZE, -- JSP 그리드 필드명에 맞춤
MD.PROCESSING_VENDOR,
MD.PROCESSING_DEADLINE,
MD.GRINDING_DEADLINE,
MD.REQUIRED_QTY,
MD.ORDER_QTY,
MD.PRODUCTION_QTY,
MD.STOCK_QTY,
MD.SHORTAGE_QTY,
-- 구매 정보
MD.VENDOR,
MD.UNIT_PRICE,
MD.TOTAL_PRICE,
MD.CURRENCY,
MD.LEAD_TIME,
MD.MIN_ORDER_QTY,
-- 기타
MD.STATUS,
MD.WRITER,
TO_CHAR(MD.REGDATE, 'YYYY-MM-DD HH24:MI:SS') AS REGDATE,
MD.EDITER,
CASE WHEN MD.EDIT_DATE IS NOT NULL THEN TO_CHAR(MD.EDIT_DATE, 'YYYY-MM-DD HH24:MI:SS') ELSE NULL END AS EDIT_DATE,
MD.REMARK,
-- E-BOM 호환을 위한 추가 컬럼
MD.PART_OBJID AS LAST_PART_OBJID,
MD.PART_OBJID AS BOM_LAST_PART_OBJID,
NULL AS PARENT_PART_NO,
NULL AS CONTRACT_OBJID,
0 AS SUB_PART_CNT,
CASE WHEN MD.LEVEL = 1 THEN MD.OBJID ELSE NULL END AS ROOT_OBJID,
CASE WHEN MD.LEVEL = 1 THEN MD.OBJID ELSE NULL END AS SUB_ROOT_OBJID,
1 AS LEAF,
-- PART_MNG 테이블에서 추가 정보 조회
PM.SPEC,
PM.MATERIAL,
PM.WEIGHT,
PM.PART_TYPE,
PM.REMARK,
PM.REVISION,
PM.MAKER,
PM.THICKNESS,
PM.WIDTH,
PM.HEIGHT,
PM.OUT_DIAMETER,
PM.IN_DIAMETER,
PM.LENGTH,
PM.SOURCING_CODE,
PM.HEAT_TREATMENT_HARDNESS,
PM.HEAT_TREATMENT_METHOD,
PM.SURFACE_TREATMENT,
(SELECT CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = PM.UNIT) AS UNIT_TITLE,
(SELECT CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = PM.PART_TYPE) AS PART_TYPE_TITLE,
(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('3D_CAD')) AS CU01_CNT,
(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_DRAWING_CAD')) AS CU02_CNT,
(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_PDF_CAD')) AS CU03_CNT
FROM MBOM_DETAIL MD
LEFT JOIN PART_MNG PM ON MD.PART_OBJID = PM.OBJID
WHERE MD.MBOM_HEADER_OBJID = #{mbomHeaderObjid}
AND MD.STATUS = 'ACTIVE'
ORDER BY MD.SEQ
</select>
</mapper>