From e70a89b4ced9d87dd6aa2e090b5cc726dd1184c7 Mon Sep 17 00:00:00 2001 From: hjjeong Date: Fri, 13 Feb 2026 20:52:14 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=ED=92=88=EB=AA=A9=EB=B3=84=EC=9E=85?= =?UTF-8?q?=EA=B3=A0=EA=B4=80=EB=A6=AC=20=EC=9E=85=EA=B3=A0=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=EC=9D=BC=20=EC=BB=AC=EB=9F=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../view/purchaseOrder/deliveryMngAcceptancePartList.jsp | 1 + src/com/pms/mapper/purchaseOrder.xml | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/WebContent/WEB-INF/view/purchaseOrder/deliveryMngAcceptancePartList.jsp b/WebContent/WEB-INF/view/purchaseOrder/deliveryMngAcceptancePartList.jsp index 94520d0..0a9be81 100644 --- a/WebContent/WEB-INF/view/purchaseOrder/deliveryMngAcceptancePartList.jsp +++ b/WebContent/WEB-INF/view/purchaseOrder/deliveryMngAcceptancePartList.jsp @@ -104,6 +104,7 @@ var columns = [ {headerHozAlign:'center', hozAlign:'left', minWidth:120, widthGrow:1.5, title:'품번', field:'PART_NO'}, {headerHozAlign:'center', hozAlign:'left', minWidth:150, widthGrow:2, title:'품명', field:'PART_NAME'}, {headerHozAlign:'center', hozAlign:'left', minWidth:120, widthGrow:1.2, title:'공급업체', field:'PARTNER_NAME'}, + {headerHozAlign:'center', hozAlign:'center', minWidth:100, widthGrow:0.8, title:'입고요청일', field:'DELIVERY_REQUEST_DATE'}, {headerHozAlign : 'center', hozAlign : 'center', minWidth : 90, widthGrow : 1, title : '구매담당자', field : 'WRITER_NAME' }, {headerHozAlign:'center', hozAlign:'right', minWidth:80, widthGrow:0.8, title:'발주수량', field:'ORDER_QTY', formatter:"money", formatterParams:{thousand:",", symbolAfter:"p", precision:false} diff --git a/src/com/pms/mapper/purchaseOrder.xml b/src/com/pms/mapper/purchaseOrder.xml index b6d5a78..e1295fb 100644 --- a/src/com/pms/mapper/purchaseOrder.xml +++ b/src/com/pms/mapper/purchaseOrder.xml @@ -6252,6 +6252,9 @@ FROM( ,(COALESCE(AP_AGG.DELIVERY_QTY, 0) - COALESCE(DEFECT_AGG.DEFECT_QTY, 0)) AS CONFIRMED_QTY + + ,POP.DELIVERY_REQUEST_DATE + ,POM.PURCHASE_CLOSE_DATE @@ -6324,11 +6327,12 @@ FROM( AND TRIM(UPPER(POM.PURCHASE_ORDER_NO)) LIKE '%'||TRIM(UPPER(#{purchase_order_no}))||'%' + - AND TO_DATE(POM.DELIVERY_DATE, 'YYYY-MM-DD') = ]]> TO_DATE(#{delivery_start_date}, 'YYYY-MM-DD') + AND TO_DATE(POP.DELIVERY_REQUEST_DATE, 'YYYY-MM-DD') = ]]> TO_DATE(#{delivery_start_date}, 'YYYY-MM-DD') - AND TO_DATE(POM.DELIVERY_DATE, 'YYYY-MM-DD') TO_DATE(#{delivery_end_date}, 'YYYY-MM-DD') + AND TO_DATE(POP.DELIVERY_REQUEST_DATE, 'YYYY-MM-DD') TO_DATE(#{delivery_end_date}, 'YYYY-MM-DD') AND POM.PARTNER_OBJID = REPLACE(#{partner_objid}, 'C_', '') From 4f00e348db13aeb96836eb9f54584d8557e64d25 Mon Sep 17 00:00:00 2001 From: hjjeong Date: Fri, 13 Feb 2026 21:12:13 +0900 Subject: [PATCH 2/2] =?UTF-8?q?mbom=20=EA=B3=84=EC=82=B0=20=EA=B7=9C?= =?UTF-8?q?=EC=B9=99=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../productionplanning/mBomPopupHeaderFs.jsp | 3 + .../view/productionplanning/mBomPopupLeft.jsp | 314 +++++++++++------- src/com/pms/mapper/admin.xml | 5 +- src/com/pms/mapper/productionplanning.xml | 69 +++- 4 files changed, 269 insertions(+), 122 deletions(-) diff --git a/WebContent/WEB-INF/view/productionplanning/mBomPopupHeaderFs.jsp b/WebContent/WEB-INF/view/productionplanning/mBomPopupHeaderFs.jsp index ccb1d56..f9f1529 100644 --- a/WebContent/WEB-INF/view/productionplanning/mBomPopupHeaderFs.jsp +++ b/WebContent/WEB-INF/view/productionplanning/mBomPopupHeaderFs.jsp @@ -7,12 +7,15 @@ if(map == null || map.isEmpty()) { } String objId = com.pms.common.utils.CommonUtils.checkNull(map.get("OBJID")); String quantity = com.pms.common.utils.CommonUtils.checkNull(map.get("QUANTITY")); +String totalProdQty = com.pms.common.utils.CommonUtils.checkNull(map.get("TOTAL_PROD_QTY")); %> diff --git a/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp b/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp index f86b799..5f6617a 100644 --- a/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp +++ b/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp @@ -81,6 +81,8 @@ var _tabulGrid; var selectedRowData = null; // 선택된 행 데이터 // 프로젝트 수주수량 (최상위 프레임에서 가져오기) var projectQuantity = 1; // 기본값 +// 총생산수량 (수주수량 + 추가생산수량) +var totalProductionQty = 1; // 기본값 // 소재 목록 전역 변수 var materialList = []; @@ -97,6 +99,14 @@ $(function(){ } else { console.log("PROJECT_QUANTITY를 찾을 수 없습니다. 기본값 1 사용"); } + // 총생산수량 가져오기 (수주수량 + 추가생산수량) + if(parent && parent.parent && parent.parent.TOTAL_PROD_QTY) { + totalProductionQty = parseFloat(parent.parent.TOTAL_PROD_QTY) || projectQuantity; + console.log("총생산수량:", totalProductionQty); + } else { + totalProductionQty = projectQuantity; + console.log("TOTAL_PROD_QTY를 찾을 수 없습니다. 수주수량 사용:", totalProductionQty); + } } catch(e) { console.log("프로젝트 수주수량 가져오기 실패:", e); } @@ -447,21 +457,26 @@ function fn_initGrid() { cellEdited: function(cell) { var row = cell.getRow(); var data = row.getData(); - // 자급 선택 시 소재 관련 필드 초기화 (null로 설정하여 DB에서 NULL 처리) if(data.SUPPLY_TYPE === '자급') { + // 자급 선택 시 소재 관련 필드 전부 초기화 row.update({ RAW_MATERIAL: null, SIZE: null, RAW_MATERIAL_NO: null, - REQUIRED_QTY: null + REQUIRED_QTY: null, + ORDER_QTY: 0 }); } else { - // 사급 선택 시 초기화 + // 사급 선택 시 소재소요량 재계산 (PART_UNIT_QTY / PART_UNIT_LENGTH) + var partUnitQty = parseFloat(data.PART_UNIT_QTY) || 0; + var partUnitLength = parseFloat(data.PART_UNIT_LENGTH) || 0; + var requiredQty = partUnitLength > 0 ? (partUnitQty / partUnitLength) : 0; row.update({ RAW_MATERIAL: null, SIZE: null, RAW_MATERIAL_NO: null, - REQUIRED_QTY: null + REQUIRED_QTY: requiredQty, + ORDER_QTY: 0 }); } } @@ -487,12 +502,25 @@ function fn_initGrid() { return cell.getValue() || ''; }, cellEdited: function(cell) { - // 소재 선택 시 사이즈 초기화 + // 소재 선택 시 사이즈 초기화 및 소재소요량/소재발주수량 재계산 var row = cell.getRow(); + var data = row.getData(); + + // 소재소요량이 비어있으면 재계산 (SUPPLY_TYPE 변경 후 바로 소재 선택한 경우 대비) + if(!data.REQUIRED_QTY && data.REQUIRED_QTY !== 0) { + var partUnitQty = parseFloat(data.PART_UNIT_QTY) || 0; + var partUnitLength = parseFloat(data.PART_UNIT_LENGTH) || 0; + data.REQUIRED_QTY = partUnitLength > 0 ? (partUnitQty / partUnitLength) : 0; + } + + data.ORDER_QTY = fn_calcOrderQty(data); row.update({ SIZE: '', - RAW_MATERIAL_NO: '' + RAW_MATERIAL_NO: '', + REQUIRED_QTY: data.REQUIRED_QTY, + ORDER_QTY: data.ORDER_QTY }); + row.reformat(); } }, { @@ -540,12 +568,11 @@ function fn_initGrid() { return cell.getValue() || ''; }, cellEdited: function(cell) { - // 사이즈 선택 시 소재품번 자동 조회 + // 사이즈 선택 시 소재품번 + UNIT_QTY/UNIT_LENGTH 자동 조회 후 소재소요량 재계산 var row = cell.getRow(); var data = row.getData(); if(data.RAW_MATERIAL && data.SIZE) { - // 서버에서 소재품번 조회 $.ajax({ url: '/admin/getMaterialPartNo.do', method: 'POST', @@ -555,7 +582,26 @@ function fn_initGrid() { }, success: function(response) { if(response && response.MATERIAL_PART_NO) { - row.update({RAW_MATERIAL_NO: response.MATERIAL_PART_NO}); + // 소재의 UNIT_QTY, UNIT_LENGTH로 소재소요량 재계산 + var partUnitQty = parseFloat(response.UNIT_QTY || response.unit_qty) || 0; + var partUnitLength = parseFloat(response.UNIT_LENGTH || response.unit_length) || 0; + var requiredQty = partUnitLength > 0 ? (partUnitQty / partUnitLength) : 0; + + data.PART_UNIT_QTY = partUnitQty; + data.PART_UNIT_LENGTH = partUnitLength; + data.REQUIRED_QTY = requiredQty; + data.ORDER_QTY = fn_calcOrderQty(data); + + row.update({ + RAW_MATERIAL_NO: response.MATERIAL_PART_NO, + PART_UNIT_QTY: partUnitQty, + PART_UNIT_LENGTH: partUnitLength, + REQUIRED_QTY: requiredQty, + ORDER_QTY: data.ORDER_QTY + }); + row.reformat(); + + console.log("소재 선택 - 품번:", response.MATERIAL_PART_NO, "UNIT_QTY:", partUnitQty, "UNIT_LENGTH:", partUnitLength, "소재소요량:", requiredQty); } } }); @@ -575,48 +621,41 @@ function fn_initGrid() { return cell.getValue() || ''; } }, - { - headerHozAlign: 'center', - hozAlign: 'right', - width: 90, - title: '소재소요량', - field: 'REQUIRED_QTY', - titleFormatter: function() { return '소재소요량'; }, - editor: 'number', - editorParams: { - min: 0, - step: 0.01, - selectContents: true // 편집 시 기존 값 전체 선택 - }, - editable: function(cell) { - return cell.getRow().getData().SUPPLY_TYPE === '사급'; - }, - formatter: function(cell) { - var data = cell.getRow().getData(); - if(data.SUPPLY_TYPE === '자급') return '-'; - var value = cell.getValue(); - return value ? Number(value).toLocaleString() : '0'; + { + headerHozAlign: 'center', + hozAlign: 'right', + width: 90, + title: '소재소요량', + field: 'REQUIRED_QTY', + editor: false, + formatter: function(cell) { + var data = cell.getRow().getData(); + if(data.SUPPLY_TYPE === '자급') return '-'; + + // 전처리에서 계산된 값 표시 (소수 두번째 자리, ex: 0.20) + var value = parseFloat(data.REQUIRED_QTY) || 0; + return value.toFixed(2); + } + }, + { + headerHozAlign: 'center', + hozAlign: 'right', + width: 90, + title: '소재발주수량', + field: 'ORDER_QTY', + editor: false, + formatter: function(cell) { + var data = cell.getRow().getData(); + + if(data.SUPPLY_TYPE !== '사급' || !data.RAW_MATERIAL) { + return '-'; } - }, - { - headerHozAlign: 'center', - hozAlign: 'right', - width: 90, - title: '소재발주수량', - field: 'ORDER_QTY', - editor: false, - formatter: function(cell) { - // 항목수량 × 프로젝트 수주수량 (수정 불가) - var data = cell.getRow().getData(); - var itemQty = parseFloat(data.ITEM_QTY) || 0; - var orderQty = itemQty * projectQuantity; - - // 실제 데이터에도 저장 (getMbomTreeData에서 사용) - cell.getRow().update({ORDER_QTY: orderQty}, false); - - return orderQty.toLocaleString(); - } - }, + + // 전처리에서 계산된 값 표시 + var value = parseFloat(data.ORDER_QTY) || 0; + return value > 0 ? value.toLocaleString() : '0'; + } + }, { headerHozAlign: 'center', hozAlign: 'right', @@ -626,35 +665,25 @@ function fn_initGrid() { editor: false, visible: true }, - { - headerHozAlign: 'center', - hozAlign: 'right', - width: 80, - title: '제작수량', - field: 'PRODUCTION_QTY', - titleFormatter: function() { return '제작수량'; }, - editor: 'number', - editorParams: { - min: 0, - step: 1, - selectContents: true // 편집 시 기존 값 전체 선택 - }, - formatter: function(cell) { - // 저장된 값이 있으면 그대로 사용, 없으면 항목수량 × 수주수량으로 계산 - var value = cell.getValue(); - - // 0은 유효한 값이므로 제외 (undefined, null, '' 만 기본값 계산) - if(value === undefined || value === null || value === '') { - var data = cell.getRow().getData(); - var itemQty = parseFloat(data.ITEM_QTY) || 0; - value = itemQty * projectQuantity; - - // 실제 데이터에도 저장 (getMbomTreeData에서 사용) - cell.getRow().update({PRODUCTION_QTY: value}, false); - } - return Number(value).toLocaleString(); - } + { + headerHozAlign: 'center', + hozAlign: 'right', + width: 80, + title: '제작수량', + field: 'PRODUCTION_QTY', + titleFormatter: function() { return '제작수량'; }, + editor: 'number', + editorParams: { + min: 0, + step: 1, + selectContents: true // 편집 시 기존 값 전체 선택 }, + formatter: function(cell) { + // 전처리에서 계산된 값 표시 + var value = parseFloat(cell.getValue()) || 0; + return Number(value).toLocaleString(); + } + }, { headerHozAlign: 'center', hozAlign: 'left', @@ -867,16 +896,83 @@ function fn_initGrid() { console.log("bomTreeData:", bomTreeData); console.log("bomTreeData length:", bomTreeData ? bomTreeData.length : 0); - // 데이터 전처리: SUPPLY_TYPE 기본값 설정 - if(bomTreeData && bomTreeData.length > 0) { - bomTreeData.forEach(function(row) { - // SUPPLY_TYPE이 없으면 '사급'으로 설정 - if(!row.SUPPLY_TYPE) { - row.SUPPLY_TYPE = '사급'; - } - }); + // 대소문자 무관하게 필드값 가져오기 (PostgreSQL map은 소문자, UpperKeyMap은 대문자) + function fn_getField(row, upperName) { + return row[upperName] !== undefined ? row[upperName] : row[upperName.toLowerCase()]; } + // 데이터 전처리 함수: 필드명 정규화 + 소재소요량, 제작수량, 소재발주수량 미리 계산 + function fn_preprocessBomData(dataList) { + if(!dataList || dataList.length === 0) return dataList; + + dataList.forEach(function(row) { + // 필드명 정규화 (소문자 → 대문자 복사, 기존 대문자 유지) + if(row.part_unit_qty !== undefined && row.PART_UNIT_QTY === undefined) { + row.PART_UNIT_QTY = row.part_unit_qty; + } + if(row.part_unit_length !== undefined && row.PART_UNIT_LENGTH === undefined) { + row.PART_UNIT_LENGTH = row.part_unit_length; + } + + // SUPPLY_TYPE 기본값 + if(!row.SUPPLY_TYPE && !row.supply_type) { + row.SUPPLY_TYPE = '사급'; + } else if(!row.SUPPLY_TYPE && row.supply_type) { + row.SUPPLY_TYPE = row.supply_type; + } + + // 소재소요량 = PART_MNG의 UNIT_QTY / UNIT_LENGTH (항상 재계산) + var partUnitQty = parseFloat(row.PART_UNIT_QTY) || 0; + var partUnitLength = parseFloat(row.PART_UNIT_LENGTH) || 0; + row.REQUIRED_QTY = partUnitLength > 0 ? (partUnitQty / partUnitLength) : 0; + + console.log("전처리 - PART_NO:", row.PART_NO, "소재품번:", row.RAW_MATERIAL_NO, "UNIT_QTY:", partUnitQty, "UNIT_LENGTH:", partUnitLength, "소재소요량:", row.REQUIRED_QTY); + + // 제작수량: 저장된 값이 있으면 유지, 없으면 항목수량 × 총생산수량으로 자동계산 + var savedProdQty = parseFloat(row.PRODUCTION_QTY) || 0; + if(savedProdQty > 0) { + row.PRODUCTION_QTY = savedProdQty; + } else { + var itemQty = parseFloat(row.ITEM_QTY || row.item_qty) || 0; + row.PRODUCTION_QTY = itemQty * totalProductionQty; + } + + // 소재발주수량 계산 + row.ORDER_QTY = fn_calcOrderQty(row); + }); + + return dataList; + } + + // 소재발주수량 계산 헬퍼 + function fn_calcOrderQty(row) { + // 소재가 선택된 경우에만 계산 (사급이고 소재재질이 있을 때) + if(row.SUPPLY_TYPE !== '사급' || !row.RAW_MATERIAL) { + return 0; + } + + var requiredQty = parseFloat(row.REQUIRED_QTY) || 0; + var productionQty = parseFloat(row.PRODUCTION_QTY) || 0; + + if(requiredQty >= 1) { + // 소재소요량이 1 이상이면 제작수량과 동일 + return productionQty; + } else if(requiredQty > 0 && requiredQty < 1) { + // 소재소요량이 1보다 작은 소수이면 + // (unit_qty * 제작수량) / (unit_length - 50) + var unitQty = parseFloat(row.PART_UNIT_QTY) || 0; + var unitLength = parseFloat(row.PART_UNIT_LENGTH) || 0; + + if(unitLength > 50) { + return Math.ceil((unitQty * productionQty) / (unitLength - 50)); + } + } + return 0; + } + + // 초기 데이터 전처리 + bomTreeData = fn_preprocessBomData(bomTreeData); + // 모든 컬럼에 headerSort: false 일괄 적용 columns.forEach(function(col) { col.headerSort = false; @@ -921,45 +1017,33 @@ function fn_initGrid() { $(row.getElement()).find('input[name=checkedPartNo]').prop('checked', true); }); - // 셀 편집 이벤트 등록 + // 셀 편집 이벤트 등록 (SUPPLY_TYPE, RAW_MATERIAL은 컬럼 레벨 cellEdited에서 처리) _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 === '자급') { - // 자급인 경우 소재, 사이즈, 소요량 초기화 (null로 설정) - row.update({ - RAW_MATERIAL: null, - SIZE: null, - REQUIRED_QTY: null - }); - } - // 행 전체 재렌더링 - row.reformat(); - } - - // 제작수량 변경 시 정미수량 자동 계산 - if(field === 'PRODUCTION_QTY' || field === 'REQUIRED_QTY') { + // 제작수량 변경 시 소재발주수량 및 정미수량 재계산 + if(field === 'PRODUCTION_QTY') { + // 수동 편집 플래그 설정 + data._PRODUCTION_QTY_EDITED = true; + data.ORDER_QTY = fn_calcOrderQty(data); 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}); + row.update({ + _PRODUCTION_QTY_EDITED: true, + ORDER_QTY: data.ORDER_QTY, + NET_QTY: netQty + }); + row.reformat(); } // 발주수량 또는 단가 변경 시 총단가 자동 계산 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}); + row.update({TOTAL_PRICE: poQty * unitPrice}); } }); } @@ -1003,12 +1087,8 @@ function fn_searchMbom(searchParams) { if(data && data.list) { console.log("데이터 개수:", data.list.length); - // ORDER_QTY, PRODUCTION_QTY 제거하여 formatter에서 재계산되도록 - var processedData = data.list.map(function(item) { - delete item.ORDER_QTY; - delete item.PRODUCTION_QTY; - return item; - }); + // 전처리 함수로 소재소요량, 제작수량, 소재발주수량 계산 + var processedData = fn_preprocessBomData(data.list); _tabulGrid.setData(processedData); } else { diff --git a/src/com/pms/mapper/admin.xml b/src/com/pms/mapper/admin.xml index 577c635..17afc5b 100644 --- a/src/com/pms/mapper/admin.xml +++ b/src/com/pms/mapper/admin.xml @@ -9452,9 +9452,10 @@ ORDER BY PART_NAME SELECT OBJID, PART_NAME as MATERIAL_CODE, - -- MATERIAL_NAME, SPEC as SIZE_SPEC, - PART_NO as MATERIAL_PART_NO + PART_NO as MATERIAL_PART_NO, + COALESCE(NULLIF(UNIT_QTY, '')::numeric, 0) AS UNIT_QTY, + COALESCE(NULLIF(UNIT_LENGTH, '')::numeric, 0) AS UNIT_LENGTH FROM PART_MNG WHERE PART_NAME = #{materialCode} AND SPEC = #{sizeSpec} diff --git a/src/com/pms/mapper/productionplanning.xml b/src/com/pms/mapper/productionplanning.xml index 467f944..d6411cd 100644 --- a/src/com/pms/mapper/productionplanning.xml +++ b/src/com/pms/mapper/productionplanning.xml @@ -3144,6 +3144,15 @@ PM.SOURCE_EBOM_OBJID, PM.SOURCE_MBOM_OBJID, PM.QUANTITY, + -- 총생산수량 = 수주수량 + 추가생산수량 (PRODUCTION_PLAN 테이블) + COALESCE( + (SELECT NULLIF(PP.TOTAL_PROD_QTY, '')::numeric + FROM PRODUCTION_PLAN PP + WHERE PP.PROJECT_OBJID = PM.OBJID + AND UPPER(PP.STATUS) = 'ACTIVE' + LIMIT 1), + COALESCE(NULLIF(PM.QUANTITY, '')::numeric, 0) + ) AS TOTAL_PROD_QTY, COALESCE( (SELECT PBR.PART_NO FROM PART_BOM_REPORT PBR @@ -3296,6 +3305,9 @@ 0 AS UNIT_PRICE, 0 AS PROCESSING_UNIT_PRICE, 0 AS TOTAL_PRICE, + -- 소재소요량 계산용 (E-BOM 단계에서는 소재 미선택이므로 0) + 0 AS PART_UNIT_QTY, + 0 AS PART_UNIT_LENGTH, 1 AS LEVEL FROM BOM_PART_QTY BPQ @@ -3377,6 +3389,9 @@ 0 AS UNIT_PRICE, 0 AS PROCESSING_UNIT_PRICE, 0 AS TOTAL_PRICE, + -- 소재소요량 계산용 (E-BOM 단계에서는 소재 미선택이므로 0) + 0 AS PART_UNIT_QTY, + 0 AS PART_UNIT_LENGTH, 1 AS LEVEL FROM PROJECT_MGMT PROJ @@ -3747,6 +3762,21 @@ (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, + -- 소재소요량 계산용: 소재품번(RAW_MATERIAL_PART_NO)에 해당하는 PART_MNG의 UNIT_QTY / UNIT_LENGTH + COALESCE( + (SELECT NULLIF(MP.UNIT_QTY, '')::numeric + FROM PART_MNG MP + WHERE MP.PART_NO = V.RAW_MATERIAL_PART_NO + LIMIT 1), + 0 + ) AS PART_UNIT_QTY, + COALESCE( + (SELECT NULLIF(MP.UNIT_LENGTH, '')::numeric + FROM PART_MNG MP + WHERE MP.PART_NO = V.RAW_MATERIAL_PART_NO + LIMIT 1), + 0 + ) AS PART_UNIT_LENGTH, V.LEV FROM VIEW_BOM V LEFT JOIN PART_MNG P ON V.PART_OBJID = P.OBJID @@ -4294,6 +4324,21 @@ (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, + -- 소재소요량 계산용: 소재품번(RAW_MATERIAL_PART_NO)에 해당하는 PART_MNG의 UNIT_QTY / UNIT_LENGTH + COALESCE( + (SELECT NULLIF(MP.UNIT_QTY, '')::numeric + FROM PART_MNG MP + WHERE MP.PART_NO = V.RAW_MATERIAL_PART_NO + LIMIT 1), + 0 + ) AS PART_UNIT_QTY, + COALESCE( + (SELECT NULLIF(MP.UNIT_LENGTH, '')::numeric + FROM PART_MNG MP + WHERE MP.PART_NO = V.RAW_MATERIAL_PART_NO + LIMIT 1), + 0 + ) AS PART_UNIT_LENGTH, V.LEV FROM VIEW_BOM V INNER JOIN PART_MNG P ON P.OBJID = V.PART_OBJID @@ -4323,7 +4368,8 @@ PATH2, CYCLE, UNIT, - WRITER + WRITER, + RAW_MATERIAL_PART_NO ) AS ( SELECT A.MBOM_HEADER_OBJID, @@ -4344,7 +4390,8 @@ ARRAY [A.SEQ::TEXT], FALSE, A.UNIT, - A.WRITER + A.WRITER, + A.RAW_MATERIAL_PART_NO FROM MBOM_DETAIL A WHERE 1=1 @@ -4373,7 +4420,8 @@ PATH2||B.SEQ::TEXT, B.PARENT_OBJID = ANY(PATH), B.UNIT, - B.WRITER + B.WRITER, + B.RAW_MATERIAL_PART_NO FROM MBOM_DETAIL B JOIN @@ -4455,6 +4503,21 @@ (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, + -- 소재소요량 계산용: 소재품번(RAW_MATERIAL_PART_NO)에 해당하는 PART_MNG의 UNIT_QTY / UNIT_LENGTH + COALESCE( + (SELECT NULLIF(MP.UNIT_QTY, '')::numeric + FROM PART_MNG MP + WHERE MP.PART_NO = V.RAW_MATERIAL_PART_NO + LIMIT 1), + 0 + ) AS PART_UNIT_QTY, + COALESCE( + (SELECT NULLIF(MP.UNIT_LENGTH, '')::numeric + FROM PART_MNG MP + WHERE MP.PART_NO = V.RAW_MATERIAL_PART_NO + LIMIT 1), + 0 + ) AS PART_UNIT_LENGTH, V.LEV FROM VIEW_BOM V INNER JOIN PART_MNG P ON P.OBJID = V.PART_OBJID