제품구분이 Machine 이외인 경우 동일 품번이 수주되었을 경우 저장되어 있는 M-BOM을 자동으로 가져오기!

This commit is contained in:
2025-11-25 18:30:44 +09:00
parent 884dc44dd1
commit a3d0d09355
6 changed files with 241 additions and 22 deletions

View File

@@ -107,13 +107,23 @@ $(function(){
var sourceBomType = "${info.SOURCE_BOM_TYPE}";
var sourceEbomObjId = "${info.SOURCE_EBOM_OBJID}";
var sourceMbomObjId = "${info.SOURCE_MBOM_OBJID}";
var productCode = "${info.PRODUCT_CODE}";
console.log("할당된 BOM 정보:", {
sourceBomType: sourceBomType,
sourceEbomObjId: sourceEbomObjId,
sourceMbomObjId: sourceMbomObjId
sourceMbomObjId: sourceMbomObjId,
productCode: productCode
});
// Machine 이외 제품: M-BOM 템플릿 자동 로드
<c:if test="${not empty mbomTemplateDetails}">
console.log("M-BOM 템플릿 발견 - 자동 로드 시작");
setTimeout(function() {
fn_loadMbomTemplate();
}, 500);
</c:if>
// Controller에서 이미 데이터를 로드하여 JSP에 전달하므로 자동 조회 불필요
// setTimeout(function() {
// fn_searchMbom();
@@ -197,6 +207,59 @@ function fn_applyBulkDeadline() {
}
}
// M-BOM 템플릿 로드 (Machine 이외 제품)
function fn_loadMbomTemplate() {
console.log("fn_loadMbomTemplate 호출됨");
// 템플릿 데이터를 JSP에서 받아옴
var templateDetails = [];
<c:if test="${not empty mbomTemplateDetails}">
<c:forEach items="${mbomTemplateDetails}" var="item">
templateDetails.push({
OBJID: '', // 새로 생성될 ID
CHILD_OBJID: '${item.CHILD_OBJID}', // 템플릿의 CHILD_OBJID 유지 (트리 구조용)
PARENT_OBJID: '${item.PARENT_OBJID}',
SEQ: ${item.SEQ},
LEVEL: ${item.LEVEL},
PART_OBJID: '${item.PART_OBJID}',
PART_NO: '${item.PART_NO}',
PART_NAME: '${item.PART_NAME}',
QTY: ${item.QTY},
ITEM_QTY: ${item.QTY}, // 항목수량
QTY_TEMP: ${item.QTY},
UNIT: '${item.UNIT}',
SUPPLY_TYPE: '${item.SUPPLY_TYPE}',
MAKE_OR_BUY: '${item.MAKE_OR_BUY}',
RAW_MATERIAL: '${item.RAW_MATERIAL}',
RAW_MATERIAL_SPEC: '${item.RAW_MATERIAL_SPEC}',
SIZE: '${item.RAW_MATERIAL_SIZE}',
RAW_MATERIAL_NO: '${item.RAW_MATERIAL_PART_NO}',
PROCESSING_VENDOR: '${item.PROCESSING_VENDOR}',
PROCESSING_DEADLINE: '${item.PROCESSING_DEADLINE}',
GRINDING_DEADLINE: '${item.GRINDING_DEADLINE}',
REQUIRED_QTY: ${item.REQUIRED_QTY != null ? item.REQUIRED_QTY : 0},
// ORDER_QTY, PRODUCTION_QTY는 명시적으로 설정하지 않음 (undefined)
// 이렇게 하면 formatter에서 자동 계산됨
REMARK: '${item.REMARK}',
STATUS: 'ACTIVE'
});
</c:forEach>
</c:if>
console.log("템플릿 데이터 개수:", templateDetails.length);
// 왼쪽 프레임에 데이터 로드
var bottomFrame = parent.frames[1];
var leftFrame = bottomFrame ? bottomFrame.frames['leftFrame'] : null;
if(leftFrame && leftFrame._tabulGrid) {
leftFrame._tabulGrid.setData(templateDetails);
console.log("템플릿 데이터 로드 완료");
} else {
console.error("왼쪽 프레임 또는 그리드를 찾을 수 없습니다.");
}
}
// M-BOM 조회
function fn_searchMbom() {
var partNo = $("#search_part_no").val().trim();

View File

@@ -384,13 +384,26 @@ function fn_checkAssignmentAndOpenMbom(projectObjId) {
success: function(response) {
console.log("BOM 할당 정보:", response);
// Machine(0000928) 이외 제품인지 확인
var productCode = response ? response.PRODUCT_CODE : null;
var partNo = response ? response.PART_NO : null;
if(!response || !response.SOURCE_BOM_TYPE) {
// 할당 정보가 없는 경우
Swal.fire({
title: '알림',
text: 'BOM 할당 정보가 없습니다.\nBOM 복사 버튼을 통해 먼저 BOM을 할당해주세요.',
icon: 'info'
});
// Machine 이외 제품이고 품번이 있으면 템플릿 확인
if(productCode && productCode !== '0000928' && partNo) {
console.log("Machine 이외 제품 - 템플릿 확인 후 팝업 열기");
// 템플릿이 있을 수 있으므로 팝업 열기
fn_openMBomFormPopup(projectObjId);
} else {
// Machine 제품이거나 품번이 없으면 할당 필요
Swal.fire({
title: '알림',
text: 'BOM 할당 정보가 없습니다.\nBOM 복사 버튼을 통해 먼저 BOM을 할당해주세요.',
icon: 'info'
});
}
return;
}

View File

@@ -397,6 +397,10 @@ function fn_initGrid() {
var data = cell.getRow().getData();
var itemQty = parseFloat(data.ITEM_QTY) || 0;
var orderQty = itemQty * projectQuantity;
// 실제 데이터에도 저장 (getMbomTreeData에서 사용)
cell.getRow().update({ORDER_QTY: orderQty}, false);
return orderQty.toLocaleString();
}
},
@@ -421,12 +425,16 @@ function fn_initGrid() {
step: 1
},
formatter: function(cell) {
// 초기값은 소재발주수량 (항목수량 × 프로젝트 수주수량)
// 초기값은 소재발주수량과 동일
var value = cell.getValue();
if(!value) {
if(value === undefined || value === null || value === '' || value === 0) {
var data = cell.getRow().getData();
var itemQty = parseFloat(data.ITEM_QTY) || 0;
value = itemQty * projectQuantity;
// ORDER_QTY 값을 그대로 사용
value = data.ORDER_QTY || 0;
// 실제 데이터에도 저장 (getMbomTreeData에서 사용)
cell.getRow().update({PRODUCTION_QTY: value}, false);
}
return Number(value).toLocaleString();
}
@@ -704,7 +712,15 @@ function fn_searchMbom(searchParams) {
console.log("M-BOM 조회 결과:", data);
if(data && data.list) {
console.log("데이터 개수:", data.list.length);
_tabulGrid.setData(data.list);
// ORDER_QTY, PRODUCTION_QTY 제거하여 formatter에서 재계산되도록
var processedData = data.list.map(function(item) {
delete item.ORDER_QTY;
delete item.PRODUCTION_QTY;
return item;
});
_tabulGrid.setData(processedData);
} else {
console.log("데이터 없음");
_tabulGrid.setData([]);

View File

@@ -967,6 +967,38 @@ public class ProductionPlanningController extends BaseService {
if(projectInfo != null && !projectInfo.isEmpty()) {
request.setAttribute("info", projectInfo);
// Machine 이외 제품: 품번 기준 M-BOM 템플릿 조회
String productCode = CommonUtils.checkNull(projectInfo.get("PRODUCT_CODE"));
String partNo = CommonUtils.checkNull(projectInfo.get("PART_NO"));
System.out.println("제품구분 코드: " + productCode);
System.out.println("품번: " + partNo);
// Machine(0000928) 이외 제품이고 품번이 있는 경우
if(!"0000928".equals(productCode) && !"".equals(partNo)) {
Map<String, Object> templateParam = new HashMap<>();
templateParam.put("partNo", partNo);
// 품번 기준 최신 M-BOM 템플릿 조회
Map<String, Object> template = commonService.selectOne("productionplanning.getLatestMbomTemplateByPartNo", request, templateParam);
if(template != null && !template.isEmpty()) {
System.out.println("M-BOM 템플릿 발견: " + template.get("TEMPLATE_MBOM_NO"));
// 템플릿 상세 항목 조회
Map<String, Object> detailParam = new HashMap<>();
detailParam.put("mbomHeaderObjid", template.get("TEMPLATE_HEADER_OBJID"));
List<Map<String, Object>> templateDetails = commonService.selectList("productionplanning.getMbomTemplateDetails", request, detailParam);
System.out.println("템플릿 상세 항목 수: " + (templateDetails != null ? templateDetails.size() : 0));
request.setAttribute("mbomTemplate", template);
request.setAttribute("mbomTemplateDetails", templateDetails);
} else {
System.out.println("해당 품번의 M-BOM 템플릿 없음");
}
}
} else {
System.out.println("projectInfo is null or empty!");
}
@@ -1115,8 +1147,29 @@ public class ProductionPlanningController extends BaseService {
bomReportObjid = sourceMbomObjId;
System.out.println("할당된 M-BOM 사용: " + bomReportObjid);
} else {
bomReportObjid = CommonUtils.checkNull(projectInfo.get("BOM_REPORT_OBJID"));
System.out.println("기존 BOM_REPORT_OBJID 사용: " + bomReportObjid);
// 할당된 BOM도 없으면 Machine 이외 제품은 템플릿 확인
String productCode = CommonUtils.checkNull(projectInfo.get("PRODUCT_CODE"));
String partNo = CommonUtils.checkNull(projectInfo.get("PART_NO"));
if(!"0000928".equals(productCode) && !"".equals(partNo)) {
System.out.println("Machine 이외 제품 - 템플릿 조회 시도");
Map<String, Object> templateParam = new HashMap<>();
templateParam.put("partNo", partNo);
Map<String, Object> template = commonService.selectOne("productionplanning.getLatestMbomTemplateByPartNo", request, templateParam);
if(template != null && !template.isEmpty()) {
bomReportObjid = CommonUtils.checkNull(template.get("TEMPLATE_HEADER_OBJID"));
isSavedMbom = true; // 템플릿도 MBOM_DETAIL에서 조회
System.out.println("템플릿 M-BOM 사용: " + bomReportObjid);
} else {
bomReportObjid = CommonUtils.checkNull(projectInfo.get("BOM_REPORT_OBJID"));
System.out.println("기존 BOM_REPORT_OBJID 사용: " + bomReportObjid);
}
} else {
bomReportObjid = CommonUtils.checkNull(projectInfo.get("BOM_REPORT_OBJID"));
System.out.println("기존 BOM_REPORT_OBJID 사용: " + bomReportObjid);
}
}
}
@@ -1470,13 +1523,15 @@ public class ProductionPlanningController extends BaseService {
if(assignment == null || assignment.isEmpty()) {
resultMap.put("result", "fail");
resultMap.put("message", "M-BOM 기준 정보가 없습니다. BOM 복사 팝업에서 먼저 기준을 설정해주세요.");
resultMap.put("message", "프로젝트 정보를 찾을 수 없습니다.");
return resultMap;
}
String sourceBomType = CommonUtils.checkNull(assignment.get("SOURCE_BOM_TYPE"));
String sourceBomObjId = "";
String baseBomPartNo = "";
String productCode = CommonUtils.checkNull(assignment.get("PRODUCT_CODE"));
String partNo = CommonUtils.checkNull(assignment.get("PART_NO"));
if("EBOM".equals(sourceBomType)) {
sourceBomObjId = CommonUtils.checkNull(assignment.get("SOURCE_EBOM_OBJID"));
@@ -1484,12 +1539,18 @@ public class ProductionPlanningController extends BaseService {
} 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;
} else {
// 할당 정보가 없는 경우 - Machine 이외 제품은 템플릿 기반 저장 허용
if(!"0000928".equals(productCode) && !"".equals(partNo)) {
System.out.println("Machine 이외 제품 - 템플릿 기반 저장 허용");
sourceBomType = "TEMPLATE"; // 템플릿 기반 저장 표시
baseBomPartNo = partNo;
} else {
// Machine 제품이거나 품번이 없으면 할당 필요
resultMap.put("result", "fail");
resultMap.put("message", "M-BOM 기준 정보가 없습니다. BOM 복사 팝업에서 먼저 기준을 설정해주세요.");
return resultMap;
}
}
// M-BOM 품번 생성 또는 사용

View File

@@ -3060,6 +3060,7 @@
''
) AS CATEGORY_NAME,
CM.PRODUCT,
CM.PRODUCT AS PRODUCT_CODE,
COALESCE(
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.PRODUCT LIMIT 1),
''
@@ -3442,6 +3443,59 @@
LIMIT 1
</select>
<!-- 품번 기준 최신 M-BOM 템플릿 조회 (Machine 이외 제품용) -->
<select id="getLatestMbomTemplateByPartNo" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT
MH.OBJID AS TEMPLATE_HEADER_OBJID,
MH.MBOM_NO AS TEMPLATE_MBOM_NO,
MH.PART_NO,
MH.PART_NAME,
MH.SOURCE_BOM_TYPE,
MH.SOURCE_EBOM_OBJID,
MH.SOURCE_MBOM_OBJID,
TO_CHAR(MH.REGDATE, 'YYYY-MM-DD HH24:MI:SS') AS REGDATE
FROM MBOM_HEADER MH
INNER JOIN PROJECT_MGMT PM ON MH.PROJECT_OBJID = PM.OBJID
INNER JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
WHERE MH.PART_NO = #{partNo}
AND MH.STATUS = 'Y'
AND CM.PRODUCT != '0000928' <!-- Machine 제외 -->
ORDER BY MH.REGDATE DESC
LIMIT 1
</select>
<!-- 템플릿 M-BOM의 상세 항목 조회 -->
<select id="getMbomTemplateDetails" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT
MD.OBJID,
MD.MBOM_HEADER_OBJID,
MD.PARENT_OBJID,
MD.CHILD_OBJID,
MD.SEQ,
MD.LEVEL,
MD.PART_OBJID,
MD.PART_NO,
MD.PART_NAME,
MD.QTY,
MD.UNIT,
MD.SUPPLY_TYPE,
MD.MAKE_OR_BUY,
MD.RAW_MATERIAL_PART_NO,
MD.RAW_MATERIAL_SPEC,
MD.RAW_MATERIAL,
MD.RAW_MATERIAL_SIZE,
MD.PROCESSING_VENDOR,
MD.PROCESSING_DEADLINE,
MD.GRINDING_DEADLINE,
MD.REQUIRED_QTY,
-- ORDER_QTY, PRODUCTION_QTY는 새 프로젝트에서 재계산되므로 제외
MD.REMARK
FROM MBOM_DETAIL MD
WHERE MD.MBOM_HEADER_OBJID = #{mbomHeaderObjid}
AND MD.STATUS = 'ACTIVE'
ORDER BY MD.SEQ, MD.LEVEL
</select>
<!-- M-BOM 할당 정보 조회 -->
<select id="getMbomAssignment" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT
@@ -3451,8 +3505,8 @@
PM.SOURCE_MBOM_OBJID,
PM.PART_NO,
PM.PART_NAME,
PM.PRODUCT,
CODE_NAME(PM.PRODUCT) AS PRODUCT_NAME,
CM.PRODUCT AS PRODUCT_CODE,
CODE_NAME(CM.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)
@@ -3468,6 +3522,7 @@
(SELECT PART_NAME FROM MBOM_HEADER WHERE OBJID = PM.SOURCE_MBOM_OBJID)
END AS MBOM_PART_NAME
FROM PROJECT_MGMT PM
INNER JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
WHERE PM.OBJID::VARCHAR = #{projectObjId}
</select>

View File

@@ -1119,6 +1119,13 @@ public class ProductionPlanningService {
cleanPartNo = cleanPartNo.substring(2); // "M-" 제거
}
mbomPrefix = "M-" + cleanPartNo + "-" + dateStr;
} else if("TEMPLATE".equals(sourceBomType)) {
// 템플릿 기준: M-{품번}-YYMMDD
String cleanPartNo = baseBomPartNo.trim();
if(cleanPartNo.startsWith("M-")) {
cleanPartNo = cleanPartNo.substring(2); // "M-" 제거
}
mbomPrefix = "M-" + cleanPartNo + "-" + dateStr;
} else if("MBOM".equals(sourceBomType)) {
// M-BOM 기준: 기존 M-BOM 품번에서 날짜/순번 부분 제거 후 새 날짜 추가
// 예: M-000AN014000-251124-01 → M-000AN014000 → M-000AN014000-251124
@@ -1430,6 +1437,10 @@ public class ProductionPlanningService {
} else if("MBOM".equals(sourceBomType)) {
paramMap.put("sourceEbomObjid", null);
paramMap.put("sourceMbomObjid", sourceBomObjId);
} else if("TEMPLATE".equals(sourceBomType)) {
// 템플릿 기반 저장: 할당 정보 없음
paramMap.put("sourceEbomObjid", null);
paramMap.put("sourceMbomObjid", null);
}
// MBOM_HEADER 삽입