Merge pull request 'V20260210' (#138) from V20260210 into main

Reviewed-on: #138
This commit was merged in pull request #138.
This commit is contained in:
2026-02-13 12:12:51 +00:00
6 changed files with 276 additions and 124 deletions

View File

@@ -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"));
%>
<html>
<head>
<script>
// 프로젝트 수주수량을 전역 변수로 설정 (하위 프레임에서 접근 가능)
var PROJECT_QUANTITY = <%=quantity.isEmpty() ? "1" : quantity%>;
// 총생산수량 (수주수량 + 추가생산수량) - 생산계획에서 가져옴
var TOTAL_PROD_QTY = <%=totalProdQty.isEmpty() ? (quantity.isEmpty() ? "1" : quantity) : totalProdQty%>;
</script>
</head>
<frameset rows="100px, *" border="0" noresize>

View File

@@ -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 '<span class="editable-header">소재소요량</span>'; },
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 '<span class="editable-header">제작수량</span>'; },
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 '<span class="editable-header">제작수량</span>'; },
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 {

View File

@@ -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}

View File

@@ -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}

View File

@@ -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

View File

@@ -6252,6 +6252,9 @@ FROM(
<!-- 매입마감수량 확정입고수량 = 입고수량 - 폐기수량 -->
,(COALESCE(AP_AGG.DELIVERY_QTY, 0) - COALESCE(DEFECT_AGG.DEFECT_QTY, 0)) AS CONFIRMED_QTY
<!-- 품목별 입고요청일 (BOM → 품의서 → 발주서 품목으로 전달된 값) -->
,POP.DELIVERY_REQUEST_DATE
<!-- 매입마감일 -->
,POM.PURCHASE_CLOSE_DATE
@@ -6324,11 +6327,12 @@ FROM(
<if test="purchase_order_no != null and purchase_order_no != ''">
AND TRIM(UPPER(POM.PURCHASE_ORDER_NO)) LIKE '%'||TRIM(UPPER(#{purchase_order_no}))||'%'
</if>
<!-- 입고요청일 검색: 품목별 입고요청일(POP) 기준 -->
<if test="delivery_start_date != null and delivery_start_date != ''">
AND TO_DATE(POM.DELIVERY_DATE, 'YYYY-MM-DD') <![CDATA[ >= ]]> TO_DATE(#{delivery_start_date}, 'YYYY-MM-DD')
AND TO_DATE(POP.DELIVERY_REQUEST_DATE, 'YYYY-MM-DD') <![CDATA[ >= ]]> TO_DATE(#{delivery_start_date}, 'YYYY-MM-DD')
</if>
<if test="delivery_end_date != null and delivery_end_date != ''">
AND TO_DATE(POM.DELIVERY_DATE, 'YYYY-MM-DD') <![CDATA[ <= ]]> TO_DATE(#{delivery_end_date}, 'YYYY-MM-DD')
AND TO_DATE(POP.DELIVERY_REQUEST_DATE, 'YYYY-MM-DD') <![CDATA[ <= ]]> TO_DATE(#{delivery_end_date}, 'YYYY-MM-DD')
</if>
<if test="partner_objid != null and partner_objid != ''">
AND POM.PARTNER_OBJID = REPLACE(#{partner_objid}, 'C_', '')