From 57b14daf1961789d2ee9335450f35a633434bcb9 Mon Sep 17 00:00:00 2001 From: hjjeong Date: Mon, 22 Dec 2025 11:26:55 +0900 Subject: [PATCH] =?UTF-8?q?=EC=9B=90=EC=9E=90=EC=9E=AC,=20=EA=B5=AC?= =?UTF-8?q?=EB=A7=A4=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EA=B0=80=EA=B3=B5?= =?UTF-8?q?=EC=97=85=EC=B2=B4=20=EC=88=98=EC=A0=95~~?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rawMaterialRequirementList.jsp | 24 ++++--- .../semiProductRequirementList.jsp | 2 +- .../view/salesMng/purchaseListFormPopUp.jsp | 35 +++++----- src/com/pms/mapper/productionplanning.xml | 4 +- src/com/pms/mapper/salesMng.xml | 9 ++- .../service/ProductionPlanningService.java | 65 +++++++++++++------ 6 files changed, 90 insertions(+), 49 deletions(-) diff --git a/WebContent/WEB-INF/view/productionplanning/rawMaterialRequirementList.jsp b/WebContent/WEB-INF/view/productionplanning/rawMaterialRequirementList.jsp index 6ad46d8..09265d3 100644 --- a/WebContent/WEB-INF/view/productionplanning/rawMaterialRequirementList.jsp +++ b/WebContent/WEB-INF/view/productionplanning/rawMaterialRequirementList.jsp @@ -176,11 +176,12 @@ function fn_initResultGrid() { data: [], layout: "fitColumns", height: "calc(100vh - 450px)", + pagination: false, // 페이지네이션 비활성화 (전체 데이터 표시) columns: [ { title: '구분', field: 'CATEGORY_NAME', - width: 100, + width: 150, headerHozAlign: 'center', headerSort: true, hozAlign: 'center' @@ -188,7 +189,7 @@ function fn_initResultGrid() { { title: '품번', field: 'PART_NO', - width: 180, + width: 320, headerHozAlign: 'center', headerSort: true, hozAlign: 'left' @@ -203,7 +204,7 @@ function fn_initResultGrid() { { title: '소요량', field: 'REQUIRED_QTY', - width: 100, + width: 150, headerHozAlign: 'center', headerSort: true, hozAlign: 'right', @@ -218,7 +219,7 @@ function fn_initResultGrid() { { title: '소재', field: 'MATERIAL', - width: 120, + width: 150, headerHozAlign: 'center', headerSort: true, hozAlign: 'center' @@ -226,7 +227,7 @@ function fn_initResultGrid() { { title: '사이즈', field: 'SPEC', - width: 120, + width: 150, headerHozAlign: 'center', headerSort: true, hozAlign: 'center' @@ -234,7 +235,7 @@ function fn_initResultGrid() { { title: '소재품번', field: 'MATERIAL_PART_NO', - width: 180, + width: 250, headerHozAlign: 'center', headerSort: true, hozAlign: 'left' @@ -242,7 +243,7 @@ function fn_initResultGrid() { { title: '소재소요량', field: 'MATERIAL_REQUIRED_QTY', - width: 120, + width: 150, headerHozAlign: 'center', headerSort: true, hozAlign: 'right', @@ -321,10 +322,17 @@ function fn_search() { data: JSON.stringify({mbomItems: mbomItems}), dataType: "json", success: function(data) { + console.log("=== 서버 응답 데이터 ==="); + console.log("전체 응답:", data); + console.log("리스트 개수:", data.list ? data.list.length : 0); + console.log("리스트 데이터:", data.list); + if(data.result === "success") { resultGrid.setData(data.list || []); var cnt = data.list ? data.list.length : 0; $("#resultCnt").text(cnt); + + console.log("그리드 데이터 개수:", resultGrid.getData().length); if(cnt === 0) { Swal.fire({ title: '조회 결과 없음', @@ -374,7 +382,7 @@ function fn_search() { -
원자재 소요량 (구매품) - 조회결과: 0
+
원자재 소요량 (구매품, 원소재) - 조회결과: 0
diff --git a/WebContent/WEB-INF/view/productionplanning/semiProductRequirementList.jsp b/WebContent/WEB-INF/view/productionplanning/semiProductRequirementList.jsp index f59eb89..4773041 100644 --- a/WebContent/WEB-INF/view/productionplanning/semiProductRequirementList.jsp +++ b/WebContent/WEB-INF/view/productionplanning/semiProductRequirementList.jsp @@ -188,7 +188,7 @@ function fn_initResultGrid() { { title: '품번', field: 'PART_NO', - width: 300, + width: 320, headerHozAlign: 'center', headerSort: true, hozAlign: 'left' diff --git a/WebContent/WEB-INF/view/salesMng/purchaseListFormPopUp.jsp b/WebContent/WEB-INF/view/salesMng/purchaseListFormPopUp.jsp index 962c2a8..9ede541 100644 --- a/WebContent/WEB-INF/view/salesMng/purchaseListFormPopUp.jsp +++ b/WebContent/WEB-INF/view/salesMng/purchaseListFormPopUp.jsp @@ -85,7 +85,7 @@ body, html { - ${resultMap.PROJECT_NO} + ${resultMap.PROJECT_NUMBER} @@ -115,7 +115,7 @@ body, html { - ${resultMap.DELIVERY_REQUEST_DATE} + ${resultMap.DUE_DATE} @@ -542,7 +542,13 @@ function fn_initGrid() { }, formatter: function(cell) { var value = cell.getValue(); - if(!value) return ''; + + // 저장된 값이 없으면 기본값 '5001'(RPS) 설정 + if(value === undefined || value === null || value === '') { + value = '5001'; + cell.getRow().update({PROCESSING_VENDOR: value}, false); + } + // OBJID로 업체명 조회하여 표시 for(var i = 0; i < processingVendorList.length; i++) { if(processingVendorList[i].id == value) { @@ -632,28 +638,27 @@ function fn_initGrid() { return value ? Number(value).toLocaleString() : '0'; } }, - // 30. 공급업체 (수정가능 - 기준정보에서 선택) + // 30. 공급업체 (수정가능 - Select2 에디터) { headerHozAlign: 'center', hozAlign: 'left', width: 150, title: '공급업체', field: 'VENDOR_PM', - editor: 'list', - editorParams: function(cell) { - return { - values: vendorList, - autocomplete: true, - listOnEmpty: true, - freetext: true, - allowEmpty: true - }; + editor: function(cell, onRendered, success, cancel, editorParams) { + // Select2 에디터 (가공업체와 동일한 목록 사용) + return createSelect2Editor(processingVendorList)(cell, onRendered, success, cancel, editorParams); }, formatter: function(cell) { var value = cell.getValue(); if(!value) return ''; - // vendorList에서 해당 값의 이름 찾기 - return vendorList[value] || value; + // processingVendorList에서 해당 값의 이름 찾기 + for(var i = 0; i < processingVendorList.length; i++) { + if(processingVendorList[i].id == value) { + return processingVendorList[i].text; + } + } + return value; } }, // 31. 단가 (수정가능) diff --git a/src/com/pms/mapper/productionplanning.xml b/src/com/pms/mapper/productionplanning.xml index 5f2c41f..717efaa 100644 --- a/src/com/pms/mapper/productionplanning.xml +++ b/src/com/pms/mapper/productionplanning.xml @@ -4796,7 +4796,7 @@ SELECT MD.RAW_MATERIAL_PART_NO AS PART_NO, MD.RAW_MATERIAL AS PART_NAME, - COALESCE(MD.REQUIRED_QTY, '1')::INTEGER AS ITEM_QTY, + COALESCE(MD.REQUIRED_QTY, '0')::NUMERIC AS ITEM_QTY, '원소재' AS CATEGORY_NAME, '' AS UNIT, MD.RAW_MATERIAL AS MATERIAL, @@ -4804,7 +4804,7 @@ MD.RAW_MATERIAL, MD.RAW_MATERIAL_SIZE, MD.RAW_MATERIAL_PART_NO, - COALESCE(MD.REQUIRED_QTY, '1')::INTEGER AS RAW_MATERIAL_QTY + COALESCE(MD.REQUIRED_QTY, '0')::NUMERIC AS RAW_MATERIAL_QTY FROM MBOM_DETAIL MD WHERE MD.MBOM_HEADER_OBJID = #{mbomHeaderObjid} AND MD.STATUS = 'ACTIVE' diff --git a/src/com/pms/mapper/salesMng.xml b/src/com/pms/mapper/salesMng.xml index a1e8c8f..3009f6a 100644 --- a/src/com/pms/mapper/salesMng.xml +++ b/src/com/pms/mapper/salesMng.xml @@ -665,6 +665,9 @@ VALUES SRM.PROJECT_NO, PM.PROJECT_NO AS PROJECT_NUMBER, PM.PROJECT_NAME, + PM.PART_NO, + PM.PART_NAME, + PM.DUE_DATE, COALESCE( PM.OBJID, (SELECT OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1) @@ -718,9 +721,9 @@ VALUES COALESCE(NULLIF(SRM.AREA_CD, ''), SM.AREA_CD) AS AREA_CD, -- 국내/해외 COALESCE(NULLIF(SRM.CUSTOMER_OBJID, ''), SM.OBJID::VARCHAR) AS CUSTOMER_OBJID, -- 고객사 COALESCE(NULLIF(SRM.PAID_TYPE, ''), CM.PAID_TYPE) AS PAID_TYPE, -- 유/무상 - CM.CATEGORY_CD AS CATEGORY_CD, -- 제품유형 코드 ID (드롭다운 선택용) + CM.CATEGORY_CD AS CATEGORY_CD -- 제품유형 코드 ID (드롭다운 선택용) -- 품번/품명: 첫 번째 품목 + 외 N건 형태 - (SELECT + FROM SALES_REQUEST_MASTER SRM diff --git a/src/com/pms/service/ProductionPlanningService.java b/src/com/pms/service/ProductionPlanningService.java index 56077d3..0091073 100644 --- a/src/com/pms/service/ProductionPlanningService.java +++ b/src/com/pms/service/ProductionPlanningService.java @@ -2004,10 +2004,10 @@ public class ProductionPlanningService { newItem.put("PART_NAME", bomItem.get("part_name")); newItem.put("CATEGORY_NAME", bomItem.get("category_name")); newItem.put("UNIT", bomItem.get("unit")); - newItem.put("MATERIAL", bomItem.get("material")); - newItem.put("SPEC", bomItem.get("spec")); + // 구매품은 소재 관련 컬럼 전부 빈값 + newItem.put("MATERIAL", ""); + newItem.put("SPEC", ""); newItem.put("REQUIRED_QTY", requiredQty); - // 구매품은 소재 관련 컬럼 빈값 newItem.put("RAW_MATERIAL", ""); newItem.put("RAW_MATERIAL_SIZE", ""); newItem.put("MATERIAL_PART_NO", ""); @@ -2017,40 +2017,50 @@ public class ProductionPlanningService { } // 2. 원소재 조회 (RAW_MATERIAL_PART_NO가 있는 항목) + // 원소재는 소재품번 기준으로 합산 (소수점 합산 후 올림) List> rawSourceItems = sqlSession.selectList("productionplanning.getMbomRawSourceItems", queryParam); for(Map bomItem : rawSourceItems) { - String partNo = CommonUtils.nullToEmpty((String)bomItem.get("part_no")); - if("".equals(partNo)) continue; + String materialPartNo = CommonUtils.nullToEmpty((String)bomItem.get("raw_material_part_no")); + if("".equals(materialPartNo)) continue; - int itemQty = getIntValue(bomItem.get("item_qty")); - int requiredQty = inputQty * itemQty; + double itemQty = getDoubleValue(bomItem.get("item_qty")); + double requiredQty = inputQty * itemQty; - if(rawSourcePartNoMap.containsKey(partNo)) { - Map existingItem = rawSourcePartNoMap.get(partNo); - int existingQty = (Integer)existingItem.get("REQUIRED_QTY"); - existingItem.put("REQUIRED_QTY", existingQty + requiredQty); + if(rawSourcePartNoMap.containsKey(materialPartNo)) { + Map existingItem = rawSourcePartNoMap.get(materialPartNo); + double existingQty = (Double)existingItem.get("MATERIAL_REQUIRED_QTY_RAW"); + existingItem.put("MATERIAL_REQUIRED_QTY_RAW", existingQty + requiredQty); } else { Map newItem = new LinkedHashMap<>(); - newItem.put("PART_NO", partNo); - newItem.put("PART_NAME", bomItem.get("part_name")); + // 원소재는 품번, 품명, 소요량 빈값 + newItem.put("PART_NO", ""); + newItem.put("PART_NAME", ""); newItem.put("CATEGORY_NAME", "원소재"); newItem.put("UNIT", ""); newItem.put("MATERIAL", bomItem.get("raw_material")); newItem.put("SPEC", bomItem.get("raw_material_size")); - newItem.put("REQUIRED_QTY", requiredQty); - // 원소재 관련 컬럼 + newItem.put("REQUIRED_QTY", ""); + // 원소재 관련 컬럼만 표시 newItem.put("RAW_MATERIAL", bomItem.get("raw_material")); newItem.put("RAW_MATERIAL_SIZE", bomItem.get("raw_material_size")); - newItem.put("MATERIAL_PART_NO", bomItem.get("raw_material_part_no")); - newItem.put("MATERIAL_REQUIRED_QTY", requiredQty); - rawSourcePartNoMap.put(partNo, newItem); + newItem.put("MATERIAL_PART_NO", materialPartNo); + newItem.put("MATERIAL_REQUIRED_QTY_RAW", requiredQty); // 합산용 (소수점) + rawSourcePartNoMap.put(materialPartNo, newItem); } } } - // 구매품 먼저, 원소재 나중에 합침 + // 구매품 먼저 추가 resultList.addAll(purchasePartNoMap.values()); - resultList.addAll(rawSourcePartNoMap.values()); + + // 원소재는 소수점 합산 후 올림 처리하여 추가 + for(Map item : rawSourcePartNoMap.values()) { + double rawQty = (Double)item.get("MATERIAL_REQUIRED_QTY_RAW"); + int ceilQty = (int)Math.ceil(rawQty); // 올림 처리 + item.put("MATERIAL_REQUIRED_QTY", ceilQty); + item.remove("MATERIAL_REQUIRED_QTY_RAW"); // 임시 필드 제거 + resultList.add(item); + } } catch(Exception e) { e.printStackTrace(); @@ -2077,4 +2087,19 @@ public class ProductionPlanningService { return 0; } } + + /** + * Object를 double로 변환하는 유틸 메서드 + */ + private double getDoubleValue(Object obj) { + if(obj == null) return 0.0; + if(obj instanceof Number) { + return ((Number)obj).doubleValue(); + } + try { + return Double.parseDouble(obj.toString()); + } catch(NumberFormatException e) { + return 0.0; + } + } }