diff --git a/WebContent/WEB-INF/view/quality/incomingInspectionProgressList.jsp b/WebContent/WEB-INF/view/quality/incomingInspectionProgressList.jsp
index d1240fb..461c10d 100644
--- a/WebContent/WEB-INF/view/quality/incomingInspectionProgressList.jsp
+++ b/WebContent/WEB-INF/view/quality/incomingInspectionProgressList.jsp
@@ -86,6 +86,8 @@ $(document).ready(function(){
// 컬럼: 품의서 No, 발주서 No, 프로젝트번호, 품번, 품명, 공급업체, 입고결과, 요청일, 요청자, 검사자, 검사일, 검사결과
var columns = [
+ {headerHozAlign:'center', hozAlign:'center', minWidth:100, widthGrow:1, title:'검사일', field:'INSPECTION_DATE'},
+ {headerHozAlign:'center', hozAlign:'center', minWidth:80, widthGrow:1, title:'검사자', field:'INSPECTOR_NAME'},
{headerHozAlign:'center', hozAlign:'center', minWidth:120, widthGrow:1, title:'품의서 No', field:'PROPOSAL_NO'
// formatter:fnc_createGridAnchorTag,
// cellClick:function(e, cell){
@@ -103,7 +105,7 @@ var columns = [
{headerHozAlign:'center', hozAlign:'center', minWidth:130, widthGrow:1, title:'프로젝트번호', field:'PROJECT_NO'},
{headerHozAlign:'center', hozAlign:'center', minWidth:110, widthGrow:1, title:'제품구분', field:'PRODUCT_NAME'},
{headerHozAlign:'center', hozAlign:'left', minWidth:120, widthGrow:2, title:'품번', field:'PART_NO'},
- {headerHozAlign:'center', hozAlign:'left', minWidth:150, widthGrow:3, title:'품명', field:'PART_NAME'},
+ {headerHozAlign:'center', hozAlign:'left', minWidth:130, widthGrow:3, title:'품명', field:'PART_NAME'},
{headerHozAlign:'center', hozAlign:'left', minWidth:130, widthGrow:2, title:'공급업체', field:'PARTNER_NAME'},
{headerHozAlign:'center', hozAlign:'center', minWidth:80, widthGrow:1, title:'입고결과', field:'DELIVERY_STATUS',
formatter:fnc_createGridAnchorTag,
@@ -115,28 +117,26 @@ var columns = [
},
// {headerHozAlign:'center', hozAlign:'center', minWidth:100, widthGrow:1, title:'요청일', field:'REQUEST_DATE'},
// {headerHozAlign:'center', hozAlign:'center', minWidth:80, widthGrow:1, title:'요청자', field:'REQUEST_USER_NAME'},
- {headerHozAlign:'center', hozAlign:'center', minWidth:100, widthGrow:1, title:'검사일', field:'INSPECTION_DATE'},
- {headerHozAlign:'center', hozAlign:'center', minWidth:80, widthGrow:1, title:'검사자', field:'INSPECTOR_NAME'},
- {headerHozAlign : 'center', hozAlign : 'center', minWidth : 100, widthGrow : 1, title : '업체성적서', field : 'INSPECTION_FILE_CNT',
- formatter:fnc_subInfoValueFormatter,
- cellClick:function(e, cell){
- var objid = fnc_checkNull(cell.getData().OBJID);
- fn_FileRegist(objid,"INSPECTION_FILE","검사성적서");
- }
- },
- {headerHozAlign:'center', hozAlign:'center', minWidth:80, widthGrow:1, title:'검사결과', field:'INSPECTION_RESULT',
+ {headerHozAlign:'center', hozAlign:'center', minWidth:80, widthGrow:1, title:'검사현황', field:'INSPECTION_RESULT',
formatter: function(cell, formatterParams, onRendered){
var val = fnc_checkNull(cell.getValue());
- if(val === 'NG') return 'NG';
- if(val === 'OK') return 'OK';
- if(val === '검사중') return '검사중';
+ // 처리결과 기준: 전부 입력 = 완료, 일부만 입력 = 진행중, 없으면 미검사
+ if(val === '완료') return '완료';
+ if(val === '진행중') return '진행중';
return '미검사';
},
cellClick:function(e, cell){
var objId = fnc_checkNull(cell.getData().OBJID);
fn_inspectionPopUp(objId);
}
- }
+ },
+ {headerHozAlign : 'center', hozAlign : 'center', minWidth : 100, widthGrow : 1, title : '업체성적서', field : 'INSPECTION_FILE_CNT',
+ formatter:fnc_subInfoValueFormatter,
+ cellClick:function(e, cell){
+ var objid = fnc_checkNull(cell.getData().OBJID);
+ fn_FileRegist(objid,"INSPECTION_FILE","검사성적서");
+ }
+ }
];
// 조회
diff --git a/WebContent/WEB-INF/view/quality/incomingInspectionProgressPopUp.jsp b/WebContent/WEB-INF/view/quality/incomingInspectionProgressPopUp.jsp
index f7e55bf..c3032f7 100644
--- a/WebContent/WEB-INF/view/quality/incomingInspectionProgressPopUp.jsp
+++ b/WebContent/WEB-INF/view/quality/incomingInspectionProgressPopUp.jsp
@@ -136,15 +136,15 @@ var _DEFECT_TYPE_LIST = [];
// 처리현황 목록
var _ACTION_STATUS_LIST = [
{"CODE": "", "NAME": "선택"},
- {"CODE": "Rework", "NAME": "Rework"},
- {"CODE": "Scrap", "NAME": "Scrap"}
+ {"CODE": "Rework", "NAME": "수정"},
+ {"CODE": "Scrap", "NAME": "폐기"}
];
// 처리결과 목록
var _ACTION_RESULT_LIST = [
{"CODE": "", "NAME": "선택"},
- {"CODE": "수정", "NAME": "수정"},
+ {"CODE": "수정", "NAME": "수정완료"},
{"CODE": "폐기", "NAME": "폐기"},
- {"CODE": "특채", "NAME": "특채"}
+ {"CODE": "특채", "NAME": "특채완료"}
];
// 검사자 목록
var _INSPECTOR_LIST = [];
@@ -208,8 +208,8 @@ $(document).ready(function(){
// =====================================================
function fn_initLeftGrid() {
var columns = [
- {formatter:"rowSelection", titleFormatter:"rowSelection", headerHozAlign:"center", hozAlign:"center", headerSort:false, width:30},
- {title:'품번', field:'PART_NO', headerHozAlign:'center', hozAlign:'left', width:150,
+ {formatter:"rowSelection", titleFormatter:"rowSelection", headerHozAlign:"center", hozAlign:"center", headerSort:false, width:30, frozen: true},
+ {title:'품번', field:'PART_NO', headerHozAlign:'center', hozAlign:'left', width:150, frozen: true,
formatter: fnc_createGridAnchorTag,
cellClick: function(e, cell) {
// 품번 클릭 시 품목상세 팝업
@@ -218,18 +218,52 @@ function fn_initLeftGrid() {
}
}
},
- {title:'품명', field:'PART_NAME', headerHozAlign:'center', hozAlign:'left', width:150},
+ {title:'품명', field:'PART_NAME', headerHozAlign:'center', hozAlign:'left', width:150, frozen: true},
{title:'입고일', field:'DELIVERY_DATE', headerHozAlign:'center', hozAlign:'center', width:90},
{title:'입고수량', field:'DELIVERY_QTY', headerHozAlign:'center', hozAlign:'right', width:90,
formatter:"money", formatterParams:{thousand:",", precision:false}
},
- {title:'검사여부', field:'INSPECTION_YN', headerHozAlign:'center', hozAlign:'center', width:70,
+ {title:'검사여부', field:'INSPECTION_YN', headerHozAlign:'center', hozAlign:'center', width:80,
formatter: function(cell) {
var val = cell.getValue();
if(val === '검사') return '검사';
if(val === '스킵') return '스킵';
return val;
}
+ },
+ {title:'검사수량', field:'INSPECTION_QTY', headerHozAlign:'center', hozAlign:'right', width:85,
+ editor:"number",
+ editorParams: {min:0, step:1},
+ formatter: function(cell) {
+ var val = cell.getValue();
+ if(val === null || val === '' || val === undefined) return '';
+ return parseInt(val).toLocaleString();
+ }
+ },
+ {title:'불량수량', field:'DEFECT_QTY_SUM', headerHozAlign:'center', hozAlign:'right', width:80,
+ formatter: function(cell) {
+ var val = cell.getValue();
+ if(val === null || val === '' || val === undefined) return '0';
+ return parseInt(val).toLocaleString();
+ }
+ },
+ {title:'불량율', field:'LEFT_DEFECT_RATE', headerHozAlign:'center', hozAlign:'right', width:70,
+ formatter: function(cell) {
+ var val = cell.getValue();
+ if(val === null || val === '' || val === undefined) return '';
+ return val + '%';
+ }
+ },
+ {title:'검사성적서', field:'INSPECTION_FILE_CNT', headerHozAlign:'center', hozAlign:'center', width:90,
+ formatter: fnc_subInfoValueFormatter,
+ cellClick: function(e, cell) {
+ var objId = fnc_checkNull(cell.getData().INSPECTION_DETAIL_OBJID);
+ if(objId) {
+ fn_openInspectionFilePopUp(objId);
+ } else {
+ Swal.fire("먼저 저장 후 파일을 등록할 수 있습니다.");
+ }
+ }
}
];
@@ -272,7 +306,75 @@ function fn_initLeftGrid() {
// 셀 편집 이벤트
leftGrid.on("cellEdited", function(cell) {
- cell.getData().GRID_STATUS = 'U';
+ var row = cell.getRow();
+ var data = row.getData();
+ var field = cell.getField();
+
+ // 검사수량 변경 시 불량율 재계산
+ if (field === 'INSPECTION_QTY') {
+ fn_calcLeftGridDefectRate(row);
+ }
+
+ data.GRID_STATUS = 'U';
+ });
+}
+
+// 좌측 그리드 불량율 계산 (불량수량합계 / 입고수량 * 100)
+function fn_calcLeftGridDefectRate(row) {
+ var data = row.getData();
+ var deliveryQty = parseInt(data.DELIVERY_QTY) || 0;
+ var defectQtySum = parseInt(data.DEFECT_QTY_SUM) || 0;
+
+ if (deliveryQty > 0) {
+ var rate = (defectQtySum / deliveryQty * 100).toFixed(2);
+ row.update({"LEFT_DEFECT_RATE": rate});
+ } else {
+ row.update({"LEFT_DEFECT_RATE": ""});
+ }
+}
+
+// 검사성적서 파일 팝업
+function fn_openInspectionFilePopUp(objId) {
+ var popup_width = 800;
+ var popup_height = 300;
+ var params = "?targetObjId=" + objId + "&docType=INSPECTION_REPORT&docTypeName=검사성적서";
+ var url = "/common/FileRegistPopup.do" + params;
+ window.open(url, "inspectionFilePopUp", "width=" + popup_width + ",height=" + popup_height + ",scrollbars=yes,resizable=yes");
+}
+
+// 좌측 그리드 불량수량 합계/불량율 실시간 업데이트 (우측 그리드 변경 시)
+function fn_updateLeftGridDefectSum() {
+ if(!selectedRowData) return;
+
+ // 우측 그리드의 불량수량 합계 계산
+ var rightGridData = rightGrid.getData();
+ var defectQtySum = 0;
+ rightGridData.forEach(function(row) {
+ if(row.GRID_STATUS !== 'D') { // 삭제 표시된 행 제외
+ defectQtySum += parseInt(row.DEFECT_QTY) || 0;
+ }
+ });
+
+ // 좌측 그리드에서 현재 선택된 행 찾기
+ var leftRows = leftGrid.getRows();
+ leftRows.forEach(function(row) {
+ var data = row.getData();
+ if(data.INSPECTION_DETAIL_OBJID === selectedDetailObjid) {
+ // 불량수량 합계 업데이트
+ row.update({"DEFECT_QTY_SUM": defectQtySum});
+
+ // 불량율 재계산 (불량수량합계 / 입고수량 * 100)
+ var deliveryQty = parseInt(data.DELIVERY_QTY) || 0;
+ if(deliveryQty > 0) {
+ var rate = (defectQtySum / deliveryQty * 100).toFixed(2);
+ row.update({"LEFT_DEFECT_RATE": rate});
+ } else {
+ row.update({"LEFT_DEFECT_RATE": ""});
+ }
+
+ // 변경 표시
+ data.GRID_STATUS = 'U';
+ }
});
}
@@ -334,29 +436,30 @@ function fn_initRightGrid() {
},
editorParams: {valueId:"CODE", labelId:"NAME", values:_ACTION_STATUS_LIST}
},
- {title:'검사수량', field:'INSPECTION_QTY', headerHozAlign:'center', hozAlign:'right', width:80,
- editor:"input",
- formatter: function(cell) {
- var val = cell.getValue();
- if(val === null || val === '' || val === undefined) return '';
- return parseInt(val);
- }
- },
+ // {title:'검사수량', field:'INSPECTION_QTY', headerHozAlign:'center', hozAlign:'right', width:80,
+ // editor:"input",
+ // formatter: function(cell) {
+ // var val = cell.getValue();
+ // if(val === null || val === '' || val === undefined) return '';
+ // return parseInt(val);
+ // }
+ // },
{title:'불량수량', field:'DEFECT_QTY', headerHozAlign:'center', hozAlign:'right', width:80,
- editor:"input",
+ editor:"number",
+ editorParams: {min:0, step:1},
formatter: function(cell) {
var val = cell.getValue();
if(val === null || val === '' || val === undefined) return '';
return parseInt(val);
}
},
- {title:'불량율', field:'DEFECT_RATE', headerHozAlign:'center', hozAlign:'right', width:70, editor:false,
- formatter: function(cell) {
- var val = cell.getValue();
- if (val) return val + '%';
- return '';
- }
- },
+ // {title:'불량율', field:'DEFECT_RATE', headerHozAlign:'center', hozAlign:'right', width:70, editor:false,
+ // formatter: function(cell) {
+ // var val = cell.getValue();
+ // if (val) return val + '%';
+ // return '';
+ // }
+ // },
{title:'검사일', field:'INSPECTION_DATE', headerHozAlign:'center', hozAlign:'center', width:100,
editor:"date"
},
@@ -427,25 +530,33 @@ function fn_initRightGrid() {
rightGrid.on("cellEdited", function(cell) {
var row = cell.getRow();
var data = row.getData();
+ var field = cell.getField();
// 불량유형 변경 시 불량원인 초기화
- if (cell.getField() === 'DEFECT_TYPE') {
+ if (field === 'DEFECT_TYPE') {
row.update({"DEFECT_REASON": ""});
}
- // 검사수량, 불량수량 변경 시 불량율 자동 계산
- if (cell.getField() === 'INSPECTION_QTY' || cell.getField() === 'DEFECT_QTY') {
+ // 불량수량 변경 시 정수로 변환
+ if (field === 'DEFECT_QTY') {
+ var defectQty = parseInt(data.DEFECT_QTY) || 0;
+ row.update({"DEFECT_QTY": defectQty});
+ // 불량율 계산
+ fn_calcDefectRate(row);
+ // 검사결과 자동 설정
+ fn_updateInspectionResult(row);
+ // 좌측 그리드 불량수량 합계/불량율 업데이트
+ fn_updateLeftGridDefectSum();
+ }
+
+ // 검사수량 변경 시 불량율 자동 계산
+ if (field === 'INSPECTION_QTY') {
fn_calcDefectRate(row);
}
- // 불량수량 변경 시 검사결과 자동 설정
- if (cell.getField() === 'DEFECT_QTY') {
- var defectQty = parseInt(data.DEFECT_QTY) || 0;
- if (defectQty > 0) {
- row.update({"INSPECTION_RESULT": "NG"});
- } else {
- row.update({"INSPECTION_RESULT": "OK"});
- }
+ // 처리결과 변경 시 검사결과 자동 설정
+ if (field === 'ACTION_RESULT') {
+ fn_updateInspectionResult(row);
}
data.GRID_STATUS = data.GRID_STATUS === 'I' ? 'I' : 'U';
@@ -466,6 +577,28 @@ function fn_calcDefectRate(row) {
}
}
+// 검사결과 자동 설정
+// 처리결과가 '수정' 또는 '특채'이면 OK, 불량수량 > 0 이면 NG, 그 외 OK
+function fn_updateInspectionResult(row) {
+ var data = row.getData();
+ var defectQty = parseInt(data.DEFECT_QTY) || 0;
+ var actionResult = fnc_checkNull(data.ACTION_RESULT);
+
+ console.log("[검사결과 자동설정] 불량수량:", defectQty, ", 처리결과:", actionResult);
+
+ var newResult = "OK";
+ // 처리결과가 '수정' 또는 '특채'이면 불량수량 있어도 OK
+ if (actionResult === '수정' || actionResult === '특채') {
+ newResult = "OK";
+ } else if (defectQty > 0) {
+ // 불량수량 있으면 NG
+ newResult = "NG";
+ }
+
+ console.log("[검사결과 자동설정] 결과:", newResult);
+ row.update({"INSPECTION_RESULT": newResult});
+}
+
// =====================================================
// 좌측 그리드 조회
// =====================================================
@@ -609,6 +742,8 @@ function fn_deleteDefectRow() {
row.getElement().style.display = 'none';
}
});
+ // 좌측 그리드 불량수량 합계/불량율 업데이트
+ fn_updateLeftGridDefectSum();
}
});
}
diff --git a/src/com/pms/mapper/quality.xml b/src/com/pms/mapper/quality.xml
index a448a55..ba5892e 100644
--- a/src/com/pms/mapper/quality.xml
+++ b/src/com/pms/mapper/quality.xml
@@ -711,10 +711,9 @@
,DEFECT.INSPECTOR_NAME_DISPLAY AS INSPECTOR_NAME
/* 검사일: YYYY-MM-DD 외 N건 형태 */
,DEFECT.INSPECTION_DATE_DISPLAY AS INSPECTION_DATE
- /* 검사결과: 하나라도 NG면 NG, 검사 대상(스킵 제외) 모두 검사완료면 OK, 일부만 검사면 검사중 */
- ,(CASE WHEN DEFECT.NG_COUNT > 0 THEN 'NG'
- WHEN DEFECT.INSPECTION_TARGET_COUNT > 0 AND DEFECT.INSPECTION_TARGET_COUNT = DEFECT.INSPECTED_COUNT THEN 'OK'
- WHEN DEFECT.INSPECTED_COUNT > 0 THEN '검사중'
+ /* 검사현황: 불량상세 처리결과(ACTION_RESULT)가 전부 있으면 완료, 일부만 있으면 진행중 */
+ ,(CASE WHEN DEFECT.DEFECT_TOTAL_COUNT > 0 AND DEFECT.DEFECT_TOTAL_COUNT = DEFECT.ACTION_RESULT_COUNT THEN '완료'
+ WHEN DEFECT.ACTION_RESULT_COUNT > 0 THEN '진행중'
ELSE '' END) AS INSPECTION_RESULT
/* 검사여부: 검사가 하나라도 있으면 '검사', 모두 스킵이면 '스킵', 아무것도 없으면 빈값 */
@@ -764,6 +763,10 @@
END AS INSPECTION_DATE_DISPLAY
/* 검사 대상 건수 (스킵 제외, 검사인 항목만) */
,COUNT(CASE WHEN IID2.INSPECTION_YN = '검사' THEN 1 END) AS INSPECTION_TARGET_COUNT
+ /* 불량상세 테이블 전체 건수 (검사인 항목 기준) */
+ ,COUNT(CASE WHEN IID2.INSPECTION_YN = '검사' THEN IDF.OBJID END) AS DEFECT_TOTAL_COUNT
+ /* 처리결과(ACTION_RESULT) 입력된 건수 */
+ ,COUNT(CASE WHEN IID2.INSPECTION_YN = '검사' AND IDF.ACTION_RESULT IS NOT NULL AND IDF.ACTION_RESULT != '' THEN 1 END) AS ACTION_RESULT_COUNT
/* 검사결과 입력된 건수 */
,COUNT(CASE WHEN IDF.INSPECTION_RESULT IS NOT NULL AND IDF.INSPECTION_RESULT != '' THEN 1 END) AS INSPECTED_COUNT
,COUNT(CASE WHEN IDF.INSPECTION_RESULT = 'NG' THEN 1 END) AS NG_COUNT
@@ -2266,6 +2269,14 @@
, IID.REMARK
, IMI.PURCHASE_ORDER_MASTER_OBJID
, POM.PURCHASE_ORDER_NO
+ /* 불량수량 합계 (INCOMING_INSPECTION_DETAIL.DEFECT_QTY에 저장된 값 사용) */
+ , COALESCE(NULLIF(IID.DEFECT_QTY, '')::NUMERIC, 0) AS DEFECT_QTY_SUM
+ /* 불량율 (불량수량합계 / 입고수량 * 100) */
+ , CASE WHEN IMI.RECEIPT_QTY::NUMERIC > 0
+ THEN ROUND(COALESCE(NULLIF(IID.DEFECT_QTY, '')::NUMERIC, 0) / IMI.RECEIPT_QTY::NUMERIC * 100, 2)
+ ELSE NULL END AS LEFT_DEFECT_RATE
+ /* 검사성적서 파일 수 */
+ , (SELECT COUNT(*) FROM ATTACH_FILE_INFO AFI WHERE AFI.TARGET_OBJID = IID.OBJID AND AFI.DOC_TYPE = 'INSPECTION_REPORT' AND UPPER(AFI.STATUS) = 'ACTIVE') AS INSPECTION_FILE_CNT
FROM INVENTORY_MGMT_IN IMI
INNER JOIN INVENTORY_MGMT IM ON IM.OBJID = IMI.PARENT_OBJID
INNER JOIN PART_MNG PM ON PM.OBJID::VARCHAR = IM.PART_OBJID
diff --git a/src/com/pms/service/QualityService.java b/src/com/pms/service/QualityService.java
index e600ebd..2f5d73c 100644
--- a/src/com/pms/service/QualityService.java
+++ b/src/com/pms/service/QualityService.java
@@ -1773,6 +1773,8 @@ public class QualityService extends BaseService{
sqlParamMap.put("INSPECTION_TYPE", CommonUtils.checkNull(data.get("INSPECTION_TYPE")));
sqlParamMap.put("INSPECTION_DATE", inspectionDate);
sqlParamMap.put("INSPECTOR_ID", inspectorId);
+ sqlParamMap.put("INSPECTION_QTY", CommonUtils.checkNull(data.get("INSPECTION_QTY"))); // 검사수량
+ sqlParamMap.put("DEFECT_QTY", CommonUtils.checkNull(data.get("DEFECT_QTY_SUM"))); // 불량수량 합계
sqlParamMap.put("WRITER", writer);
sqlSession.update("quality.saveIncomingInspectionDetail", sqlParamMap);
@@ -1788,7 +1790,7 @@ public class QualityService extends BaseService{
for(Map defect : defectList) {
String gridStatus = CommonUtils.checkNull(defect.get("GRID_STATUS"));
-
+
Map sqlParamMap = new HashMap();
sqlParamMap.put("OBJID", CommonUtils.checkNull(defect.get("OBJID")));
sqlParamMap.put("INSPECTION_DETAIL_OBJID", selectedDetailObjid);
@@ -1804,7 +1806,7 @@ public class QualityService extends BaseService{
sqlParamMap.put("INSPECTION_RESULT", CommonUtils.checkNull(defect.get("INSPECTION_RESULT")));
sqlParamMap.put("REMARK", CommonUtils.checkNull(defect.get("REMARK")));
sqlParamMap.put("WRITER", writer);
-
+
if("D".equals(gridStatus)) {
// 삭제
sqlSession.delete("quality.deleteIncomingInspectionDefect", sqlParamMap);