Compare commits
4 Commits
60c054f33d
...
b85dd415fb
| Author | SHA1 | Date | |
|---|---|---|---|
| b85dd415fb | |||
| 57b14daf19 | |||
| e1db86179d | |||
| 1aa7cb5544 |
@@ -0,0 +1,391 @@
|
||||
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||||
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
||||
<%@ page import="com.pms.common.utils.*"%>
|
||||
<%@ page import="java.util.*" %>
|
||||
<%@include file= "/init.jsp" %>
|
||||
<%
|
||||
// DB에서 메뉴명 조회 (공통 유틸 사용)
|
||||
String menuObjId = request.getParameter("menuObjId");
|
||||
String menuName = CommonUtils.getMenuName(menuObjId, "원자재소요량");
|
||||
%>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title><%=Constants.SYSTEM_NAME%></title>
|
||||
<link href="/css/tabulator/tabulator.min.css" rel="stylesheet">
|
||||
<script type="text/javascript" src="/js/tabulator/tabulator.min.js"></script>
|
||||
<style>
|
||||
body, html {
|
||||
overflow-x: hidden;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.section-title {
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
margin: 10px 0 8px 0;
|
||||
color: #333;
|
||||
border-left: 3px solid #3498db;
|
||||
padding-left: 8px;
|
||||
}
|
||||
#inputGrid {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
// 입력 그리드 (M-BOM 선택 + 수량 입력)
|
||||
var inputGrid;
|
||||
// 결과 그리드 (소요량 목록)
|
||||
var resultGrid;
|
||||
// 입력 행 번호
|
||||
var rowSeq = 0;
|
||||
// M-BOM 옵션 데이터
|
||||
var mbomOptionsData = {};
|
||||
|
||||
$(document).ready(function(){
|
||||
$('.select2').select2();
|
||||
|
||||
// M-BOM 옵션 데이터 초기화
|
||||
fn_initMbomOptions();
|
||||
|
||||
// 입력 그리드 초기화
|
||||
fn_initInputGrid();
|
||||
|
||||
// 결과 그리드 초기화
|
||||
fn_initResultGrid();
|
||||
|
||||
// 조회 버튼
|
||||
$("#btnSearch").click(function(){
|
||||
fn_search();
|
||||
});
|
||||
|
||||
// 행 추가 버튼
|
||||
$("#btnAddRow").click(function(){
|
||||
fn_addInputRow();
|
||||
});
|
||||
|
||||
// 행 삭제 버튼
|
||||
$("#btnDeleteRow").click(function(){
|
||||
fn_deleteInputRow();
|
||||
});
|
||||
});
|
||||
|
||||
// M-BOM 옵션 데이터 초기화
|
||||
function fn_initMbomOptions() {
|
||||
mbomOptionsData = {"": "선택"};
|
||||
$("#MBOM_SELECT_HIDDEN option").each(function(){
|
||||
var val = $(this).val();
|
||||
var text = $(this).text();
|
||||
if(val !== '') {
|
||||
mbomOptionsData[val] = text;
|
||||
}
|
||||
});
|
||||
console.log("M-BOM 옵션:", mbomOptionsData);
|
||||
}
|
||||
|
||||
// 입력 그리드 초기화
|
||||
function fn_initInputGrid() {
|
||||
// 초기 데이터 1행 포함
|
||||
var initialData = [{
|
||||
ROW_ID: 1,
|
||||
MBOM_OBJID: "",
|
||||
PART_NAME: "",
|
||||
QTY: 1
|
||||
}];
|
||||
rowSeq = 1;
|
||||
|
||||
inputGrid = new Tabulator("#inputGrid", {
|
||||
data: initialData,
|
||||
layout: "fitColumns",
|
||||
height: "180px",
|
||||
columns: [
|
||||
{
|
||||
title: '',
|
||||
field: 'CHK',
|
||||
width: 40,
|
||||
headerSort: false,
|
||||
hozAlign: 'center',
|
||||
formatter: function(cell) {
|
||||
return '<input type="checkbox" class="row-check">';
|
||||
}
|
||||
},
|
||||
{title: 'ROW_ID', field: 'ROW_ID', visible: false},
|
||||
{
|
||||
title: 'M-BOM 선택',
|
||||
field: 'MBOM_OBJID',
|
||||
headerHozAlign: 'center',
|
||||
headerSort: false,
|
||||
editor: "list",
|
||||
editorParams: function(cell) {
|
||||
return {
|
||||
values: mbomOptionsData,
|
||||
autocomplete: true,
|
||||
clearable: true,
|
||||
listOnEmpty: true
|
||||
};
|
||||
},
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
return mbomOptionsData[value] || "";
|
||||
},
|
||||
cellEdited: function(cell) {
|
||||
// M-BOM 선택 시 품명 자동 입력
|
||||
var mbomObjid = cell.getValue();
|
||||
var row = cell.getRow();
|
||||
if(mbomObjid) {
|
||||
var mbomName = mbomOptionsData[mbomObjid] || "";
|
||||
row.update({PART_NAME: mbomName});
|
||||
} else {
|
||||
row.update({PART_NAME: ""});
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '품명',
|
||||
field: 'PART_NAME',
|
||||
headerHozAlign: 'center',
|
||||
headerSort: false,
|
||||
editor: false
|
||||
},
|
||||
{
|
||||
title: '수량',
|
||||
field: 'QTY',
|
||||
width: 200,
|
||||
headerHozAlign: 'center',
|
||||
headerSort: false,
|
||||
hozAlign: 'right',
|
||||
editor: "number",
|
||||
editorParams: {
|
||||
min: 1,
|
||||
step: 1
|
||||
}
|
||||
}
|
||||
],
|
||||
placeholder: "M-BOM을 선택하고 수량을 입력하세요."
|
||||
});
|
||||
}
|
||||
|
||||
// 결과 그리드 초기화
|
||||
function fn_initResultGrid() {
|
||||
resultGrid = new Tabulator("#resultGrid", {
|
||||
data: [],
|
||||
layout: "fitColumns",
|
||||
height: "calc(100vh - 450px)",
|
||||
pagination: false, // 페이지네이션 비활성화 (전체 데이터 표시)
|
||||
columns: [
|
||||
{
|
||||
title: '구분',
|
||||
field: 'CATEGORY_NAME',
|
||||
width: 150,
|
||||
headerHozAlign: 'center',
|
||||
headerSort: true,
|
||||
hozAlign: 'center'
|
||||
},
|
||||
{
|
||||
title: '품번',
|
||||
field: 'PART_NO',
|
||||
width: 320,
|
||||
headerHozAlign: 'center',
|
||||
headerSort: true,
|
||||
hozAlign: 'left'
|
||||
},
|
||||
{
|
||||
title: '품명',
|
||||
field: 'PART_NAME',
|
||||
headerHozAlign: 'center',
|
||||
headerSort: true,
|
||||
hozAlign: 'left'
|
||||
},
|
||||
{
|
||||
title: '소요량',
|
||||
field: 'REQUIRED_QTY',
|
||||
width: 150,
|
||||
headerHozAlign: 'center',
|
||||
headerSort: true,
|
||||
hozAlign: 'right',
|
||||
formatter: function(cell) {
|
||||
var val = cell.getValue();
|
||||
if(val != null && val !== '') {
|
||||
return Number(val).toLocaleString();
|
||||
}
|
||||
return '';
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '소재',
|
||||
field: 'MATERIAL',
|
||||
width: 150,
|
||||
headerHozAlign: 'center',
|
||||
headerSort: true,
|
||||
hozAlign: 'center'
|
||||
},
|
||||
{
|
||||
title: '사이즈',
|
||||
field: 'SPEC',
|
||||
width: 150,
|
||||
headerHozAlign: 'center',
|
||||
headerSort: true,
|
||||
hozAlign: 'center'
|
||||
},
|
||||
{
|
||||
title: '소재품번',
|
||||
field: 'MATERIAL_PART_NO',
|
||||
width: 250,
|
||||
headerHozAlign: 'center',
|
||||
headerSort: true,
|
||||
hozAlign: 'left'
|
||||
},
|
||||
{
|
||||
title: '소재소요량',
|
||||
field: 'MATERIAL_REQUIRED_QTY',
|
||||
width: 150,
|
||||
headerHozAlign: 'center',
|
||||
headerSort: true,
|
||||
hozAlign: 'right',
|
||||
formatter: function(cell) {
|
||||
var val = cell.getValue();
|
||||
if(val != null && val !== '') {
|
||||
return Number(val).toLocaleString();
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
],
|
||||
placeholder: "조회 결과가 없습니다."
|
||||
});
|
||||
}
|
||||
|
||||
// 입력 행 추가
|
||||
function fn_addInputRow() {
|
||||
rowSeq++;
|
||||
inputGrid.addRow({
|
||||
ROW_ID: rowSeq,
|
||||
MBOM_OBJID: "",
|
||||
PART_NAME: "",
|
||||
QTY: 1
|
||||
});
|
||||
}
|
||||
|
||||
// 입력 행 삭제
|
||||
function fn_deleteInputRow() {
|
||||
var rows = inputGrid.getRows();
|
||||
var deleteRows = [];
|
||||
|
||||
rows.forEach(function(row) {
|
||||
var el = row.getElement();
|
||||
var checkbox = el.querySelector('.row-check');
|
||||
if(checkbox && checkbox.checked) {
|
||||
deleteRows.push(row);
|
||||
}
|
||||
});
|
||||
|
||||
if(deleteRows.length === 0) {
|
||||
Swal.fire('삭제할 행을 선택해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
deleteRows.forEach(function(row) {
|
||||
row.delete();
|
||||
});
|
||||
}
|
||||
|
||||
// 조회
|
||||
function fn_search() {
|
||||
var inputData = inputGrid.getData();
|
||||
|
||||
// 유효한 입력만 필터링
|
||||
var mbomItems = [];
|
||||
inputData.forEach(function(row) {
|
||||
if(row.MBOM_OBJID && row.QTY > 0) {
|
||||
mbomItems.push({
|
||||
mbomObjid: row.MBOM_OBJID,
|
||||
qty: row.QTY
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if(mbomItems.length === 0) {
|
||||
Swal.fire('M-BOM을 선택하고 수량을 입력해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
// AJAX 조회
|
||||
$.ajax({
|
||||
url: "/productionplanning/getRawMaterialRequirementList.do",
|
||||
type: "POST",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
data: JSON.stringify({mbomItems: mbomItems}),
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
console.log("=== 서버 응답 데이터 ===");
|
||||
console.log("전체 응답:", data);
|
||||
console.log("리스트 개수:", data.list ? data.list.length : 0);
|
||||
console.log("리스트 데이터:", data.list);
|
||||
|
||||
if(data.result === "success") {
|
||||
resultGrid.setData(data.list || []);
|
||||
var cnt = data.list ? data.list.length : 0;
|
||||
$("#resultCnt").text(cnt);
|
||||
|
||||
console.log("그리드 데이터 개수:", resultGrid.getData().length);
|
||||
if(cnt === 0) {
|
||||
Swal.fire({
|
||||
title: '조회 결과 없음',
|
||||
text: '구매품 항목이 없습니다.',
|
||||
icon: 'info'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
Swal.fire('조회 실패: ' + (data.msg || ''));
|
||||
resultGrid.setData([]);
|
||||
$("#resultCnt").text("0");
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error('조회 오류:', error);
|
||||
Swal.fire('조회 중 오류가 발생했습니다.');
|
||||
resultGrid.setData([]);
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<form name="form1" id="form1" method="post">
|
||||
<!-- M-BOM 옵션을 위한 숨김 select -->
|
||||
<select id="MBOM_SELECT_HIDDEN" style="display:none;">
|
||||
<option value="">선택</option>
|
||||
${code_map.mbom_list}
|
||||
</select>
|
||||
|
||||
<div class="content-box">
|
||||
<div class="content-box-s">
|
||||
<div class="plm_menu_name_gdnsi">
|
||||
<h2>
|
||||
<span><%=menuName%></span>
|
||||
</h2>
|
||||
<div class="btnArea">
|
||||
<input type="button" class="plm_btns" value="행 추가" id="btnAddRow">
|
||||
<input type="button" class="plm_btns" value="행 삭제" id="btnDeleteRow">
|
||||
<input type="button" class="plm_btns" value="조회" id="btnSearch">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 입력 영역 -->
|
||||
<div id="plmSearchZon">
|
||||
<div class="section-title">M-BOM 선택 및 수량 입력</div>
|
||||
<div id="inputGrid" style="margin-right: 16px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 결과 그리드 영역 -->
|
||||
<div class="section-title" style="margin-left: 16px;">원자재 소요량 (구매품, 원소재) - 조회결과: <span id="resultCnt">0</span>건</div>
|
||||
<div id="resultGrid" style="margin: 0 16px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,344 @@
|
||||
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||||
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
||||
<%@ page import="com.pms.common.utils.*"%>
|
||||
<%@ page import="java.util.*" %>
|
||||
<%@include file= "/init.jsp" %>
|
||||
<%
|
||||
// DB에서 메뉴명 조회 (공통 유틸 사용)
|
||||
String menuObjId = request.getParameter("menuObjId");
|
||||
String menuName = CommonUtils.getMenuName(menuObjId, "반제품소요량");
|
||||
%>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title><%=Constants.SYSTEM_NAME%></title>
|
||||
<link href="/css/tabulator/tabulator.min.css" rel="stylesheet">
|
||||
<script type="text/javascript" src="/js/tabulator/tabulator.min.js"></script>
|
||||
<style>
|
||||
body, html {
|
||||
overflow-x: hidden;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.section-title {
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
margin: 10px 0 8px 0;
|
||||
color: #333;
|
||||
border-left: 3px solid #3498db;
|
||||
padding-left: 8px;
|
||||
}
|
||||
#inputGrid {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
// 입력 그리드 (M-BOM 선택 + 수량 입력)
|
||||
var inputGrid;
|
||||
// 결과 그리드 (소요량 목록)
|
||||
var resultGrid;
|
||||
// 입력 행 번호
|
||||
var rowSeq = 0;
|
||||
// M-BOM 옵션 데이터
|
||||
var mbomOptionsData = {};
|
||||
|
||||
$(document).ready(function(){
|
||||
$('.select2').select2();
|
||||
|
||||
// M-BOM 옵션 데이터 초기화
|
||||
fn_initMbomOptions();
|
||||
|
||||
// 입력 그리드 초기화
|
||||
fn_initInputGrid();
|
||||
|
||||
// 결과 그리드 초기화
|
||||
fn_initResultGrid();
|
||||
|
||||
// 조회 버튼
|
||||
$("#btnSearch").click(function(){
|
||||
fn_search();
|
||||
});
|
||||
|
||||
// 행 추가 버튼
|
||||
$("#btnAddRow").click(function(){
|
||||
fn_addInputRow();
|
||||
});
|
||||
|
||||
// 행 삭제 버튼
|
||||
$("#btnDeleteRow").click(function(){
|
||||
fn_deleteInputRow();
|
||||
});
|
||||
});
|
||||
|
||||
// M-BOM 옵션 데이터 초기화
|
||||
function fn_initMbomOptions() {
|
||||
mbomOptionsData = {"": "선택"};
|
||||
$("#MBOM_SELECT_HIDDEN option").each(function(){
|
||||
var val = $(this).val();
|
||||
var text = $(this).text();
|
||||
if(val !== '') {
|
||||
mbomOptionsData[val] = text;
|
||||
}
|
||||
});
|
||||
console.log("M-BOM 옵션:", mbomOptionsData);
|
||||
}
|
||||
|
||||
// 입력 그리드 초기화
|
||||
function fn_initInputGrid() {
|
||||
// 초기 데이터 1행 포함
|
||||
var initialData = [{
|
||||
ROW_ID: 1,
|
||||
MBOM_OBJID: "",
|
||||
PART_NAME: "",
|
||||
QTY: 1
|
||||
}];
|
||||
rowSeq = 1;
|
||||
|
||||
inputGrid = new Tabulator("#inputGrid", {
|
||||
data: initialData,
|
||||
layout: "fitColumns",
|
||||
height: "180px",
|
||||
columns: [
|
||||
{
|
||||
title: '',
|
||||
field: 'CHK',
|
||||
width: 40,
|
||||
headerSort: false,
|
||||
hozAlign: 'center',
|
||||
formatter: function(cell) {
|
||||
return '<input type="checkbox" class="row-check">';
|
||||
}
|
||||
},
|
||||
{title: 'ROW_ID', field: 'ROW_ID', visible: false},
|
||||
{
|
||||
title: 'M-BOM 선택',
|
||||
field: 'MBOM_OBJID',
|
||||
headerHozAlign: 'center',
|
||||
headerSort: false,
|
||||
editor: "list",
|
||||
editorParams: function(cell) {
|
||||
return {
|
||||
values: mbomOptionsData,
|
||||
autocomplete: true,
|
||||
clearable: true,
|
||||
listOnEmpty: true
|
||||
};
|
||||
},
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
return mbomOptionsData[value] || "";
|
||||
},
|
||||
cellEdited: function(cell) {
|
||||
// M-BOM 선택 시 품명 자동 입력
|
||||
var mbomObjid = cell.getValue();
|
||||
var row = cell.getRow();
|
||||
if(mbomObjid) {
|
||||
var mbomName = mbomOptionsData[mbomObjid] || "";
|
||||
row.update({PART_NAME: mbomName});
|
||||
} else {
|
||||
row.update({PART_NAME: ""});
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '품명',
|
||||
field: 'PART_NAME',
|
||||
headerHozAlign: 'center',
|
||||
headerSort: false,
|
||||
editor: false
|
||||
},
|
||||
{
|
||||
title: '수량',
|
||||
field: 'QTY',
|
||||
width: 200,
|
||||
headerHozAlign: 'center',
|
||||
headerSort: false,
|
||||
hozAlign: 'right',
|
||||
editor: "number",
|
||||
editorParams: {
|
||||
min: 1,
|
||||
step: 1
|
||||
}
|
||||
}
|
||||
],
|
||||
placeholder: "M-BOM을 선택하고 수량을 입력하세요."
|
||||
});
|
||||
}
|
||||
|
||||
// 결과 그리드 초기화
|
||||
function fn_initResultGrid() {
|
||||
resultGrid = new Tabulator("#resultGrid", {
|
||||
data: [],
|
||||
layout: "fitColumns",
|
||||
height: "calc(100vh - 450px)",
|
||||
columns: [
|
||||
{
|
||||
title: '구분',
|
||||
field: 'CATEGORY_NAME',
|
||||
width: 200,
|
||||
headerHozAlign: 'center',
|
||||
headerSort: true,
|
||||
hozAlign: 'center'
|
||||
},
|
||||
{
|
||||
title: '품번',
|
||||
field: 'PART_NO',
|
||||
width: 320,
|
||||
headerHozAlign: 'center',
|
||||
headerSort: true,
|
||||
hozAlign: 'left'
|
||||
},
|
||||
{
|
||||
title: '품명',
|
||||
field: 'PART_NAME',
|
||||
headerHozAlign: 'center',
|
||||
headerSort: true,
|
||||
hozAlign: 'left'
|
||||
},
|
||||
{
|
||||
title: '소요량',
|
||||
field: 'REQUIRED_QTY',
|
||||
width: 200,
|
||||
headerHozAlign: 'center',
|
||||
headerSort: true,
|
||||
hozAlign: 'right',
|
||||
formatter: function(cell) {
|
||||
var val = cell.getValue();
|
||||
if(val != null && val !== '') {
|
||||
return Number(val).toLocaleString();
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
],
|
||||
placeholder: "조회 결과가 없습니다."
|
||||
});
|
||||
}
|
||||
|
||||
// 입력 행 추가
|
||||
function fn_addInputRow() {
|
||||
rowSeq++;
|
||||
inputGrid.addRow({
|
||||
ROW_ID: rowSeq,
|
||||
MBOM_OBJID: "",
|
||||
PART_NAME: "",
|
||||
QTY: 1
|
||||
});
|
||||
}
|
||||
|
||||
// 입력 행 삭제
|
||||
function fn_deleteInputRow() {
|
||||
var rows = inputGrid.getRows();
|
||||
var deleteRows = [];
|
||||
|
||||
rows.forEach(function(row) {
|
||||
var el = row.getElement();
|
||||
var checkbox = el.querySelector('.row-check');
|
||||
if(checkbox && checkbox.checked) {
|
||||
deleteRows.push(row);
|
||||
}
|
||||
});
|
||||
|
||||
if(deleteRows.length === 0) {
|
||||
Swal.fire('삭제할 행을 선택해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
deleteRows.forEach(function(row) {
|
||||
row.delete();
|
||||
});
|
||||
}
|
||||
|
||||
// 조회
|
||||
function fn_search() {
|
||||
var inputData = inputGrid.getData();
|
||||
|
||||
// 유효한 입력만 필터링
|
||||
var mbomItems = [];
|
||||
inputData.forEach(function(row) {
|
||||
if(row.MBOM_OBJID && row.QTY > 0) {
|
||||
mbomItems.push({
|
||||
mbomObjid: row.MBOM_OBJID,
|
||||
qty: row.QTY
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if(mbomItems.length === 0) {
|
||||
Swal.fire('M-BOM을 선택하고 수량을 입력해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
// AJAX 조회
|
||||
$.ajax({
|
||||
url: "/productionplanning/getSemiProductRequirementList.do",
|
||||
type: "POST",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
data: JSON.stringify({mbomItems: mbomItems}),
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
if(data.result === "success") {
|
||||
resultGrid.setData(data.list || []);
|
||||
var cnt = data.list ? data.list.length : 0;
|
||||
$("#resultCnt").text(cnt);
|
||||
if(cnt === 0) {
|
||||
Swal.fire({
|
||||
title: '조회 결과 없음',
|
||||
text: '부품 또는 조립품 항목이 없습니다.',
|
||||
icon: 'info'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
Swal.fire('조회 실패: ' + (data.msg || ''));
|
||||
resultGrid.setData([]);
|
||||
$("#resultCnt").text("0");
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error('조회 오류:', error);
|
||||
Swal.fire('조회 중 오류가 발생했습니다.');
|
||||
resultGrid.setData([]);
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<form name="form1" id="form1" method="post">
|
||||
<!-- M-BOM 옵션을 위한 숨김 select -->
|
||||
<select id="MBOM_SELECT_HIDDEN" style="display:none;">
|
||||
<option value="">선택</option>
|
||||
${code_map.mbom_list}
|
||||
</select>
|
||||
|
||||
<div class="content-box">
|
||||
<div class="content-box-s">
|
||||
<div class="plm_menu_name_gdnsi">
|
||||
<h2>
|
||||
<span><%=menuName%></span>
|
||||
</h2>
|
||||
<div class="btnArea">
|
||||
<input type="button" class="plm_btns" value="행 추가" id="btnAddRow">
|
||||
<input type="button" class="plm_btns" value="행 삭제" id="btnDeleteRow">
|
||||
<input type="button" class="plm_btns" value="조회" id="btnSearch">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 입력 영역 -->
|
||||
<div id="plmSearchZon">
|
||||
<div class="section-title">M-BOM 선택 및 수량 입력</div>
|
||||
<div id="inputGrid" style="margin-right: 16px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 결과 그리드 영역 -->
|
||||
<div class="section-title" style="margin-left: 16px;">반제품 소요량 (부품/조립품) - 조회결과: <span id="resultCnt">0</span>건</div>
|
||||
<div id="resultGrid" style="margin: 0 16px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -85,7 +85,7 @@ body, html {
|
||||
<tr>
|
||||
<td>
|
||||
<label>프로젝트번호:</label>
|
||||
<span id="infoProjectNo">${resultMap.PROJECT_NO}</span>
|
||||
<span id="infoProjectNo">${resultMap.PROJECT_NUMBER}</span>
|
||||
</td>
|
||||
<td>
|
||||
<label>고객사:</label>
|
||||
@@ -115,7 +115,7 @@ body, html {
|
||||
</td>
|
||||
<td>
|
||||
<label>입고요청일:</label>
|
||||
<span id="infoDeliveryDate">${resultMap.DELIVERY_REQUEST_DATE}</span>
|
||||
<span id="infoDeliveryDate">${resultMap.DUE_DATE}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -134,6 +134,7 @@ var projectMgmtObjid = "${resolvedProjectId}";
|
||||
var bomReportObjid = "${resolvedBomReportObjid}";
|
||||
var mbomHeaderObjid = "${resolvedMbomHeaderObjid}"; // MBOM_HEADER.OBJID (M-BOM 관리 화면에서 사용하는 ID)
|
||||
var vendorList = []; // 공급업체 목록
|
||||
var processingVendorList = []; // 가공업체 목록 (Select2용 배열)
|
||||
|
||||
// 디버그: resultMap 내용 확인 (주석처리)
|
||||
// console.log("=== JSP resultMap 디버그 ===");
|
||||
@@ -156,8 +157,17 @@ function logError(){
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
// 공급업체 목록 먼저 로드
|
||||
// 공급업체 목록 로드 (가공업체도 동일 테이블 사용)
|
||||
fn_loadVendorList(function(){
|
||||
// vendorList에서 processingVendorList 변환 (Select2용 배열 형태)
|
||||
processingVendorList = [];
|
||||
for(var key in vendorList) {
|
||||
if(key !== '') { // 빈 값 제외
|
||||
processingVendorList.push({id: key, text: vendorList[key]});
|
||||
}
|
||||
}
|
||||
console.log("가공업체 목록 변환 완료:", processingVendorList.length + "개");
|
||||
|
||||
fn_initGrid();
|
||||
logDebug("purchaseListFormPopUp :: grid initialized");
|
||||
fn_loadInitialData();
|
||||
@@ -196,6 +206,7 @@ function fn_loadVendorList(callback) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function fn_loadInitialData(){
|
||||
logDebug("purchaseListFormPopUp :: fn_loadInitialData start",
|
||||
"projectMgmtObjid=", projectMgmtObjid,
|
||||
@@ -224,6 +235,62 @@ function fn_loadInitialData(){
|
||||
}
|
||||
}
|
||||
|
||||
// Select2 커스텀 에디터 생성 함수
|
||||
function createSelect2Editor(options) {
|
||||
return function(cell, onRendered, success, cancel, editorParams) {
|
||||
var cellValue = cell.getValue();
|
||||
var container = document.createElement("span");
|
||||
var select = document.createElement("select");
|
||||
select.style.width = "100%";
|
||||
|
||||
// 빈 옵션 추가
|
||||
var emptyOption = document.createElement("option");
|
||||
emptyOption.value = "";
|
||||
emptyOption.text = "선택";
|
||||
select.appendChild(emptyOption);
|
||||
|
||||
// 옵션 추가
|
||||
options.forEach(function(opt) {
|
||||
var option = document.createElement("option");
|
||||
if(typeof opt === 'object') {
|
||||
option.value = opt.id || opt.value || '';
|
||||
option.text = opt.text || opt.label || '';
|
||||
} else {
|
||||
option.value = opt;
|
||||
option.text = opt;
|
||||
}
|
||||
if(option.value == cellValue) {
|
||||
option.selected = true;
|
||||
}
|
||||
select.appendChild(option);
|
||||
});
|
||||
|
||||
container.appendChild(select);
|
||||
|
||||
onRendered(function() {
|
||||
$(select).select2({
|
||||
width: '100%',
|
||||
dropdownAutoWidth: true,
|
||||
allowClear: true,
|
||||
placeholder: '선택'
|
||||
});
|
||||
$(select).select2('open');
|
||||
});
|
||||
|
||||
$(select).on('select2:select select2:clear', function(e) {
|
||||
success($(select).val());
|
||||
});
|
||||
|
||||
$(select).on('select2:close', function() {
|
||||
setTimeout(function() {
|
||||
success($(select).val());
|
||||
}, 100);
|
||||
});
|
||||
|
||||
return container;
|
||||
};
|
||||
}
|
||||
|
||||
// Tabulator 그리드 초기화
|
||||
function fn_initGrid() {
|
||||
var columns = [
|
||||
@@ -462,13 +529,34 @@ function fn_initGrid() {
|
||||
return value ? Number(value).toLocaleString() : '0';
|
||||
}
|
||||
},
|
||||
// 24. 가공업체
|
||||
// 24. 가공업체 (수정가능 - Select2 에디터)
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 150,
|
||||
title: '가공업체',
|
||||
field: 'PROCESSING_VENDOR'
|
||||
title: '<span style="background-color: #FFFF00; padding: 2px 5px;">가공업체</span>',
|
||||
field: 'PROCESSING_VENDOR',
|
||||
editor: function(cell, onRendered, success, cancel, editorParams) {
|
||||
// Select2 에디터
|
||||
return createSelect2Editor(processingVendorList)(cell, onRendered, success, cancel, editorParams);
|
||||
},
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
|
||||
// 저장된 값이 없으면 기본값 '5001'(RPS) 설정
|
||||
if(value === undefined || value === null || value === '') {
|
||||
value = '5001';
|
||||
cell.getRow().update({PROCESSING_VENDOR: value}, false);
|
||||
}
|
||||
|
||||
// OBJID로 업체명 조회하여 표시
|
||||
for(var i = 0; i < processingVendorList.length; i++) {
|
||||
if(processingVendorList[i].id == value) {
|
||||
return processingVendorList[i].text;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
},
|
||||
/* // 25. 가공납기 - 주석처리
|
||||
{
|
||||
@@ -550,28 +638,27 @@ function fn_initGrid() {
|
||||
return value ? Number(value).toLocaleString() : '0';
|
||||
}
|
||||
},
|
||||
// 30. 공급업체 (수정가능 - 기준정보에서 선택)
|
||||
// 30. 공급업체 (수정가능 - Select2 에디터)
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 150,
|
||||
title: '<span style="background-color: #FFFF00; padding: 2px 5px;">공급업체</span>',
|
||||
field: 'VENDOR_PM',
|
||||
editor: 'list',
|
||||
editorParams: function(cell) {
|
||||
return {
|
||||
values: vendorList,
|
||||
autocomplete: true,
|
||||
listOnEmpty: true,
|
||||
freetext: true,
|
||||
allowEmpty: true
|
||||
};
|
||||
editor: function(cell, onRendered, success, cancel, editorParams) {
|
||||
// Select2 에디터 (가공업체와 동일한 목록 사용)
|
||||
return createSelect2Editor(processingVendorList)(cell, onRendered, success, cancel, editorParams);
|
||||
},
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
if(!value) return '';
|
||||
// vendorList에서 해당 값의 이름 찾기
|
||||
return vendorList[value] || value;
|
||||
// processingVendorList에서 해당 값의 이름 찾기
|
||||
for(var i = 0; i < processingVendorList.length; i++) {
|
||||
if(processingVendorList[i].id == value) {
|
||||
return processingVendorList[i].text;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
},
|
||||
// 31. 단가 (수정가능)
|
||||
|
||||
@@ -1853,4 +1853,82 @@ public class ProductionPlanningController extends BaseService {
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 반제품소요량 조회 화면
|
||||
*/
|
||||
@RequestMapping("/productionplanning/semiProductRequirementList.do")
|
||||
public String semiProductRequirementList(HttpServletRequest request, @RequestParam Map<String, Object> paramMap) {
|
||||
Map code_map = new HashMap();
|
||||
try {
|
||||
// M-BOM 목록 (셀렉트박스용)
|
||||
code_map.put("mbom_list", commonService.bizMakeOptionList("", "", "productionplanning.getMbomListForSelect2"));
|
||||
|
||||
request.setAttribute("code_map", code_map);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "/productionplanning/semiProductRequirementList";
|
||||
}
|
||||
|
||||
/**
|
||||
* M-BOM 기준 반제품 소요량 조회
|
||||
* @param request
|
||||
* @param paramMap - mbomItems: [{mbomObjid, qty}, ...]
|
||||
* @return 품번별 합산된 소요량 목록
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping(value="/productionplanning/getSemiProductRequirementList.do", produces="application/json;charset=UTF-8")
|
||||
public Map getSemiProductRequirementList(HttpServletRequest request, @RequestBody Map<String, Object> paramMap) {
|
||||
Map<String, Object> resultMap = new HashMap<String, Object>();
|
||||
try {
|
||||
List list = productionPlanningService.getSemiProductRequirementList(paramMap);
|
||||
resultMap.put("result", "success");
|
||||
resultMap.put("list", list);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
resultMap.put("result", "fail");
|
||||
resultMap.put("msg", "조회 실패: " + e.getMessage());
|
||||
}
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 원자재소요량 조회 화면
|
||||
*/
|
||||
@RequestMapping("/productionplanning/rawMaterialRequirementList.do")
|
||||
public String rawMaterialRequirementList(HttpServletRequest request, @RequestParam Map<String, Object> paramMap) {
|
||||
Map code_map = new HashMap();
|
||||
try {
|
||||
// M-BOM 목록 (셀렉트박스용)
|
||||
code_map.put("mbom_list", commonService.bizMakeOptionList("", "", "productionplanning.getMbomListForSelect2"));
|
||||
|
||||
request.setAttribute("code_map", code_map);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "/productionplanning/rawMaterialRequirementList";
|
||||
}
|
||||
|
||||
/**
|
||||
* M-BOM 기준 원자재(구매품) 소요량 조회
|
||||
* @param request
|
||||
* @param paramMap - mbomItems: [{mbomObjid, qty}, ...]
|
||||
* @return 품번별 합산된 소요량 목록
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping(value="/productionplanning/getRawMaterialRequirementList.do", produces="application/json;charset=UTF-8")
|
||||
public Map getRawMaterialRequirementList(HttpServletRequest request, @RequestBody Map<String, Object> paramMap) {
|
||||
Map<String, Object> resultMap = new HashMap<String, Object>();
|
||||
try {
|
||||
List list = productionPlanningService.getRawMaterialRequirementList(paramMap);
|
||||
resultMap.put("result", "success");
|
||||
resultMap.put("list", list);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
resultMap.put("result", "fail");
|
||||
resultMap.put("msg", "조회 실패: " + e.getMessage());
|
||||
}
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4791,4 +4791,73 @@
|
||||
WHERE OBJID = #{OBJID}
|
||||
</update>
|
||||
|
||||
<!-- M-BOM 반제품 항목 조회 (PART_TYPE이 부품(0001812), 조립품(0001813)인 항목만, 1레벨 제외) -->
|
||||
<select id="getMbomSemiProductItems" parameterType="map" resultType="map">
|
||||
/* productionplanning.getMbomSemiProductItems - M-BOM에서 부품/조립품 조회 (1레벨 제외) */
|
||||
SELECT
|
||||
MD.PART_NO,
|
||||
MD.PART_NAME,
|
||||
COALESCE(MD.QTY, '1')::INTEGER AS ITEM_QTY,
|
||||
P.PART_TYPE,
|
||||
COALESCE((SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = P.PART_TYPE LIMIT 1), '') AS CATEGORY_NAME,
|
||||
COALESCE(P.UNIT, '') AS UNIT,
|
||||
COALESCE(P.MATERIAL, '') AS MATERIAL,
|
||||
COALESCE(P.SPEC, '') AS SPEC
|
||||
FROM MBOM_DETAIL MD
|
||||
INNER JOIN PART_MNG P ON P.OBJID::VARCHAR = MD.PART_OBJID
|
||||
WHERE MD.MBOM_HEADER_OBJID = #{mbomHeaderObjid}
|
||||
AND MD.STATUS = 'ACTIVE'
|
||||
AND (MD.PARENT_OBJID IS NOT NULL AND MD.PARENT_OBJID != '') -- 1레벨 제외 (PARENT_OBJID가 있는 항목만)
|
||||
AND P.PART_TYPE IN ('0001812', '0001813') -- 부품, 조립품
|
||||
ORDER BY P.PART_TYPE, MD.PART_NO
|
||||
</select>
|
||||
|
||||
<!-- M-BOM 원자재(구매품) 항목 조회 (PART_TYPE이 구매품(0000063)인 항목만, 1레벨 제외) -->
|
||||
<select id="getMbomRawMaterialItems" parameterType="map" resultType="map">
|
||||
/* productionplanning.getMbomRawMaterialItems - M-BOM에서 구매품 조회 (1레벨 제외) */
|
||||
SELECT
|
||||
MD.PART_NO,
|
||||
MD.PART_NAME,
|
||||
COALESCE(MD.QTY, '1')::INTEGER AS ITEM_QTY,
|
||||
P.PART_TYPE,
|
||||
COALESCE((SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = P.PART_TYPE LIMIT 1), '') AS CATEGORY_NAME,
|
||||
COALESCE(P.UNIT, '') AS UNIT,
|
||||
COALESCE(P.MATERIAL, '') AS MATERIAL,
|
||||
COALESCE(P.SPEC, '') AS SPEC,
|
||||
'' AS RAW_MATERIAL,
|
||||
'' AS RAW_MATERIAL_SIZE,
|
||||
'' AS RAW_MATERIAL_PART_NO,
|
||||
0 AS RAW_MATERIAL_QTY
|
||||
FROM MBOM_DETAIL MD
|
||||
INNER JOIN PART_MNG P ON P.OBJID::VARCHAR = MD.PART_OBJID
|
||||
WHERE MD.MBOM_HEADER_OBJID = #{mbomHeaderObjid}
|
||||
AND MD.STATUS = 'ACTIVE'
|
||||
AND (MD.PARENT_OBJID IS NOT NULL AND MD.PARENT_OBJID != '') -- 1레벨 제외 (PARENT_OBJID가 있는 항목만)
|
||||
AND P.PART_TYPE = '0000063' -- 구매품
|
||||
ORDER BY MD.PART_NO
|
||||
</select>
|
||||
|
||||
<!-- M-BOM 원소재 항목 조회 (RAW_MATERIAL_PART_NO가 있는 항목만) -->
|
||||
<select id="getMbomRawSourceItems" parameterType="map" resultType="map">
|
||||
/* productionplanning.getMbomRawSourceItems - M-BOM에서 원소재 조회 */
|
||||
SELECT
|
||||
MD.RAW_MATERIAL_PART_NO AS PART_NO,
|
||||
MD.RAW_MATERIAL AS PART_NAME,
|
||||
COALESCE(MD.REQUIRED_QTY, '0')::NUMERIC AS ITEM_QTY,
|
||||
'원소재' AS CATEGORY_NAME,
|
||||
'' AS UNIT,
|
||||
MD.RAW_MATERIAL AS MATERIAL,
|
||||
MD.RAW_MATERIAL_SIZE AS SPEC,
|
||||
MD.RAW_MATERIAL,
|
||||
MD.RAW_MATERIAL_SIZE,
|
||||
MD.RAW_MATERIAL_PART_NO,
|
||||
COALESCE(MD.REQUIRED_QTY, '0')::NUMERIC AS RAW_MATERIAL_QTY
|
||||
FROM MBOM_DETAIL MD
|
||||
WHERE MD.MBOM_HEADER_OBJID = #{mbomHeaderObjid}
|
||||
AND MD.STATUS = 'ACTIVE'
|
||||
AND MD.RAW_MATERIAL_PART_NO IS NOT NULL
|
||||
AND MD.RAW_MATERIAL_PART_NO != ''
|
||||
ORDER BY MD.RAW_MATERIAL_PART_NO
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -665,6 +665,9 @@ VALUES
|
||||
SRM.PROJECT_NO,
|
||||
PM.PROJECT_NO AS PROJECT_NUMBER,
|
||||
PM.PROJECT_NAME,
|
||||
PM.PART_NO,
|
||||
PM.PART_NAME,
|
||||
PM.DUE_DATE,
|
||||
COALESCE(
|
||||
PM.OBJID,
|
||||
(SELECT OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1)
|
||||
@@ -718,9 +721,9 @@ VALUES
|
||||
COALESCE(NULLIF(SRM.AREA_CD, ''), SM.AREA_CD) AS AREA_CD, -- 국내/해외
|
||||
COALESCE(NULLIF(SRM.CUSTOMER_OBJID, ''), SM.OBJID::VARCHAR) AS CUSTOMER_OBJID, -- 고객사
|
||||
COALESCE(NULLIF(SRM.PAID_TYPE, ''), CM.PAID_TYPE) AS PAID_TYPE, -- 유/무상
|
||||
CM.CATEGORY_CD AS CATEGORY_CD, -- 제품유형 코드 ID (드롭다운 선택용)
|
||||
CM.CATEGORY_CD AS CATEGORY_CD -- 제품유형 코드 ID (드롭다운 선택용)
|
||||
-- 품번/품명: 첫 번째 품목 + 외 N건 형태
|
||||
(SELECT
|
||||
<!-- (SELECT
|
||||
CASE
|
||||
WHEN (SELECT COUNT(*) FROM SALES_REQUEST_PART WHERE SALES_REQUEST_MASTER_OBJID = SRM.OBJID) > 1 THEN
|
||||
COALESCE((SELECT PM2.PART_NO FROM PART_MNG PM2 WHERE PM2.OBJID::VARCHAR = (SELECT PART_OBJID FROM SALES_REQUEST_PART WHERE SALES_REQUEST_MASTER_OBJID = SRM.OBJID ORDER BY REGDATE LIMIT 1)), '') || ' 외 ' || ((SELECT COUNT(*) FROM SALES_REQUEST_PART WHERE SALES_REQUEST_MASTER_OBJID = SRM.OBJID) - 1)::TEXT || '건'
|
||||
@@ -735,7 +738,7 @@ VALUES
|
||||
ELSE
|
||||
COALESCE((SELECT PM2.PART_NAME FROM PART_MNG PM2 WHERE PM2.OBJID::VARCHAR = (SELECT PART_OBJID FROM SALES_REQUEST_PART WHERE SALES_REQUEST_MASTER_OBJID = SRM.OBJID ORDER BY REGDATE LIMIT 1)), '')
|
||||
END
|
||||
) AS PART_NAME
|
||||
) AS PART_NAME -->
|
||||
|
||||
FROM
|
||||
SALES_REQUEST_MASTER SRM
|
||||
@@ -3084,7 +3087,7 @@ UPDATE SET
|
||||
0 AS ORDER_QTY,
|
||||
0 AS ITEM_QTY2,
|
||||
0 AS PRODUCTION_QTY,
|
||||
'' AS PROCESSING_VENDOR,
|
||||
COALESCE(SRP.PROCESSING_VENDOR, '') AS PROCESSING_VENDOR,
|
||||
NULL AS PROCESSING_DEADLINE,
|
||||
NULL AS GRINDING_DEADLINE,
|
||||
-- 구매 관련 컬럼 (SALES_REQUEST_PART에서 조회)
|
||||
@@ -3376,6 +3379,7 @@ ORDER BY V.PATH2
|
||||
NET_QTY = COALESCE(NULLIF(TRIM(#{NET_QTY}::TEXT), '')::NUMERIC, 0),
|
||||
PO_QTY = COALESCE(NULLIF(TRIM(#{PO_QTY}::TEXT), '')::NUMERIC, 0),
|
||||
VENDOR = #{VENDOR_PM},
|
||||
PROCESSING_VENDOR = #{PROCESSING_VENDOR},
|
||||
UNIT_PRICE = COALESCE(NULLIF(TRIM(#{UNIT_PRICE}::TEXT), '')::NUMERIC, 0),
|
||||
TOTAL_PRICE = COALESCE(NULLIF(TRIM(#{TOTAL_PRICE}::TEXT), '')::NUMERIC, 0),
|
||||
EDITER = #{EDITER},
|
||||
@@ -3390,6 +3394,7 @@ ORDER BY V.PATH2
|
||||
NET_QTY = COALESCE(NULLIF(TRIM(#{NET_QTY}::TEXT), '')::NUMERIC, 0),
|
||||
PO_QTY = COALESCE(NULLIF(TRIM(#{PO_QTY}::TEXT), '')::NUMERIC, 0),
|
||||
VENDOR_PM = #{VENDOR_PM},
|
||||
PROCESSING_VENDOR = #{PROCESSING_VENDOR},
|
||||
UNIT_PRICE = COALESCE(NULLIF(TRIM(#{UNIT_PRICE}::TEXT), '')::NUMERIC, 0),
|
||||
TOTAL_PRICE = COALESCE(NULLIF(TRIM(#{TOTAL_PRICE}::TEXT), '')::NUMERIC, 0),
|
||||
WRITER = #{EDITER}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.pms.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -1827,4 +1828,278 @@ public class ProductionPlanningService {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* M-BOM 기준 반제품 소요량 조회
|
||||
* - 여러 M-BOM을 입력받아 범주가 '부품', '조립품'인 항목만 조회
|
||||
* - 동일 품번은 합산하여 반환
|
||||
* @param paramMap - mbomItems: [{mbomObjid, qty}, ...]
|
||||
* @return 품번별 합산된 소요량 목록
|
||||
*/
|
||||
public List getSemiProductRequirementList(Map paramMap) {
|
||||
SqlSession sqlSession = null;
|
||||
List resultList = new ArrayList();
|
||||
|
||||
try {
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession();
|
||||
|
||||
// 입력받은 M-BOM 목록
|
||||
List<Map<String, Object>> mbomItems = (List<Map<String, Object>>) paramMap.get("mbomItems");
|
||||
if(mbomItems == null || mbomItems.isEmpty()) {
|
||||
return resultList;
|
||||
}
|
||||
|
||||
// 품번별 소요량을 합산하기 위한 Map (key: PART_NO, value: {품번정보, 소요량합계})
|
||||
Map<String, Map<String, Object>> partNoMap = new LinkedHashMap<>();
|
||||
|
||||
// 각 M-BOM별로 조회하여 합산
|
||||
for(Map<String, Object> mbomItem : mbomItems) {
|
||||
String mbomObjid = CommonUtils.nullToEmpty((String)mbomItem.get("mbomObjid"));
|
||||
int inputQty = 0;
|
||||
Object qtyObj = mbomItem.get("qty");
|
||||
if(qtyObj != null) {
|
||||
if(qtyObj instanceof Number) {
|
||||
inputQty = ((Number)qtyObj).intValue();
|
||||
} else {
|
||||
try {
|
||||
inputQty = Integer.parseInt(qtyObj.toString());
|
||||
} catch(NumberFormatException e) {
|
||||
inputQty = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if("".equals(mbomObjid) || inputQty <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// M-BOM 항목 조회 (범주가 '부품', '조립품'인 것만)
|
||||
Map<String, Object> queryParam = new HashMap<>();
|
||||
queryParam.put("mbomHeaderObjid", mbomObjid);
|
||||
List<Map<String, Object>> bomItems = sqlSession.selectList("productionplanning.getMbomSemiProductItems", queryParam);
|
||||
|
||||
// 소요량 합산 (PostgreSQL은 소문자 키로 반환)
|
||||
for(Map<String, Object> bomItem : bomItems) {
|
||||
String partNo = CommonUtils.nullToEmpty((String)bomItem.get("part_no"));
|
||||
if("".equals(partNo)) continue;
|
||||
|
||||
// M-BOM의 항목수량
|
||||
int itemQty = 0;
|
||||
Object itemQtyObj = bomItem.get("item_qty");
|
||||
if(itemQtyObj != null) {
|
||||
if(itemQtyObj instanceof Number) {
|
||||
itemQty = ((Number)itemQtyObj).intValue();
|
||||
} else {
|
||||
try {
|
||||
itemQty = Integer.parseInt(itemQtyObj.toString());
|
||||
} catch(NumberFormatException e) {
|
||||
itemQty = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 소요량 = 입력수량 × 항목수량
|
||||
int requiredQty = inputQty * itemQty;
|
||||
|
||||
if(partNoMap.containsKey(partNo)) {
|
||||
// 기존 품번이면 소요량만 합산
|
||||
Map<String, Object> existingItem = partNoMap.get(partNo);
|
||||
int existingQty = (Integer)existingItem.get("REQUIRED_QTY");
|
||||
existingItem.put("REQUIRED_QTY", existingQty + requiredQty);
|
||||
} else {
|
||||
// 새로운 품번이면 추가
|
||||
Map<String, Object> newItem = new LinkedHashMap<>();
|
||||
newItem.put("PART_NO", partNo);
|
||||
newItem.put("PART_NAME", bomItem.get("part_name"));
|
||||
newItem.put("CATEGORY_NAME", bomItem.get("category_name"));
|
||||
newItem.put("UNIT", bomItem.get("unit"));
|
||||
newItem.put("MATERIAL", bomItem.get("material"));
|
||||
newItem.put("SPEC", bomItem.get("spec"));
|
||||
newItem.put("REQUIRED_QTY", requiredQty);
|
||||
partNoMap.put(partNo, newItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Map -> List 변환
|
||||
resultList = new ArrayList(partNoMap.values());
|
||||
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if(sqlSession != null) {
|
||||
sqlSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* M-BOM 기준 원자재(구매품 + 원소재) 소요량 조회
|
||||
* - 여러 M-BOM을 입력받아 PART_TYPE이 '0000063'(구매품)인 항목 조회
|
||||
* - RAW_MATERIAL_PART_NO가 있는 항목은 "원소재"로 별도 조회
|
||||
* - 동일 품번은 합산하여 반환
|
||||
* @param paramMap - mbomItems: [{mbomObjid, qty}, ...]
|
||||
* @return 품번별 합산된 소요량 목록
|
||||
*/
|
||||
public List getRawMaterialRequirementList(Map paramMap) {
|
||||
SqlSession sqlSession = null;
|
||||
List resultList = new ArrayList();
|
||||
|
||||
try {
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession();
|
||||
|
||||
// 입력받은 M-BOM 목록
|
||||
List<Map<String, Object>> mbomItems = (List<Map<String, Object>>) paramMap.get("mbomItems");
|
||||
if(mbomItems == null || mbomItems.isEmpty()) {
|
||||
return resultList;
|
||||
}
|
||||
|
||||
// 구매품 품번별 소요량 Map
|
||||
Map<String, Map<String, Object>> purchasePartNoMap = new LinkedHashMap<>();
|
||||
// 원소재 품번별 소요량 Map
|
||||
Map<String, Map<String, Object>> rawSourcePartNoMap = new LinkedHashMap<>();
|
||||
|
||||
// 각 M-BOM별로 조회하여 합산
|
||||
for(Map<String, Object> mbomItem : mbomItems) {
|
||||
String mbomObjid = CommonUtils.nullToEmpty((String)mbomItem.get("mbomObjid"));
|
||||
int inputQty = 0;
|
||||
Object qtyObj = mbomItem.get("qty");
|
||||
if(qtyObj != null) {
|
||||
if(qtyObj instanceof Number) {
|
||||
inputQty = ((Number)qtyObj).intValue();
|
||||
} else {
|
||||
try {
|
||||
inputQty = Integer.parseInt(qtyObj.toString());
|
||||
} catch(NumberFormatException e) {
|
||||
inputQty = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if("".equals(mbomObjid) || inputQty <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Map<String, Object> queryParam = new HashMap<>();
|
||||
queryParam.put("mbomHeaderObjid", mbomObjid);
|
||||
|
||||
// 1. 구매품 조회
|
||||
List<Map<String, Object>> purchaseItems = sqlSession.selectList("productionplanning.getMbomRawMaterialItems", queryParam);
|
||||
for(Map<String, Object> bomItem : purchaseItems) {
|
||||
String partNo = CommonUtils.nullToEmpty((String)bomItem.get("part_no"));
|
||||
if("".equals(partNo)) continue;
|
||||
|
||||
int itemQty = getIntValue(bomItem.get("item_qty"));
|
||||
int requiredQty = inputQty * itemQty;
|
||||
|
||||
if(purchasePartNoMap.containsKey(partNo)) {
|
||||
Map<String, Object> existingItem = purchasePartNoMap.get(partNo);
|
||||
int existingQty = (Integer)existingItem.get("REQUIRED_QTY");
|
||||
existingItem.put("REQUIRED_QTY", existingQty + requiredQty);
|
||||
} else {
|
||||
Map<String, Object> newItem = new LinkedHashMap<>();
|
||||
newItem.put("PART_NO", partNo);
|
||||
newItem.put("PART_NAME", bomItem.get("part_name"));
|
||||
newItem.put("CATEGORY_NAME", bomItem.get("category_name"));
|
||||
newItem.put("UNIT", bomItem.get("unit"));
|
||||
// 구매품은 소재 관련 컬럼 전부 빈값
|
||||
newItem.put("MATERIAL", "");
|
||||
newItem.put("SPEC", "");
|
||||
newItem.put("REQUIRED_QTY", requiredQty);
|
||||
newItem.put("RAW_MATERIAL", "");
|
||||
newItem.put("RAW_MATERIAL_SIZE", "");
|
||||
newItem.put("MATERIAL_PART_NO", "");
|
||||
newItem.put("MATERIAL_REQUIRED_QTY", "");
|
||||
purchasePartNoMap.put(partNo, newItem);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 원소재 조회 (RAW_MATERIAL_PART_NO가 있는 항목)
|
||||
// 원소재는 소재품번 기준으로 합산 (소수점 합산 후 올림)
|
||||
List<Map<String, Object>> rawSourceItems = sqlSession.selectList("productionplanning.getMbomRawSourceItems", queryParam);
|
||||
for(Map<String, Object> bomItem : rawSourceItems) {
|
||||
String materialPartNo = CommonUtils.nullToEmpty((String)bomItem.get("raw_material_part_no"));
|
||||
if("".equals(materialPartNo)) continue;
|
||||
|
||||
double itemQty = getDoubleValue(bomItem.get("item_qty"));
|
||||
double requiredQty = inputQty * itemQty;
|
||||
|
||||
if(rawSourcePartNoMap.containsKey(materialPartNo)) {
|
||||
Map<String, Object> existingItem = rawSourcePartNoMap.get(materialPartNo);
|
||||
double existingQty = (Double)existingItem.get("MATERIAL_REQUIRED_QTY_RAW");
|
||||
existingItem.put("MATERIAL_REQUIRED_QTY_RAW", existingQty + requiredQty);
|
||||
} else {
|
||||
Map<String, Object> newItem = new LinkedHashMap<>();
|
||||
// 원소재는 품번, 품명, 소요량 빈값
|
||||
newItem.put("PART_NO", "");
|
||||
newItem.put("PART_NAME", "");
|
||||
newItem.put("CATEGORY_NAME", "원소재");
|
||||
newItem.put("UNIT", "");
|
||||
newItem.put("MATERIAL", bomItem.get("raw_material"));
|
||||
newItem.put("SPEC", bomItem.get("raw_material_size"));
|
||||
newItem.put("REQUIRED_QTY", "");
|
||||
// 원소재 관련 컬럼만 표시
|
||||
newItem.put("RAW_MATERIAL", bomItem.get("raw_material"));
|
||||
newItem.put("RAW_MATERIAL_SIZE", bomItem.get("raw_material_size"));
|
||||
newItem.put("MATERIAL_PART_NO", materialPartNo);
|
||||
newItem.put("MATERIAL_REQUIRED_QTY_RAW", requiredQty); // 합산용 (소수점)
|
||||
rawSourcePartNoMap.put(materialPartNo, newItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 구매품 먼저 추가
|
||||
resultList.addAll(purchasePartNoMap.values());
|
||||
|
||||
// 원소재는 소수점 합산 후 올림 처리하여 추가
|
||||
for(Map<String, Object> item : rawSourcePartNoMap.values()) {
|
||||
double rawQty = (Double)item.get("MATERIAL_REQUIRED_QTY_RAW");
|
||||
int ceilQty = (int)Math.ceil(rawQty); // 올림 처리
|
||||
item.put("MATERIAL_REQUIRED_QTY", ceilQty);
|
||||
item.remove("MATERIAL_REQUIRED_QTY_RAW"); // 임시 필드 제거
|
||||
resultList.add(item);
|
||||
}
|
||||
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if(sqlSession != null) {
|
||||
sqlSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Object를 int로 변환하는 유틸 메서드
|
||||
*/
|
||||
private int getIntValue(Object obj) {
|
||||
if(obj == null) return 0;
|
||||
if(obj instanceof Number) {
|
||||
return ((Number)obj).intValue();
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(obj.toString());
|
||||
} catch(NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Object를 double로 변환하는 유틸 메서드
|
||||
*/
|
||||
private double getDoubleValue(Object obj) {
|
||||
if(obj == null) return 0.0;
|
||||
if(obj instanceof Number) {
|
||||
return ((Number)obj).doubleValue();
|
||||
}
|
||||
try {
|
||||
return Double.parseDouble(obj.toString());
|
||||
} catch(NumberFormatException e) {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user