ebom, mbom
E-BOM & M-BOM 파트 추가 삭제시 반제품 추가 삭제하면 하위 품목 같이 추가 삭제 되는 기능 E-BOM & M-BOM 파트 추가시 원하는 위치로 집어 넣는 기능(현재는 왼쪽에서 선택한 하위레벨의 제일 밑으로만 들어감) E-BOM & M-BOM 파트 추가 삭제시 자동저장이 아니라, 저장/닫기 버튼이 있어서 저장버튼 누를때만 저장되도록 변경 필요 신규 프로젝트 생성하고, M-BOM 처음 만들때 E-BOM 을 가져와서 할당할때 최상위 제품을 변경하는 로직이 필요(최상위 제품을 삭제하고 반제품을 최상위 품으로 만드는 로직) 최상위 제품으로 만들려고 하는 반제품의 하위 부품도 딸려와서 구성이 되어야 하며, M-BOM 의 이름도 변경된 최상위 제품의 품번으로 변경되어 저장되어야 함
This commit is contained in:
@@ -1223,6 +1223,58 @@ public class PartMngController {
|
||||
return bomTreeList != null ? bomTreeList : new ArrayList<Map>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 품번 기준 E-BOM 하위 구조 조회 (반제품 추가 시 하위 품목 연동용)
|
||||
* 품번에 해당하는 E-BOM이 있으면 하위 트리를 반환, 없으면 빈 리스트 반환
|
||||
*/
|
||||
@RequestMapping("/partMng/getEbomSubTreeByPartNo.do")
|
||||
@ResponseBody
|
||||
public Map<String, Object> getEbomSubTreeByPartNo(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
String partNo = CommonUtils.checkNull((String)paramMap.get("partNo"));
|
||||
if(partNo.isEmpty()) {
|
||||
result.put("hasEbom", false);
|
||||
result.put("subTree", new ArrayList<>());
|
||||
return result;
|
||||
}
|
||||
|
||||
// 1차: 품번으로 단독 E-BOM 존재 여부 확인 (PART_BOM_REPORT)
|
||||
Map bomReport = partMngService.getBomObjIdByPartNo(partNo);
|
||||
if(bomReport != null && !bomReport.isEmpty()) {
|
||||
String bomReportObjId = CommonUtils.checkNull(bomReport.get("OBJID"));
|
||||
if(bomReportObjId.isEmpty()) {
|
||||
bomReportObjId = CommonUtils.checkNull(bomReport.get("objid"));
|
||||
}
|
||||
Map<String, Object> treeParam = new HashMap<>();
|
||||
treeParam.put("bomReportObjId", bomReportObjId);
|
||||
treeParam.put("search_type", "working");
|
||||
List subTree = partMngService.getBOMPartTreeListSimple(treeParam);
|
||||
|
||||
result.put("hasEbom", true);
|
||||
result.put("bomReportObjId", bomReportObjId);
|
||||
result.put("subTree", subTree != null ? subTree : new ArrayList<>());
|
||||
return result;
|
||||
}
|
||||
|
||||
// 2차 fallback: 다른 E-BOM 안에서 해당 품번이 하위 구조를 가진 경우 조회
|
||||
List subTreeFallback = partMngService.findEbomSubTreeForPart(partNo);
|
||||
if(subTreeFallback != null && !subTreeFallback.isEmpty()) {
|
||||
result.put("hasEbom", true);
|
||||
result.put("subTree", subTreeFallback);
|
||||
return result;
|
||||
}
|
||||
|
||||
result.put("hasEbom", false);
|
||||
result.put("subTree", new ArrayList<>());
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
result.put("hasEbom", false);
|
||||
result.put("subTree", new ArrayList<>());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@RequestMapping("/partMng/structurePopupCenter.do")
|
||||
public String structurePopupCenter(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
|
||||
@@ -1250,6 +1302,44 @@ public class PartMngController {
|
||||
return "/partMng/structurePopupCenter";
|
||||
}
|
||||
|
||||
/**
|
||||
* E-BOM 일괄 저장 (클라이언트 편집 후 저장)
|
||||
*/
|
||||
@RequestMapping("/partMng/saveEbom.do")
|
||||
@ResponseBody
|
||||
public Map<String, Object> saveEbom(HttpServletRequest request, @RequestBody Map<String, Object> paramMap) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
String bomReportObjId = CommonUtils.checkNull((String)paramMap.get("bomReportObjId"));
|
||||
List<Map<String, Object>> ebomData = (List<Map<String, Object>>) paramMap.get("ebomData");
|
||||
|
||||
if(bomReportObjId.isEmpty() || ebomData == null || ebomData.isEmpty()) {
|
||||
result.put("result", "fail");
|
||||
result.put("message", "저장할 데이터가 없습니다.");
|
||||
return result;
|
||||
}
|
||||
|
||||
HttpSession session = request.getSession();
|
||||
PersonBean person = (PersonBean) session.getAttribute(Constants.PERSON_BEAN);
|
||||
Map info = person.getLoginInfo();
|
||||
String userId = CommonUtils.checkNull(info.get("userId"));
|
||||
|
||||
boolean saved = partMngService.saveEbomBatch(bomReportObjId, ebomData, userId);
|
||||
|
||||
if(saved) {
|
||||
result.put("result", "success");
|
||||
} else {
|
||||
result.put("result", "fail");
|
||||
result.put("message", "저장에 실패했습니다.");
|
||||
}
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
result.put("result", "fail");
|
||||
result.put("message", e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 구조등록 우측 프레임
|
||||
* @param request
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
A.SEQ,
|
||||
1,
|
||||
ARRAY [A.CHILD_OBJID::TEXT],
|
||||
ARRAY [A.SEQ::TEXT],
|
||||
ARRAY [LPAD(A.SEQ::TEXT, 10, '0')],
|
||||
FALSE
|
||||
FROM
|
||||
BOM_PART_QTY A
|
||||
@@ -53,7 +53,7 @@
|
||||
B.SEQ,
|
||||
LEV + 1,
|
||||
PATH||B.CHILD_OBJID::TEXT,
|
||||
PATH2||B.SEQ::TEXT,
|
||||
PATH2||LPAD(B.SEQ::TEXT, 10, '0'),
|
||||
B.PARENT_OBJID = ANY(PATH)
|
||||
FROM
|
||||
BOM_PART_QTY B
|
||||
@@ -3322,7 +3322,7 @@ SELECT T1.LEV, T1.BOM_REPORT_OBJID, T1.ROOT_PART_NO, T1.PATH, T1.LEAF, T2.*
|
||||
(SELECT PART_NO FROM PART_MNG P WHERE 1=1 AND P.OBJID::varchar = A.PARENT_PART_NO) AS PARENT_PART_MNG_NO,
|
||||
1,
|
||||
ARRAY [A.CHILD_OBJID::TEXT],
|
||||
ARRAY [A.SEQ::TEXT],
|
||||
ARRAY [LPAD(A.SEQ::TEXT, 10, '0')],
|
||||
FALSE
|
||||
FROM
|
||||
BOM_PART_QTY A
|
||||
@@ -3361,7 +3361,7 @@ SELECT T1.LEV, T1.BOM_REPORT_OBJID, T1.ROOT_PART_NO, T1.PATH, T1.LEAF, T2.*
|
||||
(SELECT PART_NO FROM PART_MNG P WHERE 1=1 AND P.OBJID::varchar = B.PARENT_PART_NO) AS PARENT_PART_MNG_NO,
|
||||
LEV + 1,
|
||||
PATH||B.CHILD_OBJID::TEXT,
|
||||
PATH2||B.SEQ::TEXT,
|
||||
PATH2||LPAD(B.SEQ::TEXT, 10, '0'),
|
||||
B.PARENT_OBJID = ANY(PATH)
|
||||
FROM
|
||||
BOM_PART_QTY B
|
||||
@@ -3949,6 +3949,122 @@ SELECT T1.LEV, T1.BOM_REPORT_OBJID, T1.ROOT_PART_NO, T1.PATH, T1.LEAF, T2.*
|
||||
</insert>
|
||||
|
||||
|
||||
<!-- E-BOM 내에서 특정 품번이 하위 품목을 가진 채 존재하는 BOM 찾기 (fallback용) -->
|
||||
<select id="findPartInEbomWithChildren" parameterType="map" resultType="map">
|
||||
SELECT BPQ.BOM_REPORT_OBJID, BPQ.CHILD_OBJID, BPQ.PART_NO AS PART_OBJID
|
||||
FROM BOM_PART_QTY BPQ
|
||||
INNER JOIN PART_MNG PM ON PM.OBJID::VARCHAR = BPQ.PART_NO AND PM.IS_LAST = '1'
|
||||
WHERE PM.PART_NO = #{partNo}
|
||||
AND (BPQ.STATUS NOT IN ('deleting', 'deleted') OR BPQ.STATUS IS NULL)
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM BOM_PART_QTY SUB
|
||||
WHERE SUB.PARENT_OBJID = BPQ.CHILD_OBJID
|
||||
AND SUB.BOM_REPORT_OBJID = BPQ.BOM_REPORT_OBJID
|
||||
AND (SUB.STATUS NOT IN ('deleting', 'deleted') OR SUB.STATUS IS NULL)
|
||||
)
|
||||
ORDER BY BPQ.REGDATE DESC
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<!-- 특정 CHILD_OBJID 아래의 하위 트리 조회 (반제품 하위 구조 fallback용) -->
|
||||
<select id="getSubTreeByParentChildObjid" parameterType="map" resultType="map">
|
||||
WITH RECURSIVE sub_tree(
|
||||
BOM_REPORT_OBJID, OBJID, PARENT_OBJID, CHILD_OBJID,
|
||||
PARENT_PART_NO, PART_NO, LAST_PART_OBJID,
|
||||
QTY, ITEM_QTY, QTY_TEMP, SEQ, STATUS, LEV
|
||||
) AS (
|
||||
SELECT A.BOM_REPORT_OBJID, A.OBJID, A.PARENT_OBJID, A.CHILD_OBJID,
|
||||
A.PARENT_PART_NO, A.PART_NO, A.LAST_PART_OBJID,
|
||||
A.QTY, A.ITEM_QTY, A.QTY_TEMP, A.SEQ, A.STATUS, 1
|
||||
FROM BOM_PART_QTY A
|
||||
WHERE A.PARENT_OBJID = #{parentChildObjid}
|
||||
AND A.BOM_REPORT_OBJID = #{bomReportObjId}
|
||||
AND (A.STATUS NOT IN ('deleting', 'deleted') OR A.STATUS IS NULL)
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT B.BOM_REPORT_OBJID, B.OBJID, B.PARENT_OBJID, B.CHILD_OBJID,
|
||||
B.PARENT_PART_NO, B.PART_NO, B.LAST_PART_OBJID,
|
||||
B.QTY, B.ITEM_QTY, B.QTY_TEMP, B.SEQ, B.STATUS, S.LEV + 1
|
||||
FROM BOM_PART_QTY B
|
||||
JOIN sub_tree S ON B.PARENT_OBJID = S.CHILD_OBJID
|
||||
AND B.BOM_REPORT_OBJID = S.BOM_REPORT_OBJID
|
||||
WHERE (B.STATUS NOT IN ('deleting', 'deleted') OR B.STATUS IS NULL)
|
||||
)
|
||||
SELECT
|
||||
S.BOM_REPORT_OBJID
|
||||
,S.OBJID
|
||||
,S.PARENT_OBJID
|
||||
,S.CHILD_OBJID
|
||||
,S.PARENT_PART_NO
|
||||
,S.PART_NO AS PART_OBJID
|
||||
,S.LAST_PART_OBJID AS BOM_LAST_PART_OBJID
|
||||
,P.OBJID AS LAST_PART_OBJID
|
||||
,P.PART_NO
|
||||
,P.PART_NAME
|
||||
,S.QTY
|
||||
,S.ITEM_QTY
|
||||
,(CASE WHEN S.STATUS = 'deploy' THEN S.QTY
|
||||
WHEN S.STATUS = 'beforeEdit' THEN S.QTY
|
||||
WHEN S.STATUS != 'editing' AND (S.QTY_TEMP IS NULL OR S.QTY_TEMP = '') THEN S.QTY
|
||||
ELSE COALESCE(S.QTY_TEMP, S.QTY) END) AS QTY_TEMP
|
||||
,S.LEV AS LEVEL
|
||||
,(SELECT COUNT(*) FROM BOM_PART_QTY WHERE PARENT_OBJID = S.CHILD_OBJID) AS SUB_PART_CNT
|
||||
,S.SEQ
|
||||
,S.STATUS
|
||||
,P.SPEC
|
||||
,P.MATERIAL
|
||||
,P.REVISION
|
||||
,(SELECT CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = P.PART_TYPE) AS PART_TYPE_TITLE
|
||||
,(SELECT CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = P.UNIT) AS UNIT_TITLE
|
||||
FROM sub_tree S
|
||||
INNER JOIN PART_MNG P ON P.OBJID = COALESCE(NULLIF(S.LAST_PART_OBJID, ''), S.PART_NO)
|
||||
ORDER BY S.LEV, S.SEQ
|
||||
</select>
|
||||
|
||||
<!-- E-BOM 차분 저장: 기존 데이터 조회 -->
|
||||
<select id="getExistingBomPartQty" parameterType="map" resultType="map">
|
||||
SELECT CHILD_OBJID, PARENT_OBJID, PART_NO, PARENT_PART_NO, QTY, ITEM_QTY, QTY_TEMP, SEQ, STATUS
|
||||
FROM BOM_PART_QTY
|
||||
WHERE BOM_REPORT_OBJID = #{bomReportObjId}
|
||||
</select>
|
||||
|
||||
<!-- E-BOM 차분 저장: CHILD_OBJID 기준 개별 삭제 -->
|
||||
<delete id="deleteBomPartQtyByChildObjid" parameterType="map">
|
||||
DELETE FROM BOM_PART_QTY
|
||||
WHERE BOM_REPORT_OBJID = #{bomReportObjId}
|
||||
AND CHILD_OBJID = #{childObjid}
|
||||
</delete>
|
||||
|
||||
<!-- E-BOM 차분 저장: CHILD_OBJID 기준 수정 (수량, 순서, 부모 등) -->
|
||||
<update id="updateBomPartQtyByChildObjid" parameterType="map">
|
||||
UPDATE BOM_PART_QTY
|
||||
SET PARENT_OBJID = #{PARENT_OBJID},
|
||||
QTY = COALESCE(NULLIF(#{QTY}, ''), '0')::NUMERIC,
|
||||
ITEM_QTY = COALESCE(NULLIF(#{ITEM_QTY}, ''), '0')::NUMERIC,
|
||||
QTY_TEMP = COALESCE(NULLIF(#{QTY_TEMP}, ''), '0')::NUMERIC,
|
||||
SEQ = #{SEQ}
|
||||
WHERE BOM_REPORT_OBJID = #{bomReportObjId}
|
||||
AND CHILD_OBJID = #{childObjid}
|
||||
</update>
|
||||
|
||||
<!-- E-BOM 차분 저장: 신규 행 INSERT -->
|
||||
<insert id="insertBomPartQtyBatch" parameterType="map">
|
||||
INSERT INTO BOM_PART_QTY (
|
||||
BOM_REPORT_OBJID, OBJID, PARENT_OBJID, CHILD_OBJID,
|
||||
PARENT_PART_NO, PART_NO, LAST_PART_OBJID,
|
||||
QTY, ITEM_QTY, QTY_TEMP,
|
||||
REGDATE, WRITER, SEQ, STATUS
|
||||
) VALUES (
|
||||
#{BOM_REPORT_OBJID}, #{OBJID}, #{PARENT_OBJID}, #{CHILD_OBJID},
|
||||
#{PARENT_PART_NO}, #{PART_NO}, #{LAST_PART_OBJID},
|
||||
COALESCE(NULLIF(#{QTY}, ''), '0')::NUMERIC,
|
||||
COALESCE(NULLIF(#{ITEM_QTY}, ''), '0')::NUMERIC,
|
||||
COALESCE(NULLIF(#{QTY_TEMP}, ''), '0')::NUMERIC,
|
||||
NOW(), #{WRITER}, #{SEQ}, #{STATUS}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<!-- //BOM 구조등록 -->
|
||||
<insert id="relatePartInfo" parameterType="map">
|
||||
INSERT INTO BOM_PART_QTY
|
||||
@@ -5778,7 +5894,7 @@ SELECT T1.LEV, T1.BOM_REPORT_OBJID, T1.ROOT_PART_NO, T1.PATH, T1.LEAF, T2.*
|
||||
B.LENGTH,
|
||||
1,
|
||||
ARRAY [A.CHILD_OBJID::TEXT],
|
||||
ARRAY [A.SEQ::TEXT],
|
||||
ARRAY [LPAD(A.SEQ::TEXT, 10, '0')],
|
||||
FALSE,
|
||||
A.SEQ,
|
||||
B.MAKER,
|
||||
@@ -5899,7 +6015,7 @@ SELECT T1.LEV, T1.BOM_REPORT_OBJID, T1.ROOT_PART_NO, T1.PATH, T1.LEAF, T2.*
|
||||
B.LENGTH,
|
||||
LEV + 1,
|
||||
PATH||A.CHILD_OBJID::TEXT,
|
||||
PATH2||A.SEQ::TEXT,
|
||||
PATH2||LPAD(A.SEQ::TEXT, 10, '0'),
|
||||
A.PARENT_OBJID = ANY(PATH),
|
||||
A.SEQ,
|
||||
B.MAKER,
|
||||
@@ -6058,7 +6174,7 @@ SELECT T1.LEV, T1.BOM_REPORT_OBJID, T1.ROOT_PART_NO, T1.PATH, T1.LEAF, T2.*
|
||||
COALESCE(BPQ.LAST_PART_OBJID, BPQ.PART_NO) AS LAST_PART_OBJID,
|
||||
1 AS LEV,
|
||||
ARRAY[BPQ.CHILD_OBJID::TEXT] AS PATH,
|
||||
ARRAY[BPQ.SEQ::TEXT] AS PATH2,
|
||||
ARRAY[LPAD(BPQ.SEQ::TEXT, 10, '0')] AS PATH2,
|
||||
0 AS LEAF
|
||||
FROM BOM_PART_QTY BPQ
|
||||
LEFT JOIN PART_BOM_REPORT PBR ON BPQ.BOM_REPORT_OBJID = PBR.OBJID
|
||||
@@ -6109,7 +6225,7 @@ SELECT T1.LEV, T1.BOM_REPORT_OBJID, T1.ROOT_PART_NO, T1.PATH, T1.LEAF, T2.*
|
||||
COALESCE(BPQ.LAST_PART_OBJID, BPQ.PART_NO) AS LAST_PART_OBJID,
|
||||
BT.LEV + 1,
|
||||
BT.PATH || BPQ.CHILD_OBJID::TEXT,
|
||||
BT.PATH2 || BPQ.SEQ::TEXT,
|
||||
BT.PATH2 || LPAD(BPQ.SEQ::TEXT, 10, '0'),
|
||||
0 AS LEAF
|
||||
FROM BOM_PART_QTY BPQ
|
||||
INNER JOIN BOM_TREE BT ON BPQ.PARENT_OBJID = BT.CHILD_OBJID
|
||||
|
||||
@@ -1238,7 +1238,7 @@
|
||||
-->
|
||||
1,
|
||||
ARRAY [A.CHILD_OBJID::TEXT],
|
||||
ARRAY [A.SEQ::TEXT],
|
||||
ARRAY [LPAD(A.SEQ::TEXT, 10, '0')],
|
||||
FALSE,
|
||||
A.SEQ,
|
||||
A.LAST_PART_OBJID
|
||||
@@ -1337,7 +1337,7 @@
|
||||
-->
|
||||
LEV + 1,
|
||||
PATH||A.CHILD_OBJID::TEXT,
|
||||
PATH2||A.SEQ::TEXT,
|
||||
PATH2||LPAD(A.SEQ::TEXT, 10, '0'),
|
||||
A.PARENT_OBJID = ANY(PATH),
|
||||
A.SEQ,
|
||||
A.LAST_PART_OBJID
|
||||
@@ -3626,7 +3626,7 @@
|
||||
A.STATUS,
|
||||
1,
|
||||
ARRAY [A.CHILD_OBJID::TEXT],
|
||||
ARRAY [A.SEQ::TEXT],
|
||||
ARRAY [LPAD(A.SEQ::TEXT, 10, '0')],
|
||||
FALSE,
|
||||
A.UNIT,
|
||||
A.SUPPLY_TYPE,
|
||||
@@ -3668,7 +3668,7 @@
|
||||
B.STATUS,
|
||||
LEV + 1,
|
||||
PATH||B.CHILD_OBJID::TEXT,
|
||||
PATH2||B.SEQ::TEXT,
|
||||
PATH2||LPAD(B.SEQ::TEXT, 10, '0'),
|
||||
B.PARENT_OBJID = ANY(PATH),
|
||||
B.UNIT,
|
||||
B.SUPPLY_TYPE,
|
||||
@@ -4155,7 +4155,7 @@
|
||||
A.STATUS,
|
||||
1,
|
||||
ARRAY [A.CHILD_OBJID::TEXT],
|
||||
ARRAY [A.SEQ::TEXT],
|
||||
ARRAY [LPAD(A.SEQ::TEXT, 10, '0')],
|
||||
FALSE,
|
||||
A.UNIT,
|
||||
A.SUPPLY_TYPE,
|
||||
@@ -4208,7 +4208,7 @@
|
||||
B.STATUS,
|
||||
LEV + 1,
|
||||
PATH||B.CHILD_OBJID::TEXT,
|
||||
PATH2||B.SEQ::TEXT,
|
||||
PATH2||LPAD(B.SEQ::TEXT, 10, '0'),
|
||||
B.PARENT_OBJID = ANY(PATH),
|
||||
B.UNIT,
|
||||
B.SUPPLY_TYPE,
|
||||
@@ -4381,7 +4381,7 @@
|
||||
A.STATUS,
|
||||
1,
|
||||
ARRAY [A.CHILD_OBJID::TEXT],
|
||||
ARRAY [A.SEQ::TEXT],
|
||||
ARRAY [LPAD(A.SEQ::TEXT, 10, '0')],
|
||||
FALSE,
|
||||
A.UNIT,
|
||||
A.WRITER,
|
||||
@@ -4411,7 +4411,7 @@
|
||||
B.STATUS,
|
||||
LEV + 1,
|
||||
PATH||B.CHILD_OBJID::TEXT,
|
||||
PATH2||B.SEQ::TEXT,
|
||||
PATH2||LPAD(B.SEQ::TEXT, 10, '0'),
|
||||
B.PARENT_OBJID = ANY(PATH),
|
||||
B.UNIT,
|
||||
B.WRITER,
|
||||
|
||||
@@ -2235,7 +2235,7 @@ WITH RECURSIVE VIEW_BOM(
|
||||
A.SEQ,
|
||||
1,
|
||||
ARRAY [A.CHILD_OBJID::TEXT],
|
||||
ARRAY [A.SEQ::TEXT],
|
||||
ARRAY [LPAD(A.SEQ::TEXT, 10, '0')],
|
||||
FALSE
|
||||
FROM
|
||||
BOM_PART_QTY A
|
||||
@@ -2268,8 +2268,8 @@ WITH RECURSIVE VIEW_BOM(
|
||||
B.SEQ,
|
||||
LEV + 1,
|
||||
PATH||B.CHILD_OBJID::TEXT,
|
||||
PATH2||B.SEQ::TEXT,
|
||||
B.PARENT_OBJID = ANY(PATH)
|
||||
PATH2||LPAD(B.SEQ::TEXT, 10, '0'),
|
||||
B.PARENT_OBJID = ANY(PATH)
|
||||
FROM
|
||||
BOM_PART_QTY B
|
||||
JOIN
|
||||
@@ -3312,7 +3312,7 @@ WITH RECURSIVE VIEW_BOM(
|
||||
A.STATUS,
|
||||
1,
|
||||
ARRAY [A.CHILD_OBJID::TEXT],
|
||||
ARRAY [A.SEQ::TEXT],
|
||||
ARRAY [LPAD(A.SEQ::TEXT, 10, '0')],
|
||||
FALSE,
|
||||
A.UNIT,
|
||||
A.SUPPLY_TYPE,
|
||||
@@ -3375,7 +3375,7 @@ WITH RECURSIVE VIEW_BOM(
|
||||
B.STATUS,
|
||||
LEV + 1,
|
||||
PATH||B.CHILD_OBJID::TEXT,
|
||||
PATH2||B.SEQ::TEXT,
|
||||
PATH2||LPAD(B.SEQ::TEXT, 10, '0'),
|
||||
B.PARENT_OBJID = ANY(PATH),
|
||||
B.UNIT,
|
||||
B.SUPPLY_TYPE,
|
||||
@@ -3691,7 +3691,7 @@ WITH RECURSIVE VIEW_BOM(
|
||||
A.STATUS,
|
||||
1,
|
||||
ARRAY [A.CHILD_OBJID::TEXT],
|
||||
ARRAY [A.SEQ::TEXT],
|
||||
ARRAY [LPAD(A.SEQ::TEXT, 10, '0')],
|
||||
FALSE,
|
||||
A.UNIT,
|
||||
A.SUPPLY_TYPE,
|
||||
@@ -3755,7 +3755,7 @@ WITH RECURSIVE VIEW_BOM(
|
||||
B.STATUS,
|
||||
LEV + 1,
|
||||
PATH||B.CHILD_OBJID::TEXT,
|
||||
PATH2||B.SEQ::TEXT,
|
||||
PATH2||LPAD(B.SEQ::TEXT, 10, '0'),
|
||||
B.PARENT_OBJID = ANY(PATH),
|
||||
B.UNIT,
|
||||
B.SUPPLY_TYPE,
|
||||
|
||||
@@ -1475,8 +1475,8 @@ public class PartMngService extends BaseService {
|
||||
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("QTY", "1");
|
||||
sqlParamMap.put("QTY_TEMP", "1");
|
||||
sqlParamMap.put("STATUS", "adding");
|
||||
sqlParamMap.put("WRITER", userId);
|
||||
//sqlParamMap.put("bomReportObjId", CommonUtils.checkNull(paramMap.get("OBJID")));
|
||||
@@ -3840,6 +3840,195 @@ public class PartMngService extends BaseService {
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 품번(String)으로 E-BOM 존재 여부 조회
|
||||
*/
|
||||
public Map<String, Object> getBomObjIdByPartNo(String partNo) throws Exception {
|
||||
Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("partNo", partNo);
|
||||
return getBomObjIdByPartNo(paramMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* E-BOM 하위 트리 조회 (반제품 추가 시 하위 품목 연동용)
|
||||
* getBOMPartTreeList와 동일하지만 HttpServletRequest 없이 직접 bomReportObjId로 조회
|
||||
*/
|
||||
public List getBOMPartTreeListSimple(Map<String, Object> paramMap) {
|
||||
List<Map<String,Object>> resultList = new ArrayList();
|
||||
List<Map<String,Object>> finalList = new ArrayList();
|
||||
SqlSession sqlSession = SqlMapConfig.getInstance().getSqlSession();
|
||||
try {
|
||||
resultList = sqlSession.selectList("partMng.getBOMTreeList", paramMap);
|
||||
int maxLevel = 0;
|
||||
if(null != resultList && 0 < resultList.size()) {
|
||||
for(int i = 0; i < resultList.size(); i++) {
|
||||
Map resultMap = (HashMap) resultList.get(i);
|
||||
int resultLevel = Integer.parseInt(CommonUtils.checkNull(resultMap.get("level"), "0"));
|
||||
if(maxLevel < resultLevel) {
|
||||
maxLevel = resultLevel;
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < resultList.size(); i++) {
|
||||
Map resultMap = (HashMap) resultList.get(i);
|
||||
resultMap.put("MAX_LEVEL", maxLevel);
|
||||
finalList.add(resultMap);
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
sqlSession.close();
|
||||
}
|
||||
return finalList;
|
||||
}
|
||||
|
||||
/**
|
||||
* E-BOM 내에서 특정 품번이 하위 구조를 가진 채 존재하는 경우 그 하위 트리를 조회
|
||||
* 단독 E-BOM(PART_BOM_REPORT)이 없는 반제품도 다른 E-BOM 안에서 하위 구조를 찾아 반환
|
||||
*/
|
||||
public List findEbomSubTreeForPart(String partNo) {
|
||||
List resultList = new ArrayList();
|
||||
SqlSession sqlSession = SqlMapConfig.getInstance().getSqlSession();
|
||||
try {
|
||||
Map<String, Object> findParam = new HashMap<>();
|
||||
findParam.put("partNo", partNo);
|
||||
Map<String, Object> found = (Map<String, Object>) sqlSession.selectOne("partMng.findPartInEbomWithChildren", findParam);
|
||||
|
||||
if(found == null || found.isEmpty()) {
|
||||
return resultList;
|
||||
}
|
||||
|
||||
String bomReportObjId = CommonUtils.checkNull(found.get("bom_report_objid"), CommonUtils.checkNull(found.get("BOM_REPORT_OBJID")));
|
||||
String parentChildObjid = CommonUtils.checkNull(found.get("child_objid"), CommonUtils.checkNull(found.get("CHILD_OBJID")));
|
||||
|
||||
if(bomReportObjId.isEmpty() || parentChildObjid.isEmpty()) {
|
||||
return resultList;
|
||||
}
|
||||
|
||||
Map<String, Object> treeParam = new HashMap<>();
|
||||
treeParam.put("bomReportObjId", bomReportObjId);
|
||||
treeParam.put("parentChildObjid", parentChildObjid);
|
||||
resultList = sqlSession.selectList("partMng.getSubTreeByParentChildObjid", treeParam);
|
||||
|
||||
if(resultList != null && resultList.size() > 0) {
|
||||
int maxLevel = 0;
|
||||
for(int i = 0; i < resultList.size(); i++) {
|
||||
Map row = (HashMap) resultList.get(i);
|
||||
int lev = Integer.parseInt(CommonUtils.checkNull(row.get("level"), "0"));
|
||||
if(maxLevel < lev) maxLevel = lev;
|
||||
}
|
||||
for(int i = 0; i < resultList.size(); i++) {
|
||||
Map row = (HashMap) resultList.get(i);
|
||||
row.put("MAX_LEVEL", maxLevel);
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
sqlSession.close();
|
||||
}
|
||||
return resultList != null ? resultList : new ArrayList();
|
||||
}
|
||||
|
||||
/**
|
||||
* E-BOM 일괄 저장 (차분 방식: 기존 CHILD_OBJID 보존, 추가/삭제/수정 분리)
|
||||
* ASSEMBLY_WBS_TASK, SALES_BOM_REPORT_PART 등이 CHILD_OBJID를 참조하므로 전체 삭제 불가
|
||||
*/
|
||||
public boolean saveEbomBatch(String bomReportObjId, List<Map<String, Object>> ebomData, String userId) {
|
||||
SqlSession sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
|
||||
try {
|
||||
// 1. 기존 데이터 조회
|
||||
Map<String, Object> queryParam = new HashMap<>();
|
||||
queryParam.put("bomReportObjId", bomReportObjId);
|
||||
List<Map<String, Object>> existingList = sqlSession.selectList("partMng.getExistingBomPartQty", queryParam);
|
||||
|
||||
// 기존 CHILD_OBJID 맵 (CHILD_OBJID -> 행 데이터)
|
||||
Map<String, Map<String, Object>> existingMap = new HashMap<>();
|
||||
for(Map<String, Object> row : existingList) {
|
||||
String childObjid = CommonUtils.checkNull(row.get("child_objid"), CommonUtils.checkNull(row.get("CHILD_OBJID")));
|
||||
if(!childObjid.isEmpty()) {
|
||||
existingMap.put(childObjid, row);
|
||||
}
|
||||
}
|
||||
|
||||
// 새 데이터의 CHILD_OBJID 셋
|
||||
Set<String> newChildObjids = new HashSet<>();
|
||||
for(Map<String, Object> item : ebomData) {
|
||||
String childObjid = CommonUtils.checkNull(item.get("childObjid"));
|
||||
if(!childObjid.isEmpty()) {
|
||||
newChildObjids.add(childObjid);
|
||||
}
|
||||
}
|
||||
|
||||
// 새 데이터에서 참조하는 PARENT_OBJID 셋 (삭제 보호용)
|
||||
Set<String> referencedParentObjids = new HashSet<>();
|
||||
for(Map<String, Object> item : ebomData) {
|
||||
String parentObjid = CommonUtils.checkNull(item.get("parentObjid"));
|
||||
if(!parentObjid.isEmpty()) {
|
||||
referencedParentObjids.add(parentObjid);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 삭제: 기존에 있지만 새 데이터에 없는 항목 (다른 행이 참조하는 부모는 보호)
|
||||
for(String existingChildObjid : existingMap.keySet()) {
|
||||
if(!newChildObjids.contains(existingChildObjid)) {
|
||||
if(referencedParentObjids.contains(existingChildObjid)) {
|
||||
continue;
|
||||
}
|
||||
Map<String, Object> deleteParam = new HashMap<>();
|
||||
deleteParam.put("bomReportObjId", bomReportObjId);
|
||||
deleteParam.put("childObjid", existingChildObjid);
|
||||
sqlSession.delete("partMng.deleteBomPartQtyByChildObjid", deleteParam);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 추가/수정
|
||||
for(int i = 0; i < ebomData.size(); i++) {
|
||||
Map<String, Object> item = ebomData.get(i);
|
||||
String childObjid = CommonUtils.checkNull(item.get("childObjid"));
|
||||
|
||||
if(existingMap.containsKey(childObjid)) {
|
||||
// 기존 항목 → 수정 (수량, 순서 등만 업데이트)
|
||||
Map<String, Object> updateParam = new HashMap<>();
|
||||
updateParam.put("bomReportObjId", bomReportObjId);
|
||||
updateParam.put("childObjid", childObjid);
|
||||
updateParam.put("PARENT_OBJID", CommonUtils.checkNull(item.get("parentObjid")));
|
||||
updateParam.put("QTY", CommonUtils.checkNull(item.get("qty"), "1"));
|
||||
updateParam.put("ITEM_QTY", CommonUtils.checkNull(item.get("itemQty"), "1"));
|
||||
updateParam.put("QTY_TEMP", CommonUtils.checkNull(item.get("qtyTemp"), "1"));
|
||||
updateParam.put("SEQ", i + 1);
|
||||
sqlSession.update("partMng.updateBomPartQtyByChildObjid", updateParam);
|
||||
} else {
|
||||
// 신규 항목 → INSERT
|
||||
Map<String, Object> insertParam = new HashMap<>();
|
||||
insertParam.put("BOM_REPORT_OBJID", bomReportObjId);
|
||||
insertParam.put("OBJID", CommonUtils.createObjId());
|
||||
insertParam.put("PARENT_OBJID", CommonUtils.checkNull(item.get("parentObjid")));
|
||||
insertParam.put("CHILD_OBJID", childObjid.startsWith("-") ? CommonUtils.createObjId() : childObjid);
|
||||
insertParam.put("PARENT_PART_NO", CommonUtils.checkNull(item.get("parentPartNo")));
|
||||
insertParam.put("PART_NO", CommonUtils.checkNull(item.get("partNo")));
|
||||
insertParam.put("LAST_PART_OBJID", CommonUtils.checkNull(item.get("lastPartObjid")));
|
||||
insertParam.put("QTY", CommonUtils.checkNull(item.get("qty"), "1"));
|
||||
insertParam.put("ITEM_QTY", CommonUtils.checkNull(item.get("itemQty"), "1"));
|
||||
insertParam.put("QTY_TEMP", CommonUtils.checkNull(item.get("qtyTemp"), "1"));
|
||||
insertParam.put("SEQ", i + 1);
|
||||
insertParam.put("STATUS", "editing");
|
||||
insertParam.put("WRITER", userId);
|
||||
sqlSession.insert("partMng.insertBomPartQtyBatch", insertParam);
|
||||
}
|
||||
}
|
||||
|
||||
sqlSession.commit();
|
||||
return true;
|
||||
} catch(Exception e) {
|
||||
sqlSession.rollback();
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} finally {
|
||||
sqlSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* BOM 복사를 위한 데이터 조회 (엑셀 파싱 형식과 동일하게 반환)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user