일단 커밋

This commit is contained in:
leeheejin
2025-11-26 15:35:49 +09:00
parent 47cfa6bbf9
commit b647ecf70d
5 changed files with 836 additions and 219 deletions

View File

@@ -663,15 +663,20 @@ VALUES
SRM.PROJECT_NO,
PM.PROJECT_NO AS PROJECT_NUMBER,
PM.PROJECT_NAME,
COALESCE(
PM.OBJID,
(SELECT OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1)
) AS PROJECT_MGMT_OBJID,
-- M-BOM 조회용 BOM_REPORT_OBJID
COALESCE(
PM.BOM_REPORT_OBJID,
(SELECT BOM_REPORT_OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1)
) AS BOM_REPORT_OBJID,
COALESCE(
PM.OBJID,
(SELECT OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1)
) AS PROJECT_MGMT_OBJID,
-- M-BOM 조회용: MBOM_HEADER에서 직접 OBJID 가져오기
(SELECT MH.OBJID FROM MBOM_HEADER MH
WHERE MH.PROJECT_OBJID = COALESCE(PM.OBJID, (SELECT OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1))
AND MH.STATUS = 'Y'
ORDER BY MH.REGDATE DESC LIMIT 1
) AS MBOM_HEADER_OBJID,
COALESCE(
PM.BOM_REPORT_OBJID,
(SELECT BOM_REPORT_OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1)
) AS BOM_REPORT_OBJID,
PM.SETUP,
SM.SUPPLY_NAME AS CUSTOMER_NAME,
SM.OBJID::VARCHAR AS CUSTOMER_OBJID, -- 고객사 OBJID (드롭다운 선택용)
@@ -2927,26 +2932,26 @@ UPDATE SET
</update>
<!-- 구매리스트 상세 조회 (기존 저장된 데이터) -->
<select id="getPurchaseListDetail" parameterType="map" resultType="map">
<select id="getPurchaseListDetail" parameterType="map" resultType="com.pms.common.UpperKeyMap">
<!-- SALES_REQUEST_PART에서 저장된 데이터 조회, PART_MNG에서 품목정보 가져옴 -->
SELECT
SRP.OBJID,
SRP.SALES_REQUEST_MASTER_OBJID,
SRP.PART_OBJID,
COALESCE(PMG.PART_NO, '') AS PART_NO,
COALESCE(PMG.PART_NAME, '') AS PART_NAME,
COALESCE(PM.PART_NO, '') AS PART_NO,
COALESCE(PM.PART_NAME, '') AS PART_NAME,
SRP.QTY,
0 AS ITEM_QTY,
-- 파일 개수 (PART_MNG.OBJID 기준으로 조회)
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = PMG.OBJID AND DOC_TYPE IN ('3D_CAD') AND UPPER(STATUS) = 'ACTIVE'), 0) AS CU01_CNT,
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = PMG.OBJID AND DOC_TYPE IN ('2D_DRAWING_CAD') AND UPPER(STATUS) = 'ACTIVE'), 0) AS CU02_CNT,
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = PMG.OBJID AND DOC_TYPE IN ('2D_PDF_CAD') AND UPPER(STATUS) = 'ACTIVE'), 0) AS CU03_CNT,
COALESCE(PMG.MATERIAL, '') AS MATERIAL,
COALESCE(PMG.HEAT_TREATMENT_HARDNESS, '') AS HEAT_TREATMENT_HARDNESS,
COALESCE(PMG.HEAT_TREATMENT_METHOD, '') AS HEAT_TREATMENT_METHOD,
COALESCE(PMG.SURFACE_TREATMENT, '') AS SURFACE_TREATMENT,
COALESCE(PMG.MAKER, '') AS VENDOR,
COALESCE(PMG.PART_TYPE, '') AS PART_TYPE_TITLE,
-- 파일 개수
(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('3D_CAD')) AS CU01_CNT,
(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_DRAWING_CAD')) AS CU02_CNT,
(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_PDF_CAD')) AS CU03_CNT,
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 VENDOR,
(SELECT CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = PM.PART_TYPE) AS PART_TYPE_TITLE,
'' AS SUPPLY_TYPE,
'' AS RAW_MATERIAL,
'' AS SIZE,
@@ -2958,86 +2963,314 @@ UPDATE SET
'' AS PROCESSING_VENDOR,
NULL AS PROCESSING_DEADLINE,
NULL AS GRINDING_DEADLINE,
'Y' AS USE_YN,
0 AS NET_QTY,
0 AS PO_QTY,
SRP.PARTNER_OBJID AS VENDOR_PM,
COALESCE(NULLIF(SRP.PARTNER_PRICE, '')::numeric, 0) AS UNIT_PRICE,
COALESCE(
COALESCE(NULLIF(SRP.PARTNER_PRICE, '')::numeric, 0) * COALESCE(SRP.QTY::numeric, 0),
0
) AS TOTAL_PRICE,
NULL AS PROPOSAL_DATE
-- 구매 관련 컬럼 (SALES_REQUEST_PART에서 조회)
COALESCE(SRP.USE_YN, 'Y') AS USE_YN,
COALESCE(SRP.NET_QTY, 0) AS NET_QTY,
COALESCE(SRP.PO_QTY, 0) AS PO_QTY,
COALESCE(SRP.VENDOR_PM, SRP.PARTNER_OBJID) AS VENDOR_PM,
COALESCE(SRP.UNIT_PRICE, NULLIF(SRP.PARTNER_PRICE, '')::numeric, 0) AS UNIT_PRICE,
COALESCE(SRP.TOTAL_PRICE, 0) AS TOTAL_PRICE,
SRP.PROPOSAL_DATE,
'SRP' AS DATA_SOURCE -- 데이터 소스 구분용
FROM
SALES_REQUEST_PART SRP
LEFT JOIN PART_MNG PMG ON SRP.PART_OBJID = PMG.OBJID::VARCHAR AND PMG.IS_LAST = '1'
LEFT JOIN PART_MNG PM ON SRP.PART_OBJID::VARCHAR = PM.OBJID::VARCHAR
WHERE
SRP.SALES_REQUEST_MASTER_OBJID = #{SALES_REQUEST_MASTER_OBJID}
ORDER BY
SRP.REGDATE
</select>
<!-- M-BOM에서 구매리스트 데이터 가져오기 (BOM_PART_QTY 기본 데이터) -->
<select id="getMBomForPurchaseList" parameterType="map" resultType="map">
<!-- MBOM_DETAIL + PART_MNG 조인하여 조회 -->
SELECT
ROW_NUMBER() OVER (ORDER BY MD.SEQ) AS ROW_NUM,
MD.OBJID::VARCHAR AS OBJID,
MH.OBJID::VARCHAR AS BOM_REPORT_OBJID,
MD.PARENT_OBJID::VARCHAR AS PARENT_OBJID,
MD.CHILD_OBJID::VARCHAR AS CHILD_OBJID,
'' AS PARENT_PART_NO,
MD.PART_OBJID::VARCHAR AS PART_OBJID,
PM.OBJID::VARCHAR AS PM_OBJID,
COALESCE(MD.PART_NO, PM.PART_NO, '') AS PART_NO,
COALESCE(MD.PART_NAME, PM.PART_NAME, '') AS PART_NAME,
COALESCE(MD.QTY, 0) AS QTY,
COALESCE(MD.QTY, 0) AS ITEM_QTY,
0 AS QTY_TEMP,
MD.SEQ,
COALESCE(MD.STATUS, '') AS STATUS,
'' AS LAST_PART_OBJID,
-- 파일 개수 (ATTACH_FILE_INFO에서 서브쿼리로 가져옴)
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('3D_CAD')), 0) AS CU01_CNT,
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_DRAWING_CAD')), 0) AS CU02_CNT,
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_PDF_CAD')), 0) AS CU03_CNT,
-- E-BOM 컬럼들 (PART_MNG에서 가져옴) - 디버그용으로 원본값도 출력
PM.HEAT_TREATMENT_HARDNESS AS PM_HEAT_RAW,
PM.HEAT_TREATMENT_METHOD AS PM_METHOD_RAW,
PM.SURFACE_TREATMENT AS PM_SURFACE_RAW,
COALESCE(PM.MATERIAL, MD.RAW_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, MD.VENDOR, '') AS VENDOR,
COALESCE((SELECT CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = PM.PART_TYPE), '') AS PART_TYPE_TITLE,
-- 생산관리 컬럼들 (MBOM_DETAIL에서 가져옴)
COALESCE(MD.SUPPLY_TYPE, '') AS SUPPLY_TYPE,
COALESCE(MD.RAW_MATERIAL, '') AS RAW_MATERIAL,
COALESCE(MD.RAW_MATERIAL_SIZE, '') AS SIZE,
COALESCE(MD.RAW_MATERIAL_PART_NO, '') AS RAW_MATERIAL_NO,
COALESCE(MD.REQUIRED_QTY, 0) AS REQUIRED_QTY,
COALESCE(MD.ORDER_QTY, 0) AS ORDER_QTY,
COALESCE(MD.PRODUCTION_QTY, 0) AS PRODUCTION_QTY,
COALESCE(MD.PROCESSING_VENDOR, '') AS PROCESSING_VENDOR,
MD.PROCESSING_DEADLINE,
MD.GRINDING_DEADLINE,
-- 구매 컬럼들 (편집 가능)
'Y' AS USE_YN,
0 AS NET_QTY,
0 AS PO_QTY,
COALESCE(MD.VENDOR, '') AS VENDOR_PM,
COALESCE(MD.UNIT_PRICE, 0) AS UNIT_PRICE,
COALESCE(MD.TOTAL_PRICE, 0) AS TOTAL_PRICE,
NULL AS PROPOSAL_DATE
FROM
MBOM_HEADER MH
INNER JOIN MBOM_DETAIL MD ON MH.OBJID = MD.MBOM_HEADER_OBJID
LEFT JOIN PART_MNG PM ON PM.OBJID::VARCHAR = MD.PART_OBJID::VARCHAR
WHERE
MH.PROJECT_OBJID = #{PROJECT_MGMT_OBJID}
ORDER BY
MD.SEQ
<!-- M-BOM에서 구매리스트 데이터 가져오기 (STATUS 조건 없음, LEFT JOIN으로 모든 데이터 조회) -->
<select id="getMBomForPurchaseList" parameterType="map" resultType="com.pms.common.UpperKeyMap">
WITH RECURSIVE VIEW_BOM(
MBOM_HEADER_OBJID,
OBJID,
PARENT_OBJID,
CHILD_OBJID,
PART_OBJID,
PART_NO,
PART_NAME,
QTY,
ITEM_QTY,
QTY_TEMP,
REGDATE,
SEQ,
STATUS,
LEV,
PATH,
PATH2,
CYCLE,
UNIT,
SUPPLY_TYPE,
MAKE_OR_BUY,
RAW_MATERIAL_PART_NO,
RAW_MATERIAL_SPEC,
RAW_MATERIAL,
RAW_MATERIAL_SIZE,
PROCESSING_VENDOR,
PROCESSING_DEADLINE,
GRINDING_DEADLINE,
REQUIRED_QTY,
ORDER_QTY,
PRODUCTION_QTY,
STOCK_QTY,
SHORTAGE_QTY,
VENDOR,
UNIT_PRICE,
TOTAL_PRICE,
CURRENCY,
LEAD_TIME,
MIN_ORDER_QTY,
WRITER,
EDITER,
EDIT_DATE,
REMARK,
USE_YN,
NET_QTY,
PO_QTY,
PROPOSAL_DATE
) AS (
SELECT
A.MBOM_HEADER_OBJID,
A.OBJID,
A.PARENT_OBJID,
A.CHILD_OBJID,
A.PART_OBJID,
A.PART_NO,
A.PART_NAME,
A.QTY,
A.QTY,
A.QTY,
A.REGDATE,
A.SEQ,
A.STATUS,
1,
ARRAY [A.CHILD_OBJID::TEXT],
ARRAY [A.SEQ::TEXT],
FALSE,
A.UNIT,
A.SUPPLY_TYPE,
A.MAKE_OR_BUY,
A.RAW_MATERIAL_PART_NO,
A.RAW_MATERIAL_SPEC,
A.RAW_MATERIAL,
A.RAW_MATERIAL_SIZE,
A.PROCESSING_VENDOR,
A.PROCESSING_DEADLINE,
A.GRINDING_DEADLINE,
A.REQUIRED_QTY,
A.ORDER_QTY,
A.PRODUCTION_QTY,
A.STOCK_QTY,
A.SHORTAGE_QTY,
A.VENDOR,
A.UNIT_PRICE,
A.TOTAL_PRICE,
A.CURRENCY,
A.LEAD_TIME,
A.MIN_ORDER_QTY,
A.WRITER,
A.EDITER,
A.EDIT_DATE,
A.REMARK,
COALESCE(A.USE_YN, 'Y'),
COALESCE(A.NET_QTY, 0),
COALESCE(A.PO_QTY, 0),
A.PROPOSAL_DATE
FROM
MBOM_DETAIL A
INNER JOIN MBOM_HEADER MH ON MH.OBJID = A.MBOM_HEADER_OBJID
WHERE 1=1
AND (A.PARENT_OBJID IS NULL OR A.PARENT_OBJID = '')
AND (
MH.PROJECT_OBJID::VARCHAR = #{PROJECT_MGMT_OBJID}
OR MH.OBJID::VARCHAR = #{PROJECT_MGMT_OBJID}
)
<!-- STATUS 조건 제거하여 모든 데이터 조회 -->
UNION ALL
SELECT
B.MBOM_HEADER_OBJID,
B.OBJID,
B.PARENT_OBJID,
B.CHILD_OBJID,
B.PART_OBJID,
B.PART_NO,
B.PART_NAME,
B.QTY,
B.QTY,
B.QTY,
B.REGDATE,
B.SEQ,
B.STATUS,
LEV + 1,
PATH||B.CHILD_OBJID::TEXT,
PATH2||B.SEQ::TEXT,
B.PARENT_OBJID = ANY(PATH),
B.UNIT,
B.SUPPLY_TYPE,
B.MAKE_OR_BUY,
B.RAW_MATERIAL_PART_NO,
B.RAW_MATERIAL_SPEC,
B.RAW_MATERIAL,
B.RAW_MATERIAL_SIZE,
B.PROCESSING_VENDOR,
B.PROCESSING_DEADLINE,
B.GRINDING_DEADLINE,
B.REQUIRED_QTY,
B.ORDER_QTY,
B.PRODUCTION_QTY,
B.STOCK_QTY,
B.SHORTAGE_QTY,
B.VENDOR,
B.UNIT_PRICE,
B.TOTAL_PRICE,
B.CURRENCY,
B.LEAD_TIME,
B.MIN_ORDER_QTY,
B.WRITER,
B.EDITER,
B.EDIT_DATE,
B.REMARK,
COALESCE(B.USE_YN, 'Y'),
COALESCE(B.NET_QTY, 0),
COALESCE(B.PO_QTY, 0),
B.PROPOSAL_DATE
FROM
MBOM_DETAIL B
JOIN
VIEW_BOM
ON B.PARENT_OBJID = VIEW_BOM.CHILD_OBJID
AND VIEW_BOM.MBOM_HEADER_OBJID = B.MBOM_HEADER_OBJID
<!-- STATUS 조건 제거하여 모든 데이터 조회 -->
)
SELECT
V.MBOM_HEADER_OBJID AS BOM_REPORT_OBJID,
V.OBJID,
V.PARENT_OBJID,
V.CHILD_OBJID,
V.PART_OBJID,
V.PART_OBJID AS LAST_PART_OBJID,
V.PART_OBJID AS BOM_LAST_PART_OBJID,
V.PART_NO,
V.PART_NAME,
V.QTY,
V.ITEM_QTY,
V.QTY_TEMP,
V.LEV AS LEVEL,
(SELECT COUNT(*) FROM MBOM_DETAIL WHERE PARENT_OBJID = V.CHILD_OBJID) AS SUB_PART_CNT,
V.SEQ,
V.STATUS,
-- M-BOM 전용 필드
V.UNIT,
V.SUPPLY_TYPE,
V.MAKE_OR_BUY,
V.RAW_MATERIAL_PART_NO AS RAW_MATERIAL_NO,
V.RAW_MATERIAL_SPEC,
V.RAW_MATERIAL,
V.RAW_MATERIAL_SIZE AS SIZE,
V.PROCESSING_VENDOR,
V.PROCESSING_DEADLINE,
V.GRINDING_DEADLINE,
V.REQUIRED_QTY,
V.ORDER_QTY,
V.PRODUCTION_QTY,
V.STOCK_QTY,
V.SHORTAGE_QTY,
V.VENDOR AS VENDOR_PM,
V.UNIT_PRICE,
V.TOTAL_PRICE,
V.CURRENCY,
V.LEAD_TIME,
V.MIN_ORDER_QTY,
V.WRITER,
TO_CHAR(V.REGDATE, 'YYYY-MM-DD HH24:MI:SS') AS REGDATE,
V.EDITER,
CASE WHEN V.EDIT_DATE IS NOT NULL THEN TO_CHAR(V.EDIT_DATE, 'YYYY-MM-DD HH24:MI:SS') ELSE NULL END AS EDIT_DATE,
V.REMARK,
-- E-BOM 호환 필드
NULL AS PARENT_PART_NO,
NULL AS CONTRACT_OBJID,
CASE WHEN V.LEV = 1 THEN V.OBJID ELSE NULL END AS ROOT_OBJID,
CASE WHEN V.LEV = 1 THEN V.OBJID ELSE NULL END AS SUB_ROOT_OBJID,
1 AS LEAF,
-- PART_MNG 테이블에서 추가 정보 (LEFT JOIN으로 PART_MNG에 없는 품번도 표시)
P.SPEC,
COALESCE(P.MATERIAL, V.RAW_MATERIAL) AS MATERIAL,
P.WEIGHT,
P.PART_TYPE,
P.REVISION,
COALESCE(P.MAKER, V.VENDOR) AS VENDOR,
P.THICKNESS,
P.WIDTH,
P.HEIGHT,
P.OUT_DIAMETER,
P.IN_DIAMETER,
P.LENGTH,
P.SOURCING_CODE,
COALESCE(P.HEAT_TREATMENT_HARDNESS, '') AS HEAT_TREATMENT_HARDNESS,
COALESCE(P.HEAT_TREATMENT_METHOD, '') AS HEAT_TREATMENT_METHOD,
COALESCE(P.SURFACE_TREATMENT, '') AS SURFACE_TREATMENT,
(SELECT CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = P.UNIT) AS UNIT_TITLE,
(SELECT CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = P.PART_TYPE) AS PART_TYPE_TITLE,
(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('3D_CAD')) AS CU01_CNT,
(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_DRAWING_CAD')) AS CU02_CNT,
(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_PDF_CAD')) AS CU03_CNT,
V.LEV,
-- 구매 컬럼들 (VIEW_BOM에서 가져온 MBOM_DETAIL 값)
V.USE_YN,
V.NET_QTY,
V.PO_QTY,
V.PROPOSAL_DATE,
'MBOM' AS DATA_SOURCE -- 데이터 소스 구분용
FROM VIEW_BOM V
LEFT JOIN PART_MNG P ON P.OBJID::VARCHAR = V.PART_OBJID::VARCHAR
WHERE 1=1
ORDER BY V.PATH2
</select>
<!-- PROJECT_OBJID로 MBOM_HEADER 조회 (PROJECT_MGMT.SOURCE_MBOM_OBJID 우선 사용) -->
<select id="getMbomHeaderByProjectId" parameterType="map" resultType="map">
SELECT
COALESCE(PM.SOURCE_MBOM_OBJID::VARCHAR, MH.OBJID::VARCHAR) AS OBJID,
PM.OBJID AS PROJECT_OBJID,
PM.PROJECT_NO
FROM PROJECT_MGMT PM
LEFT JOIN MBOM_HEADER MH ON MH.PROJECT_OBJID = PM.OBJID
WHERE PM.OBJID::VARCHAR = #{projectObjId}
ORDER BY MH.REGDATE DESC
LIMIT 1
</select>
<!-- 구매리스트 저장 - MBOM_DETAIL 업데이트 -->
<update id="updateMbomDetailForPurchase" parameterType="map">
UPDATE MBOM_DETAIL SET
USE_YN = #{USE_YN},
NET_QTY = COALESCE(NULLIF(TRIM(#{NET_QTY}::TEXT), '')::NUMERIC, 0),
PO_QTY = COALESCE(NULLIF(TRIM(#{PO_QTY}::TEXT), '')::NUMERIC, 0),
VENDOR = #{VENDOR_PM},
UNIT_PRICE = COALESCE(NULLIF(TRIM(#{UNIT_PRICE}::TEXT), '')::NUMERIC, 0),
TOTAL_PRICE = COALESCE(NULLIF(TRIM(#{TOTAL_PRICE}::TEXT), '')::NUMERIC, 0),
PROPOSAL_DATE = CASE WHEN NULLIF(TRIM(#{PROPOSAL_DATE}::TEXT), '') IS NOT NULL THEN #{PROPOSAL_DATE}::DATE ELSE NULL END,
EDITER = #{EDITER},
EDIT_DATE = NOW()
WHERE OBJID::VARCHAR = #{OBJID}
</update>
<!-- 구매리스트 저장 - SALES_REQUEST_PART 업데이트 -->
<update id="updateSalesRequestPartForPurchase" parameterType="map">
UPDATE SALES_REQUEST_PART SET
USE_YN = #{USE_YN},
NET_QTY = COALESCE(NULLIF(TRIM(#{NET_QTY}::TEXT), '')::NUMERIC, 0),
PO_QTY = COALESCE(NULLIF(TRIM(#{PO_QTY}::TEXT), '')::NUMERIC, 0),
VENDOR_PM = #{VENDOR_PM},
UNIT_PRICE = COALESCE(NULLIF(TRIM(#{UNIT_PRICE}::TEXT), '')::NUMERIC, 0),
TOTAL_PRICE = COALESCE(NULLIF(TRIM(#{TOTAL_PRICE}::TEXT), '')::NUMERIC, 0),
PROPOSAL_DATE = CASE WHEN NULLIF(TRIM(#{PROPOSAL_DATE}::TEXT), '') IS NOT NULL THEN #{PROPOSAL_DATE}::DATE ELSE NULL END,
WRITER = #{EDITER}
WHERE OBJID::VARCHAR = #{OBJID}
</update>
</mapper>

View File

@@ -12,6 +12,11 @@
value="${not empty param.BOM_REPORT_OBJID and param.BOM_REPORT_OBJID ne 'null'
? param.BOM_REPORT_OBJID
: (not empty resultMap.BOM_REPORT_OBJID ? resultMap.BOM_REPORT_OBJID : '')}" />
<%-- MBOM_HEADER.OBJID를 직접 사용 (M-BOM 관리 화면에서 사용하는 것과 동일) --%>
<c:set var="resolvedMbomHeaderObjid"
value="${not empty param.MBOM_HEADER_OBJID and param.MBOM_HEADER_OBJID ne 'null'
? param.MBOM_HEADER_OBJID
: (not empty resultMap.MBOM_HEADER_OBJID ? resultMap.MBOM_HEADER_OBJID : '')}" />
<!DOCTYPE html>
<html>
<head>
@@ -83,14 +88,18 @@ var _tabulGrid;
var salesRequestMasterObjid = "${param.SALES_REQUEST_MASTER_OBJID}";
var projectMgmtObjid = "${resolvedProjectId}";
var bomReportObjid = "${resolvedBomReportObjid}";
var mbomHeaderObjid = "${resolvedMbomHeaderObjid}"; // MBOM_HEADER.OBJID (M-BOM 관리 화면에서 사용하는 ID)
var vendorList = []; // 공급업체 목록
// 디버그: resultMap 내용 확인
console.log("=== JSP resultMap 디버그 ===");
console.log("resultMap.PROJECT_MGMT_OBJID:", "${resultMap.PROJECT_MGMT_OBJID}");
console.log("resultMap.BOM_REPORT_OBJID:", "${resultMap.BOM_REPORT_OBJID}");
console.log("resultMap.MBOM_HEADER_OBJID:", "${resultMap.MBOM_HEADER_OBJID}");
console.log("resultMap.PROJECT_NO:", "${resultMap.PROJECT_NO}");
console.log("resolvedProjectId:", projectMgmtObjid);
console.log("resolvedBomReportObjid:", bomReportObjid);
console.log("resolvedMbomHeaderObjid:", mbomHeaderObjid);
function logDebug(){
if(window.console && typeof window.console.log === "function"){
console.log.apply(console, arguments);
@@ -103,24 +112,66 @@ function logError(){
}
$(document).ready(function(){
fn_initGrid();
logDebug("purchaseListFormPopUp :: grid initialized");
fn_loadInitialData();
// 공급업체 목록 먼저 로드
fn_loadVendorList(function(){
fn_initGrid();
logDebug("purchaseListFormPopUp :: grid initialized");
fn_loadInitialData();
});
});
// 공급업체 목록 로드 (기준정보_협력업체관리 - ADMIN_SUPPLY_MNG)
function fn_loadVendorList(callback) {
$.ajax({
url: "/admin/supplyMngPagingGridList.do",
method: 'post',
data: {
searchStatus: 'Y',
countPerPage: 1000 // 충분히 많이 가져오기
},
dataType: 'json',
success: function(data) {
console.log("공급업체 목록 응답:", data);
if(data && data.RESULTLIST) {
vendorList = {}; // 객체 형태로 변경
vendorList[''] = '선택'; // 빈 값
data.RESULTLIST.forEach(function(item) {
var name = item.SUPPLY_NAME || '';
var objid = item.OBJID || '';
if(objid && name) {
vendorList[objid] = name;
}
});
console.log("vendorList 생성 완료:", Object.keys(vendorList).length + "개");
}
if(callback) callback();
},
error: function(xhr, status, error) {
logError("공급업체 목록 로드 실패:", error);
vendorList = {'': '선택'}; // 기본값
if(callback) callback();
}
});
}
function fn_loadInitialData(){
logDebug("purchaseListFormPopUp :: fn_loadInitialData start",
"projectMgmtObjid=", projectMgmtObjid,
"mbomHeaderObjid=", mbomHeaderObjid,
"salesRequestMasterObjid=", salesRequestMasterObjid);
var hasProject = projectMgmtObjid && projectMgmtObjid !== "" && projectMgmtObjid !== "null";
var hasMbomHeader = mbomHeaderObjid && mbomHeaderObjid !== "" && mbomHeaderObjid !== "null";
var hasMaster = salesRequestMasterObjid && salesRequestMasterObjid !== "" && salesRequestMasterObjid !== "null";
if(hasProject){
// M-BOM이 있는지 확인 (MBOM_HEADER_OBJID가 있으면 M-BOM 존재)
if(hasProject || hasMbomHeader){
logDebug("purchaseListFormPopUp :: loading MBOM first");
fn_loadFromMBom(function(){
fn_loadFromMBom(function(mbomList){
if(hasMaster){
logDebug("purchaseListFormPopUp :: merging saved purchase data after MBOM");
fn_loadPurchaseList(true);
// M-BOM 데이터가 있으면 merge, 없으면 SALES_REQUEST_PART만 로드
var hasMbomData = mbomList && mbomList.length > 0;
logDebug("purchaseListFormPopUp :: MBOM data count:", mbomList ? mbomList.length : 0);
fn_loadPurchaseList(hasMbomData); // M-BOM 있으면 merge, 없으면 단독 로드
}
});
} else if(hasMaster){
@@ -155,6 +206,23 @@ function fn_initGrid() {
field: 'ROW_NUM',
formatter: "rownum"
},
// 2-1. 구분 (M-BOM / 수동)
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 70,
title: '구분',
field: 'DATA_SOURCE',
formatter: function(cell) {
var value = cell.getValue();
if(value === 'MBOM') {
return '<span style="color: #2196F3; font-weight: bold;">M-BOM</span>';
} else if(value === 'SRP') {
return '<span style="color: #4CAF50; font-weight: bold;">수동</span>';
}
return value || '';
}
},
// 3. 품번
{
headerHozAlign: 'center',
@@ -383,7 +451,7 @@ function fn_initGrid() {
values: ['Y', 'N']
}
},
// 28. 정미수량 (편집 가능)
// 28. 정미수량 (편집 가능) - 소재소요량 × 제작수량, 소수점 올림
{
headerHozAlign: 'center',
hozAlign: 'right',
@@ -391,6 +459,15 @@ function fn_initGrid() {
title: '정미수량',
field: 'NET_QTY',
editor: 'number',
mutator: function(value, data) {
// 값이 이미 설정되어 있으면 그대로 사용
if(value && value > 0) return value;
// 소재소요량 × 제작수량, 소수점 올림
var requiredQty = parseFloat(data.REQUIRED_QTY) || 0;
var productionQty = parseFloat(data.PRODUCTION_QTY) || 0;
var calculated = requiredQty * productionQty;
return calculated > 0 ? Math.ceil(calculated) : 0;
},
formatter: function(cell) {
var value = cell.getValue();
return value ? Number(value).toLocaleString() : '0';
@@ -409,15 +486,29 @@ function fn_initGrid() {
return value ? Number(value).toLocaleString() : '0';
}
},
// 30. 공급업체2
// 30. 공급업체2 (기준정보에서 선택)
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 150,
title: '공급업체2',
title: '공급업체',
field: 'VENDOR_PM',
editor: 'input',
editable: true
editor: 'list',
editorParams: function(cell) {
return {
values: vendorList,
autocomplete: true,
listOnEmpty: true,
freetext: true,
allowEmpty: true
};
},
formatter: function(cell) {
var value = cell.getValue();
if(!value) return '';
// vendorList에서 해당 값의 이름 찾기
return vendorList[value] || value;
}
},
// 31. 단가
{
@@ -520,11 +611,17 @@ function fn_loadFromMBom(callback) {
console.log("=== fn_loadFromMBom 호출 ===");
console.log("PROJECT_MGMT_OBJID:", projectMgmtObjid);
console.log("BOM_REPORT_OBJID:", bomReportObjid);
console.log("MBOM_HEADER_OBJID:", mbomHeaderObjid);
// MBOM_HEADER_OBJID가 있으면 우선 사용 (M-BOM 관리 화면과 동일한 방식)
var mbomObjIdToUse = mbomHeaderObjid || projectMgmtObjid;
console.log("사용할 MBOM OBJID:", mbomObjIdToUse);
$.ajax({
url: "/salesMng/getMBomForPurchaseList.do",
method: 'post',
data: {
PROJECT_MGMT_OBJID: projectMgmtObjid,
PROJECT_MGMT_OBJID: mbomObjIdToUse,
bomReportObjId: bomReportObjid
},
dataType: 'json',

View File

@@ -0,0 +1,39 @@
-- SALES_REQUEST_PART 테이블에 구매관리 관련 컬럼 추가
-- 실행 전 백업 권장
-- 사용여부
ALTER TABLE SALES_REQUEST_PART ADD COLUMN IF NOT EXISTS USE_YN VARCHAR(1) DEFAULT 'Y';
COMMENT ON COLUMN SALES_REQUEST_PART.USE_YN IS '사용여부 (Y/N)';
-- 정미수량
ALTER TABLE SALES_REQUEST_PART ADD COLUMN IF NOT EXISTS NET_QTY NUMERIC DEFAULT 0;
COMMENT ON COLUMN SALES_REQUEST_PART.NET_QTY IS '정미수량';
-- 발주수량
ALTER TABLE SALES_REQUEST_PART ADD COLUMN IF NOT EXISTS PO_QTY NUMERIC DEFAULT 0;
COMMENT ON COLUMN SALES_REQUEST_PART.PO_QTY IS '발주수량';
-- 공급업체2 (기준정보에서 선택)
ALTER TABLE SALES_REQUEST_PART ADD COLUMN IF NOT EXISTS VENDOR_PM VARCHAR(255);
COMMENT ON COLUMN SALES_REQUEST_PART.VENDOR_PM IS '공급업체2 (기준정보_협력업체관리)';
-- 단가
ALTER TABLE SALES_REQUEST_PART ADD COLUMN IF NOT EXISTS UNIT_PRICE NUMERIC DEFAULT 0;
COMMENT ON COLUMN SALES_REQUEST_PART.UNIT_PRICE IS '단가';
-- 총단가
ALTER TABLE SALES_REQUEST_PART ADD COLUMN IF NOT EXISTS TOTAL_PRICE NUMERIC DEFAULT 0;
COMMENT ON COLUMN SALES_REQUEST_PART.TOTAL_PRICE IS '총단가 (발주수량 * 단가)';
-- 품의서작성일
ALTER TABLE SALES_REQUEST_PART ADD COLUMN IF NOT EXISTS PROPOSAL_DATE DATE;
COMMENT ON COLUMN SALES_REQUEST_PART.PROPOSAL_DATE IS '품의서작성일';
-- 수정자
ALTER TABLE SALES_REQUEST_PART ADD COLUMN IF NOT EXISTS EDITER VARCHAR(50);
COMMENT ON COLUMN SALES_REQUEST_PART.EDITER IS '수정자';
-- 수정일
ALTER TABLE SALES_REQUEST_PART ADD COLUMN IF NOT EXISTS EDIT_DATE TIMESTAMP;
COMMENT ON COLUMN SALES_REQUEST_PART.EDIT_DATE IS '수정일';

View File

@@ -663,15 +663,20 @@ VALUES
SRM.PROJECT_NO,
PM.PROJECT_NO AS PROJECT_NUMBER,
PM.PROJECT_NAME,
COALESCE(
PM.OBJID,
(SELECT OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1)
) AS PROJECT_MGMT_OBJID,
-- M-BOM 조회용 BOM_REPORT_OBJID
COALESCE(
PM.BOM_REPORT_OBJID,
(SELECT BOM_REPORT_OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1)
) AS BOM_REPORT_OBJID,
COALESCE(
PM.OBJID,
(SELECT OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1)
) AS PROJECT_MGMT_OBJID,
-- M-BOM 조회용: MBOM_HEADER에서 직접 OBJID 가져오기
(SELECT MH.OBJID FROM MBOM_HEADER MH
WHERE MH.PROJECT_OBJID = COALESCE(PM.OBJID, (SELECT OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1))
AND MH.STATUS = 'Y'
ORDER BY MH.REGDATE DESC LIMIT 1
) AS MBOM_HEADER_OBJID,
COALESCE(
PM.BOM_REPORT_OBJID,
(SELECT BOM_REPORT_OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1)
) AS BOM_REPORT_OBJID,
PM.SETUP,
SM.SUPPLY_NAME AS CUSTOMER_NAME,
SM.OBJID::VARCHAR AS CUSTOMER_OBJID, -- 고객사 OBJID (드롭다운 선택용)
@@ -2927,26 +2932,26 @@ UPDATE SET
</update>
<!-- 구매리스트 상세 조회 (기존 저장된 데이터) -->
<select id="getPurchaseListDetail" parameterType="map" resultType="map">
<select id="getPurchaseListDetail" parameterType="map" resultType="com.pms.common.UpperKeyMap">
<!-- SALES_REQUEST_PART에서 저장된 데이터 조회, PART_MNG에서 품목정보 가져옴 -->
SELECT
SRP.OBJID,
SRP.SALES_REQUEST_MASTER_OBJID,
SRP.PART_OBJID,
COALESCE(PMG.PART_NO, '') AS PART_NO,
COALESCE(PMG.PART_NAME, '') AS PART_NAME,
COALESCE(PM.PART_NO, '') AS PART_NO,
COALESCE(PM.PART_NAME, '') AS PART_NAME,
SRP.QTY,
0 AS ITEM_QTY,
-- 파일 개수 (PART_MNG.OBJID 기준으로 조회)
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = PMG.OBJID AND DOC_TYPE IN ('3D_CAD') AND UPPER(STATUS) = 'ACTIVE'), 0) AS CU01_CNT,
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = PMG.OBJID AND DOC_TYPE IN ('2D_DRAWING_CAD') AND UPPER(STATUS) = 'ACTIVE'), 0) AS CU02_CNT,
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = PMG.OBJID AND DOC_TYPE IN ('2D_PDF_CAD') AND UPPER(STATUS) = 'ACTIVE'), 0) AS CU03_CNT,
COALESCE(PMG.MATERIAL, '') AS MATERIAL,
COALESCE(PMG.HEAT_TREATMENT_HARDNESS, '') AS HEAT_TREATMENT_HARDNESS,
COALESCE(PMG.HEAT_TREATMENT_METHOD, '') AS HEAT_TREATMENT_METHOD,
COALESCE(PMG.SURFACE_TREATMENT, '') AS SURFACE_TREATMENT,
COALESCE(PMG.MAKER, '') AS VENDOR,
COALESCE(PMG.PART_TYPE, '') AS PART_TYPE_TITLE,
-- 파일 개수
(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('3D_CAD')) AS CU01_CNT,
(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_DRAWING_CAD')) AS CU02_CNT,
(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_PDF_CAD')) AS CU03_CNT,
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 VENDOR,
(SELECT CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = PM.PART_TYPE) AS PART_TYPE_TITLE,
'' AS SUPPLY_TYPE,
'' AS RAW_MATERIAL,
'' AS SIZE,
@@ -2958,86 +2963,314 @@ UPDATE SET
'' AS PROCESSING_VENDOR,
NULL AS PROCESSING_DEADLINE,
NULL AS GRINDING_DEADLINE,
'Y' AS USE_YN,
0 AS NET_QTY,
0 AS PO_QTY,
SRP.PARTNER_OBJID AS VENDOR_PM,
COALESCE(NULLIF(SRP.PARTNER_PRICE, '')::numeric, 0) AS UNIT_PRICE,
COALESCE(
COALESCE(NULLIF(SRP.PARTNER_PRICE, '')::numeric, 0) * COALESCE(SRP.QTY::numeric, 0),
0
) AS TOTAL_PRICE,
NULL AS PROPOSAL_DATE
-- 구매 관련 컬럼 (SALES_REQUEST_PART에서 조회)
COALESCE(SRP.USE_YN, 'Y') AS USE_YN,
COALESCE(SRP.NET_QTY, 0) AS NET_QTY,
COALESCE(SRP.PO_QTY, 0) AS PO_QTY,
COALESCE(SRP.VENDOR_PM, SRP.PARTNER_OBJID) AS VENDOR_PM,
COALESCE(SRP.UNIT_PRICE, NULLIF(SRP.PARTNER_PRICE, '')::numeric, 0) AS UNIT_PRICE,
COALESCE(SRP.TOTAL_PRICE, 0) AS TOTAL_PRICE,
SRP.PROPOSAL_DATE,
'SRP' AS DATA_SOURCE -- 데이터 소스 구분용
FROM
SALES_REQUEST_PART SRP
LEFT JOIN PART_MNG PMG ON SRP.PART_OBJID = PMG.OBJID::VARCHAR AND PMG.IS_LAST = '1'
LEFT JOIN PART_MNG PM ON SRP.PART_OBJID::VARCHAR = PM.OBJID::VARCHAR
WHERE
SRP.SALES_REQUEST_MASTER_OBJID = #{SALES_REQUEST_MASTER_OBJID}
ORDER BY
SRP.REGDATE
</select>
<!-- M-BOM에서 구매리스트 데이터 가져오기 (BOM_PART_QTY 기본 데이터) -->
<select id="getMBomForPurchaseList" parameterType="map" resultType="map">
<!-- MBOM_DETAIL + PART_MNG 조인하여 조회 -->
SELECT
ROW_NUMBER() OVER (ORDER BY MD.SEQ) AS ROW_NUM,
MD.OBJID::VARCHAR AS OBJID,
MH.OBJID::VARCHAR AS BOM_REPORT_OBJID,
MD.PARENT_OBJID::VARCHAR AS PARENT_OBJID,
MD.CHILD_OBJID::VARCHAR AS CHILD_OBJID,
'' AS PARENT_PART_NO,
MD.PART_OBJID::VARCHAR AS PART_OBJID,
PM.OBJID::VARCHAR AS PM_OBJID,
COALESCE(MD.PART_NO, PM.PART_NO, '') AS PART_NO,
COALESCE(MD.PART_NAME, PM.PART_NAME, '') AS PART_NAME,
COALESCE(MD.QTY, 0) AS QTY,
COALESCE(MD.QTY, 0) AS ITEM_QTY,
0 AS QTY_TEMP,
MD.SEQ,
COALESCE(MD.STATUS, '') AS STATUS,
'' AS LAST_PART_OBJID,
-- 파일 개수 (ATTACH_FILE_INFO에서 서브쿼리로 가져옴)
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('3D_CAD')), 0) AS CU01_CNT,
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_DRAWING_CAD')), 0) AS CU02_CNT,
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_PDF_CAD')), 0) AS CU03_CNT,
-- E-BOM 컬럼들 (PART_MNG에서 가져옴) - 디버그용으로 원본값도 출력
PM.HEAT_TREATMENT_HARDNESS AS PM_HEAT_RAW,
PM.HEAT_TREATMENT_METHOD AS PM_METHOD_RAW,
PM.SURFACE_TREATMENT AS PM_SURFACE_RAW,
COALESCE(PM.MATERIAL, MD.RAW_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, MD.VENDOR, '') AS VENDOR,
COALESCE((SELECT CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = PM.PART_TYPE), '') AS PART_TYPE_TITLE,
-- 생산관리 컬럼들 (MBOM_DETAIL에서 가져옴)
COALESCE(MD.SUPPLY_TYPE, '') AS SUPPLY_TYPE,
COALESCE(MD.RAW_MATERIAL, '') AS RAW_MATERIAL,
COALESCE(MD.RAW_MATERIAL_SIZE, '') AS SIZE,
COALESCE(MD.RAW_MATERIAL_PART_NO, '') AS RAW_MATERIAL_NO,
COALESCE(MD.REQUIRED_QTY, 0) AS REQUIRED_QTY,
COALESCE(MD.ORDER_QTY, 0) AS ORDER_QTY,
COALESCE(MD.PRODUCTION_QTY, 0) AS PRODUCTION_QTY,
COALESCE(MD.PROCESSING_VENDOR, '') AS PROCESSING_VENDOR,
MD.PROCESSING_DEADLINE,
MD.GRINDING_DEADLINE,
-- 구매 컬럼들 (편집 가능)
'Y' AS USE_YN,
0 AS NET_QTY,
0 AS PO_QTY,
COALESCE(MD.VENDOR, '') AS VENDOR_PM,
COALESCE(MD.UNIT_PRICE, 0) AS UNIT_PRICE,
COALESCE(MD.TOTAL_PRICE, 0) AS TOTAL_PRICE,
NULL AS PROPOSAL_DATE
FROM
MBOM_HEADER MH
INNER JOIN MBOM_DETAIL MD ON MH.OBJID = MD.MBOM_HEADER_OBJID
LEFT JOIN PART_MNG PM ON PM.OBJID::VARCHAR = MD.PART_OBJID::VARCHAR
WHERE
MH.PROJECT_OBJID = #{PROJECT_MGMT_OBJID}
ORDER BY
MD.SEQ
<!-- M-BOM에서 구매리스트 데이터 가져오기 (STATUS 조건 없음, LEFT JOIN으로 모든 데이터 조회) -->
<select id="getMBomForPurchaseList" parameterType="map" resultType="com.pms.common.UpperKeyMap">
WITH RECURSIVE VIEW_BOM(
MBOM_HEADER_OBJID,
OBJID,
PARENT_OBJID,
CHILD_OBJID,
PART_OBJID,
PART_NO,
PART_NAME,
QTY,
ITEM_QTY,
QTY_TEMP,
REGDATE,
SEQ,
STATUS,
LEV,
PATH,
PATH2,
CYCLE,
UNIT,
SUPPLY_TYPE,
MAKE_OR_BUY,
RAW_MATERIAL_PART_NO,
RAW_MATERIAL_SPEC,
RAW_MATERIAL,
RAW_MATERIAL_SIZE,
PROCESSING_VENDOR,
PROCESSING_DEADLINE,
GRINDING_DEADLINE,
REQUIRED_QTY,
ORDER_QTY,
PRODUCTION_QTY,
STOCK_QTY,
SHORTAGE_QTY,
VENDOR,
UNIT_PRICE,
TOTAL_PRICE,
CURRENCY,
LEAD_TIME,
MIN_ORDER_QTY,
WRITER,
EDITER,
EDIT_DATE,
REMARK,
USE_YN,
NET_QTY,
PO_QTY,
PROPOSAL_DATE
) AS (
SELECT
A.MBOM_HEADER_OBJID,
A.OBJID,
A.PARENT_OBJID,
A.CHILD_OBJID,
A.PART_OBJID,
A.PART_NO,
A.PART_NAME,
A.QTY,
A.QTY,
A.QTY,
A.REGDATE,
A.SEQ,
A.STATUS,
1,
ARRAY [A.CHILD_OBJID::TEXT],
ARRAY [A.SEQ::TEXT],
FALSE,
A.UNIT,
A.SUPPLY_TYPE,
A.MAKE_OR_BUY,
A.RAW_MATERIAL_PART_NO,
A.RAW_MATERIAL_SPEC,
A.RAW_MATERIAL,
A.RAW_MATERIAL_SIZE,
A.PROCESSING_VENDOR,
A.PROCESSING_DEADLINE,
A.GRINDING_DEADLINE,
A.REQUIRED_QTY,
A.ORDER_QTY,
A.PRODUCTION_QTY,
A.STOCK_QTY,
A.SHORTAGE_QTY,
A.VENDOR,
A.UNIT_PRICE,
A.TOTAL_PRICE,
A.CURRENCY,
A.LEAD_TIME,
A.MIN_ORDER_QTY,
A.WRITER,
A.EDITER,
A.EDIT_DATE,
A.REMARK,
COALESCE(A.USE_YN, 'Y'),
COALESCE(A.NET_QTY, 0),
COALESCE(A.PO_QTY, 0),
A.PROPOSAL_DATE
FROM
MBOM_DETAIL A
INNER JOIN MBOM_HEADER MH ON MH.OBJID = A.MBOM_HEADER_OBJID
WHERE 1=1
AND (A.PARENT_OBJID IS NULL OR A.PARENT_OBJID = '')
AND (
MH.PROJECT_OBJID::VARCHAR = #{PROJECT_MGMT_OBJID}
OR MH.OBJID::VARCHAR = #{PROJECT_MGMT_OBJID}
)
<!-- STATUS 조건 제거하여 모든 데이터 조회 -->
UNION ALL
SELECT
B.MBOM_HEADER_OBJID,
B.OBJID,
B.PARENT_OBJID,
B.CHILD_OBJID,
B.PART_OBJID,
B.PART_NO,
B.PART_NAME,
B.QTY,
B.QTY,
B.QTY,
B.REGDATE,
B.SEQ,
B.STATUS,
LEV + 1,
PATH||B.CHILD_OBJID::TEXT,
PATH2||B.SEQ::TEXT,
B.PARENT_OBJID = ANY(PATH),
B.UNIT,
B.SUPPLY_TYPE,
B.MAKE_OR_BUY,
B.RAW_MATERIAL_PART_NO,
B.RAW_MATERIAL_SPEC,
B.RAW_MATERIAL,
B.RAW_MATERIAL_SIZE,
B.PROCESSING_VENDOR,
B.PROCESSING_DEADLINE,
B.GRINDING_DEADLINE,
B.REQUIRED_QTY,
B.ORDER_QTY,
B.PRODUCTION_QTY,
B.STOCK_QTY,
B.SHORTAGE_QTY,
B.VENDOR,
B.UNIT_PRICE,
B.TOTAL_PRICE,
B.CURRENCY,
B.LEAD_TIME,
B.MIN_ORDER_QTY,
B.WRITER,
B.EDITER,
B.EDIT_DATE,
B.REMARK,
COALESCE(B.USE_YN, 'Y'),
COALESCE(B.NET_QTY, 0),
COALESCE(B.PO_QTY, 0),
B.PROPOSAL_DATE
FROM
MBOM_DETAIL B
JOIN
VIEW_BOM
ON B.PARENT_OBJID = VIEW_BOM.CHILD_OBJID
AND VIEW_BOM.MBOM_HEADER_OBJID = B.MBOM_HEADER_OBJID
<!-- STATUS 조건 제거하여 모든 데이터 조회 -->
)
SELECT
V.MBOM_HEADER_OBJID AS BOM_REPORT_OBJID,
V.OBJID,
V.PARENT_OBJID,
V.CHILD_OBJID,
V.PART_OBJID,
V.PART_OBJID AS LAST_PART_OBJID,
V.PART_OBJID AS BOM_LAST_PART_OBJID,
V.PART_NO,
V.PART_NAME,
V.QTY,
V.ITEM_QTY,
V.QTY_TEMP,
V.LEV AS LEVEL,
(SELECT COUNT(*) FROM MBOM_DETAIL WHERE PARENT_OBJID = V.CHILD_OBJID) AS SUB_PART_CNT,
V.SEQ,
V.STATUS,
-- M-BOM 전용 필드
V.UNIT,
V.SUPPLY_TYPE,
V.MAKE_OR_BUY,
V.RAW_MATERIAL_PART_NO AS RAW_MATERIAL_NO,
V.RAW_MATERIAL_SPEC,
V.RAW_MATERIAL,
V.RAW_MATERIAL_SIZE AS SIZE,
V.PROCESSING_VENDOR,
V.PROCESSING_DEADLINE,
V.GRINDING_DEADLINE,
V.REQUIRED_QTY,
V.ORDER_QTY,
V.PRODUCTION_QTY,
V.STOCK_QTY,
V.SHORTAGE_QTY,
V.VENDOR AS VENDOR_PM,
V.UNIT_PRICE,
V.TOTAL_PRICE,
V.CURRENCY,
V.LEAD_TIME,
V.MIN_ORDER_QTY,
V.WRITER,
TO_CHAR(V.REGDATE, 'YYYY-MM-DD HH24:MI:SS') AS REGDATE,
V.EDITER,
CASE WHEN V.EDIT_DATE IS NOT NULL THEN TO_CHAR(V.EDIT_DATE, 'YYYY-MM-DD HH24:MI:SS') ELSE NULL END AS EDIT_DATE,
V.REMARK,
-- E-BOM 호환 필드
NULL AS PARENT_PART_NO,
NULL AS CONTRACT_OBJID,
CASE WHEN V.LEV = 1 THEN V.OBJID ELSE NULL END AS ROOT_OBJID,
CASE WHEN V.LEV = 1 THEN V.OBJID ELSE NULL END AS SUB_ROOT_OBJID,
1 AS LEAF,
-- PART_MNG 테이블에서 추가 정보 (LEFT JOIN으로 PART_MNG에 없는 품번도 표시)
P.SPEC,
COALESCE(P.MATERIAL, V.RAW_MATERIAL) AS MATERIAL,
P.WEIGHT,
P.PART_TYPE,
P.REVISION,
COALESCE(P.MAKER, V.VENDOR) AS VENDOR,
P.THICKNESS,
P.WIDTH,
P.HEIGHT,
P.OUT_DIAMETER,
P.IN_DIAMETER,
P.LENGTH,
P.SOURCING_CODE,
COALESCE(P.HEAT_TREATMENT_HARDNESS, '') AS HEAT_TREATMENT_HARDNESS,
COALESCE(P.HEAT_TREATMENT_METHOD, '') AS HEAT_TREATMENT_METHOD,
COALESCE(P.SURFACE_TREATMENT, '') AS SURFACE_TREATMENT,
(SELECT CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = P.UNIT) AS UNIT_TITLE,
(SELECT CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = P.PART_TYPE) AS PART_TYPE_TITLE,
(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('3D_CAD')) AS CU01_CNT,
(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_DRAWING_CAD')) AS CU02_CNT,
(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_PDF_CAD')) AS CU03_CNT,
V.LEV,
-- 구매 컬럼들 (VIEW_BOM에서 가져온 MBOM_DETAIL 값)
V.USE_YN,
V.NET_QTY,
V.PO_QTY,
V.PROPOSAL_DATE,
'MBOM' AS DATA_SOURCE -- 데이터 소스 구분용
FROM VIEW_BOM V
LEFT JOIN PART_MNG P ON P.OBJID::VARCHAR = V.PART_OBJID::VARCHAR
WHERE 1=1
ORDER BY V.PATH2
</select>
<!-- PROJECT_OBJID로 MBOM_HEADER 조회 (PROJECT_MGMT.SOURCE_MBOM_OBJID 우선 사용) -->
<select id="getMbomHeaderByProjectId" parameterType="map" resultType="map">
SELECT
COALESCE(PM.SOURCE_MBOM_OBJID::VARCHAR, MH.OBJID::VARCHAR) AS OBJID,
PM.OBJID AS PROJECT_OBJID,
PM.PROJECT_NO
FROM PROJECT_MGMT PM
LEFT JOIN MBOM_HEADER MH ON MH.PROJECT_OBJID = PM.OBJID
WHERE PM.OBJID::VARCHAR = #{projectObjId}
ORDER BY MH.REGDATE DESC
LIMIT 1
</select>
<!-- 구매리스트 저장 - MBOM_DETAIL 업데이트 -->
<update id="updateMbomDetailForPurchase" parameterType="map">
UPDATE MBOM_DETAIL SET
USE_YN = #{USE_YN},
NET_QTY = COALESCE(NULLIF(TRIM(#{NET_QTY}::TEXT), '')::NUMERIC, 0),
PO_QTY = COALESCE(NULLIF(TRIM(#{PO_QTY}::TEXT), '')::NUMERIC, 0),
VENDOR = #{VENDOR_PM},
UNIT_PRICE = COALESCE(NULLIF(TRIM(#{UNIT_PRICE}::TEXT), '')::NUMERIC, 0),
TOTAL_PRICE = COALESCE(NULLIF(TRIM(#{TOTAL_PRICE}::TEXT), '')::NUMERIC, 0),
PROPOSAL_DATE = CASE WHEN NULLIF(TRIM(#{PROPOSAL_DATE}::TEXT), '') IS NOT NULL THEN #{PROPOSAL_DATE}::DATE ELSE NULL END,
EDITER = #{EDITER},
EDIT_DATE = NOW()
WHERE OBJID::VARCHAR = #{OBJID}
</update>
<!-- 구매리스트 저장 - SALES_REQUEST_PART 업데이트 -->
<update id="updateSalesRequestPartForPurchase" parameterType="map">
UPDATE SALES_REQUEST_PART SET
USE_YN = #{USE_YN},
NET_QTY = COALESCE(NULLIF(TRIM(#{NET_QTY}::TEXT), '')::NUMERIC, 0),
PO_QTY = COALESCE(NULLIF(TRIM(#{PO_QTY}::TEXT), '')::NUMERIC, 0),
VENDOR_PM = #{VENDOR_PM},
UNIT_PRICE = COALESCE(NULLIF(TRIM(#{UNIT_PRICE}::TEXT), '')::NUMERIC, 0),
TOTAL_PRICE = COALESCE(NULLIF(TRIM(#{TOTAL_PRICE}::TEXT), '')::NUMERIC, 0),
PROPOSAL_DATE = CASE WHEN NULLIF(TRIM(#{PROPOSAL_DATE}::TEXT), '') IS NOT NULL THEN #{PROPOSAL_DATE}::DATE ELSE NULL END,
WRITER = #{EDITER}
WHERE OBJID::VARCHAR = #{OBJID}
</update>
</mapper>

View File

@@ -1736,15 +1736,23 @@ public class SalesMngService {
try {
sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
String salesRequestMasterObjid = CommonUtils.checkNull(paramMap.get("SALES_REQUEST_MASTER_OBJID"));
String partListJson = CommonUtils.checkNull(paramMap.get("partList"));
String purchaseListJson = CommonUtils.checkNull(paramMap.get("purchaseListData"));
// JSON 파싱 - 기존 코드 참고하여 간단하게 처리
// partListJson이 이미 파싱된 상태일 수 있으므로 직접 처리
List<Map> partList = new ArrayList<Map>();
// TODO: JSON 파싱 로직 추가 필요
System.out.println("========== savePurchaseList ==========");
System.out.println("salesRequestMasterObjid: " + salesRequestMasterObjid);
System.out.println("purchaseListJson length: " + purchaseListJson.length());
if(partList == null || partList.isEmpty()) {
resultMap.put("result", "error");
// JSON 파싱
List<Map> purchaseList = new ArrayList<Map>();
if(purchaseListJson != null && !purchaseListJson.isEmpty()) {
org.codehaus.jackson.map.ObjectMapper mapper = new org.codehaus.jackson.map.ObjectMapper();
purchaseList = mapper.readValue(purchaseListJson, List.class);
}
System.out.println("purchaseList size: " + purchaseList.size());
if(purchaseList == null || purchaseList.isEmpty()) {
resultMap.put("resultFlag", "F");
resultMap.put("message", "저장할 데이터가 없습니다.");
return resultMap;
}
@@ -1754,29 +1762,36 @@ public class SalesMngService {
PersonBean personBean = (PersonBean) session.getAttribute(Constants.PERSON_BEAN);
String userId = personBean.getUserId();
// 각 품목별로 구매리스트 정보 저장
for(Map partData : partList) {
String objid = CommonUtils.checkNull(partData.get("OBJID"));
// 각 품목별로 데이터 소스에 따라 다른 테이블 업데이트
for(Map itemData : purchaseList) {
String objid = CommonUtils.checkNull(itemData.get("OBJID"));
String dataSource = CommonUtils.checkNull(itemData.get("DATA_SOURCE"));
if(objid.isEmpty()) {
objid = CommonUtils.createObjId();
System.out.println("OBJID가 없는 항목 스킵");
continue;
}
partData.put("OBJID", objid);
partData.put("SALES_REQUEST_MASTER_OBJID", salesRequestMasterObjid);
partData.put("WRITER", userId);
itemData.put("EDITER", userId);
// SALES_REQUEST_PART 테이블에 저장
sqlSession.insert("salesMng.mergePurchaseListInfo", partData);
if("SRP".equals(dataSource)) {
// SALES_REQUEST_PART 테이블 업데이트 (구매요청서에서 수동 추가한 품목)
System.out.println("SALES_REQUEST_PART 업데이트: " + objid);
sqlSession.update("salesMng.updateSalesRequestPartForPurchase", itemData);
} else {
// MBOM_DETAIL 테이블 업데이트 (M-BOM에서 가져온 품목)
System.out.println("MBOM_DETAIL 업데이트: " + objid);
sqlSession.update("salesMng.updateMbomDetailForPurchase", itemData);
}
}
resultMap.put("result", "success");
resultMap.put("resultFlag", "S");
resultMap.put("message", "저장되었습니다.");
sqlSession.commit();
} catch(Exception e) {
if(sqlSession != null) sqlSession.rollback();
resultMap.put("result", "error");
resultMap.put("resultFlag", "F");
resultMap.put("message", "저장 중 오류가 발생했습니다: " + e.getMessage());
e.printStackTrace();
} finally {