Merge: M-BOM 관리 기능 구현 및 버그 수정
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
FROM dockerhub.wace.me/tomcat:7.0.94-jre8-alpine.arm64 AS Development
|
||||
FROM dockerhub.wace.me/tomcat:7.0.94-jre7-alpine.arm64 AS Development
|
||||
|
||||
# Remove default webapps
|
||||
RUN rm -rf /usr/local/tomcat/webapps/*
|
||||
|
||||
@@ -2945,8 +2945,23 @@
|
||||
''
|
||||
) AS EBOM_REGDATE,
|
||||
COALESCE(PM.MBOM_STATUS, '') AS MBOM_STATUS,
|
||||
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),
|
||||
''
|
||||
) AS MBOM_PART_NO,
|
||||
'1.0' AS MBOM_VERSION,
|
||||
TO_CHAR(PM.REGDATE, 'YYYY-MM-DD') AS MBOM_REGDATE
|
||||
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),
|
||||
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
|
||||
@@ -3009,6 +3024,14 @@
|
||||
PM.BOM_REPORT_OBJID,
|
||||
PM.PART_NO,
|
||||
PM.PART_NAME,
|
||||
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),
|
||||
''
|
||||
) AS MBOM_PART_NO,
|
||||
CM.CATEGORY_CD,
|
||||
COALESCE(
|
||||
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.CATEGORY_CD LIMIT 1),
|
||||
@@ -3032,7 +3055,14 @@
|
||||
CM.PAID_TYPE,
|
||||
CM.REQ_DEL_DATE,
|
||||
TO_CHAR(PM.REGDATE, 'YYYY-MM-DD') AS RECEIPT_DATE,
|
||||
TO_CHAR(PM.REGDATE, 'YYYY-MM-DD') AS MBOM_REGDATE
|
||||
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),
|
||||
TO_CHAR(PM.REGDATE, 'YYYY-MM-DD')
|
||||
) AS MBOM_REGDATE
|
||||
FROM
|
||||
PROJECT_MGMT PM
|
||||
INNER JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
|
||||
@@ -3092,71 +3122,209 @@
|
||||
<!-- M-BOM 목록 조회 -->
|
||||
<select id="getMbomList" resultType="map" parameterType="map">
|
||||
SELECT
|
||||
MH.OBJID,
|
||||
MH.MBOM_NO,
|
||||
MH.PART_NO,
|
||||
MH.PART_NAME,
|
||||
MH.SAVE_DATE,
|
||||
MH.CREATE_USER,
|
||||
MH.CREATE_DATE,
|
||||
MH.UPDATE_USER,
|
||||
MH.UPDATE_DATE
|
||||
BPQ.OBJID,
|
||||
BPQ.BOM_REPORT_OBJID,
|
||||
BPQ.PARENT_OBJID,
|
||||
BPQ.CHILD_OBJID,
|
||||
BPQ.PARENT_PART_NO,
|
||||
BPQ.PART_NO,
|
||||
BPQ.QTY,
|
||||
BPQ.ITEM_QTY,
|
||||
BPQ.QTY_TEMP,
|
||||
BPQ.SEQ,
|
||||
BPQ.STATUS,
|
||||
BPQ.LAST_PART_OBJID,
|
||||
PM.PART_NO AS PART_NAME,
|
||||
PM.PART_NAME AS PART_FULL_NAME,
|
||||
PM.REVISION,
|
||||
PM.SPEC,
|
||||
COALESCE(
|
||||
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = PM.PRODUCT_CODE LIMIT 1),
|
||||
''
|
||||
) AS PRODUCT_NAME,
|
||||
COALESCE(
|
||||
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = PM.STATUS LIMIT 1),
|
||||
''
|
||||
) AS STATUS_NAME,
|
||||
-- 파일 개수
|
||||
COALESCE(PM.CU01_CNT, 0) AS CU01_CNT,
|
||||
COALESCE(PM.CU02_CNT, 0) AS CU02_CNT,
|
||||
COALESCE(PM.CU03_CNT, 0) AS CU03_CNT,
|
||||
-- E-BOM 컬럼들
|
||||
COALESCE(PM.MATERIAL, '') AS MATERIAL,
|
||||
COALESCE(PM.HEAT_TREATMENT_HARDNESS, '') AS HEAT_TREATMENT_HARDNESS,
|
||||
COALESCE(PM.HEAT_TREATMENT_METHOD, '') AS HEAT_TREATMENT_METHOD,
|
||||
COALESCE(PM.SURFACE_TREATMENT, '') AS SURFACE_TREATMENT,
|
||||
COALESCE(PM.MAKER, '') AS SUPPLIER,
|
||||
COALESCE(PM.CATEGORY, '') AS CATEGORY_NAME,
|
||||
-- 생산관리 컬럼들
|
||||
'' AS SUPPLY_TYPE,
|
||||
'' AS RAW_MATERIAL,
|
||||
'' AS SIZE,
|
||||
0 AS REQUIRED_QTY,
|
||||
0 AS ORDER_QTY,
|
||||
0 AS PRODUCTION_QTY,
|
||||
'' AS PROCESSING_VENDOR,
|
||||
'' AS PROCESSING_DEADLINE,
|
||||
'' AS GRINDING_DEADLINE,
|
||||
-- 구매 컬럼들
|
||||
'' AS MATERIAL_PART_NO,
|
||||
0 AS NET_QTY,
|
||||
0 AS PO_QTY,
|
||||
'' AS VENDOR,
|
||||
0 AS UNIT_PRICE,
|
||||
0 AS TOTAL_PRICE,
|
||||
1 AS LEVEL
|
||||
FROM
|
||||
MBOM_HEADER MH
|
||||
WHERE 1=1
|
||||
<!-- 품번 검색 -->
|
||||
<if test="partNo != null and partNo != ''">
|
||||
AND UPPER(MH.PART_NO) LIKE '%' || UPPER(#{partNo}) || '%'
|
||||
</if>
|
||||
<!-- 품명 검색 -->
|
||||
<if test="partName != null and partName != ''">
|
||||
AND UPPER(MH.PART_NAME) LIKE '%' || UPPER(#{partName}) || '%'
|
||||
</if>
|
||||
<!-- M-BOM 품번 검색 -->
|
||||
<if test="mbomPartNo != null and mbomPartNo != ''">
|
||||
AND UPPER(MH.MBOM_NO) LIKE '%' || UPPER(#{mbomPartNo}) || '%'
|
||||
</if>
|
||||
<!-- 저장일 검색 -->
|
||||
<if test="saveDate != null and saveDate != ''">
|
||||
AND DATE(MH.SAVE_DATE) = #{saveDate}
|
||||
</if>
|
||||
ORDER BY MH.SAVE_DATE DESC
|
||||
LIMIT 100
|
||||
BOM_PART_QTY BPQ
|
||||
LEFT JOIN PART_MGMT PM ON BPQ.PART_NO = PM.PART_NO
|
||||
LEFT JOIN PART_BOM_REPORT PBR ON BPQ.BOM_REPORT_OBJID::VARCHAR = PBR.OBJID::VARCHAR
|
||||
WHERE 1=1
|
||||
AND COALESCE(BPQ.STATUS, '') NOT IN ('deleting', 'deleted')
|
||||
<!-- BOM_REPORT_OBJID로 직접 조회 (우선순위 높음) -->
|
||||
<if test="bomReportObjId != null and bomReportObjId != ''">
|
||||
AND BPQ.BOM_REPORT_OBJID::VARCHAR = #{bomReportObjId}
|
||||
</if>
|
||||
<!-- 품번 검색 -->
|
||||
<if test="partNo != null and partNo != ''">
|
||||
AND UPPER(PBR.PART_NO) LIKE '%' || UPPER(#{partNo}) || '%'
|
||||
</if>
|
||||
<!-- 품명 검색 -->
|
||||
<if test="partName != null and partName != ''">
|
||||
AND UPPER(PBR.PART_NAME) LIKE '%' || UPPER(#{partName}) || '%'
|
||||
</if>
|
||||
<!-- M-BOM 품번 검색 -->
|
||||
<if test="mbomPartNo != null and mbomPartNo != ''">
|
||||
AND UPPER(PBR.PART_NO) LIKE '%' || UPPER(#{mbomPartNo}) || '%'
|
||||
</if>
|
||||
<!-- 저장일 검색 -->
|
||||
<if test="saveDate != null and saveDate != ''">
|
||||
AND DATE(PBR.REGDATE) = #{saveDate}
|
||||
</if>
|
||||
ORDER BY BPQ.SEQ
|
||||
LIMIT 1000
|
||||
</select>
|
||||
|
||||
<!-- M-BOM 상세 데이터 조회 (프로젝트별) -->
|
||||
<select id="getMbomDetailByProject" resultType="map" parameterType="map">
|
||||
/* productionplanning.getMbomDetailByProject - PROJECT_MGMT의 BOM_REPORT_OBJID로 M-BOM 조회 */
|
||||
SELECT
|
||||
BPQ.OBJID,
|
||||
BPQ.BOM_REPORT_OBJID,
|
||||
BPQ.PARENT_OBJID,
|
||||
BPQ.CHILD_OBJID,
|
||||
BPQ.PARENT_PART_NO,
|
||||
COALESCE(PM.PART_NO, '') AS PART_NO,
|
||||
BPQ.QTY,
|
||||
BPQ.ITEM_QTY,
|
||||
BPQ.QTY_TEMP,
|
||||
BPQ.SEQ,
|
||||
BPQ.STATUS,
|
||||
BPQ.LAST_PART_OBJID,
|
||||
COALESCE(PM.PART_NAME, '') AS PART_NAME,
|
||||
'' AS REVISION,
|
||||
'' AS SPEC,
|
||||
'' AS PRODUCT_NAME,
|
||||
'' AS STATUS_NAME,
|
||||
-- 파일 개수
|
||||
0 AS CU01_CNT,
|
||||
0 AS CU02_CNT,
|
||||
0 AS CU03_CNT,
|
||||
-- E-BOM 컬럼들
|
||||
'' AS MATERIAL,
|
||||
'' AS HEAT_TREATMENT_HARDNESS,
|
||||
'' AS HEAT_TREATMENT_METHOD,
|
||||
'' AS SURFACE_TREATMENT,
|
||||
'' AS SUPPLIER,
|
||||
'' AS CATEGORY_NAME,
|
||||
-- 생산관리 컬럼들
|
||||
'' AS SUPPLY_TYPE,
|
||||
'' AS RAW_MATERIAL,
|
||||
'' AS SIZE,
|
||||
0 AS REQUIRED_QTY,
|
||||
0 AS ORDER_QTY,
|
||||
0 AS PRODUCTION_QTY,
|
||||
'' AS PROCESSING_VENDOR,
|
||||
'' AS PROCESSING_DEADLINE,
|
||||
'' AS GRINDING_DEADLINE,
|
||||
-- 구매 컬럼들
|
||||
'' AS MATERIAL_PART_NO,
|
||||
0 AS NET_QTY,
|
||||
0 AS PO_QTY,
|
||||
'' AS VENDOR,
|
||||
0 AS UNIT_PRICE,
|
||||
0 AS TOTAL_PRICE,
|
||||
1 AS LEVEL
|
||||
FROM
|
||||
PROJECT_MGMT PROJ
|
||||
INNER JOIN BOM_PART_QTY BPQ ON PROJ.BOM_REPORT_OBJID::VARCHAR = BPQ.BOM_REPORT_OBJID::VARCHAR
|
||||
LEFT JOIN PART_MGMT PM ON PM.OBJID::VARCHAR = BPQ.PART_NO::VARCHAR
|
||||
WHERE
|
||||
PROJ.OBJID::VARCHAR = #{objId}
|
||||
AND COALESCE(BPQ.STATUS, '') NOT IN ('deleting', 'deleted')
|
||||
AND PROJ.BOM_REPORT_OBJID IS NOT NULL
|
||||
AND PROJ.BOM_REPORT_OBJID != ''
|
||||
ORDER BY
|
||||
BPQ.SEQ
|
||||
</select>
|
||||
|
||||
<!-- M-BOM 품번 최대 순번 조회 (같은 날짜) -->
|
||||
<select id="getMaxMbomSeqByDate" parameterType="map" resultType="int">
|
||||
SELECT
|
||||
MD.OBJID,
|
||||
MD.MBOM_HEADER_OBJID,
|
||||
MD.PART_NO,
|
||||
MD.PART_NAME,
|
||||
MD.QTY,
|
||||
MD.QTY_TEMP,
|
||||
MD.ITEM_QTY,
|
||||
MD.LEVEL,
|
||||
MD.REVISION,
|
||||
MD.SPEC,
|
||||
MD.PRODUCT_NAME,
|
||||
MD.STATUS_NAME,
|
||||
MD.LEVEL_1,
|
||||
MD.LEVEL_2,
|
||||
MD.LEVEL_3,
|
||||
MD.LEVEL_4,
|
||||
MD.LEVEL_5,
|
||||
MD.LEVEL_6,
|
||||
MD.LEVEL_7,
|
||||
MD.LEVEL_8,
|
||||
MD.LEVEL_9,
|
||||
MD.LEVEL_10
|
||||
COALESCE(MAX(
|
||||
CAST(
|
||||
SUBSTRING(PART_NO FROM '.+-([0-9]+)$') AS INTEGER
|
||||
)
|
||||
), 0) AS MAX_SEQ
|
||||
FROM
|
||||
MBOM_DETAIL MD
|
||||
INNER JOIN
|
||||
MBOM_HEADER MH ON MD.MBOM_HEADER_OBJID = MH.OBJID
|
||||
PART_BOM_REPORT
|
||||
WHERE
|
||||
MH.PROJECT_MGMT_OBJID = #{objId}
|
||||
PART_NO LIKE #{prefix} || '%'
|
||||
AND STATUS = 'Y'
|
||||
</select>
|
||||
|
||||
<!-- 품번으로 최신 M-BOM 조회 (Machine 이외 제품용) -->
|
||||
<select id="getLatestMbomByPartNo" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
SELECT
|
||||
PM.OBJID,
|
||||
COALESCE(
|
||||
(SELECT PBR.PART_NO
|
||||
FROM PART_BOM_REPORT PBR
|
||||
WHERE PBR.OBJID::VARCHAR = PM.BOM_REPORT_OBJID
|
||||
LIMIT 1),
|
||||
''
|
||||
) AS MBOM_PART_NO,
|
||||
PM.BOM_REPORT_OBJID,
|
||||
PM.PART_NO,
|
||||
PM.PART_NAME,
|
||||
TO_CHAR(PM.REGDATE, 'YYYY-MM-DD') AS SAVE_DATE
|
||||
FROM
|
||||
PROJECT_MGMT PM
|
||||
INNER JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
|
||||
WHERE
|
||||
PM.PART_NO = #{partNo}
|
||||
AND PM.MBOM_STATUS = 'Y'
|
||||
AND PM.BOM_REPORT_OBJID IS NOT NULL
|
||||
AND CM.PRODUCT != '0001807' <!-- Machine 제외 -->
|
||||
ORDER BY
|
||||
MD.LEVEL, MD.PART_NO
|
||||
PM.REGDATE DESC
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<!-- 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
|
||||
FROM
|
||||
PART_BOM_REPORT PBR
|
||||
WHERE
|
||||
PBR.PART_NO = #{mbomPartNo}
|
||||
ORDER BY PBR.REGDATE DESC
|
||||
</select>
|
||||
|
||||
<!-- M-BOM 헤더 저장 -->
|
||||
@@ -3229,6 +3397,7 @@
|
||||
<insert id="saveMbomFromEbom" parameterType="map">
|
||||
/* productionplanning.saveMbomFromEbom - E-BOM을 M-BOM으로 복사 */
|
||||
/* 1. 새로운 PART_BOM_REPORT 생성 (M-BOM용) */
|
||||
/* M-BOM 품번을 PART_NO에 저장 (규칙: M-{품번}-YYMMDD-01) */
|
||||
WITH new_bom_report AS (
|
||||
INSERT INTO PART_BOM_REPORT (
|
||||
OBJID,
|
||||
@@ -3239,7 +3408,7 @@
|
||||
STATUS
|
||||
) VALUES (
|
||||
(SELECT (FLOOR(RANDOM() * 1000000000) + 1000000000)::INTEGER),
|
||||
#{PART_NO},
|
||||
#{MBOM_PART_NO},
|
||||
#{PART_NAME},
|
||||
#{USER_ID},
|
||||
NOW(),
|
||||
|
||||
@@ -134,12 +134,29 @@ var selectedBomType = null; // 'EBOM' 또는 'MBOM'
|
||||
var bomGridData = []; // BOM 그리드 데이터
|
||||
|
||||
$(function(){
|
||||
// 페이지 로드 시 프로젝트 정보가 있으면 품번/품명 자동 입력
|
||||
// 페이지 로드 시 URL 파라미터 또는 프로젝트 정보에서 품번/품명 자동 입력
|
||||
var urlPartNo = "${param.partNo}";
|
||||
var urlPartName = "${param.partName}";
|
||||
var productCode = "${projectInfo.PRODUCT}";
|
||||
|
||||
if(urlPartNo && urlPartNo !== "") {
|
||||
console.log("URL 파라미터에서 품번/품명 설정 중...");
|
||||
$("#COPY_PART_NO").val(decodeURIComponent(urlPartNo));
|
||||
$("#COPY_PART_NAME").val(decodeURIComponent(urlPartName));
|
||||
}
|
||||
<c:if test="${not empty projectInfo}">
|
||||
else {
|
||||
console.log("projectInfo가 있습니다. 품번/품명 설정 중...");
|
||||
$("#COPY_PART_NO").val("${projectInfo.PART_NO}");
|
||||
$("#COPY_PART_NAME").val("${projectInfo.PART_NAME}");
|
||||
// E-BOM 품번은 사용자가 직접 입력하도록 비워둠 (M-BOM 품번과 다를 수 있음)
|
||||
}
|
||||
|
||||
// Machine이 아닌 경우, 동일 품번의 기존 M-BOM 확인 및 자동 로드
|
||||
var isMachine = productCode && (productCode === '0001807' || productCode.toUpperCase().indexOf('MACHINE') >= 0);
|
||||
if(!isMachine && "${projectInfo.PART_NO}" !== "") {
|
||||
console.log("Machine이 아닌 제품입니다. 기존 M-BOM 확인 중...");
|
||||
fn_checkExistingMbom("${projectInfo.PART_NO}");
|
||||
}
|
||||
</c:if>
|
||||
|
||||
// 담기 버튼 - 선택한 BOM을 복사 대상으로 설정
|
||||
@@ -175,9 +192,9 @@ $(function(){
|
||||
var ebomPartNo = $("#EBOM_PART_NO").val().trim();
|
||||
if(!ebomPartNo) {
|
||||
Swal.fire('E-BOM 품번을 입력해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// E-BOM 조회 후 미리보기 로드
|
||||
fn_loadBomPreview(ebomPartNo, 'EBOM');
|
||||
});
|
||||
@@ -187,9 +204,9 @@ $(function(){
|
||||
var mbomPartNo = $("#MBOM_PART_NO").val().trim();
|
||||
if(!mbomPartNo) {
|
||||
Swal.fire('M-BOM 품번을 입력해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// M-BOM 조회 후 미리보기 로드
|
||||
fn_loadBomPreview(mbomPartNo, 'MBOM');
|
||||
});
|
||||
@@ -213,6 +230,45 @@ $(function(){
|
||||
fn_initGrid([], 3);
|
||||
});
|
||||
|
||||
// 기존 M-BOM 확인 (Machine 이외 제품용)
|
||||
function fn_checkExistingMbom(partNo) {
|
||||
$.ajax({
|
||||
url: "/productionplanning/getLatestMbomByPartNo.do",
|
||||
type: "POST",
|
||||
data: { partNo: partNo },
|
||||
dataType: "json",
|
||||
success: function(response) {
|
||||
console.log("getLatestMbomByPartNo 응답:", response);
|
||||
|
||||
if(response && response.MBOM_PART_NO) {
|
||||
// 기존 M-BOM이 있는 경우 사용자에게 알림
|
||||
Swal.fire({
|
||||
title: '기존 M-BOM 발견',
|
||||
html: '동일 품번(' + partNo + ')의 M-BOM이 이미 존재합니다.<br>' +
|
||||
'M-BOM 품번: ' + response.MBOM_PART_NO + '<br>' +
|
||||
'저장일: ' + response.SAVE_DATE + '<br><br>' +
|
||||
'기존 M-BOM을 자동으로 불러오시겠습니까?',
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: '자동 불러오기',
|
||||
cancelButtonText: '새로 생성'
|
||||
}).then((result) => {
|
||||
if(result.isConfirmed) {
|
||||
// M-BOM 자동 로드
|
||||
$("#MBOM_PART_NO").val(response.MBOM_PART_NO);
|
||||
fn_loadBomPreview(response.MBOM_PART_NO, 'MBOM');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log("기존 M-BOM이 없습니다.");
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error("getLatestMbomByPartNo 에러:", xhr, status, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// BOM 미리보기 로드
|
||||
function fn_loadBomPreview(partNo, bomType) {
|
||||
console.log("fn_loadBomPreview 호출:", partNo, bomType);
|
||||
@@ -248,8 +304,8 @@ function fn_loadBomPreview(partNo, bomType) {
|
||||
// BOM 트리 데이터 로드
|
||||
function fn_loadBomTree(bomObjId) {
|
||||
console.log("fn_loadBomTree 호출:", bomObjId);
|
||||
|
||||
$.ajax({
|
||||
|
||||
$.ajax({
|
||||
url: "/partMng/getStructureTreeJson.do",
|
||||
type: "POST",
|
||||
data: {
|
||||
@@ -505,6 +561,15 @@ function fn_saveBomCopy() {
|
||||
}
|
||||
});
|
||||
|
||||
// 제품구분 가져오기
|
||||
var productCode = "${projectInfo.PRODUCT}";
|
||||
|
||||
// 기존 M-BOM 품번 가져오기 (M-BOM 선택 시 사용)
|
||||
var existingMbomPartNo = "";
|
||||
if(selectedBomType === 'MBOM') {
|
||||
existingMbomPartNo = $("#MBOM_PART_NO").val().trim();
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: "/partMng/saveBomCopy.do",
|
||||
type: "POST",
|
||||
@@ -514,6 +579,8 @@ function fn_saveBomCopy() {
|
||||
sourceBomType: selectedBomType,
|
||||
targetPartNo: copyPartNo,
|
||||
targetPartName: copyPartName,
|
||||
productCode: productCode, // 제품구분 추가
|
||||
existingMbomPartNo: existingMbomPartNo, // 기존 M-BOM 품번 추가
|
||||
bomData: bomGridData
|
||||
}),
|
||||
contentType: "application/json",
|
||||
@@ -526,9 +593,19 @@ function fn_saveBomCopy() {
|
||||
text: 'M-BOM이 성공적으로 생성되었습니다.',
|
||||
icon: 'success'
|
||||
}).then(() => {
|
||||
// 부모 창(M-BOM 관리) 새로고침하여 아이콘 업데이트
|
||||
// 부모 창(M-BOM 관리)의 검색 함수만 호출하여 그리드 업데이트
|
||||
if(window.opener && !window.opener.closed) {
|
||||
window.opener.location.reload();
|
||||
// 부모 창의 검색 조건 유지하면서 그리드만 새로고침
|
||||
if(typeof window.opener.fn_search === 'function') {
|
||||
window.opener.fn_search();
|
||||
}
|
||||
// M-BOM 품번과 저장일을 부모 창 검색 조건에 설정
|
||||
// if(response.mbomPartNo) {
|
||||
// window.opener.$("#search_mbom_part_no").val(response.mbomPartNo);
|
||||
// }
|
||||
// if(response.saveDate) {
|
||||
// window.opener.$("#search_save_date").val(response.saveDate);
|
||||
// }
|
||||
}
|
||||
window.close();
|
||||
});
|
||||
@@ -568,13 +645,37 @@ function fn_excel() {
|
||||
</script>
|
||||
</head>
|
||||
<body class="backcolor">
|
||||
<form name="form1" id="form1" action="" method="post">
|
||||
<form name="form1" id="form1" action="" method="post">
|
||||
<!-- Hidden fields -->
|
||||
<input type="hidden" id="TARGET_OBJID" name="TARGET_OBJID" value="${param.objId}">
|
||||
|
||||
<!-- 상단: 품번/품명 입력 및 BOM 선택 영역 -->
|
||||
<div class="top-input-section">
|
||||
<table class="pmsPopuptable" style="margin-bottom: 10px;">
|
||||
<colgroup>
|
||||
<col width="10%">
|
||||
<col width="25%">
|
||||
<col width="10%">
|
||||
<col width="25%">
|
||||
<col width="30%">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<td class="input_title"><label for="COPY_PART_NO">품번</label></td>
|
||||
<td>
|
||||
<input type="text" id="COPY_PART_NO" name="COPY_PART_NO" style="width: 100%;">
|
||||
</td>
|
||||
<td class="input_title"><label for="COPY_PART_NAME">품명</label></td>
|
||||
<td>
|
||||
<input type="text" id="COPY_PART_NAME" name="COPY_PART_NAME" style="width: 100%;">
|
||||
</td>
|
||||
<td style="text-align: center;">
|
||||
<input type="button" value="담기" class="plm_btns" id="btnAddItem">
|
||||
<input type="button" value="저장" class="plm_btns" id="btnSaveItem">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table class="pmsPopuptable">
|
||||
<colgroup>
|
||||
<col width="10%">
|
||||
<col width="25%">
|
||||
@@ -582,42 +683,25 @@ function fn_excel() {
|
||||
<col width="25%">
|
||||
<col width="30%">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<td class="input_title"><label for="COPY_PART_NO">품번</label></td>
|
||||
<td>
|
||||
<input type="text" id="COPY_PART_NO" name="COPY_PART_NO" style="width: 100%;">
|
||||
</td>
|
||||
<td class="input_title"><label for="COPY_PART_NAME">품명</label></td>
|
||||
<td>
|
||||
<input type="text" id="COPY_PART_NAME" name="COPY_PART_NAME" style="width: 100%;">
|
||||
</td>
|
||||
<td style="text-align: center;">
|
||||
<input type="button" value="담기" class="plm_btns" id="btnAddItem">
|
||||
<input type="button" value="저장" class="plm_btns" id="btnSaveItem">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table class="pmsPopuptable">
|
||||
<colgroup>
|
||||
<col width="15%">
|
||||
<col width="85%">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<td class="input_title"><label for="EBOM_PART_NO">E-BOM 품번</label></td>
|
||||
<td>
|
||||
<input type="text" id="EBOM_PART_NO" name="EBOM_PART_NO" style="width: 400px; margin-right: 10px;">
|
||||
<td colspan="3">
|
||||
<input type="text" id="EBOM_PART_NO" name="EBOM_PART_NO" style="width: 100%;">
|
||||
</td>
|
||||
<td style="text-align: center;">
|
||||
<input type="button" value="E-BOM 선택" class="plm_btns" id="btnSelectEbom">
|
||||
</td>
|
||||
</tr>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="input_title"><label for="MBOM_PART_NO">M-BOM 품번</label></td>
|
||||
<td>
|
||||
<input type="text" id="MBOM_PART_NO" name="MBOM_PART_NO" style="width: 400px; margin-right: 10px;">
|
||||
<td colspan="3">
|
||||
<input type="text" id="MBOM_PART_NO" name="MBOM_PART_NO" style="width: 100%;">
|
||||
</td>
|
||||
<td style="text-align: center;">
|
||||
<input type="button" value="M-BOM 선택" class="plm_btns" id="btnSelectMbom">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 중간: BOM 미리보기 그리드 -->
|
||||
@@ -627,9 +711,9 @@ function fn_excel() {
|
||||
<input type="button" value="Excel Download" class="plm_btns structure_btn" id="btnExcel" style="float:right;">
|
||||
<input type="button" value="도면 다중 업로드" class="plm_btns structure_btn" id="btnDrawingUpload" style="float:right; margin-right:5px;">
|
||||
<input type="file" id="drawingFiles" multiple style="display:none;" accept=".stp,.step,.dwg,.dxf,.pdf">
|
||||
</div>
|
||||
</div>
|
||||
<div id="structureGrid"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</body>
|
||||
|
||||
@@ -422,14 +422,16 @@ function fn_changeRelatePartInfo(objId,rightObjId,leftObjId,leftPartNoQty,leftPa
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<body class="backcolor" style="border:border:1px solid #ccc;">
|
||||
<form name="form1" id="form1" action="" method="post">
|
||||
<input type="hidden" name="objId" id="objId" value="${param.objId}" />
|
||||
|
||||
<div id="structurePopupBtnW">
|
||||
<div id="structurePopupBtnW" style="padding-top:20px;">
|
||||
<input type="button" value="변경" class="plm_btns" id="moveChange">
|
||||
<input type="button" value="<<" class="plm_btns" id="moveLeft">
|
||||
<input type="button" value=">>" class="plm_btns" id="moveRight">
|
||||
<br>
|
||||
<input type="button" value="<<" class="plm_btns" id="moveLeft" style="margin-left:0px;">
|
||||
<br>
|
||||
<input type="button" value=">>" class="plm_btns" id="moveRight" style="margin-left:0px;">
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
|
||||
@@ -50,6 +50,19 @@ $(function(){
|
||||
|
||||
$('.select2').select2();
|
||||
|
||||
// 페이지 로드 시 프로젝트 정보로 검색 필드 자동 입력
|
||||
<c:if test="${not empty info}">
|
||||
$("#search_part_no").val("${info.PART_NO}");
|
||||
$("#search_part_name").val("${info.PART_NAME}");
|
||||
$("#search_mbom_part_no").val("${info.MBOM_PART_NO}"); // M-BOM 품번 (자동 생성된 값)
|
||||
$("#search_save_date").val("${info.MBOM_REGDATE}");
|
||||
|
||||
// 자동으로 M-BOM 조회
|
||||
setTimeout(function() {
|
||||
fn_searchMbom();
|
||||
}, 500);
|
||||
</c:if>
|
||||
|
||||
//Part 연결
|
||||
$("#moveLeft").click(function(){
|
||||
// Tabulator에서 선택된 오른쪽 행 데이터 가져오기
|
||||
@@ -238,11 +251,11 @@ $(function(){
|
||||
fn_changeRelatePartInfo(leftPartBomQtyObjId, rightObjId, leftPartChildObjId, leftParentPartObjid, leftPartChildObjId, leftPartObjid, rightPartNo, rightPartRev);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// 조회 버튼 클릭
|
||||
$("#btnSearch").click(function(){
|
||||
fn_searchMbom();
|
||||
// 이력보기 버튼 클릭
|
||||
$("#btnHistory").click(function(){
|
||||
fn_showHistory();
|
||||
});
|
||||
|
||||
// 저장 버튼 클릭
|
||||
@@ -250,9 +263,9 @@ $(function(){
|
||||
fn_saveMbom();
|
||||
});
|
||||
|
||||
// BOM 복사 버튼 클릭
|
||||
$("#btnBomCopy").click(function(){
|
||||
fn_openBomCopyPopup();
|
||||
// 닫기 버튼 클릭
|
||||
$("#btnClose").click(function(){
|
||||
window.close();
|
||||
});
|
||||
|
||||
});
|
||||
@@ -454,11 +467,21 @@ function fn_searchMbom() {
|
||||
var partName = $("#search_part_name").val().trim();
|
||||
var mbomPartNo = $("#search_mbom_part_no").val().trim();
|
||||
var saveDate = $("#search_save_date").val().trim();
|
||||
var bomReportObjId = "${info.BOM_REPORT_OBJID}"; // M-BOM의 BOM_REPORT_OBJID
|
||||
|
||||
console.log("fn_searchMbom 호출:", {
|
||||
bomReportObjId: bomReportObjId,
|
||||
partNo: partNo,
|
||||
partName: partName,
|
||||
mbomPartNo: mbomPartNo,
|
||||
saveDate: saveDate
|
||||
});
|
||||
|
||||
// 왼쪽 프레임의 조회 함수 호출
|
||||
var leftFrame = parent.frames['leftFrame'];
|
||||
if(leftFrame && leftFrame.fn_searchMbom) {
|
||||
leftFrame.fn_searchMbom({
|
||||
bomReportObjId: bomReportObjId,
|
||||
partNo: partNo,
|
||||
partName: partName,
|
||||
mbomPartNo: mbomPartNo,
|
||||
@@ -469,15 +492,21 @@ function fn_searchMbom() {
|
||||
|
||||
// M-BOM 저장
|
||||
function fn_saveMbom() {
|
||||
console.log("fn_saveMbom 호출됨");
|
||||
|
||||
// 왼쪽 프레임에서 M-BOM 트리 데이터 가져오기
|
||||
var leftFrame = parent.frames['leftFrame'];
|
||||
console.log("leftFrame:", leftFrame);
|
||||
|
||||
if(!leftFrame) {
|
||||
alert("M-BOM 데이터를 가져올 수 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 트리 데이터 수집 (leftFrame에서 구현 필요)
|
||||
// 트리 데이터 수집
|
||||
var mbomData = leftFrame.getMbomTreeData ? leftFrame.getMbomTreeData() : null;
|
||||
console.log("mbomData:", mbomData);
|
||||
console.log("mbomData length:", mbomData ? mbomData.length : 0);
|
||||
|
||||
if(!mbomData || mbomData.length === 0) {
|
||||
alert("저장할 M-BOM 데이터가 없습니다.");
|
||||
@@ -489,18 +518,25 @@ function fn_saveMbom() {
|
||||
return;
|
||||
}
|
||||
|
||||
var saveData = {
|
||||
mbomData: mbomData,
|
||||
partNo: $("#search_part_no").val().trim(),
|
||||
partName: $("#search_part_name").val().trim(),
|
||||
mbomPartNo: $("#search_mbom_part_no").val().trim(),
|
||||
isUpdate: $("#search_mbom_part_no").val().trim() !== ""
|
||||
};
|
||||
|
||||
console.log("저장할 데이터:", saveData);
|
||||
|
||||
// 저장 API 호출
|
||||
$.ajax({
|
||||
url: "/productionplanning/saveMbom.do",
|
||||
method: 'post',
|
||||
data: JSON.stringify({
|
||||
mbomData: mbomData,
|
||||
partNo: $("#search_part_no").val().trim(),
|
||||
partName: $("#search_part_name").val().trim()
|
||||
}),
|
||||
data: JSON.stringify(saveData),
|
||||
contentType: 'application/json',
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
console.log("저장 응답:", data);
|
||||
if(data && data.result === "success") {
|
||||
alert("M-BOM이 저장되었습니다.");
|
||||
|
||||
@@ -512,34 +548,75 @@ function fn_saveMbom() {
|
||||
window.opener.fn_search();
|
||||
}
|
||||
} else {
|
||||
alert("M-BOM 저장에 실패했습니다.");
|
||||
alert("M-BOM 저장에 실패했습니다: " + (data.message || ""));
|
||||
}
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
console.error("M-BOM 저장 오류:", error);
|
||||
alert("M-BOM 저장 중 오류가 발생했습니다.");
|
||||
}
|
||||
console.error("응답:", jqxhr.responseText);
|
||||
alert("M-BOM 저장 중 오류가 발생했습니다.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// BOM 복사 팝업 열기
|
||||
function fn_openBomCopyPopup() {
|
||||
var objId = $("#objId").val();
|
||||
// M-BOM 이력보기
|
||||
function fn_showHistory() {
|
||||
var mbomPartNo = $("#search_mbom_part_no").val().trim();
|
||||
|
||||
if(!objId || objId === "-1") {
|
||||
alert("프로젝트 정보를 찾을 수 없습니다.");
|
||||
if(!mbomPartNo) {
|
||||
alert("M-BOM 품번이 없습니다. 먼저 M-BOM을 저장해주세요.");
|
||||
return;
|
||||
}
|
||||
|
||||
// BOM 복사 팝업 열기 (저번에 만든 화면)
|
||||
var url = "/partMng/structureBomCopyFormPopup.do?objId=" + objId;
|
||||
var popupName = "bomCopyPopup";
|
||||
var popupWidth = 1400;
|
||||
var popupHeight = 800;
|
||||
var left = (screen.width - popupWidth) / 2;
|
||||
var top = (screen.height - popupHeight) / 2;
|
||||
|
||||
window.open(url, popupName, "width=" + popupWidth + ",height=" + popupHeight + ",left=" + left + ",top=" + top + ",scrollbars=yes,resizable=yes");
|
||||
// M-BOM 이력 조회
|
||||
$.ajax({
|
||||
url: "/productionplanning/getMbomHistory.do",
|
||||
method: 'post',
|
||||
data: {
|
||||
mbomPartNo: mbomPartNo
|
||||
},
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
if(data && data.historyList && data.historyList.length > 0) {
|
||||
// 이력 팝업 표시
|
||||
var historyHtml = "<table border='1' style='width:100%; border-collapse:collapse;'>";
|
||||
historyHtml += "<thead><tr style='background:#f0f0f0;'>";
|
||||
historyHtml += "<th style='padding:8px;'>순번</th>";
|
||||
historyHtml += "<th style='padding:8px;'>M-BOM 품번</th>";
|
||||
historyHtml += "<th style='padding:8px;'>저장일</th>";
|
||||
historyHtml += "<th style='padding:8px;'>수정자</th>";
|
||||
historyHtml += "<th style='padding:8px;'>비고</th>";
|
||||
historyHtml += "</tr></thead><tbody>";
|
||||
|
||||
for(var i = 0; i < data.historyList.length; i++) {
|
||||
var item = data.historyList[i];
|
||||
historyHtml += "<tr>";
|
||||
historyHtml += "<td style='padding:5px; text-align:center;'>" + (i + 1) + "</td>";
|
||||
historyHtml += "<td style='padding:5px;'>" + (item.MBOM_PART_NO || "") + "</td>";
|
||||
historyHtml += "<td style='padding:5px; text-align:center;'>" + (item.REGDATE || "") + "</td>";
|
||||
historyHtml += "<td style='padding:5px; text-align:center;'>" + (item.REGUSER || "") + "</td>";
|
||||
historyHtml += "<td style='padding:5px;'>" + (item.REMARK || "") + "</td>";
|
||||
historyHtml += "</tr>";
|
||||
}
|
||||
|
||||
historyHtml += "</tbody></table>";
|
||||
|
||||
// 새 창으로 이력 표시
|
||||
var historyWindow = window.open("", "mbomHistory", "width=800,height=600,scrollbars=yes,resizable=yes");
|
||||
historyWindow.document.write("<html><head><title>M-BOM 이력</title></head><body>");
|
||||
historyWindow.document.write("<h2 style='text-align:center;'>M-BOM 수정 이력</h2>");
|
||||
historyWindow.document.write(historyHtml);
|
||||
historyWindow.document.write("</body></html>");
|
||||
historyWindow.document.close();
|
||||
} else {
|
||||
alert("이력이 없습니다.");
|
||||
}
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
console.error("M-BOM 이력 조회 오류:", error);
|
||||
alert("M-BOM 이력 조회 중 오류가 발생했습니다.");
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
@@ -572,9 +649,9 @@ function fn_openBomCopyPopup() {
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<input type="button" value="조회" class="plm_btns" id="btnSearch">
|
||||
<input type="button" value="이력보기" class="plm_btns" id="btnHistory">
|
||||
<input type="button" value="저장" class="plm_btns" id="btnSave">
|
||||
<input type="button" value="BOM 복사" class="plm_btns" id="btnBomCopy">
|
||||
<input type="button" value="닫기" class="plm_btns" id="btnClose">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -70,7 +70,7 @@ var columns = [
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 50,
|
||||
width: 40,
|
||||
title: '<input type="checkbox" id="checkAll">',
|
||||
field: 'CHK',
|
||||
formatter: function(cell, formatterParams, onRendered) {
|
||||
@@ -83,7 +83,7 @@ var columns = [
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 120,
|
||||
width: 100,
|
||||
title: '프로젝트번호',
|
||||
field: 'PROJECT_NO'
|
||||
},
|
||||
@@ -92,7 +92,7 @@ var columns = [
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 100,
|
||||
width: 80,
|
||||
title: '주문유형',
|
||||
field: 'CATEGORY_NAME'
|
||||
},
|
||||
@@ -101,7 +101,7 @@ var columns = [
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 100,
|
||||
width: 80,
|
||||
title: '제품구분',
|
||||
field: 'PRODUCT_NAME'
|
||||
},
|
||||
@@ -110,7 +110,7 @@ var columns = [
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 80,
|
||||
width: 70,
|
||||
title: '국내/해외',
|
||||
field: 'AREA_NAME'
|
||||
},
|
||||
@@ -119,7 +119,7 @@ var columns = [
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 100,
|
||||
width: 90,
|
||||
title: '접수일',
|
||||
field: 'RECEIPT_DATE'
|
||||
},
|
||||
@@ -128,7 +128,7 @@ var columns = [
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 150,
|
||||
width: 120,
|
||||
title: '고객사',
|
||||
field: 'CUSTOMER_NAME'
|
||||
},
|
||||
@@ -137,7 +137,7 @@ var columns = [
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 80,
|
||||
width: 70,
|
||||
title: '유/무상',
|
||||
field: 'PAID_TYPE_NAME'
|
||||
},
|
||||
@@ -146,7 +146,7 @@ var columns = [
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 150,
|
||||
width: 120,
|
||||
title: '품번',
|
||||
field: 'PART_NO'
|
||||
},
|
||||
@@ -155,7 +155,7 @@ var columns = [
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 200,
|
||||
width: 150,
|
||||
title: '품명',
|
||||
field: 'PART_NAME'
|
||||
},
|
||||
@@ -164,7 +164,7 @@ var columns = [
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 120,
|
||||
width: 100,
|
||||
title: 'S/N',
|
||||
field: 'SERIAL_NO'
|
||||
},
|
||||
@@ -173,7 +173,7 @@ var columns = [
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'right',
|
||||
width: 80,
|
||||
width: 70,
|
||||
title: '수주수량',
|
||||
field: 'QUANTITY'
|
||||
},
|
||||
@@ -182,7 +182,7 @@ var columns = [
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 100,
|
||||
width: 90,
|
||||
title: '요청납기',
|
||||
field: 'REQ_DEL_DATE'
|
||||
},
|
||||
@@ -191,7 +191,7 @@ var columns = [
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 200,
|
||||
width: 150,
|
||||
title: '고객사요청사항',
|
||||
field: 'CUSTOMER_REQUEST'
|
||||
},
|
||||
@@ -200,7 +200,7 @@ var columns = [
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 100,
|
||||
width: 70,
|
||||
title: 'M-BOM',
|
||||
field: 'MBOM_STATUS',
|
||||
formatter: fnc_subInfoValueFormatter,
|
||||
@@ -211,6 +211,12 @@ var columns = [
|
||||
|
||||
// 파란색(저장된 M-BOM)일 때만 팝업 열기
|
||||
if(mbomStatus !== '' && mbomStatus !== '0') {
|
||||
// 검색 조건에 해당 행의 데이터 자동 입력 (주석처리)
|
||||
// $("#search_part_no").val(fnc_checkNull(rowData.PART_NO));
|
||||
// $("#search_part_name").val(fnc_checkNull(rowData.PART_NAME));
|
||||
// $("#search_mbom_part_no").val(fnc_checkNull(rowData.MBOM_PART_NO)); // M-BOM 품번 (자동 생성된 값)
|
||||
// $("#search_save_date").val(fnc_checkNull(rowData.MBOM_REGDATE));
|
||||
|
||||
fn_openMBomFormPopup(objid);
|
||||
} else {
|
||||
Swal.fire({
|
||||
@@ -226,7 +232,7 @@ var columns = [
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 120,
|
||||
width: 100,
|
||||
title: '최종저장일',
|
||||
field: 'MBOM_REGDATE'
|
||||
}
|
||||
@@ -235,7 +241,7 @@ var columns = [
|
||||
// 검색 함수
|
||||
function fn_search(){
|
||||
// showCheck를 false로 설정하여 자동 체크박스 제거 (columns에 이미 체크박스 정의되어 있음)
|
||||
_tabulGrid = fnc_tabul_search(_tabul_layout_fitColumns, _tabulGrid, "/productionplanning/mBomMgmtGridList.do", columns, false);
|
||||
_tabulGrid = fnc_tabul_search(_tabul_layout_fitData, _tabulGrid, "/productionplanning/mBomMgmtGridList.do", columns, false);
|
||||
|
||||
// 그리드 로드 완료 후 행 클릭 이벤트 추가
|
||||
if(_tabulGrid) {
|
||||
@@ -355,10 +361,20 @@ function fn_openBomCopyPopup() {
|
||||
|
||||
// BOM 복사 팝업 창 열기
|
||||
function fn_openBomCopyPopupWindow(objId) {
|
||||
var popup_width = 1800;
|
||||
var popup_height = 900;
|
||||
var url = "/partMng/structureBomCopyFormPopup.do?objId=" + objId;
|
||||
fn_centerPopup(popup_width, popup_height, url, 'bomCopyPopup');
|
||||
// 선택된 행의 데이터 가져오기
|
||||
var selectedRow = _tabulGrid.searchRows("OBJID", "=", objId);
|
||||
if(selectedRow.length > 0) {
|
||||
var rowData = selectedRow[0].getData();
|
||||
var partNo = encodeURIComponent(fnc_checkNull(rowData.PART_NO));
|
||||
var partName = encodeURIComponent(fnc_checkNull(rowData.PART_NAME));
|
||||
|
||||
var popup_width = 1800;
|
||||
var popup_height = 900;
|
||||
var url = "/partMng/structureBomCopyFormPopup.do?objId=" + objId + "&partNo=" + partNo + "&partName=" + partName;
|
||||
fn_centerPopup(popup_width, popup_height, url, 'bomCopyPopup');
|
||||
} else {
|
||||
Swal.fire('선택된 데이터를 찾을 수 없습니다.');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -376,18 +392,27 @@ function fn_openBomCopyPopupWindow(objId) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 검색 영역 -->
|
||||
<div id="plmSearchZon">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="label"><label for="search_part_no">품번</label></td>
|
||||
<td><input type="text" name="search_part_no" id="search_part_no" value="${param.search_part_no}"></td>
|
||||
|
||||
<td class="label"><label for="search_part_name">품명</label></td>
|
||||
<td><input type="text" name="search_part_name" id="search_part_name" value="${param.search_part_name}"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<!-- 검색 영역 -->
|
||||
<div id="plmSearchZon">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="label"><label for="search_part_no">품번</label></td>
|
||||
<td><input type="text" name="search_part_no" id="search_part_no" value=""></td>
|
||||
|
||||
<td class="label"><label for="search_part_name">품명</label></td>
|
||||
<td><input type="text" name="search_part_name" id="search_part_name" value=""></td>
|
||||
</tr>
|
||||
<%--
|
||||
<tr>
|
||||
<td class="label"><label for="search_mbom_part_no">M-BOM 품번</label></td>
|
||||
<td><input type="text" name="search_mbom_part_no" id="search_mbom_part_no" value="${param.search_mbom_part_no}"></td>
|
||||
|
||||
<td class="label"><label for="search_save_date">저장일</label></td>
|
||||
<td><input type="date" name="search_save_date" id="search_save_date" value="${param.search_save_date}"></td>
|
||||
</tr>
|
||||
--%>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 그리드 영역 -->
|
||||
<%@include file= "/WEB-INF/view/common/common_gridArea.jsp" %>
|
||||
|
||||
@@ -38,98 +38,317 @@ $(function(){
|
||||
|
||||
$('.select2').select2();
|
||||
|
||||
// E-BOM 할당 버튼 (변경)
|
||||
$("#moveChange").click(function(){
|
||||
//Part 연결 (<< 버튼)
|
||||
$("#moveLeft").click(function(){
|
||||
// Tabulator에서 선택된 오른쪽 행 데이터 가져오기
|
||||
var rightFrame = parent.frames['rightFrame'];
|
||||
var rightSelectedRows = rightFrame.getSelectedRows ? rightFrame.getSelectedRows() : [];
|
||||
|
||||
if(rightSelectedRows.length === 0) {
|
||||
showConfirm("선택된 파트가 없습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 왼쪽 프레임에서 선택된 행 데이터 가져오기
|
||||
var leftPartNoObj = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document);
|
||||
|
||||
var leftPartChildObjId = null;
|
||||
var leftPartNo = null;
|
||||
var leftPartNoQty = null;
|
||||
var leftParentObjId = null;
|
||||
var leftPartLastObjId = null;
|
||||
var leftQtyParObjId = null;
|
||||
var leftParentParts = "";
|
||||
|
||||
if(leftPartNoObj.length > 0) {
|
||||
leftPartChildObjId = leftPartNoObj.val();
|
||||
leftPartNo = leftPartNoObj.attr("data-PART_NO");
|
||||
leftPartNoQty = leftPartNoObj.attr("data-PART_NO_QTY");
|
||||
leftParentObjId = leftPartNoObj.attr("data-OBJID");
|
||||
leftPartLastObjId = leftPartNoObj.attr("data-LAST_PART_OBJID");
|
||||
leftQtyParObjId = leftPartNoObj.attr("data-PART_OBJID");
|
||||
leftParentParts = leftPartNoObj.attr("data-PARENT_PARTS") || "";
|
||||
}
|
||||
|
||||
// 같은 Part를 연결한건지 체크
|
||||
var isSamePart = false;
|
||||
for(var i = 0; i < rightSelectedRows.length; i++){
|
||||
var rowData = rightSelectedRows[i].getData();
|
||||
var rightPartNo = rowData.PART_NO;
|
||||
if(rightPartNo == leftPartNo){
|
||||
showConfirm({
|
||||
title: '연결 불가',
|
||||
html: '오류 Part No : <strong>['+rightPartNo+']</strong><br>같은 Part No끼리 연결할 수 없습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
isSamePart = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(isSamePart) return false;
|
||||
|
||||
// 선택된 파트의 OBJID 배열 생성
|
||||
var rightCheckedArr = [];
|
||||
for(var i = 0; i < rightSelectedRows.length; i++){
|
||||
var rowData = rightSelectedRows[i].getData();
|
||||
rightCheckedArr.push(rowData.OBJID);
|
||||
}
|
||||
|
||||
// Part 연결 확인
|
||||
if(fnc_checkNull(leftPartNo) == ""){
|
||||
showConfirm({
|
||||
title: '1레벨 등록 확인',
|
||||
html: '좌측에 선택된 Part정보가 없습니다.<br>이대로 연결하면 1레벨로 등록됩니다.<br><br>진행하시겠습니까?',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: '진행',
|
||||
cancelButtonText: '취소'
|
||||
}).then(result => {
|
||||
if (result.isConfirmed) {
|
||||
fn_relatePartInfo(leftPartChildObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
showConfirm({
|
||||
title: 'E-BOM 할당',
|
||||
text: 'E-BOM을 선택하여 이 프로젝트에 할당하시겠습니까?',
|
||||
title: 'Part 연결',
|
||||
text: '선택한 Part를 연결하시겠습니까?',
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: '할당',
|
||||
confirmButtonText: '연결',
|
||||
cancelButtonText: '취소'
|
||||
}).then(result => {
|
||||
if (result.isConfirmed) {
|
||||
fn_assignEbom();
|
||||
fn_relatePartInfo(leftPartChildObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId);
|
||||
}
|
||||
});
|
||||
});
|
||||
//end of Part 연결
|
||||
|
||||
//연결된 part 삭제 (>> 버튼)
|
||||
$("#moveRight").click(function(){
|
||||
var leftPartNoObj = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document);
|
||||
var leftPartChildObjId = leftPartNoObj.val();
|
||||
var leftPartNo = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document).attr("data-PART_NO");
|
||||
var leftParentPartNo = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document).attr("data-PARENT_PART_NO");
|
||||
var leftParentObjId = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document).attr("data-PARENT_OBJID");
|
||||
var leftPartLastObjId = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document).attr("data-LAST_PART_OBJID");
|
||||
|
||||
fn_deletePartRelateInfo(leftPartNoObj.val(), leftPartLastObjId, leftParentPartNo, leftParentObjId, leftPartChildObjId);
|
||||
});
|
||||
//end of 연결된 part 삭제
|
||||
|
||||
//연결된 part 변경 (변경 버튼)
|
||||
$("#moveChange").click(function(){
|
||||
var leftPartNoList = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document);
|
||||
|
||||
if(leftPartNoList.length === 0){
|
||||
showConfirm("선택된 파트가 없습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(leftPartNoList.length > 1){
|
||||
showConfirm("한번에 1개의 파트만 변경가능합니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var leftPartNo = leftPartNoList.attr("data-PART_NO");
|
||||
var leftPartObjid = leftPartNoList.attr("data-BOM_LAST_PART_OBJID");
|
||||
var leftParentPartObjid = leftPartNoList.attr("data-PARENT_PART_NO");
|
||||
var leftPartChildObjId = leftPartNoList.val();
|
||||
var leftPartBomQtyObjId = leftPartNoList.attr("data-OBJID");
|
||||
|
||||
// Tabulator에서 선택된 오른쪽 행 데이터 가져오기
|
||||
var rightFrame = parent.frames['rightFrame'];
|
||||
var rightSelectedRows = rightFrame.getSelectedRows ? rightFrame.getSelectedRows() : [];
|
||||
|
||||
if(rightSelectedRows.length === 0){
|
||||
showConfirm("선택된 파트가 없습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(rightSelectedRows.length > 1){
|
||||
showConfirm("한번에 1개의 파트만 변경가능합니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var rightRowData = rightSelectedRows[0].getData();
|
||||
var rightPartNo = rightRowData.PART_NO;
|
||||
var rightPartRev = rightRowData.REVISION || "";
|
||||
var rightObjId = rightRowData.OBJID;
|
||||
|
||||
// Part 변경 확인
|
||||
showConfirm({
|
||||
title: 'Part 변경',
|
||||
html: '선택한 Part를 변경하시겠습니까?<br><br>' +
|
||||
'<strong>기존:</strong> ' + leftPartNo + '<br>' +
|
||||
'<strong>변경:</strong> ' + rightPartNo,
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: '변경',
|
||||
cancelButtonText: '취소'
|
||||
}).then(result => {
|
||||
if (result.isConfirmed) {
|
||||
fn_changeRelatePartInfo(leftPartBomQtyObjId, rightObjId, leftPartChildObjId, leftParentPartObjid, leftPartChildObjId, leftPartObjid, rightPartNo, rightPartRev);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// << 버튼 (현재는 사용 안 함)
|
||||
$("#moveLeft").click(function(){
|
||||
showConfirm("이 기능은 현재 사용할 수 없습니다.");
|
||||
});
|
||||
|
||||
// >> 버튼 (현재는 사용 안 함)
|
||||
$("#moveRight").click(function(){
|
||||
showConfirm("이 기능은 현재 사용할 수 없습니다.");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// E-BOM 할당 함수
|
||||
function fn_assignEbom(){
|
||||
// 오른쪽 프레임에서 선택된 E-BOM 가져오기
|
||||
var rightFrame = parent.frames['rightFrame'];
|
||||
var rightSelectedRows = rightFrame.getSelectedRows ? rightFrame.getSelectedRows() : [];
|
||||
|
||||
if(rightSelectedRows.length === 0){
|
||||
showConfirm("할당할 E-BOM을 선택해주세요.");
|
||||
return false;
|
||||
//구조 연결
|
||||
function fn_relatePartInfo(leftObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId){
|
||||
if(typeof rightCheckedArr != "undefined" && rightCheckedArr.length == 0){
|
||||
showConfirm("선택된 Part가 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(rightSelectedRows.length > 1){
|
||||
showConfirm("한 번에 1개의 E-BOM만 할당할 수 있습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var rowData = rightSelectedRows[0].getData();
|
||||
var bomReportObjid = rowData.OBJID;
|
||||
// M-BOM API 호출
|
||||
console.log("API 호출 시작: /productionplanning/relateMbomPartInfo.do");
|
||||
console.log("전송 데이터:", {
|
||||
"leftObjId": leftObjId,
|
||||
"leftPartNoQty": leftPartNoQty,
|
||||
"OBJID": $("#objId").val(),
|
||||
"rightCheckedArr[]": rightCheckedArr,
|
||||
"partObjId": leftPartLastObjId,
|
||||
"BOM_REPORT_OBJID": $("#objId").val(),
|
||||
"leftPartChildObjId": leftPartChildObjId,
|
||||
"leftQtyParObjId": leftQtyParObjId
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
url: "/productionplanning/assignEbomToMbom.do",
|
||||
url: "/productionplanning/relateMbomPartInfo.do",
|
||||
method: 'post',
|
||||
traditional: true,
|
||||
data: {
|
||||
"projectMgmtObjid": $("#objId").val(),
|
||||
"bomReportObjid": bomReportObjid
|
||||
"leftObjId": leftObjId,
|
||||
"leftPartNoQty": leftPartNoQty,
|
||||
"OBJID": $("#objId").val(),
|
||||
"rightCheckedArr[]": rightCheckedArr,
|
||||
"partObjId": leftPartLastObjId,
|
||||
"BOM_REPORT_OBJID": $("#objId").val(),
|
||||
"leftPartChildObjId": leftPartChildObjId,
|
||||
"leftQtyParObjId": leftQtyParObjId
|
||||
},
|
||||
dataType: 'json',
|
||||
async:false,
|
||||
success: function(data) {
|
||||
console.log("API 응답:", data);
|
||||
if(data.result){
|
||||
showConfirm({
|
||||
title: '할당 완료',
|
||||
text: 'E-BOM이 성공적으로 할당되었습니다.',
|
||||
icon: 'success'
|
||||
});
|
||||
// 왼쪽 프레임 새로고침 (캐시 방지)
|
||||
var leftFrame = parent.frames['leftFrame'];
|
||||
leftFrame.location.href = leftFrame.location.href.split('?')[0] + '?t=' + new Date().getTime();
|
||||
|
||||
// 왼쪽 프레임 새로고침
|
||||
parent.frames['leftFrame'].location.reload();
|
||||
|
||||
// 부모 창(M-BOM 목록) 새로고침
|
||||
if(window.opener && window.opener.fn_search) {
|
||||
window.opener.fn_search();
|
||||
// 오른쪽 프레임 선택 해제
|
||||
var rightFrame = parent.frames['rightFrame'];
|
||||
if(rightFrame.clearSelection) {
|
||||
rightFrame.clearSelection();
|
||||
}
|
||||
} else {
|
||||
showConfirm({
|
||||
title: '할당 실패',
|
||||
text: 'E-BOM 할당 중 오류가 발생했습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
console.error("API 결과 실패");
|
||||
}
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
showConfirm({
|
||||
title: '오류',
|
||||
text: 'E-BOM 할당 중 오류가 발생했습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
console.error("API 호출 실패:", error);
|
||||
console.error("상태 코드:", jqxhr.status);
|
||||
console.error("응답 텍스트:", jqxhr.responseText);
|
||||
}
|
||||
});
|
||||
}
|
||||
//end of 구조 연결
|
||||
|
||||
//구조 연결 해제
|
||||
function fn_deletePartRelateInfo(leftObjId, leftPartLastObjId, leftParentPartNo, leftParentObjId, leftPartChildObjId){
|
||||
if(leftObjId == null){
|
||||
showConfirm("연결 해제할 Part를 선택해 주시기 바랍니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
showConfirm({
|
||||
title: 'Part 연결 해제',
|
||||
text: '선택한 Part의 연결을 해제하시겠습니까?',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: '연결 해제',
|
||||
cancelButtonText: '취소'
|
||||
}).then(result => {
|
||||
if (!result.isConfirmed) return;
|
||||
|
||||
// M-BOM API 호출
|
||||
$.ajax({
|
||||
url: "/productionplanning/deleteMbomPartRelateInfo.do",
|
||||
method: 'post',
|
||||
data: {
|
||||
"OBJID": $("#objId").val(),
|
||||
"leftObjId": leftObjId,
|
||||
"partObjId": leftPartLastObjId,
|
||||
"BOM_REPORT_OBJID": $("#objId").val(),
|
||||
"leftPartChildObjId": leftPartChildObjId,
|
||||
"leftParentPartNo": leftParentPartNo,
|
||||
"leftParentObjId": leftParentObjId
|
||||
},
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
if(data.result){
|
||||
// 왼쪽 프레임 새로고침 (캐시 방지)
|
||||
var leftFrame = parent.frames['leftFrame'];
|
||||
leftFrame.location.href = leftFrame.location.href.split('?')[0] + '?t=' + new Date().getTime();
|
||||
} else {
|
||||
console.error("API 결과 실패");
|
||||
}
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
console.error("API 호출 실패:", error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
//end of 구조 연결 해제
|
||||
|
||||
//구조 연결 변경
|
||||
function fn_changeRelatePartInfo(objId,rightObjId,leftObjId,leftPartNoQty,leftPartChildObjId,leftPartObjid,rightPartNo,rightPartRev){
|
||||
// M-BOM API 호출
|
||||
$.ajax({
|
||||
url: "/productionplanning/changeMbomPartInfo.do",
|
||||
method: 'post',
|
||||
data: {
|
||||
"rightObjId": rightObjId,
|
||||
"OBJID": objId,
|
||||
"BOM_REPORT_OBJID": $("#objId").val(),
|
||||
"leftObjId": leftObjId,
|
||||
"leftPartNoQty": leftPartNoQty,
|
||||
"leftPartChildObjId": leftPartChildObjId,
|
||||
"leftPartObjid": leftPartObjid,
|
||||
"rightPartNo": rightPartNo,
|
||||
"rightPartRev": rightPartRev
|
||||
},
|
||||
dataType: 'json',
|
||||
async:false,
|
||||
success: function(data) {
|
||||
if(data.result){
|
||||
// 왼쪽 프레임 새로고침 (캐시 방지)
|
||||
var leftFrame = parent.frames['leftFrame'];
|
||||
leftFrame.location.href = leftFrame.location.href.split('?')[0] + '?t=' + new Date().getTime();
|
||||
|
||||
// 오른쪽 프레임 선택 해제
|
||||
var rightFrame = parent.frames['rightFrame'];
|
||||
if(rightFrame.clearSelection) {
|
||||
rightFrame.clearSelection();
|
||||
}
|
||||
} else {
|
||||
console.error("API 결과 실패");
|
||||
}
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
console.error("API 호출 실패:", error);
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<body class="backcolor" style="border:border:1px solid #ccc;">
|
||||
<form name="form1" id="form1" action="" method="post">
|
||||
<input type="hidden" name="objId" id="objId" value="${param.objId}" />
|
||||
|
||||
@@ -143,4 +362,3 @@ function fn_assignEbom(){
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<%String objId = com.pms.common.utils.CommonUtils.checkNull(request.getParameter("objId"));%>
|
||||
<frameset cols="*, 100px, *" border="0" noresize>
|
||||
<frameset cols="60%, 100px, 40%" border="0" noresize>
|
||||
<frame src="/productionplanning/mBomPopupLeft.do?objId=<%=objId%>" name="leftFrame">
|
||||
<frame src="/productionplanning/mBomPopupCenter.do?objId=<%=objId%>" name="centerFrame">
|
||||
<frame src="/productionplanning/mBomPopupRight.do?objId=<%=objId%>" name="rightFrame">
|
||||
|
||||
@@ -17,12 +17,17 @@
|
||||
#mBomTableWrap {
|
||||
width: 99%;
|
||||
margin: 10px auto;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
#mBomName {
|
||||
margin-bottom: 10px;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
body {
|
||||
overflow: hidden;
|
||||
}
|
||||
/* Tabulator 커스텀 스타일 */
|
||||
.tabulator-row.level-1 { background-color: #fde9d9 !important; }
|
||||
.tabulator-row.level-2 { background-color: #daeef3 !important; }
|
||||
@@ -50,13 +55,37 @@ function fn_initGrid() {
|
||||
// 컬럼 정의
|
||||
var columns = [];
|
||||
|
||||
// 라디오 버튼 컬럼 (E-BOM과 동일)
|
||||
columns.push({
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 60,
|
||||
title: '선택',
|
||||
field: 'RADIO',
|
||||
headerSort: false,
|
||||
formatter: function(cell) {
|
||||
var rowData = cell.getData();
|
||||
return '<input type="radio" name="checkedPartNo" value="' + (rowData.CHILD_OBJID || '') + '" ' +
|
||||
'data-OBJID="' + (rowData.OBJID || '') + '" ' +
|
||||
'data-PART_NO="' + (rowData.PART_NO || '') + '" ' +
|
||||
'data-PARENT_PART_NO="' + (rowData.PARENT_PART_NO || '') + '" ' +
|
||||
'data-PART_NO_QTY="' + (rowData.LAST_PART_OBJID || '') + '" ' +
|
||||
'data-PARENT_PARTS="' + (rowData.PARENT_PARTS || '') + '" ' +
|
||||
'data-LAST_PART_OBJID="' + (rowData.LAST_PART_OBJID || rowData.BOM_LAST_PART_OBJID || '') + '" ' +
|
||||
'data-PARENT_OBJID="' + (rowData.PARENT_OBJID || '') + '" ' +
|
||||
'data-PART_OBJID="' + (rowData.PART_OBJID || '') + '" ' +
|
||||
'data-BOM_LAST_PART_OBJID="' + (rowData.BOM_LAST_PART_OBJID || rowData.LAST_PART_OBJID || '') + '" ' +
|
||||
'data-CHILD_OBJID="' + (rowData.CHILD_OBJID || '') + '">';
|
||||
}
|
||||
});
|
||||
|
||||
// 수준 컬럼 그룹
|
||||
var levelColumns = [];
|
||||
for(var i = 1; i <= maxLevel; i++) {
|
||||
levelColumns.push({
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 30,
|
||||
width: 25,
|
||||
title: i,
|
||||
field: 'LEVEL_' + i,
|
||||
formatter: function(cell) {
|
||||
@@ -71,36 +100,39 @@ function fn_initGrid() {
|
||||
columns: levelColumns
|
||||
});
|
||||
|
||||
// 나머지 컬럼 추가
|
||||
// 기본 정보 컬럼들 (E-BOM 정보)
|
||||
columns.push(
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 150,
|
||||
widthGrow: 2,
|
||||
title: '품번',
|
||||
field: 'PART_NO'
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 250,
|
||||
widthGrow: 3,
|
||||
title: '품명',
|
||||
field: 'PART_NAME'
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 80,
|
||||
width: 60,
|
||||
title: '수량',
|
||||
field: 'QTY_TEMP'
|
||||
field: 'QTY_TEMP',
|
||||
visible: false
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 100,
|
||||
width: 80,
|
||||
title: '항목 수량',
|
||||
field: 'ITEM_QTY'
|
||||
field: 'ITEM_QTY',
|
||||
visible: false
|
||||
},
|
||||
/* 주석처리: Rev, 규격, 제품구분, 상태 컬럼
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
@@ -128,21 +160,351 @@ function fn_initGrid() {
|
||||
width: 100,
|
||||
title: '상태',
|
||||
field: 'STATUS_NAME'
|
||||
},
|
||||
*/
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 60,
|
||||
title: '3D',
|
||||
field: 'CU01_CNT',
|
||||
visible: false,
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
return value && value > 0 ? '<span class="file_icon"></span>' : '<span class="file_empty_icon"></span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 60,
|
||||
title: '2D',
|
||||
field: 'CU02_CNT',
|
||||
visible: false,
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
return value && value > 0 ? '<span class="file_icon"></span>' : '<span class="file_empty_icon"></span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 60,
|
||||
title: 'PDF',
|
||||
field: 'CU03_CNT',
|
||||
visible: false,
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
return value && value > 0 ? '<span class="file_icon"></span>' : '<span class="file_empty_icon"></span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 100,
|
||||
title: '재료',
|
||||
field: 'MATERIAL',
|
||||
visible: false
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 120,
|
||||
title: '열처리경도',
|
||||
field: 'HEAT_TREATMENT_HARDNESS',
|
||||
visible: false
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 120,
|
||||
title: '열처리방법',
|
||||
field: 'HEAT_TREATMENT_METHOD',
|
||||
visible: false
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 100,
|
||||
title: '표면처리',
|
||||
field: 'SURFACE_TREATMENT',
|
||||
visible: false
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 150,
|
||||
title: '공급업체',
|
||||
field: 'SUPPLIER',
|
||||
visible: false
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 100,
|
||||
title: '범주이름',
|
||||
field: 'CATEGORY_NAME',
|
||||
visible: false
|
||||
}
|
||||
);
|
||||
|
||||
// 생산관리 컬럼 그룹
|
||||
columns.push({
|
||||
title: '생산관리',
|
||||
headerHozAlign: 'center',
|
||||
columns: [
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 100,
|
||||
title: '지급/사급',
|
||||
field: 'SUPPLY_TYPE',
|
||||
editor: 'list',
|
||||
editorParams: {
|
||||
values: ['지급', '사급', '자급']
|
||||
}
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 100,
|
||||
title: '소재',
|
||||
field: 'RAW_MATERIAL',
|
||||
editor: 'input',
|
||||
editable: function(cell) {
|
||||
// 자급인 경우 입력 불가
|
||||
return cell.getRow().getData().SUPPLY_TYPE !== '자급';
|
||||
}
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 100,
|
||||
title: '사이즈',
|
||||
field: 'SIZE',
|
||||
editor: false,
|
||||
formatter: function(cell) {
|
||||
// 항목수량 × 수주수량 (수정 불가)
|
||||
var data = cell.getRow().getData();
|
||||
var itemQty = data.ITEM_QTY || 0;
|
||||
var orderQty = data.ORDER_QTY || 0;
|
||||
return itemQty * orderQty;
|
||||
}
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 100,
|
||||
title: '소요량',
|
||||
field: 'REQUIRED_QTY',
|
||||
editor: false
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 100,
|
||||
title: '발주수량',
|
||||
field: 'ORDER_QTY',
|
||||
editor: false,
|
||||
formatter: function(cell) {
|
||||
// 항목수량 (수정 불가)
|
||||
return cell.getRow().getData().ITEM_QTY || 0;
|
||||
}
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 80,
|
||||
title: "Q'ty",
|
||||
field: 'QTY',
|
||||
editor: 'number',
|
||||
editorParams: {
|
||||
min: 0,
|
||||
step: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 100,
|
||||
title: '제작수량',
|
||||
field: 'PRODUCTION_QTY',
|
||||
editor: 'number',
|
||||
editorParams: {
|
||||
min: 0,
|
||||
step: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 150,
|
||||
title: '가공업체',
|
||||
field: 'PROCESSING_VENDOR',
|
||||
editor: 'input'
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 100,
|
||||
title: '가공납기',
|
||||
field: 'PROCESSING_DEADLINE',
|
||||
editor: 'date'
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 100,
|
||||
title: '연삭납기',
|
||||
field: 'GRINDING_DEADLINE',
|
||||
editor: 'date'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// 구매 컬럼 그룹 (제작수량 기준)
|
||||
columns.push({
|
||||
title: '구매',
|
||||
headerHozAlign: 'center',
|
||||
columns: [
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 150,
|
||||
title: '소재품번',
|
||||
field: 'MATERIAL_PART_NO',
|
||||
editor: 'input'
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 100,
|
||||
title: '정미수량',
|
||||
field: 'NET_QTY',
|
||||
editor: false,
|
||||
formatter: function(cell) {
|
||||
// 소요량 × 제작수량 (소수점 무조건 올림)
|
||||
var data = cell.getRow().getData();
|
||||
var requiredQty = parseFloat(data.REQUIRED_QTY) || 0;
|
||||
var productionQty = parseFloat(data.PRODUCTION_QTY) || 0;
|
||||
var netQty = requiredQty * productionQty;
|
||||
return Math.ceil(netQty); // 무조건 올림
|
||||
}
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 100,
|
||||
title: '발주수량',
|
||||
field: 'PO_QTY',
|
||||
editor: 'number',
|
||||
editorParams: {
|
||||
min: 0,
|
||||
step: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 150,
|
||||
title: '공급업체',
|
||||
field: 'VENDOR',
|
||||
editor: 'input'
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'right',
|
||||
width: 100,
|
||||
title: '단가',
|
||||
field: 'UNIT_PRICE',
|
||||
editor: 'number',
|
||||
editorParams: {
|
||||
min: 0,
|
||||
step: 0.01
|
||||
},
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
return value ? Number(value).toLocaleString() : '0';
|
||||
}
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'right',
|
||||
width: 100,
|
||||
title: '총단가',
|
||||
field: 'TOTAL_PRICE',
|
||||
editor: false,
|
||||
formatter: function(cell) {
|
||||
// 발주수량 × 단가
|
||||
var data = cell.getRow().getData();
|
||||
var poQty = parseFloat(data.PO_QTY) || 0;
|
||||
var unitPrice = parseFloat(data.UNIT_PRICE) || 0;
|
||||
var totalPrice = poQty * unitPrice;
|
||||
return totalPrice.toLocaleString();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// 서버에서 전달받은 데이터 확인
|
||||
var bomTreeData = ${bomTreeListJson};
|
||||
console.log("bomTreeData:", bomTreeData);
|
||||
console.log("bomTreeData length:", bomTreeData ? bomTreeData.length : 0);
|
||||
|
||||
// Tabulator 생성
|
||||
_tabulGrid = new Tabulator("#mBomTableWrap", {
|
||||
layout: "fitColumns",
|
||||
layout: "fitData",
|
||||
height: "calc(100vh - 150px)",
|
||||
columns: columns,
|
||||
data: ${bomTreeListJson},
|
||||
data: bomTreeData,
|
||||
rowFormatter: function(row) {
|
||||
var data = row.getData();
|
||||
var level = data.LEVEL || 1;
|
||||
row.getElement().classList.add('level-' + level);
|
||||
}
|
||||
});
|
||||
|
||||
// 셀 편집 이벤트 등록
|
||||
_tabulGrid.on("cellEdited", function(cell) {
|
||||
var field = cell.getField();
|
||||
var row = cell.getRow();
|
||||
var data = row.getData();
|
||||
|
||||
// 지급/사급 변경 시 소재, 사이즈, 소요량 필드 재계산
|
||||
if(field === 'SUPPLY_TYPE') {
|
||||
if(data.SUPPLY_TYPE === '자급') {
|
||||
// 자급인 경우 소재, 사이즈, 소요량 초기화
|
||||
row.update({
|
||||
RAW_MATERIAL: '',
|
||||
SIZE: 0,
|
||||
REQUIRED_QTY: 0
|
||||
});
|
||||
}
|
||||
// 행 전체 재렌더링
|
||||
row.reformat();
|
||||
}
|
||||
|
||||
// 제작수량 변경 시 정미수량 자동 계산
|
||||
if(field === 'PRODUCTION_QTY' || field === 'REQUIRED_QTY') {
|
||||
var requiredQty = parseFloat(data.REQUIRED_QTY) || 0;
|
||||
var productionQty = parseFloat(data.PRODUCTION_QTY) || 0;
|
||||
var netQty = Math.ceil(requiredQty * productionQty);
|
||||
row.update({NET_QTY: netQty});
|
||||
}
|
||||
|
||||
// 발주수량 또는 단가 변경 시 총단가 자동 계산
|
||||
if(field === 'PO_QTY' || field === 'UNIT_PRICE') {
|
||||
var poQty = parseFloat(data.PO_QTY) || 0;
|
||||
var unitPrice = parseFloat(data.UNIT_PRICE) || 0;
|
||||
var totalPrice = poQty * unitPrice;
|
||||
row.update({TOTAL_PRICE: totalPrice});
|
||||
}
|
||||
|
||||
// Q'ty 초기값 설정 (발주수량에서 가져오기)
|
||||
if(field === 'ORDER_QTY' && !data.QTY) {
|
||||
row.update({QTY: data.ORDER_QTY});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 필터 적용 함수
|
||||
@@ -172,20 +534,26 @@ function fn_resetFilter() {
|
||||
|
||||
// M-BOM 조회 (헤더 프레임에서 호출)
|
||||
function fn_searchMbom(searchParams) {
|
||||
console.log("fn_searchMbom (left) 호출됨:", searchParams);
|
||||
|
||||
$.ajax({
|
||||
url: "/productionplanning/getMbomList.do",
|
||||
method: 'post',
|
||||
data: searchParams,
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
console.log("M-BOM 조회 결과:", data);
|
||||
if(data && data.list) {
|
||||
console.log("데이터 개수:", data.list.length);
|
||||
_tabulGrid.setData(data.list);
|
||||
} else {
|
||||
console.log("데이터 없음");
|
||||
_tabulGrid.setData([]);
|
||||
}
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
console.error("M-BOM 조회 오류:", error);
|
||||
console.error("응답:", jqxhr.responseText);
|
||||
_tabulGrid.setData([]);
|
||||
}
|
||||
});
|
||||
@@ -215,7 +583,7 @@ function getMbomTreeData() {
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="mBomName">
|
||||
<!-- <div id="mBomName">
|
||||
<c:choose>
|
||||
<c:when test="${not empty ebomInfo}">
|
||||
E-BOM: ${ebomInfo.PART_NO} - ${ebomInfo.PART_NAME}
|
||||
@@ -224,7 +592,7 @@ function getMbomTreeData() {
|
||||
할당된 E-BOM이 없습니다.
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</div>
|
||||
</div> -->
|
||||
<div id="mBomTableWrap"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -29,7 +29,7 @@ body, html {
|
||||
padding-right: 5px;
|
||||
}
|
||||
#ebomTable {
|
||||
height: calc(100% - 80px);
|
||||
height: 540px;
|
||||
}
|
||||
</style>
|
||||
<link href="/css/tabulator/tabulator.min.css" rel="stylesheet">
|
||||
@@ -70,10 +70,32 @@ body, html {
|
||||
</div>
|
||||
|
||||
<div id="ebomTable"></div>
|
||||
|
||||
<div class="table_paging" style="display: flex; align-items: center; justify-content: space-between; padding: 10px 0;">
|
||||
<div id="pagingButtons" style="flex: 1; text-align: center;"></div>
|
||||
<div style="display: flex; align-items: center; gap: 10px;">
|
||||
<select id="countPerPage" name="countPerPage" class="selectType02 listCount" onchange="javascript:fnc_goPage(1);">
|
||||
<option value="10">10</option>
|
||||
<option value="20" selected="">20</option>
|
||||
<option value="30">30</option>
|
||||
<option value="50">50</option>
|
||||
<option value="100">100</option>
|
||||
<option value="150">150</option>
|
||||
<option value="200">200</option>
|
||||
<option value="1000">1000</option>
|
||||
</select>
|
||||
<div class="table_Status" style="font-size: 12px;">
|
||||
<b id="bTableStatus">0</b> 건
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
var ebomTable;
|
||||
var allData = [];
|
||||
var currentPage = 1;
|
||||
var pageSize = 20;
|
||||
|
||||
$(document).ready(function(){
|
||||
initEbomTable();
|
||||
@@ -97,7 +119,7 @@ $(document).ready(function(){
|
||||
function initEbomTable() {
|
||||
ebomTable = new Tabulator("#ebomTable", {
|
||||
layout: "fitColumns",
|
||||
height: "100%",
|
||||
height: 540,
|
||||
selectable: true,
|
||||
columns: [
|
||||
{formatter:"rowSelection", titleFormatter:"rowSelection", hozAlign:"center", vertAlign:"middle", headerSort:false, width: 40},
|
||||
@@ -130,22 +152,63 @@ function fn_searchEbom() {
|
||||
success: function(data) {
|
||||
if(data && data.list) {
|
||||
// 품번과 품명이 비어있지 않은 데이터만 필터링
|
||||
var filteredList = data.list.filter(function(item) {
|
||||
allData = data.list.filter(function(item) {
|
||||
return item.PART_NO && item.PART_NO.trim() !== '' &&
|
||||
item.PART_NAME && item.PART_NAME.trim() !== '';
|
||||
});
|
||||
ebomTable.setData(filteredList);
|
||||
} else {
|
||||
ebomTable.setData([]);
|
||||
allData = [];
|
||||
}
|
||||
currentPage = 1;
|
||||
fnc_goPage(1);
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
console.error("E-BOM 조회 오류:", error);
|
||||
allData = [];
|
||||
ebomTable.setData([]);
|
||||
updatePagination();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 페이지 이동
|
||||
function fnc_goPage(page) {
|
||||
pageSize = parseInt($("#countPerPage").val());
|
||||
var totalPages = Math.ceil(allData.length / pageSize);
|
||||
|
||||
if(page < 1) page = 1;
|
||||
if(page > totalPages) page = totalPages;
|
||||
if(totalPages === 0) page = 1;
|
||||
|
||||
currentPage = page;
|
||||
|
||||
var startIdx = (page - 1) * pageSize;
|
||||
var endIdx = startIdx + pageSize;
|
||||
var pageData = allData.slice(startIdx, endIdx);
|
||||
|
||||
ebomTable.setData(pageData);
|
||||
updatePagination();
|
||||
}
|
||||
|
||||
// 페이지네이션 UI 업데이트
|
||||
function updatePagination() {
|
||||
var totalPages = Math.ceil(allData.length / pageSize);
|
||||
if(totalPages === 0) totalPages = 1;
|
||||
|
||||
$("#bTableStatus").text(allData.length);
|
||||
|
||||
// 페이지 버튼 생성
|
||||
var pagingHtml = '';
|
||||
for(var i = 1; i <= totalPages; i++) {
|
||||
if(i === currentPage) {
|
||||
pagingHtml += '<input type="button" name="mailPaging" class="paging selected" value="' + i + '">';
|
||||
} else {
|
||||
pagingHtml += '<input type="button" name="mailPaging" class="paging" onclick="javascript:fnc_goPage(' + i + ');" value="' + i + '">';
|
||||
}
|
||||
}
|
||||
$("#pagingButtons").html(pagingHtml);
|
||||
}
|
||||
|
||||
// 선택된 행 가져오기 (중앙 프레임에서 호출)
|
||||
function getSelectedRows() {
|
||||
return ebomTable.getSelectedRows();
|
||||
|
||||
@@ -957,6 +957,7 @@ public class PartMngController {
|
||||
String sourceBomObjId = CommonUtils.checkNull((String)paramMap.get("sourceBomObjId"));
|
||||
String targetPartNo = CommonUtils.checkNull((String)paramMap.get("targetPartNo"));
|
||||
String targetPartName = CommonUtils.checkNull((String)paramMap.get("targetPartName"));
|
||||
String productCode = CommonUtils.checkNull((String)paramMap.get("productCode")); // 제품구분
|
||||
List<Map<String, Object>> bomData = (List<Map<String, Object>>)paramMap.get("bomData");
|
||||
|
||||
if(bomData == null || bomData.isEmpty()) {
|
||||
@@ -974,14 +975,83 @@ public class PartMngController {
|
||||
saveParam.put("BOM_DATA", bomData);
|
||||
saveParam.put("USER_ID", userId);
|
||||
|
||||
// SqlSession을 통해 직접 실행
|
||||
SqlSession sqlSession = SqlMapConfig.getInstance().getSqlSession();
|
||||
// M-BOM 품번 자동 생성
|
||||
// E-BOM 선택 시: M-{E-BOM 품번}-YYMMDD-01
|
||||
// M-BOM 선택 시: 기존 M-BOM 품번에서 YYMMDD-순번만 업데이트
|
||||
java.text.SimpleDateFormat dateFormat = new java.text.SimpleDateFormat("yyMMdd");
|
||||
String dateStr = dateFormat.format(new java.util.Date());
|
||||
|
||||
String mbomPartNo = "";
|
||||
String sourceBomType = CommonUtils.checkNull((String)paramMap.get("sourceBomType"));
|
||||
|
||||
// 제품구분 확인 (Machine 여부)
|
||||
// Machine 제품코드: COMM_CODE 테이블에서 확인 필요 (예: 0001807, MACHINE 등)
|
||||
boolean isMachine = productCode != null && (
|
||||
productCode.equals("0001807") ||
|
||||
productCode.toUpperCase().contains("MACHINE")
|
||||
);
|
||||
|
||||
// M-BOM 품번 prefix 생성
|
||||
String mbomPrefix = "";
|
||||
|
||||
if("EBOM".equals(sourceBomType)) {
|
||||
// E-BOM 선택: M-{E-BOM 품번}-YYMMDD-순번
|
||||
mbomPrefix = "M-" + targetPartNo + "-" + dateStr;
|
||||
} else if("MBOM".equals(sourceBomType)) {
|
||||
// M-BOM 선택: 기존 M-BOM 품번에서 날짜-순번만 업데이트
|
||||
String existingMbomPartNo = CommonUtils.checkNull((String)paramMap.get("existingMbomPartNo"));
|
||||
if(!"".equals(existingMbomPartNo) && existingMbomPartNo.startsWith("M-")) {
|
||||
// M-{품번} 부분 추출 (마지막 두 개의 대시 앞부분)
|
||||
int lastDashIndex = existingMbomPartNo.lastIndexOf("-");
|
||||
if(lastDashIndex > 0) {
|
||||
int secondLastDashIndex = existingMbomPartNo.lastIndexOf("-", lastDashIndex - 1);
|
||||
if(secondLastDashIndex > 0) {
|
||||
String partPrefix = existingMbomPartNo.substring(0, secondLastDashIndex);
|
||||
mbomPrefix = partPrefix + "-" + dateStr;
|
||||
} else {
|
||||
mbomPrefix = "M-" + targetPartNo + "-" + dateStr;
|
||||
}
|
||||
} else {
|
||||
mbomPrefix = "M-" + targetPartNo + "-" + dateStr;
|
||||
}
|
||||
} else {
|
||||
mbomPrefix = "M-" + targetPartNo + "-" + dateStr;
|
||||
}
|
||||
} else {
|
||||
// 기본값
|
||||
mbomPrefix = "M-" + targetPartNo + "-" + dateStr;
|
||||
}
|
||||
|
||||
// 같은 날짜의 최대 순번 조회
|
||||
SqlSession sqlSession = null;
|
||||
int maxSeq = 0;
|
||||
try {
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession();
|
||||
Map<String, Object> seqParam = new HashMap<String, Object>();
|
||||
seqParam.put("prefix", mbomPrefix);
|
||||
Integer maxSeqResult = sqlSession.selectOne("productionplanning.getMaxMbomSeqByDate", seqParam);
|
||||
if(maxSeqResult != null) {
|
||||
maxSeq = maxSeqResult.intValue();
|
||||
}
|
||||
|
||||
// 순번 증가
|
||||
int newSeq = maxSeq + 1;
|
||||
mbomPartNo = mbomPrefix + "-" + String.format("%02d", newSeq);
|
||||
|
||||
saveParam.put("MBOM_PART_NO", mbomPartNo);
|
||||
saveParam.put("IS_MACHINE", isMachine ? "Y" : "N");
|
||||
|
||||
// M-BOM 저장 실행
|
||||
sqlSession.insert("productionplanning.saveMbomFromEbom", saveParam);
|
||||
sqlSession.commit();
|
||||
|
||||
resultMap.put("result", "success");
|
||||
resultMap.put("message", "M-BOM이 성공적으로 생성되었습니다.");
|
||||
// M-BOM 품번과 저장일 추가 (부모 창 검색 조건에 사용)
|
||||
resultMap.put("mbomPartNo", mbomPartNo); // 자동 생성된 M-BOM 품번
|
||||
// 현재 날짜를 YYYY-MM-DD 형식으로 반환
|
||||
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd");
|
||||
resultMap.put("saveDate", sdf.format(new java.util.Date()));
|
||||
} finally {
|
||||
if(sqlSession != null) {
|
||||
sqlSession.close();
|
||||
|
||||
@@ -1078,9 +1078,23 @@ public class ProductionPlanningController extends BaseService {
|
||||
paramMap.put("objId", objId);
|
||||
Map<String, Object> projectInfo = commonService.selectOne("productionplanning.getProjectMgmtDetail", request, paramMap);
|
||||
|
||||
System.out.println("========== mBomPopupLeft ==========");
|
||||
System.out.println("objId: " + objId);
|
||||
System.out.println("projectInfo: " + projectInfo);
|
||||
|
||||
if(projectInfo != null) {
|
||||
System.out.println("BOM_REPORT_OBJID: " + projectInfo.get("BOM_REPORT_OBJID"));
|
||||
System.out.println("MBOM_STATUS: " + projectInfo.get("MBOM_STATUS"));
|
||||
|
||||
// 1. 먼저 저장된 M-BOM 데이터가 있는지 확인
|
||||
List<Map<String, Object>> mbomDetailList = commonService.selectList("productionplanning.getMbomDetailByProject", request, paramMap);
|
||||
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");
|
||||
|
||||
List<Map<String, Object>> mbomDetailList = commonService.selectList("partMng.getBOMTreeList", request, bomParam);
|
||||
System.out.println("mbomDetailList size: " + (mbomDetailList != null ? mbomDetailList.size() : 0));
|
||||
|
||||
if(mbomDetailList != null && !mbomDetailList.isEmpty()) {
|
||||
// 저장된 M-BOM 데이터가 있으면 이를 표시
|
||||
@@ -1090,41 +1104,25 @@ public class ProductionPlanningController extends BaseService {
|
||||
if(level != null && level > maxLevel) {
|
||||
maxLevel = level;
|
||||
}
|
||||
|
||||
// LEVEL_1, LEVEL_2, ... 필드 추가
|
||||
if(level != null) {
|
||||
for(int i = 1; i <= level; i++) {
|
||||
if(i == level) {
|
||||
item.put("LEVEL_" + i, "*");
|
||||
} else {
|
||||
item.put("LEVEL_" + i, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
request.setAttribute("MAXLEV", maxLevel);
|
||||
request.setAttribute("bomTreeListJson", gson.toJson(mbomDetailList));
|
||||
return "/productionplanning/mBomPopupLeft";
|
||||
}
|
||||
|
||||
// 저장된 M-BOM이 없으면 할당된 E-BOM 정보 조회
|
||||
String bomReportObjid = CommonUtils.checkNull(projectInfo.get("BOM_REPORT_OBJID"));
|
||||
if(!"".equals(bomReportObjid)) {
|
||||
Map<String, Object> ebomParam = new HashMap<>();
|
||||
ebomParam.put("objId", bomReportObjid);
|
||||
ebomParam.put("bomReportObjId", bomReportObjid);
|
||||
|
||||
// E-BOM 정보 조회
|
||||
Map<String, Object> ebomInfo = commonService.selectOne("partMng.getBomReportInfo", request, ebomParam);
|
||||
request.setAttribute("ebomInfo", ebomInfo);
|
||||
|
||||
// BOM 트리 데이터 조회 (레벨 정보 포함)
|
||||
List<Map<String, Object>> bomTreeList = commonService.selectList("partMng.getBOMTreeList", request, ebomParam);
|
||||
|
||||
if(bomTreeList != null && !bomTreeList.isEmpty()) {
|
||||
// MAX LEVEL 계산
|
||||
int maxLevel = 1;
|
||||
for(Map<String, Object> item : bomTreeList) {
|
||||
Integer level = (Integer) item.get("LEVEL");
|
||||
if(level != null && level > maxLevel) {
|
||||
maxLevel = level;
|
||||
}
|
||||
}
|
||||
request.setAttribute("MAXLEV", maxLevel);
|
||||
request.setAttribute("bomTreeListJson", gson.toJson(bomTreeList));
|
||||
return "/productionplanning/mBomPopupLeft";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
@@ -1213,6 +1211,8 @@ public class ProductionPlanningController extends BaseService {
|
||||
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");
|
||||
@@ -1221,11 +1221,12 @@ public class ProductionPlanningController extends BaseService {
|
||||
}
|
||||
|
||||
// M-BOM 저장 서비스 호출
|
||||
int saveResult = productionPlanningService.saveMbom(request, mbomData, partNo, partName);
|
||||
// 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", "M-BOM이 저장되었습니다.");
|
||||
resultMap.put("message", isUpdate ? "M-BOM이 수정되었습니다." : "M-BOM이 저장되었습니다.");
|
||||
} else {
|
||||
resultMap.put("result", "fail");
|
||||
resultMap.put("message", "저장에 실패했습니다.");
|
||||
@@ -1237,4 +1238,123 @@ public class ProductionPlanningController extends BaseService {
|
||||
}
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 품번으로 최신 M-BOM 조회 (Machine 이외 제품용)
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/productionplanning/getLatestMbomByPartNo.do")
|
||||
public Map<String, Object> getLatestMbomByPartNo(HttpServletRequest request, @RequestParam Map<String, Object> paramMap) {
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
try {
|
||||
String partNo = CommonUtils.checkNull(paramMap.get("partNo"));
|
||||
|
||||
if("".equals(partNo)) {
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
// 최신 M-BOM 조회
|
||||
Map<String, Object> mbomInfo = commonService.selectOne("productionplanning.getLatestMbomByPartNo", request, paramMap);
|
||||
|
||||
if(mbomInfo != null) {
|
||||
resultMap.putAll(mbomInfo);
|
||||
}
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* M-BOM 이력 조회
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/productionplanning/getMbomHistory.do")
|
||||
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"));
|
||||
|
||||
if("".equals(mbomPartNo)) {
|
||||
resultMap.put("historyList", new ArrayList<>());
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
// M-BOM 이력 조회 (PART_BOM_REPORT 테이블에서 동일 PART_NO로 조회)
|
||||
List<Map<String, Object>> historyList = commonService.selectList("productionplanning.getMbomHistory", request, paramMap);
|
||||
|
||||
resultMap.put("historyList", historyList != null ? historyList : new ArrayList<>());
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
resultMap.put("historyList", new ArrayList<>());
|
||||
}
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* M-BOM Part 연결 (E-BOM의 relatePartInfo와 동일)
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @param rightCheckedArr
|
||||
* @return
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/productionplanning/relateMbomPartInfo.do")
|
||||
public Map<String, Object> relateMbomPartInfo(HttpServletRequest request, @RequestParam Map<String, Object> paramMap, @RequestParam(value = "rightCheckedArr[]") List<String> rightCheckedArr){
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
try {
|
||||
boolean result = productionPlanningService.relateMbomPartInfo(request, paramMap, rightCheckedArr);
|
||||
resultMap.put("result", result);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
resultMap.put("result", false);
|
||||
}
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* M-BOM Part 연결 해제 (E-BOM의 deleteStatusPartRelateInfo와 동일)
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/productionplanning/deleteMbomPartRelateInfo.do")
|
||||
public Map<String, Object> deleteMbomPartRelateInfo(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
try {
|
||||
boolean result = productionPlanningService.deleteMbomPartRelateInfo(request, paramMap);
|
||||
resultMap.put("result", result);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
resultMap.put("result", false);
|
||||
}
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* M-BOM Part 변경 (E-BOM의 changeRelatePartInfo와 동일)
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/productionplanning/changeMbomPartInfo.do")
|
||||
public Map<String, Object> changeMbomPartInfo(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
try {
|
||||
boolean result = productionPlanningService.changeMbomPartInfo(request, paramMap);
|
||||
resultMap.put("result", result);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
resultMap.put("result", false);
|
||||
}
|
||||
return resultMap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2945,8 +2945,23 @@
|
||||
''
|
||||
) AS EBOM_REGDATE,
|
||||
COALESCE(PM.MBOM_STATUS, '') AS MBOM_STATUS,
|
||||
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),
|
||||
''
|
||||
) AS MBOM_PART_NO,
|
||||
'1.0' AS MBOM_VERSION,
|
||||
TO_CHAR(PM.REGDATE, 'YYYY-MM-DD') AS MBOM_REGDATE
|
||||
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),
|
||||
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
|
||||
@@ -3009,6 +3024,14 @@
|
||||
PM.BOM_REPORT_OBJID,
|
||||
PM.PART_NO,
|
||||
PM.PART_NAME,
|
||||
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),
|
||||
''
|
||||
) AS MBOM_PART_NO,
|
||||
CM.CATEGORY_CD,
|
||||
COALESCE(
|
||||
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.CATEGORY_CD LIMIT 1),
|
||||
@@ -3032,7 +3055,14 @@
|
||||
CM.PAID_TYPE,
|
||||
CM.REQ_DEL_DATE,
|
||||
TO_CHAR(PM.REGDATE, 'YYYY-MM-DD') AS RECEIPT_DATE,
|
||||
TO_CHAR(PM.REGDATE, 'YYYY-MM-DD') AS MBOM_REGDATE
|
||||
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),
|
||||
TO_CHAR(PM.REGDATE, 'YYYY-MM-DD')
|
||||
) AS MBOM_REGDATE
|
||||
FROM
|
||||
PROJECT_MGMT PM
|
||||
INNER JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
|
||||
@@ -3092,71 +3122,209 @@
|
||||
<!-- M-BOM 목록 조회 -->
|
||||
<select id="getMbomList" resultType="map" parameterType="map">
|
||||
SELECT
|
||||
MH.OBJID,
|
||||
MH.MBOM_NO,
|
||||
MH.PART_NO,
|
||||
MH.PART_NAME,
|
||||
MH.SAVE_DATE,
|
||||
MH.CREATE_USER,
|
||||
MH.CREATE_DATE,
|
||||
MH.UPDATE_USER,
|
||||
MH.UPDATE_DATE
|
||||
BPQ.OBJID,
|
||||
BPQ.BOM_REPORT_OBJID,
|
||||
BPQ.PARENT_OBJID,
|
||||
BPQ.CHILD_OBJID,
|
||||
BPQ.PARENT_PART_NO,
|
||||
BPQ.PART_NO,
|
||||
BPQ.QTY,
|
||||
BPQ.ITEM_QTY,
|
||||
BPQ.QTY_TEMP,
|
||||
BPQ.SEQ,
|
||||
BPQ.STATUS,
|
||||
BPQ.LAST_PART_OBJID,
|
||||
PM.PART_NO AS PART_NAME,
|
||||
PM.PART_NAME AS PART_FULL_NAME,
|
||||
PM.REVISION,
|
||||
PM.SPEC,
|
||||
COALESCE(
|
||||
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = PM.PRODUCT_CODE LIMIT 1),
|
||||
''
|
||||
) AS PRODUCT_NAME,
|
||||
COALESCE(
|
||||
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = PM.STATUS LIMIT 1),
|
||||
''
|
||||
) AS STATUS_NAME,
|
||||
-- 파일 개수
|
||||
COALESCE(PM.CU01_CNT, 0) AS CU01_CNT,
|
||||
COALESCE(PM.CU02_CNT, 0) AS CU02_CNT,
|
||||
COALESCE(PM.CU03_CNT, 0) AS CU03_CNT,
|
||||
-- E-BOM 컬럼들
|
||||
COALESCE(PM.MATERIAL, '') AS MATERIAL,
|
||||
COALESCE(PM.HEAT_TREATMENT_HARDNESS, '') AS HEAT_TREATMENT_HARDNESS,
|
||||
COALESCE(PM.HEAT_TREATMENT_METHOD, '') AS HEAT_TREATMENT_METHOD,
|
||||
COALESCE(PM.SURFACE_TREATMENT, '') AS SURFACE_TREATMENT,
|
||||
COALESCE(PM.MAKER, '') AS SUPPLIER,
|
||||
COALESCE(PM.CATEGORY, '') AS CATEGORY_NAME,
|
||||
-- 생산관리 컬럼들
|
||||
'' AS SUPPLY_TYPE,
|
||||
'' AS RAW_MATERIAL,
|
||||
'' AS SIZE,
|
||||
0 AS REQUIRED_QTY,
|
||||
0 AS ORDER_QTY,
|
||||
0 AS PRODUCTION_QTY,
|
||||
'' AS PROCESSING_VENDOR,
|
||||
'' AS PROCESSING_DEADLINE,
|
||||
'' AS GRINDING_DEADLINE,
|
||||
-- 구매 컬럼들
|
||||
'' AS MATERIAL_PART_NO,
|
||||
0 AS NET_QTY,
|
||||
0 AS PO_QTY,
|
||||
'' AS VENDOR,
|
||||
0 AS UNIT_PRICE,
|
||||
0 AS TOTAL_PRICE,
|
||||
1 AS LEVEL
|
||||
FROM
|
||||
MBOM_HEADER MH
|
||||
WHERE 1=1
|
||||
<!-- 품번 검색 -->
|
||||
<if test="partNo != null and partNo != ''">
|
||||
AND UPPER(MH.PART_NO) LIKE '%' || UPPER(#{partNo}) || '%'
|
||||
</if>
|
||||
<!-- 품명 검색 -->
|
||||
<if test="partName != null and partName != ''">
|
||||
AND UPPER(MH.PART_NAME) LIKE '%' || UPPER(#{partName}) || '%'
|
||||
</if>
|
||||
<!-- M-BOM 품번 검색 -->
|
||||
<if test="mbomPartNo != null and mbomPartNo != ''">
|
||||
AND UPPER(MH.MBOM_NO) LIKE '%' || UPPER(#{mbomPartNo}) || '%'
|
||||
</if>
|
||||
<!-- 저장일 검색 -->
|
||||
<if test="saveDate != null and saveDate != ''">
|
||||
AND DATE(MH.SAVE_DATE) = #{saveDate}
|
||||
</if>
|
||||
ORDER BY MH.SAVE_DATE DESC
|
||||
LIMIT 100
|
||||
BOM_PART_QTY BPQ
|
||||
LEFT JOIN PART_MGMT PM ON BPQ.PART_NO = PM.PART_NO
|
||||
LEFT JOIN PART_BOM_REPORT PBR ON BPQ.BOM_REPORT_OBJID::VARCHAR = PBR.OBJID::VARCHAR
|
||||
WHERE 1=1
|
||||
AND COALESCE(BPQ.STATUS, '') NOT IN ('deleting', 'deleted')
|
||||
<!-- BOM_REPORT_OBJID로 직접 조회 (우선순위 높음) -->
|
||||
<if test="bomReportObjId != null and bomReportObjId != ''">
|
||||
AND BPQ.BOM_REPORT_OBJID::VARCHAR = #{bomReportObjId}
|
||||
</if>
|
||||
<!-- 품번 검색 -->
|
||||
<if test="partNo != null and partNo != ''">
|
||||
AND UPPER(PBR.PART_NO) LIKE '%' || UPPER(#{partNo}) || '%'
|
||||
</if>
|
||||
<!-- 품명 검색 -->
|
||||
<if test="partName != null and partName != ''">
|
||||
AND UPPER(PBR.PART_NAME) LIKE '%' || UPPER(#{partName}) || '%'
|
||||
</if>
|
||||
<!-- M-BOM 품번 검색 -->
|
||||
<if test="mbomPartNo != null and mbomPartNo != ''">
|
||||
AND UPPER(PBR.PART_NO) LIKE '%' || UPPER(#{mbomPartNo}) || '%'
|
||||
</if>
|
||||
<!-- 저장일 검색 -->
|
||||
<if test="saveDate != null and saveDate != ''">
|
||||
AND DATE(PBR.REGDATE) = #{saveDate}
|
||||
</if>
|
||||
ORDER BY BPQ.SEQ
|
||||
LIMIT 1000
|
||||
</select>
|
||||
|
||||
<!-- M-BOM 상세 데이터 조회 (프로젝트별) -->
|
||||
<select id="getMbomDetailByProject" resultType="map" parameterType="map">
|
||||
/* productionplanning.getMbomDetailByProject - PROJECT_MGMT의 BOM_REPORT_OBJID로 M-BOM 조회 */
|
||||
SELECT
|
||||
BPQ.OBJID,
|
||||
BPQ.BOM_REPORT_OBJID,
|
||||
BPQ.PARENT_OBJID,
|
||||
BPQ.CHILD_OBJID,
|
||||
BPQ.PARENT_PART_NO,
|
||||
COALESCE(PM.PART_NO, '') AS PART_NO,
|
||||
BPQ.QTY,
|
||||
BPQ.ITEM_QTY,
|
||||
BPQ.QTY_TEMP,
|
||||
BPQ.SEQ,
|
||||
BPQ.STATUS,
|
||||
BPQ.LAST_PART_OBJID,
|
||||
COALESCE(PM.PART_NAME, '') AS PART_NAME,
|
||||
'' AS REVISION,
|
||||
'' AS SPEC,
|
||||
'' AS PRODUCT_NAME,
|
||||
'' AS STATUS_NAME,
|
||||
-- 파일 개수
|
||||
0 AS CU01_CNT,
|
||||
0 AS CU02_CNT,
|
||||
0 AS CU03_CNT,
|
||||
-- E-BOM 컬럼들
|
||||
'' AS MATERIAL,
|
||||
'' AS HEAT_TREATMENT_HARDNESS,
|
||||
'' AS HEAT_TREATMENT_METHOD,
|
||||
'' AS SURFACE_TREATMENT,
|
||||
'' AS SUPPLIER,
|
||||
'' AS CATEGORY_NAME,
|
||||
-- 생산관리 컬럼들
|
||||
'' AS SUPPLY_TYPE,
|
||||
'' AS RAW_MATERIAL,
|
||||
'' AS SIZE,
|
||||
0 AS REQUIRED_QTY,
|
||||
0 AS ORDER_QTY,
|
||||
0 AS PRODUCTION_QTY,
|
||||
'' AS PROCESSING_VENDOR,
|
||||
'' AS PROCESSING_DEADLINE,
|
||||
'' AS GRINDING_DEADLINE,
|
||||
-- 구매 컬럼들
|
||||
'' AS MATERIAL_PART_NO,
|
||||
0 AS NET_QTY,
|
||||
0 AS PO_QTY,
|
||||
'' AS VENDOR,
|
||||
0 AS UNIT_PRICE,
|
||||
0 AS TOTAL_PRICE,
|
||||
1 AS LEVEL
|
||||
FROM
|
||||
PROJECT_MGMT PROJ
|
||||
INNER JOIN BOM_PART_QTY BPQ ON PROJ.BOM_REPORT_OBJID::VARCHAR = BPQ.BOM_REPORT_OBJID::VARCHAR
|
||||
LEFT JOIN PART_MGMT PM ON PM.OBJID::VARCHAR = BPQ.PART_NO::VARCHAR
|
||||
WHERE
|
||||
PROJ.OBJID::VARCHAR = #{objId}
|
||||
AND COALESCE(BPQ.STATUS, '') NOT IN ('deleting', 'deleted')
|
||||
AND PROJ.BOM_REPORT_OBJID IS NOT NULL
|
||||
AND PROJ.BOM_REPORT_OBJID != ''
|
||||
ORDER BY
|
||||
BPQ.SEQ
|
||||
</select>
|
||||
|
||||
<!-- M-BOM 품번 최대 순번 조회 (같은 날짜) -->
|
||||
<select id="getMaxMbomSeqByDate" parameterType="map" resultType="int">
|
||||
SELECT
|
||||
MD.OBJID,
|
||||
MD.MBOM_HEADER_OBJID,
|
||||
MD.PART_NO,
|
||||
MD.PART_NAME,
|
||||
MD.QTY,
|
||||
MD.QTY_TEMP,
|
||||
MD.ITEM_QTY,
|
||||
MD.LEVEL,
|
||||
MD.REVISION,
|
||||
MD.SPEC,
|
||||
MD.PRODUCT_NAME,
|
||||
MD.STATUS_NAME,
|
||||
MD.LEVEL_1,
|
||||
MD.LEVEL_2,
|
||||
MD.LEVEL_3,
|
||||
MD.LEVEL_4,
|
||||
MD.LEVEL_5,
|
||||
MD.LEVEL_6,
|
||||
MD.LEVEL_7,
|
||||
MD.LEVEL_8,
|
||||
MD.LEVEL_9,
|
||||
MD.LEVEL_10
|
||||
COALESCE(MAX(
|
||||
CAST(
|
||||
SUBSTRING(PART_NO FROM '.+-([0-9]+)$') AS INTEGER
|
||||
)
|
||||
), 0) AS MAX_SEQ
|
||||
FROM
|
||||
MBOM_DETAIL MD
|
||||
INNER JOIN
|
||||
MBOM_HEADER MH ON MD.MBOM_HEADER_OBJID = MH.OBJID
|
||||
PART_BOM_REPORT
|
||||
WHERE
|
||||
MH.PROJECT_MGMT_OBJID = #{objId}
|
||||
PART_NO LIKE #{prefix} || '%'
|
||||
AND STATUS = 'Y'
|
||||
</select>
|
||||
|
||||
<!-- 품번으로 최신 M-BOM 조회 (Machine 이외 제품용) -->
|
||||
<select id="getLatestMbomByPartNo" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
SELECT
|
||||
PM.OBJID,
|
||||
COALESCE(
|
||||
(SELECT PBR.PART_NO
|
||||
FROM PART_BOM_REPORT PBR
|
||||
WHERE PBR.OBJID::VARCHAR = PM.BOM_REPORT_OBJID
|
||||
LIMIT 1),
|
||||
''
|
||||
) AS MBOM_PART_NO,
|
||||
PM.BOM_REPORT_OBJID,
|
||||
PM.PART_NO,
|
||||
PM.PART_NAME,
|
||||
TO_CHAR(PM.REGDATE, 'YYYY-MM-DD') AS SAVE_DATE
|
||||
FROM
|
||||
PROJECT_MGMT PM
|
||||
INNER JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
|
||||
WHERE
|
||||
PM.PART_NO = #{partNo}
|
||||
AND PM.MBOM_STATUS = 'Y'
|
||||
AND PM.BOM_REPORT_OBJID IS NOT NULL
|
||||
AND CM.PRODUCT != '0001807' <!-- Machine 제외 -->
|
||||
ORDER BY
|
||||
MD.LEVEL, MD.PART_NO
|
||||
PM.REGDATE DESC
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<!-- 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
|
||||
FROM
|
||||
PART_BOM_REPORT PBR
|
||||
WHERE
|
||||
PBR.PART_NO = #{mbomPartNo}
|
||||
ORDER BY PBR.REGDATE DESC
|
||||
</select>
|
||||
|
||||
<!-- M-BOM 헤더 저장 -->
|
||||
@@ -3229,6 +3397,7 @@
|
||||
<insert id="saveMbomFromEbom" parameterType="map">
|
||||
/* productionplanning.saveMbomFromEbom - E-BOM을 M-BOM으로 복사 */
|
||||
/* 1. 새로운 PART_BOM_REPORT 생성 (M-BOM용) */
|
||||
/* M-BOM 품번을 PART_NO에 저장 (규칙: M-{품번}-YYMMDD-01) */
|
||||
WITH new_bom_report AS (
|
||||
INSERT INTO PART_BOM_REPORT (
|
||||
OBJID,
|
||||
@@ -3239,7 +3408,7 @@
|
||||
STATUS
|
||||
) VALUES (
|
||||
(SELECT (FLOOR(RANDOM() * 1000000000) + 1000000000)::INTEGER),
|
||||
#{PART_NO},
|
||||
#{MBOM_PART_NO},
|
||||
#{PART_NAME},
|
||||
#{USER_ID},
|
||||
NOW(),
|
||||
|
||||
@@ -759,6 +759,10 @@ public class ProductionPlanningService {
|
||||
* @return
|
||||
*/
|
||||
public int saveMbom(HttpServletRequest request, List<Map<String, Object>> mbomData, String partNo, String partName) {
|
||||
return saveMbom(request, mbomData, partNo, partName, "", false);
|
||||
}
|
||||
|
||||
public int saveMbom(HttpServletRequest request, List<Map<String, Object>> mbomData, String partNo, String partName, String mbomPartNo, boolean isUpdate) {
|
||||
SqlSession sqlSession = null;
|
||||
int result = 0;
|
||||
|
||||
@@ -768,23 +772,48 @@ public class ProductionPlanningService {
|
||||
PersonBean person = (PersonBean)session.getAttribute(Constants.PERSON_BEAN);
|
||||
String userId = CommonUtils.checkNull(person.getUserId());
|
||||
|
||||
// M-BOM 헤더 정보 생성
|
||||
Map<String, Object> headerMap = new HashMap<>();
|
||||
headerMap.put("PART_NO", partNo);
|
||||
headerMap.put("PART_NAME", partName);
|
||||
headerMap.put("CREATE_USER", userId);
|
||||
headerMap.put("UPDATE_USER", userId);
|
||||
|
||||
// M-BOM 헤더 저장
|
||||
sqlSession.insert("productionplanning.insertMbomHeader", headerMap);
|
||||
String mbomHeaderObjid = (String) headerMap.get("OBJID");
|
||||
|
||||
// M-BOM 상세 데이터 저장
|
||||
for(Map<String, Object> item : mbomData) {
|
||||
item.put("MBOM_HEADER_OBJID", mbomHeaderObjid);
|
||||
item.put("CREATE_USER", userId);
|
||||
item.put("UPDATE_USER", userId);
|
||||
sqlSession.insert("productionplanning.insertMbomDetail", item);
|
||||
if(isUpdate && !"".equals(mbomPartNo)) {
|
||||
// M-BOM 수정: 기존 데이터 삭제 후 재저장 (동일 품번 유지)
|
||||
// 기존 M-BOM 상세 데이터 삭제
|
||||
Map<String, Object> deleteParam = new HashMap<>();
|
||||
deleteParam.put("MBOM_PART_NO", mbomPartNo);
|
||||
sqlSession.delete("productionplanning.deleteMbomDetailByPartNo", deleteParam);
|
||||
|
||||
// M-BOM 헤더 업데이트
|
||||
Map<String, Object> headerMap = new HashMap<>();
|
||||
headerMap.put("MBOM_PART_NO", mbomPartNo);
|
||||
headerMap.put("PART_NO", partNo);
|
||||
headerMap.put("PART_NAME", partName);
|
||||
headerMap.put("UPDATE_USER", userId);
|
||||
sqlSession.update("productionplanning.updateMbomHeader", headerMap);
|
||||
|
||||
// M-BOM 상세 데이터 재저장
|
||||
for(Map<String, Object> item : mbomData) {
|
||||
item.put("MBOM_PART_NO", mbomPartNo);
|
||||
item.put("CREATE_USER", userId);
|
||||
item.put("UPDATE_USER", userId);
|
||||
sqlSession.insert("productionplanning.insertMbomDetail", item);
|
||||
}
|
||||
} else {
|
||||
// M-BOM 신규 저장
|
||||
// M-BOM 헤더 정보 생성
|
||||
Map<String, Object> headerMap = new HashMap<>();
|
||||
headerMap.put("PART_NO", partNo);
|
||||
headerMap.put("PART_NAME", partName);
|
||||
headerMap.put("CREATE_USER", userId);
|
||||
headerMap.put("UPDATE_USER", userId);
|
||||
|
||||
// M-BOM 헤더 저장
|
||||
sqlSession.insert("productionplanning.insertMbomHeader", headerMap);
|
||||
String mbomHeaderObjid = (String) headerMap.get("OBJID");
|
||||
|
||||
// M-BOM 상세 데이터 저장
|
||||
for(Map<String, Object> item : mbomData) {
|
||||
item.put("MBOM_HEADER_OBJID", mbomHeaderObjid);
|
||||
item.put("CREATE_USER", userId);
|
||||
item.put("UPDATE_USER", userId);
|
||||
sqlSession.insert("productionplanning.insertMbomDetail", item);
|
||||
}
|
||||
}
|
||||
|
||||
sqlSession.commit();
|
||||
@@ -802,4 +831,180 @@ public class ProductionPlanningService {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* M-BOM Part 연결 (E-BOM의 relatePartInfo와 동일한 로직)
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @param partList
|
||||
* @return
|
||||
*/
|
||||
public boolean relateMbomPartInfo(HttpServletRequest request, Map paramMap, List<String> partList){
|
||||
boolean result = false;
|
||||
SqlSession sqlSession = null;
|
||||
|
||||
try{
|
||||
HttpSession session = request.getSession();
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession();
|
||||
PersonBean person = (PersonBean)session.getAttribute(Constants.PERSON_BEAN);
|
||||
Map info = person.getLoginInfo();
|
||||
String userId = CommonUtils.checkNull(info.get("userId"));
|
||||
|
||||
Map sqlParamMap = new HashMap();
|
||||
sqlParamMap.put("BOM_REPORT_OBJID", CommonUtils.checkNull(paramMap.get("BOM_REPORT_OBJID")));
|
||||
sqlParamMap.put("PARENT_OBJID", CommonUtils.checkNull(paramMap.get("leftObjId")));
|
||||
sqlParamMap.put("PARENT_PART_OBJID", CommonUtils.checkNull(paramMap.get("leftObjId")));
|
||||
sqlParamMap.put("PARENT_PART_NO", CommonUtils.checkNull(paramMap.get("leftPartNoQty")));
|
||||
sqlParamMap.put("PARENT_QTY_CHILD_OBJID", CommonUtils.checkNull(paramMap.get("leftPartChildObjId")));
|
||||
sqlParamMap.put("QTY", 1);
|
||||
sqlParamMap.put("QTY_TEMP", 1);
|
||||
sqlParamMap.put("STATUS", "adding");
|
||||
sqlParamMap.put("WRITER", userId);
|
||||
|
||||
// 각 Part를 BOM_PART_QTY 테이블에 삽입
|
||||
for(String partObjId : partList){
|
||||
sqlParamMap.put("OBJID", CommonUtils.createObjId());
|
||||
sqlParamMap.put("CHILD_OBJID", CommonUtils.createObjId());
|
||||
sqlParamMap.put("PART_NO", partObjId);
|
||||
|
||||
sqlSession.insert("partMng.relatePartInfo", sqlParamMap);
|
||||
|
||||
// 히스토리 저장
|
||||
sqlParamMap.put("OBJID", CommonUtils.checkNull(partObjId));
|
||||
sqlParamMap.put("OBJID_LEFT", CommonUtils.checkNull(paramMap.get("partObjId")));
|
||||
sqlParamMap.put("CHANGE_TYPE", CommonUtils.checkNull(paramMap.get("CHANGE_TYPE")));
|
||||
sqlParamMap.put("HIS_STATUS", "ADD");
|
||||
sqlParamMap.put("CHANGE_OPTION", CommonUtils.checkNull(paramMap.get("CHANGE_OPTION")));
|
||||
sqlSession.update("partMng.insertPartMngHistory",sqlParamMap);
|
||||
}
|
||||
|
||||
// BOM 상태 변경
|
||||
sqlSession.insert("partMng.changeStatusBomReport", sqlParamMap);
|
||||
|
||||
sqlSession.commit();
|
||||
result = true;
|
||||
|
||||
}catch(Exception e){
|
||||
if(sqlSession != null) {
|
||||
sqlSession.rollback();
|
||||
}
|
||||
e.printStackTrace();
|
||||
}finally{
|
||||
if(sqlSession != null) {
|
||||
sqlSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* M-BOM Part 연결 해제 (E-BOM의 deleteStatusPartRelateInfo와 동일한 로직)
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
public boolean deleteMbomPartRelateInfo(HttpServletRequest request, Map paramMap){
|
||||
boolean result = false;
|
||||
SqlSession sqlSession = null;
|
||||
|
||||
try{
|
||||
HttpSession session = request.getSession();
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession();
|
||||
PersonBean person = (PersonBean)session.getAttribute(Constants.PERSON_BEAN);
|
||||
Map info = person.getLoginInfo();
|
||||
String userId = CommonUtils.checkNull(info.get("userId"));
|
||||
|
||||
Map sqlParamMap = new HashMap();
|
||||
sqlParamMap.put("BOM_REPORT_OBJID", CommonUtils.checkNull(paramMap.get("BOM_REPORT_OBJID")));
|
||||
sqlParamMap.put("OBJID", CommonUtils.checkNull(paramMap.get("leftObjId")));
|
||||
sqlParamMap.put("PART_OBJID", CommonUtils.checkNull(paramMap.get("partObjId")));
|
||||
sqlParamMap.put("leftPartChildObjId", CommonUtils.checkNull(paramMap.get("leftPartChildObjId")));
|
||||
sqlParamMap.put("leftParentPartNo", CommonUtils.checkNull(paramMap.get("leftParentPartNo")));
|
||||
sqlParamMap.put("leftParentObjId", CommonUtils.checkNull(paramMap.get("leftParentObjId")));
|
||||
sqlParamMap.put("STATUS", "deleting");
|
||||
sqlParamMap.put("WRITER", userId);
|
||||
|
||||
// BOM_PART_QTY 테이블에서 상태를 'deleting'으로 변경
|
||||
sqlSession.update("partMng.deleteStatusPartRelateInfo", sqlParamMap);
|
||||
|
||||
// 히스토리 저장
|
||||
sqlParamMap.put("HIS_STATUS", "DELETE");
|
||||
sqlSession.update("partMng.insertPartMngHistory", sqlParamMap);
|
||||
|
||||
// BOM 상태 변경
|
||||
sqlSession.insert("partMng.changeStatusBomReport", sqlParamMap);
|
||||
|
||||
sqlSession.commit();
|
||||
result = true;
|
||||
|
||||
}catch(Exception e){
|
||||
if(sqlSession != null) {
|
||||
sqlSession.rollback();
|
||||
}
|
||||
e.printStackTrace();
|
||||
}finally{
|
||||
if(sqlSession != null) {
|
||||
sqlSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* M-BOM Part 변경 (E-BOM의 changeRelatePartInfo와 동일한 로직)
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
public boolean changeMbomPartInfo(HttpServletRequest request, Map paramMap){
|
||||
boolean result = false;
|
||||
SqlSession sqlSession = null;
|
||||
|
||||
try{
|
||||
HttpSession session = request.getSession();
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession();
|
||||
PersonBean person = (PersonBean)session.getAttribute(Constants.PERSON_BEAN);
|
||||
Map info = person.getLoginInfo();
|
||||
String userId = CommonUtils.checkNull(info.get("userId"));
|
||||
|
||||
Map sqlParamMap = new HashMap();
|
||||
sqlParamMap.put("BOM_REPORT_OBJID", CommonUtils.checkNull(paramMap.get("BOM_REPORT_OBJID")));
|
||||
sqlParamMap.put("OBJID", CommonUtils.checkNull(paramMap.get("OBJID")));
|
||||
sqlParamMap.put("rightObjId", CommonUtils.checkNull(paramMap.get("rightObjId")));
|
||||
sqlParamMap.put("leftObjId", CommonUtils.checkNull(paramMap.get("leftObjId")));
|
||||
sqlParamMap.put("leftPartNoQty", CommonUtils.checkNull(paramMap.get("leftPartNoQty")));
|
||||
sqlParamMap.put("leftPartChildObjId", CommonUtils.checkNull(paramMap.get("leftPartChildObjId")));
|
||||
sqlParamMap.put("leftPartObjid", CommonUtils.checkNull(paramMap.get("leftPartObjid")));
|
||||
sqlParamMap.put("rightPartNo", CommonUtils.checkNull(paramMap.get("rightPartNo")));
|
||||
sqlParamMap.put("rightPartRev", CommonUtils.checkNull(paramMap.get("rightPartRev")));
|
||||
sqlParamMap.put("WRITER", userId);
|
||||
|
||||
// BOM_PART_QTY 테이블에서 Part 변경
|
||||
sqlSession.update("partMng.changeRelatePartInfo", sqlParamMap);
|
||||
|
||||
// 히스토리 저장
|
||||
sqlParamMap.put("HIS_STATUS", "CHANGE");
|
||||
sqlSession.update("partMng.insertPartMngHistory", sqlParamMap);
|
||||
|
||||
// BOM 상태 변경
|
||||
sqlSession.insert("partMng.changeStatusBomReport", sqlParamMap);
|
||||
|
||||
sqlSession.commit();
|
||||
result = true;
|
||||
|
||||
}catch(Exception e){
|
||||
if(sqlSession != null) {
|
||||
sqlSession.rollback();
|
||||
}
|
||||
e.printStackTrace();
|
||||
}finally{
|
||||
if(sqlSession != null) {
|
||||
sqlSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user