diff --git a/WebContent/WEB-INF/view/productionplanning/prodPlanFormPopup.jsp b/WebContent/WEB-INF/view/productionplanning/prodPlanFormPopup.jsp index 6cccde9..e164789 100644 --- a/WebContent/WEB-INF/view/productionplanning/prodPlanFormPopup.jsp +++ b/WebContent/WEB-INF/view/productionplanning/prodPlanFormPopup.jsp @@ -44,6 +44,8 @@ $(function(){ $("#PROJECT_NO").on("change select2:select", function(){ var projectObjid = $(this).val(); console.log("프로젝트번호 변경됨:", projectObjid); + // PROJECT_OBJID hidden 필드에도 값 설정 + $("#PROJECT_OBJID").val(projectObjid); if(fnc_checkNull(projectObjid) != ""){ fn_loadProjectInfo(projectObjid); } else { @@ -113,11 +115,25 @@ function fn_loadProjectInfo(projectObjid){ $("#CATEGORY_CODE").val(info.category_code).trigger("change.select2"); } - // 고객사 (C_ 접두어 제거) + // 고객사 설정 (C_ 접두어 유무 모두 시도) if(fnc_checkNull(info.customer_objid) != ""){ - var customerObjid = info.customer_objid.replace("C_", ""); - console.log("고객사 설정:", customerObjid); - $("#CUSTOMER_OBJID").val(customerObjid).trigger("change.select2"); + var customerObjid = info.customer_objid; + console.log("고객사 원본값:", customerObjid); + + // 먼저 원본값으로 시도 + $("#CUSTOMER_OBJID").val(customerObjid); + if($("#CUSTOMER_OBJID").val() != customerObjid) { + // C_ 제거 후 시도 + customerObjid = info.customer_objid.replace("C_", ""); + $("#CUSTOMER_OBJID").val(customerObjid); + } + if($("#CUSTOMER_OBJID").val() != customerObjid) { + // C_ 추가 후 시도 + customerObjid = "C_" + info.customer_objid.replace("C_", ""); + $("#CUSTOMER_OBJID").val(customerObjid); + } + console.log("고객사 최종설정:", $("#CUSTOMER_OBJID").val()); + $("#CUSTOMER_OBJID").trigger("change.select2"); } // 품번 @@ -166,11 +182,21 @@ function fn_clearProjectInfo(){ // 기존 데이터 로드 (수정 모드) function fn_loadExistingData(){ - // JSP EL로 기존 데이터 설정 + // JSP EL로 기존 데이터 설정 (resultMap 키는 소문자) <% if(info != null) { %> - $("#PRODUCT_CODE").val("${resultMap.PRODUCT_CODE}").trigger("change"); - $("#CATEGORY_CODE").val("${resultMap.CATEGORY_CODE}").trigger("change"); - $("#CUSTOMER_OBJID").val("${resultMap.CUSTOMER_OBJID}").trigger("change"); + // 프로젝트번호 설정 + var projectObjid = "${resultMap.project_objid}"; + if(projectObjid) { + $("#PROJECT_NO").val(projectObjid).trigger("change.select2"); + } + // 제품구분 + $("#PRODUCT_CODE").val("${resultMap.product_code}").trigger("change.select2"); + // 주문유형 + $("#CATEGORY_CODE").val("${resultMap.category_code}").trigger("change.select2"); + // 생산유형 + $("#PRODUCTION_TYPE").val("${resultMap.production_type}").trigger("change.select2"); + // 고객사 + $("#CUSTOMER_OBJID").val("${resultMap.customer_objid}").trigger("change.select2"); fn_calcTotalQty(); <% } %> } @@ -254,8 +280,8 @@ function fn_save(){
- - + +
@@ -319,7 +345,7 @@ function fn_save(){ - + @@ -327,15 +353,15 @@ function fn_save(){ - + - + - + @@ -343,15 +369,15 @@ function fn_save(){ - + - + - + @@ -359,7 +385,7 @@ function fn_save(){ - + diff --git a/WebContent/WEB-INF/view/productionplanning/prodPlanResultMgmtList.jsp b/WebContent/WEB-INF/view/productionplanning/prodPlanResultMgmtList.jsp index 4a25b1a..08506c3 100644 --- a/WebContent/WEB-INF/view/productionplanning/prodPlanResultMgmtList.jsp +++ b/WebContent/WEB-INF/view/productionplanning/prodPlanResultMgmtList.jsp @@ -244,11 +244,9 @@ var columns = [ width: 80, title: '완조립', field: 'ASSEMBLY_QTY', - formatter:fnc_createGridAnchorTag, + formatter: fnc_createGridAnchorTag, cellClick: function(e, cell) { - if(cell.getValue() > 0) { - fn_openQtyDetailPopup(cell.getData().OBJID, 'ASSEMBLY'); - } + fn_openProdResultPopup(cell.getData().OBJID, 'ASSEMBLY'); } }, @@ -259,11 +257,9 @@ var columns = [ width: 70, title: '검사', field: 'INSPECTION_QTY', - formatter:fnc_createGridAnchorTag, + formatter: fnc_createGridAnchorTag, cellClick: function(e, cell) { - if(cell.getValue() > 0) { - fn_openQtyDetailPopup(cell.getData().OBJID, 'INSPECTION'); - } + fn_openProdResultPopup(cell.getData().OBJID, 'INSPECTION'); } }, @@ -274,11 +270,9 @@ var columns = [ width: 90, title: '출하대기', field: 'SHIP_WAIT_QTY', - formatter:fnc_createGridAnchorTag, + formatter: fnc_createGridAnchorTag, cellClick: function(e, cell) { - if(cell.getValue() > 0) { - fn_openQtyDetailPopup(cell.getData().OBJID, 'SHIP_WAIT'); - } + fn_openProdResultPopup(cell.getData().OBJID, 'SHIP_WAIT'); } }, @@ -332,7 +326,7 @@ function fn_createProdPlan() { var checkedRows = getCheckedRows(); var popup_width = 900; - var popup_height = 500; + var popup_height = 400; var url = "/productionplanning/prodPlanFormPopup.do"; if(checkedRows.length === 1) { @@ -399,18 +393,16 @@ function fn_registProdResult() { } var rowData = checkedRows[0]; - var popup_width = 1000; - var popup_height = 700; - var url = "/productionplanning/prodResultFormPopup.do?projectObjid=" + rowData.OBJID; - fn_centerPopup(popup_width, popup_height, url, 'prodResultPopup'); + // 실적유형 선택 없이 팝업 열기 (팝업에서 선택 가능) + fn_openProdResultPopup(rowData.OBJID, ''); } -// 수량 상세 팝업 (완조립, 검사, 출하대기 클릭 시) -function fn_openQtyDetailPopup(projectObjid, qtyType) { - var popup_width = 800; - var popup_height = 500; - var url = "/productionplanning/prodQtyDetailPopup.do?projectObjid=" + projectObjid + "&qtyType=" + qtyType; - fn_centerPopup(popup_width, popup_height, url, 'qtyDetailPopup'); +// 생산실적 등록/수정 팝업 (완조립, 검사, 출하대기 클릭 시) +function fn_openProdResultPopup(projectObjid, resultType) { + var popup_width = 1000; + var popup_height = 700; + var url = "/productionplanning/prodResultFormPopup.do?projectObjid=" + projectObjid + "&resultType=" + resultType; + fn_centerPopup(popup_width, popup_height, url, 'prodResultPopup'); } // 선택된 행 가져오기 (Tabulator 선택 기능 사용) @@ -440,7 +432,7 @@ function getCheckedRows() {
- +
diff --git a/WebContent/WEB-INF/view/productionplanning/prodResultFormPopup.jsp b/WebContent/WEB-INF/view/productionplanning/prodResultFormPopup.jsp new file mode 100644 index 0000000..105b8a3 --- /dev/null +++ b/WebContent/WEB-INF/view/productionplanning/prodResultFormPopup.jsp @@ -0,0 +1,302 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> +<%@ page import="com.pms.common.utils.*"%> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ page import="java.util.*" %> +<%@include file= "/init_new.jsp" %> + + + + + + +<%=Constants.SYSTEM_NAME%> + + + + + + + + + +
+
+

+ 생산실적 등록/수정 +

+
+ + +
+ + + + + + + + + + + +
프로젝트:-품번:-품명:-수주수량:-
+
+ +
+

실적 목록

+
+ + + + +
+
+ +
+
+ + + diff --git a/WebContent/WEB-INF/view/quality/incomingInspectionProgressList.jsp b/WebContent/WEB-INF/view/quality/incomingInspectionProgressList.jsp index 8ce2021..fe593b9 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/WebContent/WEB-INF/view/quality/processInspectionFormPopUp.jsp b/WebContent/WEB-INF/view/quality/processInspectionFormPopUp.jsp index 8d62ff1..3c72c75 100644 --- a/WebContent/WEB-INF/view/quality/processInspectionFormPopUp.jsp +++ b/WebContent/WEB-INF/view/quality/processInspectionFormPopUp.jsp @@ -42,6 +42,8 @@ String connector = person.getUserId(); /* 검사결과 스타일 */ .inspection-ng { color: #dc3545; font-weight: bold; } .inspection-ok { color: #28a745; font-weight: bold; } + /* 공통에서 추가되는 초기화, Excel Download 버튼 숨기기 */ + .resetBtn, .excelBtn { display: none !important; } diff --git a/WebContent/css/basic_new.css b/WebContent/css/basic_new.css index 68d1f97..05dfad6 100644 --- a/WebContent/css/basic_new.css +++ b/WebContent/css/basic_new.css @@ -27,7 +27,7 @@ /* 기본 바디 스타일 - 깔끔한 배경 */ body { background: var(--background); - min-height: 100vh; + /* min-height: 100vh; */ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans KR', Roboto, 'Helvetica Neue', Arial, sans-serif; color: var(--text-primary); line-height: 1.6; diff --git a/src/com/pms/controller/ProductionPlanningController.java b/src/com/pms/controller/ProductionPlanningController.java index e4e6225..41b40c5 100644 --- a/src/com/pms/controller/ProductionPlanningController.java +++ b/src/com/pms/controller/ProductionPlanningController.java @@ -1788,4 +1788,60 @@ public class ProductionPlanningController extends BaseService { return resultMap; } + /** + * 생산실적 등록/수정 팝업 + */ + @RequestMapping("/productionplanning/prodResultFormPopup.do") + public String prodResultFormPopup(HttpServletRequest request, @RequestParam Map paramMap) { + return "/productionplanning/prodResultFormPopup"; + } + + /** + * 생산실적 목록 조회 + */ + @ResponseBody + @RequestMapping("/productionplanning/getProdResultList.do") + public Map getProdResultList(HttpServletRequest request, @RequestParam Map paramMap) { + Map resultMap = new HashMap(); + try { + List list = productionPlanningService.getProdResultList(paramMap); + resultMap.put("result", "success"); + resultMap.put("list", list); + } catch(Exception e) { + e.printStackTrace(); + resultMap.put("result", "fail"); + resultMap.put("msg", "조회 실패"); + } + return resultMap; + } + + /** + * 생산실적 저장 (JSON) + */ + @ResponseBody + @RequestMapping(value="/productionplanning/saveProdResultList.do", produces="application/json;charset=UTF-8") + public Map saveProdResultList(HttpServletRequest request, @RequestBody Map paramMap) { + Map resultMap = new HashMap(); + try { + HttpSession session = request.getSession(); + PersonBean person = (PersonBean) session.getAttribute(Constants.PERSON_BEAN); + paramMap.put("userId", person.getUserId()); + paramMap.put("userName", person.getUserName()); + + boolean success = productionPlanningService.saveProdResultList(paramMap); + if(success) { + resultMap.put("result", "success"); + resultMap.put("msg", "저장되었습니다."); + } else { + resultMap.put("result", "fail"); + resultMap.put("msg", "저장에 실패했습니다."); + } + } catch(Exception e) { + e.printStackTrace(); + resultMap.put("result", "fail"); + resultMap.put("msg", "저장 중 오류가 발생했습니다."); + } + return resultMap; + } + } diff --git a/src/com/pms/mapper/productionplanning.xml b/src/com/pms/mapper/productionplanning.xml index cb0e8d0..33ea7d3 100644 --- a/src/com/pms/mapper/productionplanning.xml +++ b/src/com/pms/mapper/productionplanning.xml @@ -4406,134 +4406,161 @@ @@ -4650,4 +4677,71 @@ WHERE OBJID = #{OBJID} + + + + + + INSERT INTO PRODUCTION_RESULT ( + OBJID, + PROJECT_OBJID, + RESULT_TYPE, + RESULT_DATE, + RESULT_QTY, + SERIAL_NO, + WORKER_ID, + WORKER_NAME, + REMARK, + STATUS, + REGDATE, + WRITER + ) VALUES ( + #{OBJID}, + #{PROJECT_OBJID}, + #{RESULT_TYPE}, + #{RESULT_DATE}, + #{RESULT_QTY}, + #{SERIAL_NO}, + #{userId}, + #{WORKER_NAME}, + #{REMARK}, + 'active', + NOW(), + #{userId} + ) + + + + + UPDATE PRODUCTION_RESULT SET + RESULT_TYPE = #{RESULT_TYPE}, + RESULT_DATE = #{RESULT_DATE}, + RESULT_QTY = #{RESULT_QTY}, + SERIAL_NO = #{SERIAL_NO}, + WORKER_NAME = #{WORKER_NAME}, + REMARK = #{REMARK}, + MODDATE = NOW(), + MODIFIER = #{userId} + WHERE OBJID = #{OBJID} + + diff --git a/src/com/pms/mapper/quality.xml b/src/com/pms/mapper/quality.xml index 993b93d..4bbcb55 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 @@ -1108,6 +1111,7 @@ FROM PROCESS_INSPECTION_DETAIL PID WHERE PID.MASTER_OBJID = PIM.OBJID ) AS INSPECTION_RESULT , PIM.REMARK + , (SELECT COUNT(*) FROM ATTACH_FILE_INFO F WHERE F.TARGET_OBJID = PIM.OBJID AND F.DOC_TYPE = 'PROCESS_INSPECTION_FILE' AND UPPER(F.STATUS) = 'ACTIVE') AS PROCESS_INSPECTION_FILE_CNT FROM PROCESS_INSPECTION_MASTER PIM WHERE 1=1 /* 프로젝트번호 */ @@ -2317,6 +2321,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/ProductionPlanningService.java b/src/com/pms/service/ProductionPlanningService.java index 26e6e26..fea250b 100644 --- a/src/com/pms/service/ProductionPlanningService.java +++ b/src/com/pms/service/ProductionPlanningService.java @@ -1758,4 +1758,73 @@ public class ProductionPlanningService { return result; } + + /** + * 생산실적 목록 조회 + */ + public List getProdResultList(Map paramMap) { + List resultList = new ArrayList(); + SqlSession sqlSession = null; + + try { + sqlSession = SqlMapConfig.getInstance().getSqlSession(); + resultList = sqlSession.selectList("productionplanning.getProdResultList", paramMap); + } catch(Exception e) { + e.printStackTrace(); + } finally { + if(sqlSession != null) { + sqlSession.close(); + } + } + + return resultList; + } + + /** + * 생산실적 저장 (리스트) + */ + @SuppressWarnings("unchecked") + public boolean saveProdResultList(Map paramMap) { + boolean result = false; + SqlSession sqlSession = null; + + try { + sqlSession = SqlMapConfig.getInstance().getSqlSession(); + + String projectObjid = CommonUtils.nullToEmpty((String)paramMap.get("projectObjid")); + String userId = CommonUtils.nullToEmpty((String)paramMap.get("userId")); + List> resultList = (List>)paramMap.get("resultList"); + + if(resultList != null && resultList.size() > 0) { + for(Map row : resultList) { + row.put("PROJECT_OBJID", projectObjid); + row.put("userId", userId); + + String objid = CommonUtils.nullToEmpty((String)row.get("OBJID")); + if("".equals(objid)) { + // 신규 등록 + row.put("OBJID", CommonUtils.createObjId()); + sqlSession.insert("productionplanning.insertProdResult", row); + } else { + // 수정 + sqlSession.update("productionplanning.updateProdResult", row); + } + } + } + + sqlSession.commit(); + result = true; + } catch(Exception e) { + e.printStackTrace(); + if(sqlSession != null) { + sqlSession.rollback(); + } + } finally { + if(sqlSession != null) { + sqlSession.close(); + } + } + + return result; + } } diff --git a/src/com/pms/service/QualityService.java b/src/com/pms/service/QualityService.java index dffaafe..823a7df 100644 --- a/src/com/pms/service/QualityService.java +++ b/src/com/pms/service/QualityService.java @@ -1806,6 +1806,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); @@ -1821,7 +1823,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); @@ -1837,7 +1839,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);