생산관리 생산계획 완성, 실적관리는 틀만..

This commit is contained in:
2025-12-19 15:19:40 +09:00
parent 708393ad7a
commit bbc4474d55
7 changed files with 676 additions and 137 deletions

View File

@@ -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(){
</script>
<body>
<form name="form1" id="form1" method="post">
<input type="hidden" name="OBJID" id="OBJID" value="${resultMap.OBJID}">
<input type="hidden" name="PROJECT_OBJID" id="PROJECT_OBJID" value="${resultMap.PROJECT_OBJID}">
<input type="hidden" name="OBJID" id="OBJID" value="${resultMap.objid}">
<input type="hidden" name="PROJECT_OBJID" id="PROJECT_OBJID" value="${resultMap.project_objid}">
<input type="hidden" name="actionType" id="actionType" value="${actionType}">
<section>
@@ -319,7 +345,7 @@ function fn_save(){
</td>
<td class="input_title"><label>요청납기<span class="required-mark">*</span></label></td>
<td>
<input type="text" name="REQ_DEL_DATE" id="REQ_DEL_DATE" class="date_icon" value="${resultMap.REQ_DEL_DATE}">
<input type="text" name="REQ_DEL_DATE" id="REQ_DEL_DATE" class="date_icon" value="${resultMap.req_del_date}">
</td>
</tr>
@@ -327,15 +353,15 @@ function fn_save(){
<tr>
<td class="input_title"><label>품번<span class="required-mark">*</span></label></td>
<td>
<input type="text" name="PART_NO" id="PART_NO" value="${resultMap.PART_NO}">
<input type="text" name="PART_NO" id="PART_NO" value="${resultMap.part_no}">
</td>
<td class="input_title"><label>품명<span class="required-mark">*</span></label></td>
<td>
<input type="text" name="PART_NAME" id="PART_NAME" value="${resultMap.PART_NAME}">
<input type="text" name="PART_NAME" id="PART_NAME" value="${resultMap.part_name}">
</td>
<td class="input_title"><label>S/N</label></td>
<td>
<input type="text" name="SERIAL_NO" id="SERIAL_NO" value="${resultMap.SERIAL_NO}">
<input type="text" name="SERIAL_NO" id="SERIAL_NO" value="${resultMap.serial_no}">
</td>
</tr>
@@ -343,15 +369,15 @@ function fn_save(){
<tr>
<td class="input_title"><label>수주수량<span class="required-mark">*</span></label></td>
<td>
<input type="number" name="ORDER_QTY" id="ORDER_QTY" min="0" value="${resultMap.ORDER_QTY}">
<input type="number" name="ORDER_QTY" id="ORDER_QTY" min="0" value="${resultMap.order_qty}">
</td>
<td class="input_title"><label>추가생산수량</label></td>
<td>
<input type="number" name="EXTRA_PROD_QTY" id="EXTRA_PROD_QTY" min="0" value="${resultMap.EXTRA_PROD_QTY}" placeholder="0">
<input type="number" name="EXTRA_PROD_QTY" id="EXTRA_PROD_QTY" min="0" value="${resultMap.extra_prod_qty}" placeholder="0">
</td>
<td class="input_title"><label>총생산수량</label></td>
<td>
<input type="text" name="TOTAL_PROD_QTY" id="TOTAL_PROD_QTY" class="readonly-field" readonly value="${resultMap.TOTAL_PROD_QTY}">
<input type="text" name="TOTAL_PROD_QTY" id="TOTAL_PROD_QTY" class="readonly-field" readonly value="${resultMap.total_prod_qty}">
</td>
</tr>
@@ -359,7 +385,7 @@ function fn_save(){
<tr>
<td class="input_title"><label>고객사 요청사항</label></td>
<td colspan="5">
<input type="text" name="CUSTOMER_REQUEST" id="CUSTOMER_REQUEST" value="${resultMap.CUSTOMER_REQUEST}" style="width:100%;">
<input type="text" name="CUSTOMER_REQUEST" id="CUSTOMER_REQUEST" value="${resultMap.customer_request}" style="width:100%;">
</td>
</tr>
</table>

View File

@@ -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() {
<div class="btnArea">
<input type="button" class="plm_btns" value="조회" id="btnSearch">
<input type="button" class="plm_btns" value="생산계획 생성" id="btnCreateProdPlan">
<input type="button" class="plm_btns" value="작업지시 생성" id="btnCreateWorkOrder">
<!-- <input type="button" class="plm_btns" value="작업지시 생성" id="btnCreateWorkOrder"> -->
<input type="button" class="plm_btns" value="생산실적 등록" id="btnRegistProdResult">
</div>
</div>

View File

@@ -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" %>
<c:set var="now" value="<%=new java.util.Date()%>" />
<c:set var="today"><fmt:formatDate value="${now}" pattern="yyyy-MM-dd" /></c:set>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><%=Constants.SYSTEM_NAME%></title>
<style>
.input_title {border-left:1px solid #ccc; background-color:#f5f5f5; font-weight:bold;}
.pmsPopupForm tr:last-child td{border-bottom:1px solid #ccc;}
.pmsPopupForm td { padding: 5px 8px; }
.required-mark { color: red; font-weight: bold; margin-left: 2px; }
.readonly-field { background-color: #eee !important; }
/* 공통 버튼 숨기기 */
.resetBtn, .excelBtn { display: none !important; }
body { min-height: auto !important; }
</style>
</head>
<script type="text/javascript" src="/js/tabulator/tabulator_custom.js"></script>
<script>
var grid;
var _projectObjid = "${param.projectObjid}";
var _resultType = "${param.resultType}";
// 실적유형 목록
var _RESULT_TYPE_LIST = [
{"CODE": "ASSEMBLY", "NAME": "완조립"},
{"CODE": "INSPECTION", "NAME": "검사"},
{"CODE": "SHIP_WAIT", "NAME": "출하대기"}
];
$(function(){
fnc_datepick();
$(".select2").select2();
// 프로젝트 정보 로드
if(_projectObjid) {
fn_loadProjectInfo();
}
// 그리드 초기화
fn_initGrid();
// 실적 목록 조회
fn_search();
// 행추가 버튼
$("#btnAddRow").click(function(){
fn_addRow();
});
// 행삭제 버튼
$("#btnDelRow").click(function(){
fn_delRow();
});
// 저장 버튼
$("#btnSave").click(function(){
fn_save();
});
});
// 날짜 선택기 초기화
function fnc_datepick(){
var $dateinput = $("input.date_icon");
for(var i=0; i<$dateinput.length; i++){
$dateinput.eq(i).attr("size","10");
$dateinput.eq(i).datepicker({
changeMonth:true,
changeYear:true
});
}
}
// 프로젝트 정보 로드
function fn_loadProjectInfo() {
$.ajax({
url: "/productionplanning/getProdPlanProjectInfo.do",
type: "POST",
data: { "projectObjid": _projectObjid },
dataType: "json",
async: false,
success: function(data){
if(data && data.result == "success" && data.info){
var info = data.info;
$("#PROJECT_NO").text(fnc_checkNull(info.project_no));
$("#PART_NO").text(fnc_checkNull(info.part_no));
$("#PART_NAME").text(fnc_checkNull(info.part_name));
$("#ORDER_QTY").text(fnc_checkNull(info.order_qty));
}
}
});
}
// 그리드 컬럼 정의
var columns = [
{formatter:"rowSelection", titleFormatter:"rowSelection", headerHozAlign:'center', hozAlign:"center", headerSort:false, width:30},
{title:'OBJID', field:'OBJID', visible: false},
{title:'실적유형', field:'RESULT_TYPE', headerHozAlign:'center', hozAlign:'center', width:100,
editor: "list",
editorParams: {
values: {"ASSEMBLY":"완조립", "INSPECTION":"검사", "SHIP_WAIT":"출하대기"}
},
formatter: function(cell) {
var val = cell.getValue();
if(val == 'ASSEMBLY') return '완조립';
if(val == 'INSPECTION') return '검사';
if(val == 'SHIP_WAIT') return '출하대기';
return val;
}
},
{title:'실적일자', field:'RESULT_DATE', headerHozAlign:'center', hozAlign:'center', width:110,
editor: "input"
},
{title:'실적수량', field:'RESULT_QTY', headerHozAlign:'center', hozAlign:'right', width:90,
editor: "number",
formatter: "money", formatterParams: {thousand:",", precision:false}
},
{title:'S/N', field:'SERIAL_NO', headerHozAlign:'center', hozAlign:'left', width:120,
editor: "input"
},
{title:'작업자', field:'WORKER_NAME', headerHozAlign:'center', hozAlign:'center', width:100,
editor: "input"
},
{title:'비고', field:'REMARK', headerHozAlign:'center', hozAlign:'left', minWidth:150,
editor: "input"
}
];
// 그리드 초기화
function fn_initGrid() {
grid = new Tabulator("#grid", {
layout: "fitColumns",
height: "calc(100vh - 200px)",
columns: columns,
data: [],
selectableRows: true,
placeholder: "데이터가 없습니다."
});
}
// 실적 목록 조회
function fn_search() {
var params = {
projectObjid: _projectObjid,
resultType: _resultType
};
$.ajax({
url: "/productionplanning/getProdResultList.do",
type: "POST",
data: params,
dataType: "json",
success: function(data){
if(data && data.list) {
grid.setData(data.list);
}
},
error: function(jqxhr, status, error){
console.error("실적 조회 실패:", error);
}
});
}
// 행 추가
function fn_addRow() {
var newRow = {
OBJID: '',
RESULT_TYPE: _resultType || 'ASSEMBLY',
RESULT_DATE: '${today}',
RESULT_QTY: '',
SERIAL_NO: '',
WORKER_NAME: '${connectUserName}',
REMARK: ''
};
grid.addRow(newRow);
}
// 행 삭제
function fn_delRow() {
var selectedRows = grid.getSelectedRows();
if(selectedRows.length === 0) {
Swal.fire('삭제할 행을 선택해주세요.');
return;
}
selectedRows.forEach(function(row) {
row.delete();
});
}
// 저장
function fn_save() {
var allData = grid.getData();
if(allData.length === 0) {
Swal.fire('저장할 데이터가 없습니다.');
return;
}
// 유효성 검사
for(var i = 0; i < allData.length; i++) {
var row = allData[i];
if(!row.RESULT_TYPE) {
Swal.fire('실적유형을 선택해주세요. (행 ' + (i+1) + ')');
return;
}
if(!row.RESULT_DATE) {
Swal.fire('실적일자를 입력해주세요. (행 ' + (i+1) + ')');
return;
}
if(!row.RESULT_QTY || row.RESULT_QTY <= 0) {
Swal.fire('실적수량을 입력해주세요. (행 ' + (i+1) + ')');
return;
}
}
if(!confirm('저장하시겠습니까?')) return;
$.ajax({
url: "/productionplanning/saveProdResultList.do",
type: "POST",
contentType: "application/json",
data: JSON.stringify({
projectObjid: _projectObjid,
resultList: allData
}),
dataType: "json",
success: function(data){
if(data.result == "success") {
alert(data.msg || "저장되었습니다.");
if(opener && opener.fn_search) {
opener.fn_search();
}
fn_search(); // 새로고침
} else {
Swal.fire(data.msg || "저장에 실패했습니다.");
}
},
error: function(jqxhr, status, error){
Swal.fire("저장 중 오류가 발생했습니다.");
console.error(error);
}
});
}
// 팝업 닫힐 때 부모 새로고침
window.addEventListener('unload', function() {
if(window.opener && window.opener.fn_search) {
window.opener.fn_search();
}
});
</script>
<body style="overflow-x: hidden;">
<form name="form1" id="form1" method="post">
<input type="hidden" name="PROJECT_OBJID" id="PROJECT_OBJID" value="${param.projectObjid}">
<input type="hidden" name="RESULT_TYPE" id="RESULT_TYPE_HIDDEN" value="${param.resultType}">
<section>
<div class="plm_menu_name" style="display:flex;">
<h2 style="width:100%;height:50px;text-align:center;margin-top:10px;">
<span style="font-size:20px;">생산실적 등록/수정</span>
</h2>
</div>
<!-- 프로젝트 정보 표시 -->
<div style="padding:10px; background:#f5f5f5; border-bottom:1px solid #ddd;">
<table style="width:100%;">
<tr>
<td style="width:70px; font-weight:bold;">프로젝트:</td>
<td style="width:150px;"><span id="PROJECT_NO">-</span></td>
<td style="width:50px; font-weight:bold;">품번:</td>
<td style="width:150px;"><span id="PART_NO">-</span></td>
<td style="width:50px; font-weight:bold;">품명:</td>
<td><span id="PART_NAME">-</span></td>
<td style="width:70px; font-weight:bold;">수주수량:</td>
<td style="width:70px;"><span id="ORDER_QTY">-</span></td>
</tr>
</table>
</div>
<div class="plm_menu_name_gdnsi">
<h2><span>실적 목록</span></h2>
<div class="btnArea">
<input type="button" value="행추가" class="plm_btns" id="btnAddRow">
<input type="button" value="행삭제" class="plm_btns" id="btnDelRow">
<input type="button" value="저장" class="plm_btns" id="btnSave">
<input type="button" value="닫기" class="plm_btns" onclick="window.close();">
</div>
</div>
<div id="grid" style="margin: 10px;"></div>
</section>
</form>
</body>
</html>

View File

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

View File

@@ -1788,4 +1788,60 @@ public class ProductionPlanningController extends BaseService {
return resultMap;
}
/**
* 생산실적 등록/수정 팝업
*/
@RequestMapping("/productionplanning/prodResultFormPopup.do")
public String prodResultFormPopup(HttpServletRequest request, @RequestParam Map<String, Object> paramMap) {
return "/productionplanning/prodResultFormPopup";
}
/**
* 생산실적 목록 조회
*/
@ResponseBody
@RequestMapping("/productionplanning/getProdResultList.do")
public Map getProdResultList(HttpServletRequest request, @RequestParam Map<String, Object> paramMap) {
Map<String, Object> resultMap = new HashMap<String, Object>();
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<String, Object> paramMap) {
Map<String, Object> resultMap = new HashMap<String, Object>();
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;
}
}

View File

@@ -4406,7 +4406,8 @@
<!-- 생산계획&실적관리 그리드 목록 조회 -->
<select id="prodPlanResultMgmtGridList" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT * FROM (
-- 1. 프로젝트 기반 데이터 (기존)
SELECT
PM.OBJID,
PM.PROJECT_NO,
@@ -4420,9 +4421,11 @@
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.CATEGORY_CD LIMIT 1),
CM.CATEGORY_CD
) AS CATEGORY_CODE_NAME,
-- 생산유형 (TODO: 실제 컬럼명 확인 필요)
'' AS PRODUCTION_TYPE,
'' AS PRODUCTION_TYPE_NAME,
COALESCE(PP.PRODUCTION_TYPE, '') AS PRODUCTION_TYPE,
COALESCE(
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = PP.PRODUCTION_TYPE LIMIT 1),
''
) AS PRODUCTION_TYPE_NAME,
CM.CUSTOMER_OBJID,
COALESCE(
CASE
@@ -4433,14 +4436,10 @@
END,
''
) AS CUSTOMER_NAME,
-- 요청납기
COALESCE(CI.DUE_DATE, PM.DUE_DATE, CM.REQ_DEL_DATE) AS REQ_DEL_DATE,
-- 고객사요청사항
COALESCE(CI.CUSTOMER_REQUEST, '') AS CUSTOMER_REQUEST,
-- 품번/품명
COALESCE(CI.PART_NO, PM.PART_NO, '') AS PART_NO,
COALESCE(CI.PART_NAME, PM.PART_NAME, '') AS PART_NAME,
-- S/N
(SELECT
CASE
WHEN COUNT(*) = 0 THEN ''
@@ -4451,89 +4450,117 @@
WHERE CIS.ITEM_OBJID = CI.OBJID
AND UPPER(CIS.STATUS) = 'ACTIVE'
AND CIS.SERIAL_NO IS NOT NULL) AS SERIAL_NO,
-- 수주수량
COALESCE(PM.QUANTITY::numeric, CI.ORDER_QUANTITY::numeric, 0) AS QUANTITY,
-- 추가생산수량 (TODO: 실제 테이블/컬럼 확인 필요)
0 AS EXTRA_PROD_QTY,
-- 총생산수량 (수주수량 + 추가생산수량)
COALESCE(PM.QUANTITY::numeric, CI.ORDER_QUANTITY::numeric, 0) AS TOTAL_PROD_QTY,
-- 완조립 수량 (TODO: 실제 테이블/컬럼 확인 필요)
COALESCE(NULLIF(PM.QUANTITY, '')::numeric, NULLIF(CI.ORDER_QUANTITY, '')::numeric, 0) AS QUANTITY,
COALESCE(NULLIF(PP.EXTRA_PROD_QTY, '')::numeric, 0) AS EXTRA_PROD_QTY,
COALESCE(NULLIF(PM.QUANTITY, '')::numeric, NULLIF(CI.ORDER_QUANTITY, '')::numeric, 0) + COALESCE(NULLIF(PP.EXTRA_PROD_QTY, '')::numeric, 0) AS TOTAL_PROD_QTY,
0 AS ASSEMBLY_QTY,
-- 검사 수량 (TODO: 실제 테이블/컬럼 확인 필요)
0 AS INSPECTION_QTY,
-- 출하대기 수량 (TODO: 실제 테이블/컬럼 확인 필요)
0 AS SHIP_WAIT_QTY,
-- 장비조립WBS (TODO: 실제 테이블/컬럼 확인 필요)
'' AS EQUIPMENT_WBS,
-- 생산계획 OBJID (있으면 수정, 없으면 신규)
NULL AS PROD_PLAN_OBJID
PP.OBJID AS PROD_PLAN_OBJID,
PM.REGDATE AS SORT_DATE
FROM
PROJECT_MGMT PM
LEFT JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
LEFT OUTER JOIN CONTRACT_ITEM CI ON PM.CONTRACT_OBJID = CI.CONTRACT_OBJID
AND PM.PART_OBJID = CI.PART_OBJID
AND CI.STATUS = 'ACTIVE'
LEFT OUTER JOIN PRODUCTION_PLAN PP ON PP.PROJECT_OBJID = PM.OBJID
AND PP.STATUS = 'active'
WHERE PM.PROJECT_NO IS NOT NULL AND PM.PROJECT_NO != ''
UNION ALL
-- 2. 프로젝트 없이 등록한 생산계획
SELECT
PP.OBJID AS OBJID,
'' AS PROJECT_NO,
PP.PRODUCT_CODE AS PRODUCT,
COALESCE(
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = PP.PRODUCT_CODE LIMIT 1),
''
) AS PRODUCT_NAME,
PP.CATEGORY_CODE AS CATEGORY_CODE,
COALESCE(
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = PP.CATEGORY_CODE LIMIT 1),
''
) AS CATEGORY_CODE_NAME,
COALESCE(PP.PRODUCTION_TYPE, '') AS PRODUCTION_TYPE,
COALESCE(
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = PP.PRODUCTION_TYPE LIMIT 1),
''
) AS PRODUCTION_TYPE_NAME,
PP.CUSTOMER_OBJID,
COALESCE(
(SELECT CLIENT_NM FROM CLIENT_MNG WHERE OBJID::VARCHAR = PP.CUSTOMER_OBJID LIMIT 1),
''
) AS CUSTOMER_NAME,
PP.REQ_DEL_DATE,
COALESCE(PP.CUSTOMER_REQUEST, '') AS CUSTOMER_REQUEST,
COALESCE(PP.PART_NO, '') AS PART_NO,
COALESCE(PP.PART_NAME, '') AS PART_NAME,
COALESCE(PP.SERIAL_NO, '') AS SERIAL_NO,
COALESCE(NULLIF(PP.ORDER_QTY, '')::numeric, 0) AS QUANTITY,
COALESCE(NULLIF(PP.EXTRA_PROD_QTY, '')::numeric, 0) AS EXTRA_PROD_QTY,
COALESCE(NULLIF(PP.TOTAL_PROD_QTY, '')::numeric, 0) AS TOTAL_PROD_QTY,
0 AS ASSEMBLY_QTY,
0 AS INSPECTION_QTY,
0 AS SHIP_WAIT_QTY,
'' AS EQUIPMENT_WBS,
PP.OBJID AS PROD_PLAN_OBJID,
PP.REGDATE AS SORT_DATE
FROM PRODUCTION_PLAN PP
WHERE PP.STATUS = 'active'
AND (PP.PROJECT_OBJID IS NULL OR PP.PROJECT_OBJID = '')
) T
WHERE 1=1
AND PM.PROJECT_NO IS NOT NULL
AND PM.PROJECT_NO != ''
<!-- 프로젝트번호 검색 (multiple select) -->
<if test="search_project_nos != null and search_project_nos != ''">
AND PM.OBJID::VARCHAR IN
AND T.OBJID::VARCHAR IN
<foreach item="projNo" collection="search_project_nos.split(',')" open="(" separator="," close=")">
#{projNo}
</foreach>
</if>
<!-- 제품구분 검색 -->
<if test="search_product_code != null and search_product_code != ''">
AND CM.PRODUCT = #{search_product_code}
AND T.PRODUCT = #{search_product_code}
</if>
<!-- 주문유형 검색 -->
<if test="search_category_code != null and search_category_code != ''">
AND CM.CATEGORY_CD = #{search_category_code}
AND T.CATEGORY_CODE = #{search_category_code}
</if>
<!-- 생산유형 검색 -->
<if test="search_production_type != null and search_production_type != ''">
AND 1=1 <!-- TODO: 생산유형 컬럼 확인 후 조건 추가 -->
AND T.PRODUCTION_TYPE = #{search_production_type}
</if>
<!-- 고객사 검색 (C_ 접두사 처리) -->
<!-- 고객사 검색 -->
<if test="search_customer_objid != null and search_customer_objid != ''">
AND (
CM.CUSTOMER_OBJID = #{search_customer_objid}
OR CM.CUSTOMER_OBJID = REPLACE(#{search_customer_objid}, 'C_', '')
OR REPLACE(CM.CUSTOMER_OBJID, 'C_', '') = REPLACE(#{search_customer_objid}, 'C_', '')
T.CUSTOMER_OBJID = #{search_customer_objid}
OR T.CUSTOMER_OBJID = REPLACE(#{search_customer_objid}, 'C_', '')
OR REPLACE(T.CUSTOMER_OBJID, 'C_', '') = REPLACE(#{search_customer_objid}, 'C_', '')
)
</if>
<!-- 요청납기 검색 -->
<if test="search_req_del_date_from != null and search_req_del_date_from != ''">
AND COALESCE(CI.DUE_DATE, PM.DUE_DATE, CM.REQ_DEL_DATE) >= #{search_req_del_date_from}
AND T.REQ_DEL_DATE >= #{search_req_del_date_from}
</if>
<if test="search_req_del_date_to != null and search_req_del_date_to != ''">
AND COALESCE(CI.DUE_DATE, PM.DUE_DATE, CM.REQ_DEL_DATE) &lt;= #{search_req_del_date_to}
AND T.REQ_DEL_DATE &lt;= #{search_req_del_date_to}
</if>
<!-- 품번 검색 -->
<if test="search_part_no != null and search_part_no != ''">
AND (
UPPER(PM.PART_NO) LIKE '%' || UPPER(#{search_part_no}) || '%'
OR UPPER(CI.PART_NO) LIKE '%' || UPPER(#{search_part_no}) || '%'
)
AND UPPER(T.PART_NO) LIKE '%' || UPPER(#{search_part_no}) || '%'
</if>
<!-- 품명 검색 -->
<if test="search_part_name != null and search_part_name != ''">
AND (
UPPER(PM.PART_NAME) LIKE '%' || UPPER(#{search_part_name}) || '%'
OR UPPER(CI.PART_NAME) LIKE '%' || UPPER(#{search_part_name}) || '%'
)
AND UPPER(T.PART_NAME) LIKE '%' || UPPER(#{search_part_name}) || '%'
</if>
<!-- S/N 검색 -->
<if test="search_serial_no != null and search_serial_no != ''">
AND EXISTS (
SELECT 1 FROM CONTRACT_ITEM_SERIAL CIS
WHERE CIS.ITEM_OBJID = CI.OBJID
AND UPPER(CIS.STATUS) = 'ACTIVE'
AND UPPER(CIS.SERIAL_NO) LIKE '%' || UPPER(#{search_serial_no}) || '%'
)
AND UPPER(T.SERIAL_NO) LIKE '%' || UPPER(#{search_serial_no}) || '%'
</if>
ORDER BY PM.REGDATE DESC, PM.PROJECT_NO DESC
ORDER BY T.SORT_DATE DESC, T.PROJECT_NO DESC
</select>
<!-- 프로젝트 정보 조회 (생산계획 폼용) -->
@@ -4650,4 +4677,71 @@
WHERE OBJID = #{OBJID}
</update>
<!-- 생산실적 목록 조회 -->
<select id="getProdResultList" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT
OBJID,
PROJECT_OBJID,
RESULT_TYPE,
TO_CHAR(RESULT_DATE::DATE, 'YYYY-MM-DD') AS RESULT_DATE,
RESULT_QTY,
SERIAL_NO,
WORKER_ID,
WORKER_NAME,
REMARK,
STATUS
FROM PRODUCTION_RESULT
WHERE PROJECT_OBJID = #{projectObjid}
AND STATUS = 'active'
<if test="resultType != null and resultType != ''">
AND RESULT_TYPE = #{resultType}
</if>
ORDER BY RESULT_DATE DESC, REGDATE DESC
</select>
<!-- 생산실적 등록 -->
<insert id="insertProdResult" parameterType="map">
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}
)
</insert>
<!-- 생산실적 수정 -->
<update id="updateProdResult" parameterType="map">
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}
</update>
</mapper>

View File

@@ -1758,4 +1758,73 @@ public class ProductionPlanningService {
return result;
}
/**
* 생산실적 목록 조회
*/
public List getProdResultList(Map<String, Object> 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<String, Object> 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<Map<String, Object>> resultList = (List<Map<String, Object>>)paramMap.get("resultList");
if(resultList != null && resultList.size() > 0) {
for(Map<String, Object> 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;
}
}