diff --git a/Dockerfile b/Dockerfile
index 0f52dbc..d044e9d 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -5,7 +5,9 @@ RUN rm -rf /usr/local/tomcat/webapps/*
# Copy web application content (compiled classes and web resources)
COPY WebContent /usr/local/tomcat/webapps/ROOT
-COPY src /usr/local/tomcat/webapps/ROOT/WEB-INF/src
+
+# Copy Java source files to classes directory (for mapper XMLs)
+COPY src/com /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/com
# Copy custom Tomcat context configuration for JNDI
COPY ./tomcat-conf/context.xml /usr/local/tomcat/conf/context.xml
diff --git a/Dockerfile.dev b/Dockerfile.dev
index 03e8b29..2a377cb 100644
--- a/Dockerfile.dev
+++ b/Dockerfile.dev
@@ -5,7 +5,7 @@ RUN rm -rf /usr/local/tomcat/webapps/*
# Copy web application content (compiled classes and web resources)
COPY WebContent /usr/local/tomcat/webapps/ROOT
-COPY src /usr/local/tomcat/webapps/ROOT/WEB-INF/src
+COPY src /usr/local/tomcat/webapps/ROOT/WEB-INF/classes
# Copy custom Tomcat context configuration for JNDI
COPY ./tomcat-conf/context.xml /usr/local/tomcat/conf/context.xml
diff --git a/WebContent/WEB-INF/classes/com/pms/mapper/common.xml b/WebContent/WEB-INF/classes/com/pms/mapper/common.xml
index d718536..07508a3 100644
--- a/WebContent/WEB-INF/classes/com/pms/mapper/common.xml
+++ b/WebContent/WEB-INF/classes/com/pms/mapper/common.xml
@@ -2530,18 +2530,18 @@ SELECT option_objid::VARCHAR AS CODE
AND PRODUCT_MGMT_OBJID::VARCHAR = #{codeId}::VARCHAR
-
-
+
+ /* productionplanning.mBomMgmtGridList - 품목별로 나눠서 조회 (CONTRACT_ITEM 기준) */
SELECT
PM.OBJID,
PM.CONTRACT_OBJID,
@@ -2906,54 +2907,40 @@
ELSE ''
END
) AS PAID_TYPE_NAME,
- COALESCE(PM.PART_NO, '') AS PART_NO,
- COALESCE(PM.PART_NAME, '') AS PART_NAME,
- -- S/N: CONTRACT_ITEM_SERIAL에서 조회
+ -- 품목 정보: CONTRACT_ITEM에서 가져오기 (품목별로 펼쳐서 보이기)
+ COALESCE(CI.PART_NO, PM.PART_NO, '') AS PART_NO,
+ COALESCE(CI.PART_NAME, PM.PART_NAME, '') AS PART_NAME,
+ CI.PART_OBJID,
+ -- S/N: 해당 품목의 시리얼 번호만 표시
(SELECT
CASE
WHEN COUNT(*) = 0 THEN ''
WHEN COUNT(*) = 1 THEN MIN(CIS.SERIAL_NO)
ELSE MIN(CIS.SERIAL_NO) || ' 외 ' || (COUNT(*) - 1)::TEXT || '건'
END
- FROM CONTRACT_ITEM CI
- LEFT JOIN CONTRACT_ITEM_SERIAL CIS ON CI.OBJID = CIS.ITEM_OBJID AND UPPER(CIS.STATUS) = 'ACTIVE'
- WHERE CI.CONTRACT_OBJID = PM.CONTRACT_OBJID
- AND CI.PART_OBJID = PM.PART_OBJID
- AND CI.STATUS = 'ACTIVE'
+ FROM CONTRACT_ITEM_SERIAL CIS
+ WHERE CIS.ITEM_OBJID = CI.OBJID
+ AND UPPER(CIS.STATUS) = 'ACTIVE'
AND CIS.SERIAL_NO IS NOT NULL) AS SERIAL_NO,
- COALESCE(PM.QUANTITY::numeric, 0) AS QUANTITY,
- -- 요청납기: CONTRACT_ITEM 우선, 없으면 PROJECT_MGMT, 없으면 CONTRACT_MGMT
- COALESCE(
- (SELECT CI.DUE_DATE
- FROM CONTRACT_ITEM CI
- WHERE CI.CONTRACT_OBJID = PM.CONTRACT_OBJID
- AND CI.PART_OBJID = PM.PART_OBJID
- AND CI.STATUS = 'ACTIVE' LIMIT 1),
- PM.DUE_DATE,
- CM.req_del_date
- ) AS REQ_DEL_DATE,
+ -- 수량: CONTRACT_ITEM의 수량
+ COALESCE(CI.ORDER_QUANTITY::numeric, PM.QUANTITY::numeric, 0) AS QUANTITY,
+ -- 요청납기: CONTRACT_ITEM 우선
+ COALESCE(CI.DUE_DATE, PM.DUE_DATE, CM.req_del_date) AS REQ_DEL_DATE,
-- 고객요청사항: CONTRACT_ITEM에서 가져옴
- COALESCE(
- (SELECT CI.CUSTOMER_REQUEST
- FROM CONTRACT_ITEM CI
- WHERE CI.CONTRACT_OBJID = PM.CONTRACT_OBJID
- AND CI.PART_OBJID = PM.PART_OBJID
- AND CI.STATUS = 'ACTIVE' LIMIT 1),
- ''
- ) AS CUSTOMER_REQUEST,
- -- E-BOM 정보: PM.PART_OBJID가 E-BOM OBJID를 직접 가리킴
- PM.PART_OBJID AS BOM_REPORT_OBJID,
+ COALESCE(CI.CUSTOMER_REQUEST, '') AS CUSTOMER_REQUEST,
+ -- E-BOM 정보: CI.PART_OBJID가 E-BOM OBJID를 가리킴
+ COALESCE(CI.PART_OBJID, PM.PART_OBJID) AS BOM_REPORT_OBJID,
COALESCE(
(SELECT PBR.STATUS
FROM PART_BOM_REPORT PBR
- WHERE PBR.OBJID::VARCHAR = PM.PART_OBJID
+ WHERE PBR.OBJID::VARCHAR = COALESCE(CI.PART_OBJID, PM.PART_OBJID)
LIMIT 1),
''
) AS EBOM_STATUS,
COALESCE(
(SELECT TO_CHAR(PBR.REGDATE, 'YYYY-MM-DD')
FROM PART_BOM_REPORT PBR
- WHERE PBR.OBJID::VARCHAR = PM.PART_OBJID
+ WHERE PBR.OBJID::VARCHAR = COALESCE(CI.PART_OBJID, PM.PART_OBJID)
LIMIT 1),
''
) AS EBOM_REGDATE,
@@ -2963,18 +2950,27 @@
FROM
PROJECT_MGMT PM
LEFT JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
+ -- CONTRACT_ITEM과 LEFT JOIN하여 품목별로 펼쳐서 보이기
+ LEFT JOIN CONTRACT_ITEM CI ON CM.OBJID::VARCHAR = CI.CONTRACT_OBJID
+ AND CI.STATUS = 'ACTIVE'
WHERE 1=1
AND PM.PROJECT_NO IS NOT NULL
AND PM.PROJECT_NO != ''
- AND UPPER(PM.PART_NO) LIKE '%' || UPPER(#{search_part_no}) || '%'
+ AND (
+ UPPER(PM.PART_NO) LIKE '%' || UPPER(#{search_part_no}) || '%'
+ OR UPPER(CI.PART_NO) LIKE '%' || UPPER(#{search_part_no}) || '%'
+ )
- AND UPPER(PM.PART_NAME) LIKE '%' || UPPER(#{search_part_name}) || '%'
+ AND (
+ UPPER(PM.PART_NAME) LIKE '%' || UPPER(#{search_part_name}) || '%'
+ OR UPPER(CI.PART_NAME) LIKE '%' || UPPER(#{search_part_name}) || '%'
+ )
- ORDER BY PM.REGDATE DESC
+ ORDER BY PM.REGDATE DESC, CI.PART_NO
@@ -3003,4 +2999,299 @@
LEFT JOIN USER_INFO UI ON UI.USER_ID = T.WRITER
WHERE T.OBJID::VARCHAR = #{objid}
+
+
+
+ SELECT
+ PM.OBJID,
+ PM.CONTRACT_OBJID,
+ PM.PROJECT_NO,
+ PM.BOM_REPORT_OBJID,
+ PM.PART_NO,
+ PM.PART_NAME,
+ CM.CATEGORY_CD,
+ COALESCE(
+ (SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.CATEGORY_CD LIMIT 1),
+ ''
+ ) AS CATEGORY_NAME,
+ CM.PRODUCT,
+ COALESCE(
+ (SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.PRODUCT LIMIT 1),
+ ''
+ ) AS PRODUCT_NAME,
+ CM.AREA_CD,
+ COALESCE(
+ (SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.AREA_CD LIMIT 1),
+ ''
+ ) AS AREA_NAME,
+ CM.CUSTOMER_OBJID,
+ COALESCE(
+ (SELECT SUPPLY_NAME FROM SUPPLY_MNG WHERE OBJID = CM.CUSTOMER_OBJID::NUMERIC LIMIT 1),
+ ''
+ ) AS CUSTOMER_NAME,
+ 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
+ FROM
+ PROJECT_MGMT PM
+ INNER JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
+ WHERE
+ PM.OBJID::VARCHAR = #{objId}
+ LIMIT 1
+
+
+
+
+ SELECT
+ T.OBJID,
+ T.PRODUCT_CD,
+ COALESCE(
+ (SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = T.PRODUCT_CD LIMIT 1),
+ ''
+ ) AS PRODUCT_NAME,
+ T.PART_NO,
+ T.PART_NAME,
+ T.STATUS,
+ T.REVISION,
+ TO_CHAR(T.REGDATE, 'YYYY-MM-DD') AS REG_DATE,
+ UI.USER_NAME AS WRITER_NAME,
+ UI.DEPT_NAME,
+ COALESCE(PM.MATERIAL, '') AS MATERIAL,
+ COALESCE(PM.MAKER, '') AS SUPPLIER
+ FROM
+ PART_BOM_REPORT T
+ LEFT JOIN USER_INFO UI ON UI.USER_ID = T.WRITER
+ LEFT JOIN PART_MNG PM ON PM.PART_NO = T.PART_NO AND PM.STATUS = 'release'
+ WHERE 1=1
+
+ AND T.PART_NO IS NOT NULL
+ AND TRIM(T.PART_NO) != ''
+ AND T.PART_NAME IS NOT NULL
+ AND TRIM(T.PART_NAME) != ''
+
+
+ AND UPPER(T.PART_NO) LIKE '%' || UPPER(#{search_part_no}) || '%'
+
+
+
+ AND UPPER(T.PART_NAME) LIKE '%' || UPPER(#{search_part_name}) || '%'
+
+
+
+ AND UPPER(PM.MATERIAL) LIKE '%' || UPPER(#{search_material}) || '%'
+
+
+
+ AND UPPER(PM.MAKER) LIKE '%' || UPPER(#{search_supplier}) || '%'
+
+ ORDER BY T.REGDATE DESC
+ LIMIT 100
+
+
+
+
+ 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
+ FROM
+ MBOM_HEADER MH
+ WHERE 1=1
+
+
+ AND UPPER(MH.PART_NO) LIKE '%' || UPPER(#{partNo}) || '%'
+
+
+
+ AND UPPER(MH.PART_NAME) LIKE '%' || UPPER(#{partName}) || '%'
+
+
+
+ AND UPPER(MH.MBOM_NO) LIKE '%' || UPPER(#{mbomPartNo}) || '%'
+
+
+
+ AND DATE(MH.SAVE_DATE) = #{saveDate}
+
+ ORDER BY MH.SAVE_DATE DESC
+ LIMIT 100
+
+
+
+
+ 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
+ FROM
+ MBOM_DETAIL MD
+ INNER JOIN
+ MBOM_HEADER MH ON MD.MBOM_HEADER_OBJID = MH.OBJID
+ WHERE
+ MH.PROJECT_MGMT_OBJID = #{objId}
+ ORDER BY
+ MD.LEVEL, MD.PART_NO
+
+
+
+
+
+
+
+
+ SELECT REPLACE(UUID(),'-','') FROM DUAL
+
+ INSERT INTO MBOM_DETAIL (
+ OBJID,
+ MBOM_HEADER_OBJID,
+ PART_NO,
+ PART_NAME,
+ QTY,
+ LEVEL,
+ REVISION,
+ SPEC,
+ PRODUCT_NAME,
+ STATUS_NAME,
+ CREATE_USER,
+ CREATE_DATE,
+ UPDATE_USER,
+ UPDATE_DATE
+ ) VALUES (
+ #{OBJID},
+ #{MBOM_HEADER_OBJID},
+ #{PART_NO},
+ #{PART_NAME},
+ #{QTY},
+ #{LEVEL},
+ #{REVISION},
+ #{SPEC},
+ #{PRODUCT_NAME},
+ #{STATUS_NAME},
+ #{CREATE_USER},
+ NOW(),
+ #{UPDATE_USER},
+ NOW()
+ )
+
+
+
+
+ /* productionplanning.saveMbomFromEbom - E-BOM을 M-BOM으로 복사 */
+ /* 1. 새로운 PART_BOM_REPORT 생성 (M-BOM용) */
+ WITH new_bom_report AS (
+ INSERT INTO PART_BOM_REPORT (
+ OBJID,
+ PART_NO,
+ PART_NAME,
+ WRITER,
+ REGDATE,
+ STATUS
+ ) VALUES (
+ (SELECT (FLOOR(RANDOM() * 1000000000) + 1000000000)::INTEGER),
+ #{PART_NO},
+ #{PART_NAME},
+ #{USER_ID},
+ NOW(),
+ 'Y'
+ )
+ RETURNING OBJID
+ ),
+ /* 2. E-BOM의 BOM_PART_QTY 데이터를 새 M-BOM으로 복사 */
+ copied_bom_data AS (
+ INSERT INTO BOM_PART_QTY (
+ BOM_REPORT_OBJID,
+ OBJID,
+ PARENT_OBJID,
+ CHILD_OBJID,
+ PARENT_PART_NO,
+ PART_NO,
+ QTY,
+ ITEM_QTY,
+ QTY_TEMP,
+ REGDATE,
+ WRITER,
+ SEQ,
+ STATUS,
+ LAST_PART_OBJID
+ )
+ SELECT
+ (SELECT OBJID FROM new_bom_report),
+ (SELECT (FLOOR(RANDOM() * 1000000000) + 1000000000 + ROW_NUMBER() OVER (ORDER BY OBJID))::INTEGER),
+ PARENT_OBJID,
+ CHILD_OBJID,
+ PARENT_PART_NO,
+ PART_NO,
+ QTY,
+ ITEM_QTY,
+ QTY_TEMP,
+ NOW(),
+ #{USER_ID},
+ ROW_NUMBER() OVER (ORDER BY OBJID),
+ 'adding',
+ LAST_PART_OBJID
+ FROM BOM_PART_QTY
+ WHERE BOM_REPORT_OBJID::VARCHAR = #{SOURCE_BOM_OBJID}
+ AND COALESCE(STATUS, '') NOT IN ('deleting', 'deleted')
+ RETURNING 1
+ )
+ /* 3. PROJECT_MGMT 업데이트 */
+ UPDATE PROJECT_MGMT
+ SET
+ BOM_REPORT_OBJID = (SELECT OBJID FROM new_bom_report),
+ MBOM_STATUS = 'Y',
+ PART_NO = #{PART_NO},
+ PART_NAME = #{PART_NAME}
+ WHERE OBJID::VARCHAR = #{PROJECT_OBJID}
+
diff --git a/WebContent/WEB-INF/view/partMng/structureBomCopyFormPopup.jsp b/WebContent/WEB-INF/view/partMng/structureBomCopyFormPopup.jsp
index 0160a6d..7438365 100644
--- a/WebContent/WEB-INF/view/partMng/structureBomCopyFormPopup.jsp
+++ b/WebContent/WEB-INF/view/partMng/structureBomCopyFormPopup.jsp
@@ -134,6 +134,14 @@ var selectedBomType = null; // 'EBOM' 또는 'MBOM'
var bomGridData = []; // BOM 그리드 데이터
$(function(){
+ // 페이지 로드 시 프로젝트 정보가 있으면 품번/품명 자동 입력
+
+ console.log("projectInfo가 있습니다. 품번/품명 설정 중...");
+ $("#COPY_PART_NO").val("${projectInfo.PART_NO}");
+ $("#COPY_PART_NAME").val("${projectInfo.PART_NAME}");
+ // E-BOM 품번은 사용자가 직접 입력하도록 비워둠 (M-BOM 품번과 다를 수 있음)
+
+
// 담기 버튼 - 선택한 BOM을 복사 대상으로 설정
$("#btnAddItem").click(function(){
var partNo = $("#COPY_PART_NO").val().trim();
@@ -207,6 +215,8 @@ $(function(){
// BOM 미리보기 로드
function fn_loadBomPreview(partNo, bomType) {
+ console.log("fn_loadBomPreview 호출:", partNo, bomType);
+
// 먼저 품번으로 BOM OBJID 조회
$.ajax({
url: "/partMng/getBomObjIdByPartNo.do",
@@ -214,6 +224,8 @@ function fn_loadBomPreview(partNo, bomType) {
data: { partNo: partNo },
dataType: "json",
success: function(response) {
+ console.log("getBomObjIdByPartNo 응답:", response);
+
if(response && response.OBJID) {
$("#bomPartName").text(partNo);
// 전역 변수에 저장
@@ -222,10 +234,12 @@ function fn_loadBomPreview(partNo, bomType) {
// BOM 트리 데이터 로드
fn_loadBomTree(response.OBJID);
} else {
+ console.error("BOM OBJID를 찾을 수 없음:", response);
Swal.fire('해당 품번의 BOM을 찾을 수 없습니다.');
}
},
- error: function() {
+ error: function(xhr, status, error) {
+ console.error("getBomObjIdByPartNo 에러:", xhr, status, error);
Swal.fire('BOM 조회 중 오류가 발생했습니다.');
}
});
@@ -233,6 +247,8 @@ function fn_loadBomPreview(partNo, bomType) {
// BOM 트리 데이터 로드
function fn_loadBomTree(bomObjId) {
+ console.log("fn_loadBomTree 호출:", bomObjId);
+
$.ajax({
url: "/partMng/getStructureTreeJson.do",
type: "POST",
@@ -243,6 +259,8 @@ function fn_loadBomTree(bomObjId) {
},
dataType: "json",
success: function(response) {
+ console.log("getStructureTreeJson 응답:", response);
+
if(response && response.length > 0) {
var maxLevel = response[0].MAX_LEVEL || 3;
@@ -260,11 +278,13 @@ function fn_loadBomTree(bomObjId) {
fn_initGrid(processedData, maxLevel);
} else {
+ console.warn("BOM 트리 데이터가 비어있음");
bomGridData = [];
fn_initGrid([], 3);
}
},
- error: function() {
+ error: function(xhr, status, error) {
+ console.error("getStructureTreeJson 에러:", xhr, status, error);
Swal.fire('BOM 트리 조회 중 오류가 발생했습니다.');
}
});
@@ -506,6 +526,10 @@ function fn_saveBomCopy() {
text: 'M-BOM이 성공적으로 생성되었습니다.',
icon: 'success'
}).then(() => {
+ // 부모 창(M-BOM 관리) 새로고침하여 아이콘 업데이트
+ if(window.opener && !window.opener.closed) {
+ window.opener.location.reload();
+ }
window.close();
});
} else {
@@ -607,11 +631,6 @@ function fn_excel() {
-
-
-
-
-