Merge pull request 'V20260210' (#172) from V20260210 into main
Reviewed-on: #172
This commit was merged in pull request #172.
This commit is contained in:
@@ -369,13 +369,13 @@ $(function(){
|
||||
fn_calculateTotal(); // 합계 재계산
|
||||
});
|
||||
|
||||
// 단가 입력 완료 시 콤마 자동 추가
|
||||
// 단가 입력 완료 시 포맷 적용
|
||||
$(document).on("blur", ".item-price", function(){
|
||||
var val = $(this).val().replace(/,/g, "");
|
||||
if(!isNaN(val) && val !== "") {
|
||||
$(this).val(addComma(val));
|
||||
$(this).val(Number(val).toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 2}));
|
||||
}
|
||||
fn_calculateTotal(); // blur 시에도 합계 재계산
|
||||
fn_calculateTotal();
|
||||
});
|
||||
|
||||
// 단가 입력 시 숫자만 입력 가능하도록 제한 및 실시간 콤마 처리
|
||||
@@ -384,8 +384,8 @@ $(function(){
|
||||
var originalVal = $(this).val();
|
||||
var commasBefore = (originalVal.substring(0, cursorPos).match(/,/g) || []).length;
|
||||
|
||||
// 콤마 제거 후 숫자가 아닌 문자 제거
|
||||
var val = originalVal.replace(/,/g, "").replace(/[^0-9]/g, "");
|
||||
// 콤마 제거 후 숫자와 소수점 외 문자 제거
|
||||
var val = originalVal.replace(/,/g, "").replace(/[^0-9.]/g, "");
|
||||
|
||||
// 값 설정 (빈 문자열 포함)
|
||||
if(val !== "") {
|
||||
@@ -468,7 +468,7 @@ function fn_calculateAmount(row) {
|
||||
var qty = row.find(".item-qty").val().replace(/,/g, "") || "0";
|
||||
var price = row.find(".item-price").val().replace(/,/g, "") || "0";
|
||||
|
||||
var amount = parseInt(qty) * parseInt(price);
|
||||
var amount = parseFloat(qty) * parseFloat(price);
|
||||
if(!isNaN(amount)) {
|
||||
var currencySymbol = getCurrencySymbol();
|
||||
row.find(".item-amount").val(currencySymbol + addComma(amount));
|
||||
@@ -482,9 +482,9 @@ function fn_calculateTotal() {
|
||||
// 품목 행만 순회 (계 행, 원화환산 행, 비고 행, 참조사항 행, 회사명 행 제외)
|
||||
$("#itemsTableBody tr").not(".total-row, .total-krw-row, .remarks-row, .notes-row, .footer-row").each(function(){
|
||||
var amount = $(this).find(".item-amount").val() || "0";
|
||||
// 모든 비숫자 문자 제거 (통화 기호, 콤마 등)
|
||||
amount = amount.replace(/[^0-9]/g, "");
|
||||
var numAmount = parseInt(amount) || 0;
|
||||
// 모든 비숫자 문자 제거 (통화 기호, 콤마 등, 소수점은 유지)
|
||||
amount = amount.replace(/[^0-9.]/g, "");
|
||||
var numAmount = parseFloat(amount) || 0;
|
||||
total += numAmount;
|
||||
});
|
||||
|
||||
@@ -499,13 +499,13 @@ function fn_calculateTotal() {
|
||||
// 원화환산 공급가액 계산
|
||||
function fn_calculateTotalKRW(total) {
|
||||
var totalKRW = total * g_exchangeRate;
|
||||
$("#totalAmountKRW").text("₩" + addComma(Math.round(totalKRW)));
|
||||
$("#totalAmountKRW").text("₩" + addComma(totalKRW));
|
||||
}
|
||||
|
||||
// 콤마 추가
|
||||
// 금액 포맷 (소수점 2자리 + 천단위 콤마)
|
||||
function addComma(num) {
|
||||
var regexp = /\B(?=(\d{3})+(?!\d))/g;
|
||||
return num.toString().replace(regexp, ',');
|
||||
if(num === '' || num === null || num === undefined) return '';
|
||||
return Number(num).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
|
||||
// 통화 기호 반환
|
||||
@@ -1262,8 +1262,8 @@ function fn_save() {
|
||||
specification: row.find(".item-spec").val() || "",
|
||||
quantity: quantity.replace(/[^0-9]/g, ""), // 숫자만 추출
|
||||
unit: row.find(".item-unit").val() || "",
|
||||
unit_price: unitPrice.replace(/[^0-9]/g, ""), // 숫자만 추출
|
||||
amount: amount.replace(/[^0-9]/g, ""), // 숫자만 추출
|
||||
unit_price: unitPrice.replace(/[^0-9.]/g, ""),
|
||||
amount: amount.replace(/[^0-9.]/g, ""),
|
||||
note: row.find(".item-note").val() || ""
|
||||
});
|
||||
});
|
||||
|
||||
@@ -403,11 +403,11 @@ $(function(){
|
||||
}
|
||||
}
|
||||
|
||||
// 숫자만 입력 가능하도록 제한 (unit_price, subtotal)
|
||||
// 숫자와 소수점만 입력 가능하도록 제한 (unit_price, subtotal)
|
||||
$(document).on("keypress", ".item-price, .subtotal-amount", function(e) {
|
||||
// 숫자(0-9), 백스페이스, 삭제, 탭, 엔터, 콤마만 허용
|
||||
var charCode = (e.which) ? e.which : e.keyCode;
|
||||
if (charCode != 8 && charCode != 9 && charCode != 13 && charCode != 44 &&
|
||||
// 숫자(0-9), 백스페이스, 삭제, 탭, 엔터, 콤마, 소수점(46) 허용
|
||||
if (charCode != 8 && charCode != 9 && charCode != 13 && charCode != 44 && charCode != 46 &&
|
||||
(charCode < 48 || charCode > 57)) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
@@ -508,7 +508,7 @@ function fn_calculateAmount(row) {
|
||||
var qty = row.find(".item-qty").val() || "1";
|
||||
var price = row.find(".item-price").val().replace(/,/g, "") || "0";
|
||||
|
||||
var amount = parseInt(qty) * parseInt(price);
|
||||
var amount = parseFloat(qty) * parseFloat(price);
|
||||
if(!isNaN(amount)) {
|
||||
row.find(".item-amount").val(addComma(amount));
|
||||
}
|
||||
@@ -520,7 +520,7 @@ function fn_calculateSubtotal(tbody) {
|
||||
tbody.find("tr:not(.category-row):not(.subtotal-row)").each(function() {
|
||||
var amount = $(this).find(".item-amount").val();
|
||||
if(amount) {
|
||||
var numAmount = parseInt(amount.replace(/,/g, "").replace(/-/g, ""));
|
||||
var numAmount = parseFloat(amount.replace(/,/g, "").replace(/-/g, ""));
|
||||
if(!isNaN(numAmount)) {
|
||||
total += numAmount;
|
||||
}
|
||||
@@ -530,10 +530,10 @@ function fn_calculateSubtotal(tbody) {
|
||||
tbody.find(".subtotal-amount").val(addComma(total));
|
||||
}
|
||||
|
||||
// 콤마 추가
|
||||
// 금액 포맷 (소수점 2자리 + 천단위 콤마)
|
||||
function addComma(num) {
|
||||
var regexp = /\B(?=(\d{3})+(?!\d))/g;
|
||||
return num.toString().replace(regexp, ',');
|
||||
if(num === '' || num === null || num === undefined) return '';
|
||||
return Number(num).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
|
||||
// 카테고리 추가
|
||||
@@ -709,7 +709,7 @@ function fn_calculateTotal() {
|
||||
// 초음파 CNC Machine의 AMOUNT 값 추가
|
||||
var cncAmount = $(".category-section[data-category='cnc_machine'] .item-amount").val();
|
||||
if(cncAmount && cncAmount !== "") {
|
||||
var numVal = parseInt(cncAmount.replace(/,/g, ""));
|
||||
var numVal = parseFloat(cncAmount.replace(/,/g, ""));
|
||||
if(!isNaN(numVal)) {
|
||||
total += numVal;
|
||||
}
|
||||
@@ -719,7 +719,7 @@ function fn_calculateTotal() {
|
||||
$(".subtotal-amount").each(function() {
|
||||
var val = $(this).val();
|
||||
if(val && val !== "" && val !== "-") {
|
||||
var numVal = parseInt(val.replace(/,/g, ""));
|
||||
var numVal = parseFloat(val.replace(/,/g, ""));
|
||||
if(!isNaN(numVal)) {
|
||||
total += numVal;
|
||||
}
|
||||
@@ -1000,7 +1000,7 @@ function fn_save() {
|
||||
// 원화 환산 (TOTAL_AMOUNT_KRW)
|
||||
var totalAmountKrw = "";
|
||||
if(totalAmount && totalAmount !== "" && !isNaN(totalAmount)) {
|
||||
totalAmountKrw = Math.round(parseFloat(totalAmount) * exchangeRate).toString();
|
||||
totalAmountKrw = (parseFloat(totalAmount) * exchangeRate).toFixed(2);
|
||||
}
|
||||
|
||||
var formData = {
|
||||
|
||||
@@ -374,7 +374,7 @@ function fn_renderOrderForm(info, items){
|
||||
}
|
||||
|
||||
function fn_fmt(n){
|
||||
return Number(n).toLocaleString();
|
||||
return Number(n).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -250,7 +250,7 @@ var columns = [
|
||||
else if(currencyName.includes('유로') || currencyName === 'EUR') currencySymbol = '€';
|
||||
else if(currencyName.includes('엔') || currencyName === 'JPY') currencySymbol = '¥';
|
||||
else if(currencyName.includes('위안') || currencyName === 'CNY') currencySymbol = '¥';
|
||||
return currencySymbol + Number(value).toLocaleString();
|
||||
return currencySymbol + Number(value).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
},
|
||||
// 12. 부가세
|
||||
@@ -266,7 +266,7 @@ var columns = [
|
||||
else if(currencyName.includes('유로') || currencyName === 'EUR') currencySymbol = '€';
|
||||
else if(currencyName.includes('엔') || currencyName === 'JPY') currencySymbol = '¥';
|
||||
else if(currencyName.includes('위안') || currencyName === 'CNY') currencySymbol = '¥';
|
||||
return currencySymbol + Number(value).toLocaleString();
|
||||
return currencySymbol + Number(value).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
},
|
||||
// 13. 총액
|
||||
@@ -282,7 +282,7 @@ var columns = [
|
||||
else if(currencyName.includes('유로') || currencyName === 'EUR') currencySymbol = '€';
|
||||
else if(currencyName.includes('엔') || currencyName === 'JPY') currencySymbol = '¥';
|
||||
else if(currencyName.includes('위안') || currencyName === 'CNY') currencySymbol = '¥';
|
||||
return currencySymbol + Number(value).toLocaleString();
|
||||
return currencySymbol + Number(value).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
},
|
||||
// 14. 원화총액
|
||||
@@ -290,7 +290,7 @@ var columns = [
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
if(!value || value === '' || value === '0') return '';
|
||||
return '₩' + Number(value).toLocaleString();
|
||||
return '₩' + Number(value).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
},
|
||||
// 15. 주문서첨부
|
||||
@@ -421,7 +421,7 @@ function fn_calculateTotalFromGrid(){
|
||||
}
|
||||
|
||||
console.log("✅ [주문서관리] 표시된 데이터 합계:", totalAmountKRW);
|
||||
$("#totalAmount").text(Number(totalAmountKRW).toLocaleString());
|
||||
$("#totalAmount").text(Number(totalAmountKRW).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}));
|
||||
}
|
||||
|
||||
function _fnc_datepick(){
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
|
||||
// 숫자 입력 필드에 콤마 자동 추가 및 금액 계산
|
||||
$(document).on("keyup", "input:text[numberOnly]", function() {
|
||||
$(this).val(addComma($(this).val().replace(/[^0-9]/g, "")));
|
||||
$(this).val(addComma($(this).val().replace(/[^0-9.]/g, "")));
|
||||
|
||||
var itemId = $(this).closest("tr").attr("id");
|
||||
if(itemId) {
|
||||
@@ -95,10 +95,10 @@
|
||||
fn_loadContractItems();
|
||||
});
|
||||
|
||||
// 콤마 추가 함수
|
||||
// 금액 포맷 (소수점 2자리 + 천단위 콤마)
|
||||
function addComma(data) {
|
||||
if(!data) return '';
|
||||
return data.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
if(!data && data !== 0) return '';
|
||||
return Number(data).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
|
||||
// 콤마 제거 함수
|
||||
@@ -148,15 +148,15 @@
|
||||
// 부가세 입력 가능 (기본값: 공급가액 × 10%)
|
||||
// 공급가액 + 부가세 = 총액 (자동)
|
||||
function fn_calculateItemAmount(itemId) {
|
||||
var quantity = parseInt(removeComma($("#" + itemId + " .item-quantity").val())) || 0;
|
||||
var unitPrice = parseInt(removeComma($("#" + itemId + " .item-unit-price").val())) || 0;
|
||||
var quantity = parseFloat(removeComma($("#" + itemId + " .item-quantity").val())) || 0;
|
||||
var unitPrice = parseFloat(removeComma($("#" + itemId + " .item-unit-price").val())) || 0;
|
||||
|
||||
// 공급가액 계산
|
||||
var supplyPrice = quantity * unitPrice;
|
||||
$("#" + itemId + " .item-supply-price").val(addComma(supplyPrice));
|
||||
|
||||
// 부가세 자동 계산 (공급가액의 10%)
|
||||
var vat = Math.round(supplyPrice * 0.1);
|
||||
var vat = supplyPrice * 0.1;
|
||||
$("#" + itemId + " .item-vat").val(addComma(vat));
|
||||
|
||||
// 총액 계산
|
||||
@@ -166,8 +166,8 @@
|
||||
|
||||
// 부가세 직접 입력 시 총액만 재계산
|
||||
function fn_calculateTotalFromVat(itemId) {
|
||||
var supplyPrice = parseInt(removeComma($("#" + itemId + " .item-supply-price").val())) || 0;
|
||||
var vat = parseInt(removeComma($("#" + itemId + " .item-vat").val())) || 0;
|
||||
var supplyPrice = parseFloat(removeComma($("#" + itemId + " .item-supply-price").val())) || 0;
|
||||
var vat = parseFloat(removeComma($("#" + itemId + " .item-vat").val())) || 0;
|
||||
|
||||
// 총액 계산
|
||||
var totalAmount = supplyPrice + vat;
|
||||
|
||||
@@ -91,6 +91,9 @@ var materialList = [];
|
||||
// 공급업체(가공업체) 목록 전역 변수
|
||||
var supplyVendorList = [];
|
||||
|
||||
// 환종 목록 전역 변수
|
||||
var currencyList = [];
|
||||
|
||||
$(function(){
|
||||
// 최상위 프레임(mBomPopupHeaderFs.jsp)에서 프로젝트 수주수량 가져오기
|
||||
try {
|
||||
@@ -118,6 +121,9 @@ $(function(){
|
||||
// 공급업체(가공업체) 목록 로드
|
||||
fn_loadSupplyVendorList();
|
||||
|
||||
// 환종 목록 로드
|
||||
fn_loadCurrencyList();
|
||||
|
||||
// Tabulator 초기화
|
||||
fn_initGrid();
|
||||
});
|
||||
@@ -172,6 +178,31 @@ function fn_loadSupplyVendorList() {
|
||||
});
|
||||
}
|
||||
|
||||
// 환종(통화) 목록 로드 (공통코드 0001533)
|
||||
function fn_loadCurrencyList() {
|
||||
$.ajax({
|
||||
url: "/admin/makeCodeSelect.do",
|
||||
method: 'post',
|
||||
data: { codeId: '0001533' },
|
||||
dataType: 'json',
|
||||
async: false,
|
||||
success: function(data) {
|
||||
if(data && data.RESULT) {
|
||||
data.RESULT.forEach(function(item) {
|
||||
var codeId = item.CODE_ID || '';
|
||||
var codeName = item.CODE_NAME || '';
|
||||
if(codeId && codeName) {
|
||||
currencyList.push({id: codeId, text: codeName});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
console.error("환종 목록 로드 실패");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Select2 커스텀 에디터 생성 함수
|
||||
function createSelect2Editor(options) {
|
||||
return function(cell, onRendered, success, cancel, editorParams) {
|
||||
@@ -808,11 +839,29 @@ function fn_initGrid() {
|
||||
return cell.getValue() || '-';
|
||||
}
|
||||
},
|
||||
// 숨김 컬럼: 공급업체 코드 (저장 시 필요)
|
||||
{
|
||||
field: 'VENDOR',
|
||||
visible: false
|
||||
},
|
||||
// 숨김 컬럼: 공급업체 코드 (저장 시 필요)
|
||||
{
|
||||
field: 'VENDOR',
|
||||
visible: false
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 80,
|
||||
title: '환종',
|
||||
field: 'CURRENCY',
|
||||
editor: false,
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
if(!value) return '-';
|
||||
for(var i = 0; i < currencyList.length; i++) {
|
||||
if(currencyList[i].id == value) {
|
||||
return currencyList[i].text;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
},
|
||||
// 숨김 컬럼: 품의서 작성일 (저장 시 기존 값 유지)
|
||||
{
|
||||
field: 'PROPOSAL_DATE',
|
||||
|
||||
@@ -0,0 +1,587 @@
|
||||
<%@ 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" %>
|
||||
<c:set var="now" value="<%=new java.util.Date() %>"/>
|
||||
<c:set var="sysYear"><fmt:formatDate value="${now}" pattern="yyyy" /></c:set>
|
||||
<%
|
||||
// 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>
|
||||
<style>
|
||||
body, html {
|
||||
overflow-x: hidden;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.select2-selection__choice {
|
||||
font-size: 11px;
|
||||
background-color: #fff !important;
|
||||
border: none !important;
|
||||
margin-right: 0px !important;
|
||||
}
|
||||
.select2-selection__choice__remove {
|
||||
display: contents !important;
|
||||
}
|
||||
.select2-container .select2-selection--multiple {
|
||||
min-height: 20px !important;
|
||||
}
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice {
|
||||
margin-top: 3.5px !important;
|
||||
}
|
||||
.select2-selection__rendered {
|
||||
height: 18px !important;
|
||||
}
|
||||
.select2-container .select2-selection--multiple .select2-selection__rendered {
|
||||
overflow: auto !important;
|
||||
}
|
||||
/* WBS할당 모달 */
|
||||
.wbs-modal-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
background: rgba(0,0,0,0.4);
|
||||
z-index: 9998;
|
||||
}
|
||||
.wbs-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 50%; left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 9999;
|
||||
background: #fff;
|
||||
border: 2px solid #FFA500;
|
||||
border-radius: 4px;
|
||||
width: 420px;
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
|
||||
}
|
||||
.wbs-modal-header {
|
||||
background-color: #FFA500;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
padding: 8px 12px;
|
||||
font-size: 13px;
|
||||
}
|
||||
.wbs-modal-body {
|
||||
padding: 15px 20px;
|
||||
}
|
||||
.wbs-modal-body .wbs-desc {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.wbs-modal-body table td {
|
||||
padding: 5px 5px;
|
||||
}
|
||||
.wbs-modal-body select {
|
||||
width: 220px;
|
||||
}
|
||||
.wbs-modal-footer {
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
// Tabulator 그리드 전역 변수
|
||||
var _tabulGrid;
|
||||
|
||||
$(document).ready(function(){
|
||||
|
||||
_fnc_datepick();
|
||||
$('.select2').select2();
|
||||
|
||||
// 품번/품명 Select2 AJAX 초기화
|
||||
initPartSelect2Ajax("#search_part_no", "#search_part_name", "#search_part_objid");
|
||||
|
||||
// Enter 키로 검색
|
||||
$("#plmSearchZon input").keyup(function(e) {
|
||||
if (e.keyCode == 13) {
|
||||
fn_search();
|
||||
}
|
||||
});
|
||||
|
||||
// 조회 버튼
|
||||
$("#btnSearch").click(function(){
|
||||
fn_search();
|
||||
});
|
||||
|
||||
// WBS할당 버튼
|
||||
$("#btnWbsAssign").click(function(){
|
||||
fn_toggleWbsAssign();
|
||||
});
|
||||
|
||||
|
||||
// 초기 조회
|
||||
fn_search();
|
||||
});
|
||||
|
||||
// 날짜 선택기 초기화 함수
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 그리드 컬럼 정의
|
||||
var columns = [
|
||||
{title:'OBJID', field:'OBJID', visible: false, frozen: true},
|
||||
|
||||
// 프로젝트번호
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 130,
|
||||
title: '프로젝트번호',
|
||||
field: 'PROJECT_NO',
|
||||
frozen: true,
|
||||
formatter: fnc_createGridAnchorTag,
|
||||
cellClick: function(e, cell){
|
||||
var orderNo = cell.getData().PROJECT_NO;
|
||||
fn_openSaleRegPopup(orderNo, "detail");
|
||||
}
|
||||
},
|
||||
|
||||
// 제품구분
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 80,
|
||||
title: '제품구분',
|
||||
field: 'PRODUCT_NAME'
|
||||
},
|
||||
|
||||
// 주문유형
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 80,
|
||||
title: '주문유형',
|
||||
field: 'CATEGORY_CODE_NAME'
|
||||
},
|
||||
|
||||
// 생산유형
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 80,
|
||||
title: '생산유형',
|
||||
field: 'PRODUCTION_TYPE_NAME'
|
||||
},
|
||||
|
||||
// 고객사
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 150,
|
||||
title: '고객사',
|
||||
field: 'CUSTOMER_NAME'
|
||||
},
|
||||
|
||||
// 요청납기
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 90,
|
||||
title: '요청납기',
|
||||
field: 'REQ_DEL_DATE'
|
||||
},
|
||||
|
||||
// 고객사요청사항
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 230,
|
||||
title: '고객사요청사항',
|
||||
field: 'CUSTOMER_REQUEST'
|
||||
},
|
||||
|
||||
// 품번
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 150,
|
||||
title: '품번',
|
||||
field: 'PART_NO'
|
||||
},
|
||||
|
||||
// 품명
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 180,
|
||||
title: '품명',
|
||||
field: 'PART_NAME'
|
||||
},
|
||||
|
||||
// S/N
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 80,
|
||||
title: 'S/N',
|
||||
field: 'SERIAL_NO'
|
||||
},
|
||||
|
||||
// 생산WBS
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 100,
|
||||
title: '생산WBS',
|
||||
field: 'PROD_WBS_CNT',
|
||||
formatter: fnc_subInfoValueFormatter,
|
||||
cellClick: function(e, cell){
|
||||
var objid = fnc_checkNull(cell.getData().OBJID);
|
||||
var cnt = cell.getValue();
|
||||
if(!objid) return;
|
||||
if(!cnt || cnt == 0) { Swal.fire({title:'알림', text:'WBS할당을 먼저 진행해주세요.', icon:'info'}); return; }
|
||||
wbs_popup(objid, 'PRODUCE');
|
||||
}
|
||||
},
|
||||
|
||||
// 생산진척율(%)
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'right',
|
||||
width: 110,
|
||||
title: '생산진척율(%)',
|
||||
field: 'PROD_PROGRESS_RATE',
|
||||
formatter: function(cell) {
|
||||
var val = cell.getValue();
|
||||
if(val == null || val === '') return '';
|
||||
return val + '%';
|
||||
}
|
||||
},
|
||||
|
||||
// 납품WBS
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 100,
|
||||
title: '납품WBS',
|
||||
field: 'DELV_WBS_CNT',
|
||||
formatter: fnc_subInfoValueFormatter,
|
||||
cellClick: function(e, cell){
|
||||
var objid = fnc_checkNull(cell.getData().OBJID);
|
||||
var cnt = cell.getValue();
|
||||
if(!objid) return;
|
||||
if(!cnt || cnt == 0) { Swal.fire({title:'알림', text:'WBS할당을 먼저 진행해주세요.', icon:'info'}); return; }
|
||||
wbs_popup(objid, 'SHIP');
|
||||
}
|
||||
},
|
||||
|
||||
// 납품진척율(%)
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'right',
|
||||
width: 110,
|
||||
title: '납품진척율(%)',
|
||||
field: 'DELV_PROGRESS_RATE',
|
||||
formatter: function(cell) {
|
||||
var val = cell.getValue();
|
||||
if(val == null || val === '') return '';
|
||||
return val + '%';
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
// 검색 함수
|
||||
function fn_search(){
|
||||
var projectNos = $("#search_project_no").val();
|
||||
if(projectNos && projectNos.length > 0) {
|
||||
$("#search_project_nos_hidden").val(projectNos.join(","));
|
||||
} else {
|
||||
$("#search_project_nos_hidden").val("");
|
||||
}
|
||||
|
||||
_tabulGrid = fnc_tabul_search(_tabul_layout_fitDataStretch, _tabulGrid, "/productionplanning/prodPlanResultMgmtEquipGridList.do", columns, true);
|
||||
}
|
||||
|
||||
// WBS할당 모달 열기
|
||||
function fn_toggleWbsAssign() {
|
||||
var checkedRows = getCheckedRows();
|
||||
if(checkedRows.length === 0) {
|
||||
Swal.fire({title: '선택 필요', text: 'WBS를 할당할 프로젝트를 선택해주세요.', icon: 'warning'});
|
||||
return;
|
||||
}
|
||||
if(checkedRows.length > 1) {
|
||||
Swal.fire({title: '알림', text: '한 번에 하나의 프로젝트만 선택해주세요.', icon: 'info'});
|
||||
return;
|
||||
}
|
||||
var row = checkedRows[0];
|
||||
var hasProd = row.PROD_WBS_CNT && row.PROD_WBS_CNT > 0;
|
||||
var hasDelv = row.DELV_WBS_CNT && row.DELV_WBS_CNT > 0;
|
||||
|
||||
if(hasProd || hasDelv) {
|
||||
var msg = '이미 WBS가 할당되어 있습니다.\n재할당 시 기존 데이터(담당자, 일정, 진척율 등)가 모두 삭제됩니다.\n계속하시겠습니까?';
|
||||
Swal.fire({title:'재할당 경고', text: msg, icon:'warning', showCancelButton:true, confirmButtonText:'재할당', cancelButtonText:'취소'
|
||||
}).then(function(result){
|
||||
if(result.isConfirmed) fn_openWbsModal(row.OBJID);
|
||||
});
|
||||
} else {
|
||||
fn_openWbsModal(row.OBJID);
|
||||
}
|
||||
}
|
||||
|
||||
function fn_openWbsModal(objid) {
|
||||
$("#wbsModal").data("projectObjid", objid);
|
||||
$("#wbs_produce").val("");
|
||||
$("#wbs_delivery").val("");
|
||||
$("#wbsModalOverlay").fadeIn(200);
|
||||
$("#wbsModal").fadeIn(200);
|
||||
}
|
||||
|
||||
// WBS할당 모달 닫기
|
||||
function fn_closeWbsModal() {
|
||||
$("#wbsModal").fadeOut(200);
|
||||
$("#wbsModalOverlay").fadeOut(200);
|
||||
}
|
||||
|
||||
// WBS할당 저장 (템플릿 할당)
|
||||
function fn_saveWbsAssign() {
|
||||
var projectObjid = $("#wbsModal").data("projectObjid");
|
||||
var prodTemplate = $("#wbs_produce").val();
|
||||
var delvTemplate = $("#wbs_delivery").val();
|
||||
|
||||
if(!prodTemplate && !delvTemplate) {
|
||||
Swal.fire({title: '알림', text: '생산WBS 또는 납품WBS를 선택해주세요.', icon: 'warning'});
|
||||
return;
|
||||
}
|
||||
|
||||
var requests = [];
|
||||
if(prodTemplate) {
|
||||
requests.push({ projectObjid: projectObjid, wbsType: 'PRODUCE', templateObjid: prodTemplate });
|
||||
}
|
||||
if(delvTemplate) {
|
||||
requests.push({ projectObjid: projectObjid, wbsType: 'SHIP', templateObjid: delvTemplate });
|
||||
}
|
||||
|
||||
var completed = 0;
|
||||
var hasError = false;
|
||||
for(var i=0; i<requests.length; i++) {
|
||||
(function(req){
|
||||
// 템플릿 태스크 조회 후 저장
|
||||
$.ajax({
|
||||
url: "/productionplanning/getWbsTemplateTasks.do",
|
||||
type: "POST", data: { templateObjid: req.templateObjid },
|
||||
dataType: "json",
|
||||
success: function(result){
|
||||
if(result.list && result.list.length > 0){
|
||||
var tasks = [];
|
||||
for(var j=0; j<result.list.length; j++){
|
||||
var d = result.list[j];
|
||||
tasks.push({
|
||||
objid: '', taskName: d.TASK_NAME || d.task_name || '',
|
||||
taskSeq: j+1, taskLevel: d.TASK_LEVEL || d.task_level || '',
|
||||
unitNo: d.UNIT_NO || d.unit_no || '',
|
||||
upperTaskObjid: d.UPPER_TASK_OBJID || d.upper_task_objid || '',
|
||||
templateTaskObjid: d.OBJID || d.objid || '',
|
||||
userId: '', planStart: '', planEnd: '', actStart: '', actEnd: '', remark: ''
|
||||
});
|
||||
}
|
||||
$.ajax({
|
||||
url: "/productionplanning/saveEquipWbsAssign.do",
|
||||
type: "POST", contentType: "application/json",
|
||||
data: JSON.stringify({ projectObjid: req.projectObjid, wbsType: req.wbsType, templateObjid: req.templateObjid, tasks: tasks }),
|
||||
dataType: "json",
|
||||
success: function(res){
|
||||
if(!res.success) hasError = true;
|
||||
completed++;
|
||||
if(completed === requests.length) fn_wbsAssignDone(hasError);
|
||||
},
|
||||
error: function(){ hasError = true; completed++; if(completed === requests.length) fn_wbsAssignDone(hasError); }
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
})(requests[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function fn_wbsAssignDone(hasError) {
|
||||
fn_closeWbsModal();
|
||||
if(hasError) {
|
||||
Swal.fire({title:'오류', text:'일부 할당에 실패했습니다.', icon:'error'});
|
||||
} else {
|
||||
Swal.fire({title:'완료', text:'WBS 할당이 완료되었습니다.', icon:'success'});
|
||||
}
|
||||
fn_search();
|
||||
}
|
||||
|
||||
// 폴더 아이콘 클릭 → 상세 편집 팝업
|
||||
function wbs_popup(objId, wbsType){
|
||||
var popup_width = 1200;
|
||||
var popup_height = 600;
|
||||
var url = "/productionplanning/prodPlanWbsAssignPopup.do?projectObjid=" + objId + "&wbsType=" + wbsType;
|
||||
fn_centerPopup(popup_width, popup_height, url, 'wbsAssignPopup');
|
||||
}
|
||||
|
||||
// 프로젝트 상세 팝업
|
||||
function fn_openProjectDetailPopup(objid) {
|
||||
var popup_width = 1000;
|
||||
var popup_height = 550;
|
||||
var url = "/salesMgmt/salesRegForm.do?orderNo=&saleNo=detail&objid=" + objid;
|
||||
fn_centerPopup(popup_width, popup_height, url);
|
||||
}
|
||||
|
||||
// 선택된 행 가져오기
|
||||
function getCheckedRows() {
|
||||
if(_tabulGrid) {
|
||||
return _tabulGrid.getSelectedData();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- hiddenForm -->
|
||||
<form name="hiddenForm" id="hiddenForm" method="post">
|
||||
<input type="hidden" name="OBJID" id="OBJID">
|
||||
<input type="hidden" name="actionType" id="actionType">
|
||||
</form>
|
||||
|
||||
<form name="form1" id="form1" method="post">
|
||||
<input type="hidden" name="actionType" id="actionType">
|
||||
<input type="hidden" name="search_project_nos" id="search_project_nos_hidden">
|
||||
<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="btnSearch">
|
||||
<input type="button" class="plm_btns" value="WBS할당" id="btnWbsAssign">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 검색 영역 -->
|
||||
<div id="plmSearchZon">
|
||||
<table>
|
||||
<tr>
|
||||
<td><label>프로젝트번호</label></td>
|
||||
<td>
|
||||
<select name="search_project_no" id="search_project_no" class="select2" style="width:235px;" multiple="multiple">
|
||||
<option value="">선택</option>
|
||||
${code_map.project_no}
|
||||
</select>
|
||||
</td>
|
||||
|
||||
<td><label>제품구분</label></td>
|
||||
<td>
|
||||
<select name="search_product_code" id="search_product_code" class="select2" style="">
|
||||
<option value="">전체</option>
|
||||
${code_map.product_cd}
|
||||
</select>
|
||||
</td>
|
||||
|
||||
<td><label>주문유형</label></td>
|
||||
<td>
|
||||
<select name="search_category_code" id="search_category_code" class="select2" style="">
|
||||
<option value="">전체</option>
|
||||
${code_map.category_cd}
|
||||
</select>
|
||||
</td>
|
||||
|
||||
<td><label>생산유형</label></td>
|
||||
<td>
|
||||
<select name="search_production_type" id="search_production_type" class="select2" style="">
|
||||
<option value="">전체</option>
|
||||
${code_map.production_type_cd}
|
||||
</select>
|
||||
</td>
|
||||
|
||||
<td><label>고객사</label></td>
|
||||
<td>
|
||||
<select name="search_customer_objid" id="search_customer_objid" class="select2" style="width:250px;">
|
||||
<option value="">전체</option>
|
||||
${code_map.customer_cd}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label>요청납기</label></td>
|
||||
<td>
|
||||
<input type="text" name="search_req_del_date_from" id="search_req_del_date_from" class="date_icon" style="width:110px;" autocomplete="off">~
|
||||
<input type="text" name="search_req_del_date_to" id="search_req_del_date_to" class="date_icon" style="width:110px;" autocomplete="off">
|
||||
</td>
|
||||
|
||||
<td><label>품번</label></td>
|
||||
<td>
|
||||
<select name="search_part_no" id="search_part_no" class="select2-part" style="width:130px;">
|
||||
<option value="">품번 선택</option>
|
||||
</select>
|
||||
<input type="hidden" name="search_part_objid" id="search_part_objid" value="">
|
||||
</td>
|
||||
|
||||
<td><label>품명</label></td>
|
||||
<td>
|
||||
<select name="search_part_name" id="search_part_name" class="select2-part" style="width:130px;">
|
||||
<option value="">품명 선택</option>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
<td><label>S/N</label></td>
|
||||
<td><input type="text" name="search_serial_no" id="search_serial_no" style="" autocomplete="off"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 그리드 영역 -->
|
||||
<%@include file= "/WEB-INF/view/common/common_gridArea.jsp" %>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- WBS할당 모달 -->
|
||||
<div id="wbsModalOverlay" class="wbs-modal-overlay" onclick="fn_closeWbsModal()"></div>
|
||||
<div id="wbsModal" class="wbs-modal">
|
||||
<div class="wbs-modal-header">WBS할당</div>
|
||||
<div class="wbs-modal-body">
|
||||
<div class="wbs-desc">└ 선택후 WBS 할당 버튼 클릭하여 WBS 할당</div>
|
||||
<table>
|
||||
<tr>
|
||||
<td>생산WBS</td>
|
||||
<td>
|
||||
<select id="wbs_produce">
|
||||
<option value="">선택</option>
|
||||
${code_map.wbs_template}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>납품WBS</td>
|
||||
<td>
|
||||
<select id="wbs_delivery">
|
||||
<option value="">선택</option>
|
||||
${code_map.wbs_template}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="wbs-modal-footer">
|
||||
<input type="button" class="plm_btns" value="저장" onclick="fn_saveWbsAssign()">
|
||||
<input type="button" class="plm_btns" value="닫기" onclick="fn_closeWbsModal()">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,680 @@
|
||||
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||||
<%@ 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"%>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title><%=Constants.SYSTEM_NAME%></title>
|
||||
<style>
|
||||
html, body { height: 100%; margin: 0; overflow: hidden; }
|
||||
.info-area { padding: 8px 10px; }
|
||||
.info-area table td { padding: 2px 8px; }
|
||||
.info-area label { font-weight: bold; }
|
||||
#wbsTaskList td { text-align: center; padding: 2px 3px; vertical-align: middle; }
|
||||
#wbsTaskList input[type="text"] { width: 95%; font-size: 11px; }
|
||||
#wbsTaskList select { font-size: 11px; }
|
||||
#wbsTaskList input.date_input { width: 85px; font-size: 11px; text-align: center; }
|
||||
.row-total td { font-weight: bold; background-color: #FFF9C4 !important; }
|
||||
.row-level1 td { font-weight: bold; background-color: #FFF3E0 !important; }
|
||||
.row-level2 td { background-color: #F3E5F5 !important; }
|
||||
.calc-field { background: transparent; border: none; text-align: center; font-size: 11px; }
|
||||
.delay-plus { color: red; font-weight: bold; }
|
||||
.delay-minus { color: blue; }
|
||||
/* select2 컴팩트 스타일 */
|
||||
#wbsTaskList .select2-container { width: 100% !important; }
|
||||
#wbsTaskList .select2-container .select2-selection--single { height: 24px; min-height: 24px; }
|
||||
#wbsTaskList .select2-container .select2-selection--single .select2-selection__rendered { line-height: 24px; font-size: 11px; padding-left: 4px; }
|
||||
#wbsTaskList .select2-container .select2-selection--single .select2-selection__arrow { height: 22px; }
|
||||
</style>
|
||||
<script>
|
||||
var rowSeq = 0;
|
||||
var projectObjid = "${param.projectObjid}";
|
||||
var wbsType = "${param.wbsType}";
|
||||
var wbsTypeLabel = (wbsType === 'PRODUCE') ? '생산' : '납품';
|
||||
|
||||
// 담당자 옵션 HTML (서버에서 생성)
|
||||
var userOptionsHtml = '<option value=""></option>';
|
||||
<c:forEach var="user" items="${userList}">
|
||||
userOptionsHtml += '<option value="${user.CODE_ID}">${user.CODE_NAME}</option>';
|
||||
</c:forEach>
|
||||
|
||||
$(document).ready(function(){
|
||||
document.getElementById('wbsTypeLabel').innerText = wbsTypeLabel + ' WBS';
|
||||
|
||||
fn_loadExistingWbs();
|
||||
|
||||
$("#btnSave").click(function(){ fn_save(); });
|
||||
$("#btnClose").click(function(){ window.close(); });
|
||||
$("#wbsTemplateSelect").change(function(){
|
||||
if($(this).val()) fn_loadTemplateTasks($(this).val());
|
||||
});
|
||||
});
|
||||
|
||||
function fn_loadExistingWbs(){
|
||||
$.ajax({
|
||||
url: "/productionplanning/getEquipWbsTaskList.do",
|
||||
type: "POST", data: { projectObjid: projectObjid, wbsType: wbsType },
|
||||
dataType: "json",
|
||||
success: function(result){
|
||||
if(result.list && result.list.length > 0){
|
||||
$("#templateArea").hide();
|
||||
fn_renderRows(result.list, false);
|
||||
} else {
|
||||
$("#templateArea").show();
|
||||
addTotalRow();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function fn_loadTemplateTasks(templateObjid){
|
||||
$.ajax({
|
||||
url: "/productionplanning/getWbsTemplateTasks.do",
|
||||
type: "POST", data: { templateObjid: templateObjid },
|
||||
dataType: "json",
|
||||
success: function(result){
|
||||
if(result.list && result.list.length > 0){
|
||||
// 기존 행 제거 후 템플릿 데이터로 재구성
|
||||
$("#wbsTaskList").empty();
|
||||
fn_renderRows(result.list, true);
|
||||
$("#templateArea").hide();
|
||||
} else {
|
||||
Swal.fire({title:'알림', text:'템플릿에 등록된 태스크가 없습니다.', icon:'info'});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function fn_renderRows(list, isTemplate){
|
||||
var hasTotalRow = false;
|
||||
for(var i=0; i<list.length; i++){
|
||||
var d = list[i];
|
||||
var level = String(d.TASK_LEVEL || d.task_level || '');
|
||||
var depth = parseInt(level) || 0;
|
||||
|
||||
if(depth === 0){
|
||||
hasTotalRow = true;
|
||||
var totalUserId = d.USER_ID || d.user_id || '';
|
||||
addTotalRow(totalUserId);
|
||||
continue;
|
||||
}
|
||||
|
||||
var objId = isTemplate ? generateObjId() : (d.OBJID || d.objid || generateObjId());
|
||||
var unitNo = d.UNIT_NO || d.unit_no || '';
|
||||
var taskName = d.TASK_NAME || d.task_name || '';
|
||||
var userId = d.USER_ID || d.user_id || '';
|
||||
var planStart = d.PLAN_START || d.plan_start || '';
|
||||
var planEnd = d.PLAN_END || d.plan_end || '';
|
||||
var actStart = d.ACT_START || d.act_start || '';
|
||||
var actEnd = d.ACT_END || d.act_end || '';
|
||||
var remark = d.REMARK || d.remark || '';
|
||||
var upperTask = d.UPPER_TASK_OBJID || d.upper_task_objid || '';
|
||||
var tmplTask = isTemplate ? (d.OBJID || d.objid || '') : (d.TEMPLATE_TASK_OBJID || d.template_task_objid || '');
|
||||
var progress = d.PROGRESS || d.progress || '';
|
||||
|
||||
appendTaskRow(objId, depth, unitNo, taskName, userId, planStart, planEnd, actStart, actEnd, remark, upperTask, tmplTask, progress);
|
||||
}
|
||||
if(!hasTotalRow) addTotalRow();
|
||||
renumberAllRows();
|
||||
recalcAllParents();
|
||||
}
|
||||
|
||||
// TOTAL 행 추가
|
||||
function addTotalRow(userId){
|
||||
if($("#row_total").length > 0) return;
|
||||
var objId = generateObjId();
|
||||
var tr = '<tr id="row_total" class="row-total" data-depth="0">';
|
||||
tr += '<td></td>';
|
||||
tr += hiddens(objId, '0', '', '0', '');
|
||||
tr += '<td></td><td></td><td></td>';
|
||||
tr += '<td style="font-weight:bold;">TOTAL<input type="hidden" name="TASK_NAME_' + objId + '" value="TOTAL"></td>';
|
||||
tr += '<td><select name="USER_ID_' + objId + '" id="USER_ID_' + objId + '" class="user-select">' + userOptionsHtml + '</select></td>';
|
||||
tr += '<td class="calc-field" id="ps_' + objId + '"></td>';
|
||||
tr += '<td class="calc-field" id="pe_' + objId + '"></td>';
|
||||
tr += '<td class="calc-field" id="as_' + objId + '"></td>';
|
||||
tr += '<td class="calc-field" id="ae_' + objId + '"></td>';
|
||||
tr += '<td class="calc-field" id="pr_' + objId + '"></td>';
|
||||
tr += '<td class="calc-field" id="dd_' + objId + '"></td>';
|
||||
tr += '<td><input type="text" name="REMARK_' + objId + '" id="REMARK_' + objId + '" value="" style="width:95%;"></td>';
|
||||
tr += '</tr>';
|
||||
$("#wbsTaskList").prepend(tr);
|
||||
if(userId) $("#USER_ID_" + objId).val(userId);
|
||||
$("#USER_ID_" + objId).select2({ width: '100%', placeholder: '', allowClear: true });
|
||||
}
|
||||
|
||||
function hiddens(objId, unitNo, upperTask, level, tmplTask){
|
||||
var h = '';
|
||||
h += '<input type="hidden" name="WBS_TASK_OBJID" value="' + objId + '">';
|
||||
h += '<input type="hidden" name="UNIT_NO_' + objId + '" id="UNIT_NO_' + objId + '" value="' + unitNo + '">';
|
||||
h += '<input type="hidden" name="UPPER_TASK_OBJID_' + objId + '" id="UPPER_TASK_OBJID_' + objId + '" value="' + upperTask + '">';
|
||||
h += '<input type="hidden" name="TASK_LEVEL_' + objId + '" id="TASK_LEVEL_' + objId + '" value="' + level + '">';
|
||||
h += '<input type="hidden" name="TEMPLATE_TASK_OBJID_' + objId + '" id="TEMPLATE_TASK_OBJID_' + objId + '" value="' + tmplTask + '">';
|
||||
return h;
|
||||
}
|
||||
|
||||
function appendTaskRow(objId, depth, unitNo, taskName, userId, planStart, planEnd, actStart, actEnd, remark, upperTask, tmplTask, progress){
|
||||
var isLevel3 = (depth === 3);
|
||||
var rowClass = (depth === 1) ? 'row-level1' : (depth === 2) ? 'row-level2' : '';
|
||||
|
||||
var tr = '<tr id="row_' + objId + '" class="' + rowClass + '">';
|
||||
tr += '<td><input type="checkbox" name="rowCheck" value="' + objId + '"></td>';
|
||||
tr += hiddens(objId, unitNo, upperTask, depth, tmplTask);
|
||||
tr += '<td><input type="text" class="lvl_input" data-objid="' + objId + '" data-level="1" style="width:80%;text-align:center;"' + (depth==1 ? ' value="'+unitNo+'"' : '') + '></td>';
|
||||
tr += '<td><input type="text" class="lvl_input" data-objid="' + objId + '" data-level="2" style="width:80%;text-align:center;"' + (depth==2 ? ' value="'+unitNo+'"' : '') + '></td>';
|
||||
tr += '<td><input type="text" class="lvl_input" data-objid="' + objId + '" data-level="3" style="width:80%;text-align:center;"' + (depth==3 ? ' value="'+unitNo+'"' : '') + '></td>';
|
||||
tr += '<td><input type="text" name="TASK_NAME_' + objId + '" id="TASK_NAME_' + objId + '" value="' + escapeHtml(taskName) + '"></td>';
|
||||
|
||||
tr += '<td><select name="USER_ID_' + objId + '" id="USER_ID_' + objId + '" class="user-select">' + userOptionsHtml + '</select></td>';
|
||||
|
||||
if(isLevel3){
|
||||
tr += '<td><input type="text" class="date_input" name="PLAN_START_' + objId + '" id="PLAN_START_' + objId + '" value="' + planStart + '" autocomplete="off"></td>';
|
||||
tr += '<td><input type="text" class="date_input" name="PLAN_END_' + objId + '" id="PLAN_END_' + objId + '" value="' + planEnd + '" autocomplete="off"></td>';
|
||||
tr += '<td><input type="text" class="date_input" name="ACT_START_' + objId + '" id="ACT_START_' + objId + '" value="' + actStart + '" autocomplete="off"></td>';
|
||||
tr += '<td><input type="text" class="date_input" name="ACT_END_' + objId + '" id="ACT_END_' + objId + '" value="' + actEnd + '" autocomplete="off"></td>';
|
||||
} else {
|
||||
tr += '<td class="calc-field" id="ps_' + objId + '"></td>';
|
||||
tr += '<td class="calc-field" id="pe_' + objId + '"></td>';
|
||||
tr += '<td class="calc-field" id="as_' + objId + '"></td>';
|
||||
tr += '<td class="calc-field" id="ae_' + objId + '"></td>';
|
||||
}
|
||||
|
||||
// 진척율: Level 3은 직접 입력, 나머지는 하위 평균 자동 계산
|
||||
if(isLevel3){
|
||||
var prVal = (progress != null && progress !== '') ? progress : '0';
|
||||
tr += '<td><input type="text" name="PROGRESS_' + objId + '" id="PROGRESS_' + objId + '" value="' + prVal + '" maxlength="3" style="width:35px;text-align:center;font-size:11px;" oninput="this.value=this.value.replace(/[^0-9]/g,\'\')" onkeydown="if(event.keyCode===13){this.blur();}" onblur="validateProgress(this);recalcAllParents()"></td>';
|
||||
} else {
|
||||
tr += '<td class="calc-field" id="pr_' + objId + '"></td>';
|
||||
}
|
||||
tr += '<td class="calc-field" id="dd_' + objId + '"></td>';
|
||||
tr += '<td><input type="text" name="REMARK_' + objId + '" id="REMARK_' + objId + '" value="' + escapeHtml(remark) + '" style="width:95%;"></td>';
|
||||
tr += '</tr>';
|
||||
|
||||
$("#wbsTaskList").append(tr);
|
||||
if(userId) $("#USER_ID_" + objId).val(userId);
|
||||
$("#USER_ID_" + objId).select2({ width: '100%', placeholder: '', allowClear: true });
|
||||
bindLevelInput(objId);
|
||||
if(isLevel3) bindDatePicker(objId);
|
||||
}
|
||||
|
||||
function bindDatePicker(objId){
|
||||
var opts = { changeMonth:true, changeYear:true, dateFormat:'yy-mm-dd',
|
||||
onSelect: function(){ recalcAllParents(); }
|
||||
};
|
||||
$("#PLAN_START_" + objId).datepicker(opts);
|
||||
$("#PLAN_END_" + objId).datepicker(opts);
|
||||
$("#ACT_START_" + objId).datepicker(opts);
|
||||
$("#ACT_END_" + objId).datepicker(opts);
|
||||
}
|
||||
|
||||
function bindLevelInput(objId){
|
||||
$("#row_" + objId + " .lvl_input").on("input", function(){
|
||||
var curObjId = $(this).data("objid");
|
||||
var level = $(this).data("level");
|
||||
$("#row_" + curObjId + " .lvl_input").not(this).val("");
|
||||
$("#UNIT_NO_" + curObjId).val($(this).val());
|
||||
$("#TASK_LEVEL_" + curObjId).val($(this).val() ? level : "");
|
||||
|
||||
var tr = $("#row_" + curObjId);
|
||||
tr.removeClass('row-level1 row-level2');
|
||||
if(level == 1) tr.addClass('row-level1');
|
||||
else if(level == 2) tr.addClass('row-level2');
|
||||
});
|
||||
}
|
||||
|
||||
function generateObjId(){
|
||||
return String(Math.abs(Math.floor(Math.random() * 2147483647))) + String(++rowSeq);
|
||||
}
|
||||
|
||||
function getRowDepth(tr){
|
||||
var objId = $(tr).find("input[name='WBS_TASK_OBJID']").val();
|
||||
var taskLevel = $.trim($("#TASK_LEVEL_" + objId).val());
|
||||
if(taskLevel !== "") return parseInt(taskLevel);
|
||||
var unitNo = $.trim($("#UNIT_NO_" + objId).val());
|
||||
if(unitNo === "0") return 0;
|
||||
if(unitNo === "") return -1;
|
||||
return (unitNo.match(/\./g) || []).length + 1;
|
||||
}
|
||||
|
||||
function findLastDescendant(parentTr){
|
||||
var parentDepth = getRowDepth(parentTr[0]);
|
||||
var last = parentTr;
|
||||
parentTr.nextAll("tr").each(function(){
|
||||
if(getRowDepth(this) > parentDepth) last = $(this);
|
||||
else return false;
|
||||
});
|
||||
return last;
|
||||
}
|
||||
|
||||
function renumberAllRows(){
|
||||
var rows = $("#wbsTaskList tr:not(#row_total)");
|
||||
var counters = [0, 0, 0];
|
||||
rows.each(function(){
|
||||
var objId = $(this).find("input[name='WBS_TASK_OBJID']").val();
|
||||
var depth = parseInt($("#TASK_LEVEL_" + objId).val()) || 0;
|
||||
if(depth < 1 || depth > 3) return true;
|
||||
|
||||
if(depth === 1){ counters[0]++; counters[1]=0; counters[2]=0; }
|
||||
else if(depth === 2){ counters[1]++; counters[2]=0; }
|
||||
else { counters[2]++; }
|
||||
|
||||
var unitNo;
|
||||
if(depth === 1) unitNo = String(counters[0]);
|
||||
else if(depth === 2) unitNo = counters[0] + "." + counters[1];
|
||||
else unitNo = counters[0] + "." + counters[1] + "." + counters[2];
|
||||
|
||||
$("#UNIT_NO_" + objId).val(unitNo);
|
||||
$(this).find(".lvl_input").val("");
|
||||
$(this).find(".lvl_input[data-level='" + depth + "']").val(unitNo);
|
||||
});
|
||||
}
|
||||
|
||||
// --- 행 추가/삭제 ---
|
||||
function addRow(){
|
||||
var objId = generateObjId();
|
||||
var checked = $("input[name='rowCheck']:checked");
|
||||
var autoLevel = "";
|
||||
var insertAfterTr = null;
|
||||
|
||||
if(checked.length > 0){
|
||||
var selectedTr = checked.last().closest("tr");
|
||||
autoLevel = getRowDepth(selectedTr[0]);
|
||||
insertAfterTr = findLastDescendant(selectedTr);
|
||||
checked.prop("checked", false);
|
||||
}
|
||||
|
||||
var depth = parseInt(autoLevel) || 3;
|
||||
appendTaskRow(objId, depth, '', '', '', '', '', '', '', '', '', '', '');
|
||||
|
||||
if(insertAfterTr){
|
||||
// detach 전 select2 제거 후 재초기화
|
||||
$("#USER_ID_" + objId).select2('destroy');
|
||||
var newRow = $("#row_" + objId).detach();
|
||||
insertAfterTr.after(newRow);
|
||||
$("#USER_ID_" + objId).select2({ width: '100%', placeholder: '', allowClear: true });
|
||||
bindLevelInput(objId);
|
||||
if(depth === 3) bindDatePicker(objId);
|
||||
}
|
||||
|
||||
$("#TASK_LEVEL_" + objId).val(depth);
|
||||
var tr = $("#row_" + objId);
|
||||
tr.removeClass('row-level1 row-level2');
|
||||
if(depth === 1) tr.addClass('row-level1');
|
||||
else if(depth === 2) tr.addClass('row-level2');
|
||||
|
||||
renumberAllRows();
|
||||
}
|
||||
|
||||
function addChildRow(){
|
||||
var checked = $("input[name='rowCheck']:checked");
|
||||
if(checked.length == 0){ Swal.fire('부모 행을 선택해 주세요'); return; }
|
||||
var selectedTr = checked.last().closest("tr");
|
||||
var selectedDepth = getRowDepth(selectedTr[0]);
|
||||
if(selectedDepth >= 3){ Swal.fire('수준 3 이하로는 추가할 수 없습니다'); return; }
|
||||
|
||||
var objId = generateObjId();
|
||||
var childDepth = selectedDepth + 1;
|
||||
var insertAfterTr = findLastDescendant(selectedTr);
|
||||
|
||||
appendTaskRow(objId, childDepth, '', '', '', '', '', '', '', '', '', '', '');
|
||||
$("#USER_ID_" + objId).select2('destroy');
|
||||
var newRow = $("#row_" + objId).detach();
|
||||
insertAfterTr.after(newRow);
|
||||
$("#USER_ID_" + objId).select2({ width: '100%', placeholder: '', allowClear: true });
|
||||
bindLevelInput(objId);
|
||||
if(childDepth === 3) bindDatePicker(objId);
|
||||
|
||||
$("#TASK_LEVEL_" + objId).val(childDepth);
|
||||
var tr = $("#row_" + objId);
|
||||
tr.removeClass('row-level1 row-level2');
|
||||
if(childDepth === 1) tr.addClass('row-level1');
|
||||
else if(childDepth === 2) tr.addClass('row-level2');
|
||||
|
||||
checked.prop("checked", false);
|
||||
renumberAllRows();
|
||||
}
|
||||
|
||||
function deleteRow(){
|
||||
var checked = $("input[name='rowCheck']:checked");
|
||||
if(checked.length == 0){ Swal.fire('삭제할 행을 선택해 주세요'); return; }
|
||||
var removeTargets = [];
|
||||
var hasChildren = false;
|
||||
checked.each(function(){
|
||||
var objId = $(this).val();
|
||||
var tr = $("#row_" + objId);
|
||||
if(tr.attr("id") === "row_total") return true;
|
||||
removeTargets.push(tr);
|
||||
var parentDepth = getRowDepth(tr[0]);
|
||||
tr.nextAll("tr").each(function(){
|
||||
if(getRowDepth(this) > parentDepth){ removeTargets.push($(this)); hasChildren = true; }
|
||||
else return false;
|
||||
});
|
||||
});
|
||||
var msg = hasChildren ? '하위 항목도 함께 삭제됩니다. 삭제하시겠습니까?' : '삭제하시겠습니까?';
|
||||
Swal.fire({ title: msg, icon:'warning', showCancelButton:true, confirmButtonText:'삭제', cancelButtonText:'취소'
|
||||
}).then(function(result){
|
||||
if(result.isConfirmed){
|
||||
$.each(removeTargets, function(i, tr){ tr.remove(); });
|
||||
renumberAllRows();
|
||||
recalcAllParents();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- 자동 계산 ---
|
||||
function recalcAllParents(){
|
||||
var rows = $("#wbsTaskList tr");
|
||||
var allItems = [];
|
||||
|
||||
rows.each(function(){
|
||||
var objId = $(this).find("input[name='WBS_TASK_OBJID']").val();
|
||||
if(!objId) return true;
|
||||
var depth = getRowDepth(this);
|
||||
var item = { objId: objId, depth: depth, tr: $(this) };
|
||||
|
||||
if(depth === 3){
|
||||
item.planStart = $.trim($("#PLAN_START_" + objId).val());
|
||||
item.planEnd = $.trim($("#PLAN_END_" + objId).val());
|
||||
item.actStart = $.trim($("#ACT_START_" + objId).val());
|
||||
item.actEnd = $.trim($("#ACT_END_" + objId).val());
|
||||
var prVal = $.trim($("#PROGRESS_" + objId).val());
|
||||
item.progress = (prVal !== '') ? Number(prVal) : 0;
|
||||
item.delay = calcDelay(item);
|
||||
}
|
||||
allItems.push(item);
|
||||
});
|
||||
|
||||
// Level 2: 하위 Level 3 집계
|
||||
for(var i=0; i<allItems.length; i++){
|
||||
if(allItems[i].depth === 2) calcParentFromChildren(allItems, i, 3);
|
||||
}
|
||||
// Level 1: 하위 Level 2 집계
|
||||
for(var i=0; i<allItems.length; i++){
|
||||
if(allItems[i].depth === 1) calcParentFromChildren(allItems, i, 2);
|
||||
}
|
||||
// TOTAL: 하위 Level 1 집계
|
||||
for(var i=0; i<allItems.length; i++){
|
||||
if(allItems[i].depth === 0){
|
||||
var children = allItems.filter(function(x){ return x.depth === 1; });
|
||||
calcParentAggregate(allItems[i], children);
|
||||
}
|
||||
}
|
||||
|
||||
// DOM에 반영
|
||||
for(var i=0; i<allItems.length; i++){
|
||||
var it = allItems[i];
|
||||
if(it.depth < 3){
|
||||
$("#ps_" + it.objId).text(it.planStart || '');
|
||||
$("#pe_" + it.objId).text(it.planEnd || '');
|
||||
$("#as_" + it.objId).text(it.actStart || '');
|
||||
$("#ae_" + it.objId).text(it.actEnd || '');
|
||||
}
|
||||
if(it.depth < 3){
|
||||
var prVal = (it.progress != null && it.progress !== '') ? it.progress : 0;
|
||||
$("#pr_" + it.objId).text(Number(prVal).toFixed(1));
|
||||
}
|
||||
var ddText = '';
|
||||
if(it.delay != null && it.delay !== ''){
|
||||
if(it.delay > 0) ddText = '<span class="delay-plus">+' + it.delay + '</span>';
|
||||
else if(it.delay < 0) ddText = '<span class="delay-minus">' + it.delay + '</span>';
|
||||
else ddText = '0';
|
||||
}
|
||||
$("#dd_" + it.objId).html(ddText);
|
||||
}
|
||||
}
|
||||
|
||||
function calcParentFromChildren(allItems, parentIdx, childDepth){
|
||||
var parent = allItems[parentIdx];
|
||||
var children = [];
|
||||
for(var j=parentIdx+1; j<allItems.length; j++){
|
||||
if(allItems[j].depth <= parent.depth) break;
|
||||
if(allItems[j].depth === childDepth) children.push(allItems[j]);
|
||||
}
|
||||
calcParentAggregate(parent, children);
|
||||
}
|
||||
|
||||
function calcParentAggregate(parent, children){
|
||||
if(!children || children.length === 0){
|
||||
parent.planStart=''; parent.planEnd=''; parent.actStart=''; parent.actEnd=''; parent.progress=0; parent.delay='';
|
||||
return;
|
||||
}
|
||||
var ps=[], pe=[], as2=[], ae=[];
|
||||
var rateSum = 0;
|
||||
for(var i=0; i<children.length; i++){
|
||||
var c = children[i];
|
||||
if(c.planStart) ps.push(c.planStart);
|
||||
if(c.planEnd) pe.push(c.planEnd);
|
||||
if(c.actStart) as2.push(c.actStart);
|
||||
if(c.actEnd) ae.push(c.actEnd);
|
||||
rateSum += (c.progress != null && c.progress !== '') ? Number(c.progress) : 0;
|
||||
}
|
||||
parent.planStart = ps.length > 0 ? ps.sort()[0] : '';
|
||||
parent.planEnd = pe.length > 0 ? pe.sort().reverse()[0] : '';
|
||||
parent.actStart = as2.length > 0 ? as2.sort()[0] : '';
|
||||
parent.actEnd = ae.length > 0 ? ae.sort().reverse()[0] : '';
|
||||
parent.progress = rateSum / children.length;
|
||||
parent.delay = calcDelay(parent);
|
||||
}
|
||||
|
||||
function calcProgress3(item){
|
||||
if(item.actEnd) return 100;
|
||||
if(!item.actStart) return 0;
|
||||
if(!item.planStart || !item.planEnd) return 0;
|
||||
var today = new Date(); today.setHours(0,0,0,0);
|
||||
var s = new Date(item.planStart), e = new Date(item.planEnd), a = new Date(item.actStart);
|
||||
var total = (e - s) / 86400000;
|
||||
if(total <= 0) return 0;
|
||||
var elapsed = (today - a) / 86400000;
|
||||
return Math.max(0, Math.min(Math.round(elapsed / total * 100), 99));
|
||||
}
|
||||
|
||||
function calcDelay(item){
|
||||
if(!item.planEnd || item.progress === '' || item.progress == null) return '';
|
||||
if(Number(item.progress) === 100){
|
||||
if(!item.actEnd) return '';
|
||||
return Math.round((new Date(item.actEnd) - new Date(item.planEnd)) / 86400000);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function validateProgress(el){
|
||||
el.value = el.value.replace(/[^0-9]/g, '');
|
||||
var v = parseInt(el.value);
|
||||
if(isNaN(v) || v < 0) el.value = '0';
|
||||
else if(v > 100) el.value = '100';
|
||||
}
|
||||
|
||||
function escapeHtml(str){
|
||||
if(!str) return '';
|
||||
return String(str).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||||
}
|
||||
|
||||
function calculateParentRelations(){
|
||||
var rows = $("#wbsTaskList tr");
|
||||
var totalObjId = $("#row_total").find("input[name='WBS_TASK_OBJID']").val();
|
||||
rows.each(function(idx){
|
||||
if($(this).attr("id") === "row_total") return true;
|
||||
var objId = $(this).find("input[name='WBS_TASK_OBJID']").val();
|
||||
var depth = getRowDepth(this);
|
||||
var parentObjId = "";
|
||||
if(depth === 1){ parentObjId = totalObjId; }
|
||||
else if(depth > 1){
|
||||
$(this).prevAll("tr").each(function(){
|
||||
if(getRowDepth(this) === depth - 1){
|
||||
parentObjId = $(this).find("input[name='WBS_TASK_OBJID']").val();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
$("#UPPER_TASK_OBJID_" + objId).val(parentObjId);
|
||||
});
|
||||
}
|
||||
|
||||
// --- 저장 ---
|
||||
function fn_save(){
|
||||
var taskCount = $("input[name='WBS_TASK_OBJID']").length;
|
||||
if(taskCount <= 1){ Swal.fire({title:'알림', text:'등록할 항목을 추가해 주세요.', icon:'warning'}); return; }
|
||||
|
||||
var isValid = true;
|
||||
$("input[name='WBS_TASK_OBJID']").each(function(){
|
||||
var objId = $(this).val();
|
||||
if($(this).closest("tr").attr("id") === "row_total") return true;
|
||||
var level = $.trim($("#UNIT_NO_" + objId).val());
|
||||
var taskName = $.trim($("#TASK_NAME_" + objId).val());
|
||||
if(level == "" || taskName == ""){ isValid = false; return false; }
|
||||
});
|
||||
if(!isValid){ Swal.fire('수준과 Unit Name / 공정을 모두 입력해 주세요'); return; }
|
||||
|
||||
calculateParentRelations();
|
||||
recalcAllParents();
|
||||
|
||||
var saveData = [];
|
||||
var totalUserId = '';
|
||||
$("#wbsTaskList tr").each(function(){
|
||||
var objId = $(this).find("input[name='WBS_TASK_OBJID']").val();
|
||||
if(!objId) return true;
|
||||
var depth = getRowDepth(this);
|
||||
|
||||
// TOTAL 행은 담당자만 별도 저장
|
||||
if(depth === 0){
|
||||
totalUserId = $("#USER_ID_" + objId).val() || '';
|
||||
return true;
|
||||
}
|
||||
|
||||
var row = {
|
||||
objid: objId,
|
||||
taskName: $.trim($("#TASK_NAME_" + objId).val()),
|
||||
taskSeq: saveData.length + 1,
|
||||
taskLevel: String(depth),
|
||||
unitNo: $.trim($("#UNIT_NO_" + objId).val()),
|
||||
upperTaskObjid: $.trim($("#UPPER_TASK_OBJID_" + objId).val()),
|
||||
templateTaskObjid: $.trim($("#TEMPLATE_TASK_OBJID_" + objId).val()),
|
||||
remark: $.trim($("#REMARK_" + objId).val())
|
||||
};
|
||||
|
||||
row.userId = $("#USER_ID_" + objId).val() || '';
|
||||
if(depth === 3){
|
||||
row.planStart = $.trim($("#PLAN_START_" + objId).val());
|
||||
row.planEnd = $.trim($("#PLAN_END_" + objId).val());
|
||||
row.actStart = $.trim($("#ACT_START_" + objId).val());
|
||||
row.actEnd = $.trim($("#ACT_END_" + objId).val());
|
||||
row.progress = $.trim($("#PROGRESS_" + objId).val());
|
||||
} else {
|
||||
row.progress = $.trim($("#pr_" + objId).text()).replace('%', '');
|
||||
row.planStart = $.trim($("#ps_" + objId).text());
|
||||
row.planEnd = $.trim($("#pe_" + objId).text());
|
||||
row.actStart = $.trim($("#as_" + objId).text());
|
||||
row.actEnd = $.trim($("#ae_" + objId).text());
|
||||
}
|
||||
saveData.push(row);
|
||||
});
|
||||
|
||||
Swal.fire({ title:'저장하시겠습니까?', icon:'question', showCancelButton:true, confirmButtonText:'확인', cancelButtonText:'취소'
|
||||
}).then(function(result){
|
||||
if(result.isConfirmed){
|
||||
$.ajax({
|
||||
url: "/productionplanning/saveEquipWbsAssign.do",
|
||||
type: "POST", contentType: "application/json",
|
||||
data: JSON.stringify({ projectObjid: projectObjid, wbsType: wbsType, templateObjid: $("#wbsTemplateSelect").val() || '', totalUserId: totalUserId, tasks: saveData }),
|
||||
dataType: "json",
|
||||
success: function(res){
|
||||
if(res.success){
|
||||
Swal.fire({title:'완료', text:'저장되었습니다.', icon:'success'}).then(function(){
|
||||
if(opener && opener.fn_search) opener.fn_search();
|
||||
window.close();
|
||||
});
|
||||
} else {
|
||||
Swal.fire({title:'오류', text: res.message || '저장 실패', icon:'error'});
|
||||
}
|
||||
},
|
||||
error: function(){ Swal.fire({title:'오류', text:'서버 오류', icon:'error'}); }
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="info-area">
|
||||
<table>
|
||||
<tr>
|
||||
<td><label>프로젝트번호:</label></td>
|
||||
<td>${projectInfo.PROJECT_NO}</td>
|
||||
<td style="padding-left:20px;"><label>WBS유형:</label></td>
|
||||
<td><span style="font-weight:bold; color:#1976D2;" id="wbsTypeLabel"></span></td>
|
||||
<td style="padding-left:20px;"><label>품번:</label></td>
|
||||
<td>${projectInfo.PART_NO}</td>
|
||||
<td style="padding-left:20px;"><label>품명:</label></td>
|
||||
<td>${projectInfo.PART_NAME}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="templateArea" style="padding:0 10px 5px; display:none;">
|
||||
<label>WBS 템플릿:</label>
|
||||
<select id="wbsTemplateSelect" style="width:250px;">
|
||||
<option value="">-- 선택 --</option>
|
||||
${wbsTemplateOptions}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div style="padding:0 10px;">
|
||||
<div class="plm_btn_wrap" style="margin-bottom:5px;">
|
||||
<input type="button" value="추가" class="plm_btns" onclick="addRow();">
|
||||
<input type="button" value="하위추가" class="plm_btns" onclick="addChildRow();">
|
||||
<input type="button" value="삭제" class="plm_btns" onclick="deleteRow();">
|
||||
<input type="button" value="저장" class="plm_btns" id="btnSave">
|
||||
<input type="button" value="닫기" class="plm_btns" id="btnClose">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="width:100%; padding:0 10px;">
|
||||
<table class="plm_table" style="width:100%;border-collapse:collapse;">
|
||||
<colgroup>
|
||||
<col width="3%"/><col width="4%"/><col width="4%"/><col width="5%"/>
|
||||
<col width="11%"/><col width="10%"/>
|
||||
<col width="8%"/><col width="8%"/><col width="8%"/><col width="8%"/>
|
||||
<col width="5%"/><col width="5%"/><col width="*"/>
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr class="plm_thead">
|
||||
<td rowspan="2">선택</td>
|
||||
<td colspan="3">수준</td>
|
||||
<td rowspan="2">Unit Name / 공정</td>
|
||||
<td rowspan="2">담당자</td>
|
||||
<td colspan="2" id="thPlanGroup">계획</td>
|
||||
<td colspan="2" id="thActGroup">실적</td>
|
||||
<td rowspan="2">진척율<br/>(%)</td>
|
||||
<td rowspan="2">지연일수</td>
|
||||
<td rowspan="2">비고</td>
|
||||
</tr>
|
||||
<tr class="plm_thead">
|
||||
<td>1</td><td>2</td><td>3</td>
|
||||
<td>시작일</td><td>완료일</td>
|
||||
<td>시작일</td><td>완료일</td>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div style="width:100%;height:calc(100vh - 180px);overflow-y:auto;padding:0 10px;">
|
||||
<table class="plm_table" style="width:100%;border-collapse:collapse;">
|
||||
<colgroup>
|
||||
<col width="3%"/><col width="4%"/><col width="4%"/><col width="5%"/>
|
||||
<col width="11%"/><col width="10%"/>
|
||||
<col width="8%"/><col width="8%"/><col width="8%"/><col width="8%"/>
|
||||
<col width="5%"/><col width="5%"/><col width="*"/>
|
||||
</colgroup>
|
||||
<tbody id="wbsTaskList"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 헤더에 WBS유형 표시
|
||||
var planLabel = wbsTypeLabel;
|
||||
$("#thPlanGroup").text(planLabel + ' 계획');
|
||||
$("#thActGroup").text(planLabel + ' 실적');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -24,6 +24,11 @@ String connector = person.getUserId();
|
||||
<c:set var="sysYear"><fmt:formatDate value="${now}" pattern="yyyy" /></c:set>
|
||||
|
||||
<c:set var="connector" value="<%=connector %>" />
|
||||
<%
|
||||
// DB에서 메뉴명 조회 (공통 유틸 사용)
|
||||
String menuObjId = request.getParameter("menuObjId");
|
||||
String menuName = CommonUtils.getMenuName(menuObjId, "품목별 입고 관리");
|
||||
%>
|
||||
<style>
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
@@ -100,7 +105,7 @@ var columns = [
|
||||
// fn_openTemplateMasterPopUp(objid);
|
||||
// }
|
||||
// },
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '250', title : 'UNIT', field : 'WBS_TASK_CNT0',
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '250', title : 'WBS', field : 'WBS_TASK_CNT0',
|
||||
formatter:fnc_getFolderIcon,
|
||||
cellClick:function(e, cell){
|
||||
var objid = fnc_checkNull(cell.getData().OBJID);
|
||||
@@ -342,7 +347,7 @@ function openProjectFormPopUp(objId){
|
||||
<div class="content-box-s">
|
||||
<div class="plm_menu_name_gdnsi">
|
||||
<h2>
|
||||
<span>프로젝트관리_제품구분_UNIT관리</span>
|
||||
<span><%=menuName%></span>
|
||||
</h2>
|
||||
<div class="btnArea">
|
||||
<input type="button" value="삭제" class="plm_btns delete" id="btnDelete">
|
||||
|
||||
@@ -0,0 +1,727 @@
|
||||
<%@ 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_jqGrid.jsp"%>
|
||||
<%
|
||||
Map info = (HashMap)(request.getAttribute("info"));
|
||||
boolean isModify = true;
|
||||
if(info!=null &&
|
||||
( CommonUtils.checkNull(info.get("APPR_STATUS")).equals( "결재중" )
|
||||
||CommonUtils.checkNull(info.get("APPR_STATUS")).equals( "결재완료" )
|
||||
||CommonUtils.checkNull(info.get("STATUS")).equals( "cancel" )
|
||||
)
|
||||
){
|
||||
isModify = false;
|
||||
}
|
||||
String actType = (String)request.getAttribute("actType");
|
||||
|
||||
List userList = (List)request.getAttribute("userList");
|
||||
if(userList == null) userList = new ArrayList();
|
||||
|
||||
String managerId = CommonUtils.checkNull(info != null ? info.get("SALES_MNG_USER_ID") : "");
|
||||
String managerId2 = CommonUtils.checkNull(info != null ? info.get("SALES_MNG_USER_ID2") : "");
|
||||
%>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<c:set var="now" value="<%=new java.util.Date() %>" />
|
||||
<c:set var="sysYear"><fmt:formatDate value="${now}" pattern="yyyy" /></c:set>
|
||||
<title><%=Constants.SYSTEM_NAME%> - Purchase Order</title>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Times New Roman', 'Georgia', serif;
|
||||
font-size: 11px;
|
||||
margin: 0;
|
||||
padding: 15px 25px;
|
||||
background-color: #fff;
|
||||
overflow-x: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
input.date_icon {
|
||||
border: 1px solid #aaa !important;
|
||||
border-radius: 4px;
|
||||
padding: 5px 8px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 헤더 */
|
||||
.po-header {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.po-header .company-name {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.po-header .company-info {
|
||||
font-size: 10px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* Purchase Order 타이틀 */
|
||||
.po-title {
|
||||
text-align: center;
|
||||
font-size: 26px;
|
||||
font-weight: bold;
|
||||
letter-spacing: 3px;
|
||||
margin: 15px 0;
|
||||
font-family: 'Times New Roman', serif;
|
||||
}
|
||||
|
||||
/* 기본정보 테이블 */
|
||||
.po-info-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
border: 1px solid #000;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.po-info-table td {
|
||||
border: 1px solid #000;
|
||||
padding: 4px 8px;
|
||||
font-size: 11px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.po-info-table .label-cell {
|
||||
background-color: #d9e2f3;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
width: 90px;
|
||||
}
|
||||
.po-info-table .value-cell {
|
||||
min-width: 180px;
|
||||
}
|
||||
.po-info-table .right-label {
|
||||
background-color: #d9e2f3;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
width: 80px;
|
||||
}
|
||||
.po-info-table .right-value {
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
/* 품목 테이블 */
|
||||
.po-item-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
border: 2px solid #000;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.po-item-table th {
|
||||
border: 1px solid #000;
|
||||
padding: 6px 4px;
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
background-color: #d9e2f3;
|
||||
}
|
||||
.po-item-table td {
|
||||
border: 1px solid #000;
|
||||
padding: 4px 6px;
|
||||
font-size: 10px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* TOTAL 행 */
|
||||
.po-total-row {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.po-total-row td {
|
||||
padding: 8px 10px;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
border: 2px solid #000;
|
||||
}
|
||||
|
||||
/* 서명 영역 */
|
||||
.po-signature {
|
||||
text-align: right;
|
||||
margin-top: 40px;
|
||||
padding: 20px;
|
||||
}
|
||||
.po-signature .sign-name {
|
||||
font-size: 12px;
|
||||
font-style: italic;
|
||||
}
|
||||
.po-signature .sign-company {
|
||||
font-size: 11px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
/* 버튼 영역 */
|
||||
.btn-area {
|
||||
text-align: right;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
/* jqGrid 스타일 */
|
||||
.ui-jqgrid-view { max-height: 400px; }
|
||||
.ui-jqgrid-bdiv { overflow-y: scroll !important; max-height: 350px !important; }
|
||||
.ui-jqgrid .select2-container { z-index: 9999; }
|
||||
.ui-jqgrid .select2-container--default .select2-selection--single {
|
||||
height: 24px; min-height: 24px; border: none; background: transparent;
|
||||
}
|
||||
.ui-jqgrid .select2-container--default .select2-selection--single .select2-selection__rendered {
|
||||
line-height: 24px; padding-left: 4px; font-size: 12px;
|
||||
}
|
||||
.ui-jqgrid .select2-container--default .select2-selection--single .select2-selection__arrow {
|
||||
height: 24px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
var grid;
|
||||
window.dataLoaded = false;
|
||||
|
||||
$(document).ready(function(){
|
||||
|
||||
$("input[numberOnly='']").each(function(){
|
||||
$(this).css({'text-align':'right'})
|
||||
})
|
||||
.on("keyup", function() {
|
||||
$(this).val(fnc_addComma($(this).val().replace(/[^0-9.]/g,"")));
|
||||
});
|
||||
|
||||
var unit_cd = $.parseJSON($("#unit_cd").val());
|
||||
var currency_cd = $.parseJSON($("#currency_cd").val());
|
||||
|
||||
grid = $("#grid1").jqGrid({
|
||||
url: ""
|
||||
,datatype: "local"
|
||||
,data: $.parseJSON($("#gridDetailList").val())
|
||||
,colNames: ["OBJID","PART_OBJID","Item No.","Commodity & Description","Spec","Unit","Q'ty","Currency","Unit Price","Amount","Delivery"]
|
||||
,colModel: [
|
||||
{name:"OBJID" , hidden: true, sortable:false, editable:false}
|
||||
,{name:"PART_OBJID" , hidden: true, sortable:false, editable:false}
|
||||
,{name:"PART_NO" , width:90, align:"center", sortable:false, editable:false}
|
||||
,{name:"PART_NAME" , width:200, align:"left", sortable:false, editable:false}
|
||||
,{name:"SPEC" , width:120, align:"left", sortable:false, editable:false}
|
||||
,{name:"UNIT" , width:50, align:"center", sortable:false, editable:<%= isModify %>
|
||||
,edittype:"select", formatter:"select"
|
||||
,editoptions:{ value: unit_cd }
|
||||
}
|
||||
,{name:"ORDER_QTY" , width:60, align:"right", sortable:false, editable:<%= isModify %>
|
||||
,formatter:"integer", formatoptions:{thousandsSeparator:","}
|
||||
,editoptions:{
|
||||
dataInit: function(e){ e.style.textAlign = "right"; }
|
||||
,dataEvents: [{type:"change", fn:function(e){ gridFn.calcRowAll(e); }}]
|
||||
}
|
||||
}
|
||||
,{name:"CURRENCY" , width:65, align:"center", sortable:false, editable:<%= isModify %>
|
||||
,edittype:"select", formatter:"select"
|
||||
,editoptions:{ value: currency_cd, defaultValue: "USD" }
|
||||
}
|
||||
,{name:"PARTNER_PRICE" , width:80, align:"right", sortable:false, editable:<%= isModify %>
|
||||
,formatter:"number", formatoptions:{thousandsSeparator:",", decimalPlaces:2}
|
||||
,editoptions:{
|
||||
dataInit: function(e){
|
||||
e.style.textAlign = "right";
|
||||
var val = parseFloat($(e).val().replace(/,/g, ''));
|
||||
if(!isNaN(val)) $(e).val(numberWithCommasDecimal(val));
|
||||
}
|
||||
,dataEvents: [
|
||||
{type:"change", fn:function(e){ gridFn.calcRowAll(e); }}
|
||||
,{type:"blur", fn:function(e){
|
||||
var val = parseFloat($(e.target).val().replace(/,/g, ''));
|
||||
if(!isNaN(val)) $(e.target).val(numberWithCommasDecimal(val));
|
||||
}}
|
||||
]
|
||||
}
|
||||
}
|
||||
,{name:"SUPPLY_UNIT_PRICE", width:90, align:"right", sortable:false, editable:false
|
||||
,formatter:"number", formatoptions:{thousandsSeparator:",", decimalPlaces:2}
|
||||
}
|
||||
,{name:"DELIVERY_REQUEST_DATE", width:120, align:"center", sortable:false, editable:<%= isModify %>
|
||||
,editoptions:{
|
||||
dataInit: function(elem) {
|
||||
$(elem).datepicker({
|
||||
changeMonth: true,
|
||||
changeYear: true,
|
||||
dateFormat: "yy-mm-dd"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
,rownumbers : false
|
||||
,viewrecords : true
|
||||
,height : '300'
|
||||
,multiselect : <% if(isModify){ %>true<% }else{ %>false<% } %>
|
||||
,shrinkToFit : true
|
||||
,autowidth : true
|
||||
,sortable : false
|
||||
,rowNum : 10000
|
||||
,forceFit : true
|
||||
,jsonReader : {repeatitems: false}
|
||||
,mtype :"POST"
|
||||
,loadComplete: function(){
|
||||
var gid = this.id;
|
||||
setTimeout("fn_jqGrid_init($('#"+gid+"'), false);", 50);
|
||||
var ids = $(this).jqGrid('getDataIDs');
|
||||
for(var i = 0; i < ids.length; i++){
|
||||
$(this).jqGrid('setCell', ids[i], 'ROW_NUM', i+1);
|
||||
}
|
||||
setTimeout(function(){ gridFn.calcAllRows(); }, 100);
|
||||
}
|
||||
});
|
||||
|
||||
gridFn.opennEdit();
|
||||
gridFn.calcAllRows();
|
||||
|
||||
$(window).on('resize', function(){
|
||||
var newWidth = $("#grid1").closest(".ui-jqgrid").parent().width();
|
||||
$("#grid1").jqGrid('setGridWidth', newWidth, true);
|
||||
});
|
||||
|
||||
<% if(isModify){ %>
|
||||
$("#PARTNER_OBJID").prop("disabled","");
|
||||
$("#SHIPMENT,#PACKING,#VALIDITY,#REMARK,#ATTN_TO").removeAttr("readonly");
|
||||
|
||||
$("#btnAdd").click(function(){ fn_openPartMngListPopUp(); });
|
||||
$("#btnDel").click(function(){ gridFn.delRow(); });
|
||||
$("#btnSave").click(function(){ fn_save(); });
|
||||
|
||||
<% }else{ %>
|
||||
$("#btnDown").click(function(){
|
||||
document.form1.action = "/purchaseOrder/purchaseOrderFormPopup_english.do?actType=DOWN&PURCHASE_ORDER_MASTER_OBJID=${objId}";
|
||||
document.form1.submit();
|
||||
});
|
||||
<% } %>
|
||||
|
||||
// 영문 날짜 표시용 datepicker
|
||||
var MONTH_NAMES_EN = ["JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"];
|
||||
|
||||
function toEnglishDateDisplay(dateStr) {
|
||||
if(!dateStr) return "";
|
||||
var d = new Date(dateStr.replace(/\./g, "-"));
|
||||
if(isNaN(d.getTime())) return dateStr;
|
||||
return MONTH_NAMES_EN[d.getMonth()] + ". " + ("0"+d.getDate()).slice(-2) + ". " + d.getFullYear();
|
||||
}
|
||||
|
||||
// 저장값(hidden) → 표시값 초기 세팅
|
||||
var initDate = $("#PURCHASE_DATE").val();
|
||||
$("#PURCHASE_DATE_DISPLAY").val(toEnglishDateDisplay(initDate));
|
||||
|
||||
$("#PURCHASE_DATE_DISPLAY").datepicker({
|
||||
changeMonth: true,
|
||||
changeYear: true,
|
||||
dateFormat: "yy-mm-dd",
|
||||
onSelect: function(dateText) {
|
||||
$("#PURCHASE_DATE").val(dateText);
|
||||
$(this).val(toEnglishDateDisplay(dateText));
|
||||
}
|
||||
});
|
||||
|
||||
$(".select2").select2();
|
||||
|
||||
gridFn.opennEdit();
|
||||
gridFn.calcAllRows();
|
||||
});
|
||||
|
||||
function fn_openPartMngListPopUp(){
|
||||
var url = "/partMng/partMngListPopUp.do?callbackFnc=fn_addRow&callType=purchaseOrder";
|
||||
window.open(url,"purchaseOrderPartSelectListPopUp","width=1480,height=850");
|
||||
}
|
||||
|
||||
function fn_addRow(rowData){
|
||||
var v1 = Number(fnc_checkNullDefaultValue(rowData.map.ORDER_QTY, 0));
|
||||
var v2 = Number(fnc_checkNullDefaultValue(rowData.map.PARTNER_PRICE, 0));
|
||||
var _rowSum = v1 * v2;
|
||||
|
||||
var newId = grid.getGridParam("reccount")+1;
|
||||
var addData = {
|
||||
"PART_OBJID" : rowData.map.PART_OBJID
|
||||
,"PART_NO" : rowData.map.PART_NO
|
||||
,"PART_NAME" : rowData.map.PART_NAME
|
||||
,"SPEC" : rowData.map.SPEC
|
||||
,"ORDER_QTY" : v1
|
||||
,"UNIT" : fnc_checkNullDefaultValue(rowData.map.UNIT, '0001400')
|
||||
,"CURRENCY" : "USD"
|
||||
,"PARTNER_PRICE" : v2
|
||||
,"SUPPLY_UNIT_PRICE": _rowSum
|
||||
,"DELIVERY_REQUEST_DATE" : ""
|
||||
};
|
||||
|
||||
grid.addRowData(newId, addData);
|
||||
grid.jqGrid("editRow", newId);
|
||||
gridFn.footerSummary();
|
||||
}
|
||||
|
||||
function fn_save(){
|
||||
if(fnc_valitate("form1")){
|
||||
if(""==grid.getRowData()){
|
||||
Swal.fire('No items to save.');
|
||||
return;
|
||||
}
|
||||
if(confirm("Save this Purchase Order?")){
|
||||
fn_save_process();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<% if(isModify){ %>
|
||||
function fn_save_process(){
|
||||
$("input[name*='PRICE']").each(function(){
|
||||
$(this).val($(this).val().replace(/,/gi,""));
|
||||
});
|
||||
$("input[name*='QTY']").each(function(){
|
||||
$(this).val($(this).val().replace(/,/gi,""));
|
||||
});
|
||||
|
||||
gridFn.closeEdit();
|
||||
$.ajax({
|
||||
url:"/purchaseOrder/purchaseOrderFormPopup_englishSave.do"
|
||||
,type:"POST"
|
||||
,data: $("#form1").serialize() + "&jqGrid="+ encodeURIComponent(JSON.stringify(grid.getRowData()))
|
||||
,dataType:"json"
|
||||
,success:function(data){
|
||||
if(data && data.RESULT == 'S'){
|
||||
alert("Saved successfully.");
|
||||
if(typeof opener.fn_search =="function"){ opener.fn_search() };
|
||||
self.close();
|
||||
}else{
|
||||
alert(data.MSG);
|
||||
}
|
||||
}
|
||||
,error: function(jqxhr, status, error){
|
||||
alert('An error occurred. Please contact the system administrator.');
|
||||
}
|
||||
});
|
||||
}
|
||||
<% } %>
|
||||
|
||||
var gridFn = {
|
||||
delRow : function(){
|
||||
var selectedRowIds = grid.jqGrid("getGridParam","selarrrow");
|
||||
if(selectedRowIds.length==0){
|
||||
Swal.fire("Please select a row to delete.");
|
||||
return false;
|
||||
}
|
||||
for(var i = selectedRowIds.length - 1; i >= 0; i--){
|
||||
grid.delRowData(selectedRowIds[i]);
|
||||
}
|
||||
var ids = grid.jqGrid('getDataIDs');
|
||||
for(var i = 0; i < ids.length; i++){
|
||||
grid.jqGrid('setCell', ids[i], 'ROW_NUM', ids[i]);
|
||||
}
|
||||
gridFn.footerSummary();
|
||||
}
|
||||
,opennEdit : function() {
|
||||
var ids = grid.jqGrid("getDataIDs");
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
grid.jqGrid("editRow",ids[i]);
|
||||
}
|
||||
}
|
||||
,closeEdit : function() {
|
||||
var ids = grid.jqGrid("getDataIDs");
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
grid.jqGrid("saveRow", ids[i], null, "clientArray");
|
||||
}
|
||||
}
|
||||
,calcRowAll : function(e){
|
||||
var $g = $("#grid1");
|
||||
var rowId = e.target.id.split("_")[0];
|
||||
|
||||
var qty = Number(fnc_checkNullDefaultValue($g.find("#"+rowId+"_ORDER_QTY").val(), grid.jqGrid('getCell', rowId, "ORDER_QTY")).toString().replace(/,/g,""));
|
||||
var unitPrice = Number(fnc_checkNullDefaultValue($g.find("#"+rowId+"_PARTNER_PRICE").val(), grid.jqGrid('getCell', rowId, "PARTNER_PRICE")).toString().replace(/,/g,""));
|
||||
|
||||
var supplyPrice = qty * unitPrice;
|
||||
$g.jqGrid('setCell', rowId, "SUPPLY_UNIT_PRICE", supplyPrice);
|
||||
|
||||
this.footerSummary();
|
||||
}
|
||||
,calcAllRows: function(){
|
||||
var $g = $("#grid1");
|
||||
var ids = grid.jqGrid('getDataIDs');
|
||||
for(var i = 0; i < ids.length; i++){
|
||||
var rowId = ids[i];
|
||||
var qtyVal = $g.find("#"+rowId+"_ORDER_QTY").val();
|
||||
var priceVal = $g.find("#"+rowId+"_PARTNER_PRICE").val();
|
||||
var qty = Number(fnc_checkNullDefaultValue(qtyVal, grid.jqGrid('getCell', rowId, "ORDER_QTY")).toString().replace(/,/g,""));
|
||||
var unitPrice = Number(fnc_checkNullDefaultValue(priceVal, grid.jqGrid('getCell', rowId, "PARTNER_PRICE")).toString().replace(/,/g,""));
|
||||
grid.jqGrid('setCell', rowId, "SUPPLY_UNIT_PRICE", qty * unitPrice);
|
||||
}
|
||||
this.footerSummary();
|
||||
}
|
||||
,footerSummary: function(){
|
||||
var totalAmount = 0;
|
||||
|
||||
$.each($("#grid1").jqGrid('getDataIDs'), function(i, rowId){
|
||||
var supplyPrice = grid.jqGrid('getCell', rowId, "SUPPLY_UNIT_PRICE");
|
||||
supplyPrice = fnc_checkNullDefaultValue(supplyPrice, "0").toString().replace(/,/g,"");
|
||||
if($.isNumeric(supplyPrice)){
|
||||
totalAmount += Number(supplyPrice);
|
||||
}
|
||||
});
|
||||
|
||||
var vat = Math.floor(totalAmount * 0.1);
|
||||
var totalWithVat = totalAmount + vat;
|
||||
|
||||
$("#TOTAL_AMOUNT").val(numberWithCommasDecimal(totalAmount));
|
||||
$("#TOTAL_SUPPLY_PRICE").val(numberWithCommasDecimal(totalAmount));
|
||||
$("#TOTAL_VAT").val(numberWithCommasDecimal(vat));
|
||||
$("#TOTAL_PRICE_ALL").val(numberWithCommasDecimal(totalWithVat));
|
||||
$("#TOTAL_AMOUNT_DISPLAY").text("US$" + numberWithCommasDecimal(totalAmount));
|
||||
}
|
||||
}
|
||||
|
||||
function numberWithCommasDecimal(num) {
|
||||
var n = Number(num);
|
||||
return n.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
|
||||
$(window).on('load', function() {
|
||||
setTimeout(function() {
|
||||
if(typeof html2canvas !== 'undefined' && typeof jspdf !== 'undefined') {
|
||||
window.dataLoaded = true;
|
||||
} else if(typeof html2canvas !== 'undefined' && typeof window.jspdf !== 'undefined') {
|
||||
window.dataLoaded = true;
|
||||
} else {
|
||||
setTimeout(function() { window.dataLoaded = true; }, 1000);
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
|
||||
function fn_generateAndUploadPdf(callback) {
|
||||
if(typeof html2canvas === 'undefined') {
|
||||
if(callback && typeof callback === 'function') callback(null);
|
||||
return;
|
||||
}
|
||||
var jsPDF = window.jspdf ? window.jspdf.jsPDF : null;
|
||||
if(!jsPDF) {
|
||||
if(callback && typeof callback === 'function') callback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
$('#btnSave, #btnDown, #btnAdd, #btnDel, input[value="Close"]').closest('div').hide();
|
||||
$('.select2-container').hide();
|
||||
|
||||
var inputBackups = [];
|
||||
$('input[type="text"], input:not([type])').each(function(){
|
||||
var $input = $(this);
|
||||
var value = $input.val();
|
||||
if(value) {
|
||||
inputBackups.push({ element: $input, html: $input[0].outerHTML, parent: $input.parent() });
|
||||
var $span = $('<span class="pdf-temp-span">').text(value).css({
|
||||
'display':'inline-block','white-space':'nowrap',
|
||||
'text-align':$input.css('text-align')||'left',
|
||||
'font-size':$input.css('font-size')||'12px',
|
||||
'padding':'2px 5px','color':'#000','background':'transparent'
|
||||
});
|
||||
$input.replaceWith($span);
|
||||
inputBackups[inputBackups.length - 1].span = $span;
|
||||
}
|
||||
});
|
||||
$('select').each(function(){
|
||||
var $select = $(this);
|
||||
var value = $select.find('option:selected').text();
|
||||
if(value && value.trim() !== '' && value !== 'Select' && value !== '선택') {
|
||||
inputBackups.push({ element: $select, html: $select[0].outerHTML, parent: $select.parent(), wasHidden: $select.is(':hidden') });
|
||||
var $span = $('<span class="pdf-temp-span">').text(value).css({
|
||||
'display':'inline-block','white-space':'nowrap',
|
||||
'font-size':'12px','padding':'2px 5px','color':'#000','background':'transparent'
|
||||
});
|
||||
$select.after($span).hide();
|
||||
inputBackups[inputBackups.length - 1].span = $span;
|
||||
}
|
||||
});
|
||||
|
||||
var captureElement = document.getElementById('form1');
|
||||
html2canvas(captureElement, {
|
||||
scale: 1.5, useCORS: true, logging: false, backgroundColor: '#ffffff',
|
||||
windowWidth: captureElement.scrollWidth, windowHeight: captureElement.scrollHeight
|
||||
}).then(function(canvas) {
|
||||
$('.pdf-temp-span').remove();
|
||||
for(var i = 0; i < inputBackups.length; i++) {
|
||||
var backup = inputBackups[i];
|
||||
if(backup.element && backup.element.is('select')) { backup.element.show(); }
|
||||
else if(backup.span && backup.parent) { backup.span.replaceWith(backup.html); }
|
||||
}
|
||||
$('.select2-container').show();
|
||||
$('#btnSave, #btnDown, #btnAdd, #btnDel, input[value="Close"]').closest('div').show();
|
||||
|
||||
try {
|
||||
var imgData = canvas.toDataURL('image/jpeg', 0.7);
|
||||
var pdf = new jsPDF('p', 'mm', 'a4');
|
||||
var imgWidth = 210;
|
||||
var pageHeight = 297;
|
||||
var imgHeight = canvas.height * imgWidth / canvas.width;
|
||||
var heightLeft = imgHeight;
|
||||
var position = 0;
|
||||
pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight, undefined, 'FAST');
|
||||
heightLeft -= pageHeight;
|
||||
while (heightLeft >= 0) {
|
||||
position = heightLeft - imgHeight;
|
||||
pdf.addPage();
|
||||
pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight, undefined, 'FAST');
|
||||
heightLeft -= pageHeight;
|
||||
}
|
||||
var pdfBase64 = pdf.output('dataurlstring').split(',')[1];
|
||||
if(callback && typeof callback === 'function') callback(pdfBase64);
|
||||
} catch(pdfError) {
|
||||
if(callback && typeof callback === 'function') callback(null);
|
||||
}
|
||||
}).catch(function(error) {
|
||||
for(var i = 0; i < inputBackups.length; i++) {
|
||||
if(inputBackups[i].span) inputBackups[i].span.replaceWith(inputBackups[i].html);
|
||||
}
|
||||
$('#btnSave, #btnDown, #btnAdd, #btnDel, input[value="Close"]').closest('div').show();
|
||||
if(callback && typeof callback === 'function') callback(null);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<form name="hiddenForm" id="hiddenForm" method="post">
|
||||
<input type="hidden" name="OBJID" id="OBJID">
|
||||
</form>
|
||||
|
||||
<form name="form1" id="form1" action="" method="post">
|
||||
<input type="hidden" name="MASTER_OBJID" id="MASTER_OBJID" value="${objId}" />
|
||||
<input type="hidden" name="PROPOSAL_OBJID" id="PROPOSAL_OBJID" value="${info.PROPOSAL_OBJID}" />
|
||||
<input type="hidden" name="FORM_TYPE" id="FORM_TYPE" value="english" />
|
||||
<input type="hidden" name="CONTRACT_MGMT_OBJID" id="CONTRACT_MGMT_OBJID" value="${info.CONTRACT_MGMT_OBJID}" />
|
||||
<input type="hidden" name="SALES_REQUEST_OBJID" id="SALES_REQUEST_OBJID" value="${info.SALES_REQUEST_OBJID}" />
|
||||
<input type="hidden" name="TYPE" id="TYPE" value="${info.TYPE}" />
|
||||
<input type="hidden" name="TOTAL_AMOUNT" id="TOTAL_AMOUNT" value="" />
|
||||
<input type="hidden" name="SALES_MNG_USER_ID" id="SALES_MNG_USER_ID" value="${info.SALES_MNG_USER_ID}" />
|
||||
<input type="hidden" name="SALES_MNG_USER_ID2" id="SALES_MNG_USER_ID2" value="${info.SALES_MNG_USER_ID2}" />
|
||||
<input type="hidden" name="MANAGER_NAME" id="MANAGER_NAME" value="${info.MANAGER_NAME}" />
|
||||
<input type="hidden" name="MANAGER_POSITION" id="MANAGER_POSITION" value="${info.MANAGER_POSITION}" />
|
||||
<input type="hidden" name="MANAGER_PHONE" id="MANAGER_PHONE" value="${info.MANAGER_PHONE}" />
|
||||
<input type="hidden" name="MANAGER_EMAIL" id="MANAGER_EMAIL" value="${info.MANAGER_EMAIL}" />
|
||||
<input type="hidden" name="TOTAL_SUPPLY_PRICE" id="TOTAL_SUPPLY_PRICE" value="" />
|
||||
<input type="hidden" name="TOTAL_VAT" id="TOTAL_VAT" value="" />
|
||||
<input type="hidden" name="TOTAL_PRICE_ALL" id="TOTAL_PRICE_ALL" value="" />
|
||||
|
||||
<!-- 회사 헤더 -->
|
||||
<div class="po-header">
|
||||
<table style="width:100%; border:none;">
|
||||
<tr>
|
||||
<td style="border:none; vertical-align:top; width:120px;">
|
||||
<img src="<%=request.getContextPath()%>/images/logo.png" alt="RPS Logo" style="max-width:110px; height:auto;">
|
||||
</td>
|
||||
<td style="border:none; vertical-align:top;">
|
||||
<div class="company-name">R P S CO., LTD.</div>
|
||||
<div class="company-info">
|
||||
www.rps-korea.com<br/>
|
||||
8, Gukjegwahak 10-ro, Yuseong-gu, Daejeon, Republic of Korea<br/>
|
||||
Tel : +82-42-602-3300 / Fax : +82-42-672-3399 / E-mail : ady1225@rps-korea.com<br/>
|
||||
Purchasing Team Manager, An-Dong-Yoon
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Purchase Order 타이틀 -->
|
||||
<div class="po-title" style="text-decoration:underline;">Purchase Order</div>
|
||||
|
||||
<p style="font-size:11px; margin-bottom:8px;">We are pleased to issue Purchase Order with the terms and condition described as below.</p>
|
||||
|
||||
<!-- 기본정보 테이블 -->
|
||||
<table class="po-info-table">
|
||||
<tr>
|
||||
<td class="label-cell">Messrs.</td>
|
||||
<td class="value-cell">
|
||||
<select name="PARTNER_OBJID" id="PARTNER_OBJID" class="select2" style="width:100%;" <% if(!isModify){ %>disabled<% } %>>
|
||||
<option value="">Select</option>
|
||||
${code_map.partner_cd}
|
||||
</select>
|
||||
</td>
|
||||
<td rowspan="5" style="width:1px; border:none; padding:0;"></td>
|
||||
<td class="right-label">Shipment</td>
|
||||
<td class="right-value" style="background-color:#ebf1de;">
|
||||
<input type="text" name="SHIPMENT" id="SHIPMENT" value="${info.SHIPMENT}" style="width:100%; border:none; background-color:#ebf1de;" <% if(!isModify){ %>readonly<% } %> />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label-cell">Attn. to</td>
|
||||
<td class="value-cell">
|
||||
<input type="text" name="ATTN_TO" id="ATTN_TO" value="${info.ATTN_TO}" style="width:100%; border:none;" <% if(!isModify){ %>readonly<% } %> />
|
||||
</td>
|
||||
<td class="right-label">Payment</td>
|
||||
<td class="right-value">
|
||||
<input type="text" name="PAYMENT_TERMS" id="PAYMENT_TERMS" value="${info.PAYMENT_TERMS}" style="width:100%; border:none;" <% if(!isModify){ %>readonly<% } %> />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label-cell">Date</td>
|
||||
<td class="value-cell">
|
||||
<input type="hidden" name="PURCHASE_DATE" id="PURCHASE_DATE" value="${info.PURCHASE_DATE}" />
|
||||
<input type="text" id="PURCHASE_DATE_DISPLAY" class="date_icon" value="" style="width:100%;" <% if(!isModify){ %>readonly<% } %> />
|
||||
</td>
|
||||
<td class="right-label">Packing</td>
|
||||
<td class="right-value">
|
||||
<input type="text" name="PACKING" id="PACKING" value="${info.PACKING}" style="width:100%; border:none;" placeholder="Export Standard" <% if(!isModify){ %>readonly<% } %> />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label-cell">Ref. NO</td>
|
||||
<td class="value-cell">
|
||||
<input type="text" name="PURCHASE_ORDER_NO" id="PURCHASE_ORDER_NO" value="${info.PURCHASE_ORDER_NO}" style="width:100%; border:none; font-weight:bold;" readonly />
|
||||
</td>
|
||||
<td class="right-label">Validity</td>
|
||||
<td class="right-value">
|
||||
<input type="text" name="VALIDITY" id="VALIDITY" value="${info.VALIDITY}" style="width:100%; border:none;" <% if(!isModify){ %>readonly<% } %> />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label-cell"> </td>
|
||||
<td class="value-cell"> </td>
|
||||
<td class="right-label">Remarks</td>
|
||||
<td class="right-value">
|
||||
<input type="text" name="REMARK" id="REMARK" value="${info.REMARK}" style="width:100%; border:none;" <% if(!isModify){ %>readonly<% } %> />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- 버튼 영역 -->
|
||||
<div style="width:100%; margin:10px 0; text-align:right;">
|
||||
<% if(isModify){ %>
|
||||
<!-- <input type="button" value="Add" class="dtn" id="btnAdd" style="background:#dfeffc; padding:5px 15px; cursor:pointer; font-size:12px; border-radius:5px;">
|
||||
<input type="button" value="Delete" class="dtn" id="btnDel" style="background:#fce4ec; padding:5px 15px; cursor:pointer; font-size:12px; border-radius:5px;"> -->
|
||||
<input type="button" value="Save" class="dtn" id="btnSave" style="background:#dfeffc; padding:5px 15px; cursor:pointer; font-size:14px; border-radius:5px;">
|
||||
<% }else{ %>
|
||||
<input type="button" value="Download PO" class="" id="btnDown" style="background:#dfeffc; padding:5px 15px; cursor:pointer; font-size:14px; border-radius:5px;">
|
||||
<% } %>
|
||||
<input type="button" value="Close" class="" style="background:#dfeffc; padding:5px 15px; cursor:pointer; font-size:14px; border-radius:5px;" onclick="window.close();">
|
||||
</div>
|
||||
|
||||
<!-- 품목 그리드 -->
|
||||
<div id="plm_table_wrap1" style="width:100%; margin:0;">
|
||||
<table id="grid1"></table>
|
||||
<textarea style="display:none;" id="gridDetailList">${gridDetailList}<c:if test="${empty gridDetailList}">[]</c:if></textarea>
|
||||
</div>
|
||||
|
||||
<!-- TOTAL 영역 -->
|
||||
<table class="po-total-row" style="width:100%; margin-top:5px;">
|
||||
<tr>
|
||||
<td style="text-align:center; width:70%; background-color:#d9e2f3; font-size:14px;">TOTAL</td>
|
||||
<td style="text-align:right; width:30%;"><span id="TOTAL_AMOUNT_DISPLAY" style="font-size:14px;">US$0.00</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- 하단 메시지 -->
|
||||
<p style="font-size:11px; margin:15px 0; font-style:italic;">Look forward to your soonest delivery with good condition.</p>
|
||||
|
||||
<!-- 서명 영역 -->
|
||||
<div class="po-signature" style="position:relative;">
|
||||
<hr style="width:250px; margin:0 0 10px auto; border:none; border-top:1px solid #000;"/>
|
||||
<div class="sign-name" style="margin-right:70px;">Signed by Dong-Heon Lee / President</div>
|
||||
<div class="sign-company" style="margin-right:70px;">RPS CO.,LTD</div>
|
||||
<img src="<%=request.getContextPath()%>/images/stamp_seal.png" alt="Stamp" style="position:absolute; right:0; bottom:0; width:65px; height:65px; opacity:0.85;" onerror="this.style.display='none'">
|
||||
</div>
|
||||
|
||||
<textarea style="display:none;" id="unit_cd">${code_map.unit_cd}</textarea>
|
||||
<textarea style="display:none;" id="currency_cd">${code_map.currency_cd}</textarea>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -507,19 +507,21 @@ function fn_formPopUp(objId, copy, formType){
|
||||
var url = "";
|
||||
|
||||
if(formType == 'outsourcing'){
|
||||
// 외주가공 발주서 양식
|
||||
target = "purchaseOrderFormPopup_outsourcing";
|
||||
url = "/purchaseOrder/purchaseOrderFormPopup_outsourcing.do";
|
||||
popup_width = 1200;
|
||||
popup_height = 900;
|
||||
} else if(formType == 'english'){
|
||||
target = "purchaseOrderFormPopup_english";
|
||||
url = "/purchaseOrder/purchaseOrderFormPopup_english.do";
|
||||
popup_width = 1100;
|
||||
popup_height = 900;
|
||||
} else if(formType == 'general'){
|
||||
// 일반 발주서 양식
|
||||
target = "purchaseOrderFormPopup_general";
|
||||
url = "/purchaseOrder/purchaseOrderFormPopup_general.do";
|
||||
popup_width = 1000;
|
||||
popup_height = 900;
|
||||
} else {
|
||||
// 기존 발주서 양식 (FORM_TYPE이 없거나 기존 데이터)
|
||||
target = "purchaseOrderFormPopup_new";
|
||||
url = "/purchaseOrder/purchaseOrderFormPopup_new.do";
|
||||
}
|
||||
|
||||
@@ -529,21 +529,24 @@ function fn_generatePdfAndSend(){
|
||||
}
|
||||
});
|
||||
|
||||
// 발주서 양식 타입 확인 (일반/외주)
|
||||
// 발주서 양식 타입 확인 (일반/외주/영문)
|
||||
var formType = fnc_checkNull(purchaseOrderInfo.FORM_TYPE) || 'general';
|
||||
var url = "";
|
||||
|
||||
if(formType === 'outsourcing') {
|
||||
url = "/purchaseOrder/purchaseOrderFormPopup_outsourcing.do?actType=VIEW&PURCHASE_ORDER_MASTER_OBJID=" + purchaseOrderObjId;
|
||||
} else if(formType === 'english') {
|
||||
url = "/purchaseOrder/purchaseOrderFormPopup_english.do?actType=VIEW&PURCHASE_ORDER_MASTER_OBJID=" + purchaseOrderObjId;
|
||||
} else {
|
||||
url = "/purchaseOrder/purchaseOrderFormPopup_general.do?actType=VIEW&PURCHASE_ORDER_MASTER_OBJID=" + purchaseOrderObjId;
|
||||
}
|
||||
|
||||
// 숨겨진 iframe으로 발주서 페이지 로드
|
||||
var iframeWidth = (formType === 'english') ? '1100px' : '900px';
|
||||
var iframe = $('<iframe>', {
|
||||
id: 'pdfGeneratorFrame',
|
||||
src: url,
|
||||
style: 'position:absolute;left:-9999px;top:-9999px;width:900px;height:1200px;border:none;'
|
||||
style: 'position:absolute;left:-9999px;top:-9999px;width:' + iframeWidth + ';height:1200px;border:none;'
|
||||
}).appendTo('body');
|
||||
|
||||
// iframe 로드 완료 대기
|
||||
|
||||
@@ -55,6 +55,9 @@ String menuName = CommonUtils.getMenuName(menuObjId, "구매관리_품의서관
|
||||
max-height: 48px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
.swal2-styled {
|
||||
padding: 1em 1.5em !important;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var _tabulGrid;
|
||||
@@ -126,9 +129,10 @@ $(document).ready(function(){
|
||||
// 발주서 양식 선택 팝업
|
||||
Swal.fire({
|
||||
title: '발주서 양식을 선택하세요',
|
||||
html: '<div style="margin: 20px 0;">' +
|
||||
'<button onclick="window.openGeneralPO()" class="swal2-confirm swal2-styled" style="margin: 0 10px; background-color: #3085d6; min-width: 140px;">일반 발주서</button>' +
|
||||
'<button onclick="window.openOutsourcingPO()" class="swal2-confirm swal2-styled" style="margin: 0 10px; background-color: #28a745; min-width: 140px;">외주가공 발주서</button>' +
|
||||
html: '<div style="display:flex; justify-content:center; gap:12px; margin:20px 0;">' +
|
||||
'<button onclick="window.openGeneralPO()" class="swal2-confirm swal2-styled" style="margin:0; background-color:#3085d6; min-width:140px;">일반 발주서</button>' +
|
||||
'<button onclick="window.openOutsourcingPO()" class="swal2-confirm swal2-styled" style="margin:0; background-color:#28a745; min-width:140px;">외주가공 발주서</button>' +
|
||||
'<button onclick="window.openEnglishPO()" class="swal2-confirm swal2-styled" style="margin:0; background-color:#6f42c1; min-width:140px;">영문 발주서</button>' +
|
||||
'</div>',
|
||||
showConfirmButton: false,
|
||||
showCancelButton: true,
|
||||
@@ -147,13 +151,19 @@ $(document).ready(function(){
|
||||
Swal.close();
|
||||
fn_createPurchaseOrder(selectedRowIds, "outsourcing");
|
||||
};
|
||||
|
||||
// 영문 발주서 양식으로 발주서 자동 생성
|
||||
window.openEnglishPO = function() {
|
||||
Swal.close();
|
||||
fn_createPurchaseOrder(selectedRowIds, "english");
|
||||
};
|
||||
});
|
||||
|
||||
// 발주서 자동 생성 (기존 로직 + 양식 타입 추가)
|
||||
function fn_createPurchaseOrder(selectedRowIds, formType) {
|
||||
Swal.fire({
|
||||
title: '발주서 생성',
|
||||
text: '선택한 품의서로 ' + (formType == 'general' ? '일반' : '외주가공') + ' 발주서를 생성하시겠습니까?',
|
||||
text: '선택한 품의서로 ' + (formType == 'general' ? '일반' : formType == 'outsourcing' ? '외주가공' : '영문') + ' 발주서를 생성하시겠습니까?',
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: '생성',
|
||||
|
||||
@@ -168,6 +168,8 @@ var mbomHeaderObjid = "${resolvedMbomHeaderObjid}"; // MBOM_HEADER.OBJID (M-BOM
|
||||
var vendorList = []; // 공급업체 목록
|
||||
var processingVendorList = []; // 가공업체 목록 (Select2용 배열)
|
||||
var copiedVendorData = { field: null, value: null, displayName: '' }; // 복사된 업체 정보
|
||||
var currencyList = []; // 환종 목록 (Select2용 배열)
|
||||
var defaultCurrencyCode = ''; // 기본 환종 코드 (원)
|
||||
|
||||
// 디버그: resultMap 내용 확인 (주석처리)
|
||||
// console.log("=== JSP resultMap 디버그 ===");
|
||||
@@ -201,9 +203,11 @@ $(document).ready(function(){
|
||||
}
|
||||
console.log("가공업체 목록 변환 완료:", processingVendorList.length + "개");
|
||||
|
||||
fn_initGrid();
|
||||
logDebug("purchaseListFormPopUp :: grid initialized");
|
||||
fn_loadInitialData();
|
||||
fn_loadCurrencyList(function(){
|
||||
fn_initGrid();
|
||||
logDebug("purchaseListFormPopUp :: grid initialized");
|
||||
fn_loadInitialData();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -240,6 +244,37 @@ function fn_loadVendorList(callback) {
|
||||
}
|
||||
|
||||
|
||||
// 환종(통화) 목록 로드 (공통코드 0001533)
|
||||
function fn_loadCurrencyList(callback) {
|
||||
$.ajax({
|
||||
url: "/admin/makeCodeSelect.do",
|
||||
method: 'post',
|
||||
data: { codeId: '0001533' },
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
currencyList = [];
|
||||
if(data && data.RESULT) {
|
||||
data.RESULT.forEach(function(item) {
|
||||
var codeId = item.CODE_ID || '';
|
||||
var codeName = item.CODE_NAME || '';
|
||||
if(codeId && codeName) {
|
||||
currencyList.push({id: codeId, text: codeName});
|
||||
if(codeName === '원' || codeName === 'KRW' || codeName.indexOf('원') >= 0) {
|
||||
defaultCurrencyCode = codeId;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
console.log("환종 목록 로드 완료:", currencyList.length + "개, 기본값:", defaultCurrencyCode);
|
||||
if(callback) callback();
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
logError("환종 목록 로드 실패:", error);
|
||||
if(callback) callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function fn_loadInitialData(){
|
||||
logDebug("purchaseListFormPopUp :: fn_loadInitialData start",
|
||||
"projectMgmtObjid=", projectMgmtObjid,
|
||||
@@ -520,8 +555,8 @@ function fn_initGrid() {
|
||||
title: '지급/사급',
|
||||
field: 'SUPPLY_TYPE'
|
||||
},
|
||||
// 20. 소재소요량
|
||||
{
|
||||
// 20. 소재소요량
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'right',
|
||||
width: 100,
|
||||
@@ -610,6 +645,32 @@ function fn_initGrid() {
|
||||
return value;
|
||||
}
|
||||
},
|
||||
|
||||
// 30-1. 환종 (수정가능 - Select2 에디터, 기본값: 원)
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 100,
|
||||
title: '<span style="background-color: #FFFF00; padding: 2px 5px;">환종</span>',
|
||||
field: 'CURRENCY',
|
||||
editor: function(cell, onRendered, success, cancel, editorParams) {
|
||||
return createSelect2Editor(currencyList)(cell, onRendered, success, cancel, editorParams);
|
||||
},
|
||||
mutator: function(value, data) {
|
||||
if(!value && defaultCurrencyCode) return defaultCurrencyCode;
|
||||
return value || '';
|
||||
},
|
||||
formatter: function(cell) {
|
||||
var value = (typeof cell.getValue === 'function') ? cell.getValue() : (cell.value || '');
|
||||
if(!value) return '';
|
||||
for(var i = 0; i < currencyList.length; i++) {
|
||||
if(currencyList[i].id == value) {
|
||||
return currencyList[i].text;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
},
|
||||
// 31. 단가 (수정가능) -> 소재단가
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
|
||||
@@ -453,7 +453,7 @@ var columns = [
|
||||
else if(currencyName.includes('유로') || currencyName === 'EUR') currencySymbol = '€';
|
||||
else if(currencyName.includes('엔') || currencyName === 'JPY') currencySymbol = '¥';
|
||||
else if(currencyName.includes('위안') || currencyName === 'CNY') currencySymbol = '¥';
|
||||
return currencySymbol + Number(value).toLocaleString();
|
||||
return currencySymbol + Number(value).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
},
|
||||
// 11. 공급가액 (환종에 따라 표기)
|
||||
@@ -469,7 +469,7 @@ var columns = [
|
||||
else if(currencyName.includes('유로') || currencyName === 'EUR') currencySymbol = '€';
|
||||
else if(currencyName.includes('엔') || currencyName === 'JPY') currencySymbol = '¥';
|
||||
else if(currencyName.includes('위안') || currencyName === 'CNY') currencySymbol = '¥';
|
||||
return currencySymbol + Number(value).toLocaleString();
|
||||
return currencySymbol + Number(value).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
},
|
||||
// 12. 부가세 (환종에 따라 표기)
|
||||
@@ -485,7 +485,7 @@ var columns = [
|
||||
else if(currencyName.includes('유로') || currencyName === 'EUR') currencySymbol = '€';
|
||||
else if(currencyName.includes('엔') || currencyName === 'JPY') currencySymbol = '¥';
|
||||
else if(currencyName.includes('위안') || currencyName === 'CNY') currencySymbol = '¥';
|
||||
return currencySymbol + Number(value).toLocaleString();
|
||||
return currencySymbol + Number(value).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
},
|
||||
// 13. 총액 (환종에 따라 표기)
|
||||
@@ -501,7 +501,7 @@ var columns = [
|
||||
else if(currencyName.includes('유로') || currencyName === 'EUR') currencySymbol = '€';
|
||||
else if(currencyName.includes('엔') || currencyName === 'JPY') currencySymbol = '¥';
|
||||
else if(currencyName.includes('위안') || currencyName === 'CNY') currencySymbol = '¥';
|
||||
return currencySymbol + Number(value).toLocaleString();
|
||||
return currencySymbol + Number(value).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
},
|
||||
// 14. 원화총액
|
||||
@@ -509,7 +509,7 @@ var columns = [
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
if(!value || value === '' || value === '0') return '';
|
||||
return '₩' + Number(value).toLocaleString();
|
||||
return '₩' + Number(value).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
},
|
||||
// 15. 출하일
|
||||
@@ -629,9 +629,9 @@ function fn_search(){
|
||||
var vat = totals.total_vat || totals.TOTAL_VAT || 0;
|
||||
var amount = totals.total_amount || totals.TOTAL_AMOUNT || 0;
|
||||
|
||||
$("#totalSupplyPrice").text(Number(supplyPrice).toLocaleString());
|
||||
$("#totalVat").text(Number(vat).toLocaleString());
|
||||
$("#totalAmount").text(Number(amount).toLocaleString());
|
||||
$("#totalSupplyPrice").text(Number(supplyPrice).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}));
|
||||
$("#totalVat").text(Number(vat).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}));
|
||||
$("#totalAmount").text(Number(amount).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}));
|
||||
} else {
|
||||
$("#totalSupplyPrice").text("0");
|
||||
$("#totalVat").text("0");
|
||||
|
||||
@@ -358,7 +358,7 @@ var columns = [
|
||||
else if(currencyName.includes('유로') || currencyName === 'EUR') currencySymbol = '€';
|
||||
else if(currencyName.includes('엔') || currencyName === 'JPY') currencySymbol = '¥';
|
||||
else if(currencyName.includes('위안') || currencyName === 'CNY') currencySymbol = '¥';
|
||||
return currencySymbol + Number(value).toLocaleString();
|
||||
return currencySymbol + Number(value).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
},
|
||||
// 13. 판매공급가액
|
||||
@@ -374,7 +374,7 @@ var columns = [
|
||||
else if(currencyName.includes('유로') || currencyName === 'EUR') currencySymbol = '€';
|
||||
else if(currencyName.includes('엔') || currencyName === 'JPY') currencySymbol = '¥';
|
||||
else if(currencyName.includes('위안') || currencyName === 'CNY') currencySymbol = '¥';
|
||||
return currencySymbol + Number(value).toLocaleString();
|
||||
return currencySymbol + Number(value).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
},
|
||||
// 14. 부가세
|
||||
@@ -390,7 +390,7 @@ var columns = [
|
||||
else if(currencyName.includes('유로') || currencyName === 'EUR') currencySymbol = '€';
|
||||
else if(currencyName.includes('엔') || currencyName === 'JPY') currencySymbol = '¥';
|
||||
else if(currencyName.includes('위안') || currencyName === 'CNY') currencySymbol = '¥';
|
||||
return currencySymbol + Number(value).toLocaleString();
|
||||
return currencySymbol + Number(value).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
},
|
||||
// 15. 판매총액
|
||||
@@ -406,7 +406,7 @@ var columns = [
|
||||
else if(currencyName.includes('유로') || currencyName === 'EUR') currencySymbol = '€';
|
||||
else if(currencyName.includes('엔') || currencyName === 'JPY') currencySymbol = '¥';
|
||||
else if(currencyName.includes('위안') || currencyName === 'CNY') currencySymbol = '¥';
|
||||
return currencySymbol + Number(value).toLocaleString();
|
||||
return currencySymbol + Number(value).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
},
|
||||
// 16. 판매원화총액
|
||||
@@ -414,7 +414,7 @@ var columns = [
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
if(!value || value === '' || value === '0') return '';
|
||||
return '₩' + Number(value).toLocaleString();
|
||||
return '₩' + Number(value).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
},
|
||||
// 17. 잔량원화총액
|
||||
@@ -422,7 +422,7 @@ var columns = [
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
if(!value || value === '' || value === '0') return '';
|
||||
return '₩' + Number(value).toLocaleString();
|
||||
return '₩' + Number(value).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
},
|
||||
// 18. 수주상태
|
||||
@@ -554,9 +554,9 @@ function fn_search(){
|
||||
}
|
||||
|
||||
// 합계 표시
|
||||
$("#totalSalesAmountKRW").text(Number(totalSalesAmountKRW).toLocaleString());
|
||||
$("#shippedAmountKRW").text(Number(shippedAmountKRW).toLocaleString());
|
||||
$("#notShippedAmountKRW").text(Number(notShippedAmountKRW).toLocaleString());
|
||||
$("#totalSalesAmountKRW").text(Number(totalSalesAmountKRW).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}));
|
||||
$("#shippedAmountKRW").text(Number(shippedAmountKRW).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}));
|
||||
$("#notShippedAmountKRW").text(Number(notShippedAmountKRW).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}));
|
||||
|
||||
// 페이징 HTML 업데이트
|
||||
if(response.PAGE_HTML){
|
||||
|
||||
@@ -709,7 +709,7 @@ function fn_loadSavedStatement(projectObjid, gridData) {
|
||||
row.append($("<td contenteditable='true'>").text(quantity));
|
||||
row.append($("<td contenteditable='true' class='text-right'>").text(fn_num(item.isprice || item.ISPRICE || 0)));
|
||||
row.append($("<td contenteditable='true' class='text-right'>").text(fn_num(supply)));
|
||||
row.append($("<td contenteditable='true' class='text-right'>").text(fn_num(Math.round(vat))));
|
||||
row.append($("<td contenteditable='true' class='text-right'>").text(fn_num(vat)));
|
||||
tbody.append(row);
|
||||
}
|
||||
|
||||
@@ -725,11 +725,11 @@ function fn_loadSavedStatement(projectObjid, gridData) {
|
||||
// 합계 업데이트
|
||||
$("#totalQuantity").text(totalQuantity);
|
||||
$("#totalSupplyPrice").text(fn_num(totalSupply));
|
||||
$("#totalVat").text(fn_num(Math.round(totalVat)));
|
||||
$("#totalVat").text(fn_num(totalVat));
|
||||
|
||||
var total = totalSupply + totalVat;
|
||||
$("#totalText").text(fn_numberToKorean(Math.round(total)));
|
||||
$("#totalNum").text(fn_num(Math.round(total)));
|
||||
$("#totalNum").text(fn_num(total));
|
||||
|
||||
// contenteditable 셀 변경 시 합계 자동 업데이트
|
||||
fn_attachCellListeners();
|
||||
@@ -963,7 +963,7 @@ function fn_recalculateTotal() {
|
||||
}
|
||||
|
||||
function fn_num(n) {
|
||||
return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
return Number(n).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
|
||||
// 숫자를 한글로 변환하는 함수
|
||||
|
||||
@@ -1719,6 +1719,154 @@ public class ProductionPlanningController extends BaseService {
|
||||
return paramMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 생산관리 -> 생산계획&실적관리(장비) 목록
|
||||
*/
|
||||
@RequestMapping("/productionplanning/prodPlanResultMgmtEquipList.do")
|
||||
public String prodPlanResultMgmtEquipList(HttpServletRequest request, @RequestParam Map paramMap){
|
||||
Map code_map = new HashMap();
|
||||
try{
|
||||
code_map.put("project_no", commonService.bizMakeOptionList("", CommonUtils.nullToEmpty((String)paramMap.get("project_no")), "common.getCusProjectNoList"));
|
||||
code_map.put("product_cd", commonService.bizMakeOptionList("0000001", CommonUtils.nullToEmpty((String)paramMap.get("product_code")), "common.getCodeselect"));
|
||||
code_map.put("category_cd", commonService.bizMakeOptionList("0000167", CommonUtils.nullToEmpty((String)paramMap.get("category_code")), "common.getCodeselect"));
|
||||
code_map.put("production_type_cd", commonService.bizMakeOptionList("0001832", CommonUtils.nullToEmpty((String)paramMap.get("production_type")), "common.getCodeselect"));
|
||||
code_map.put("customer_cd", commonService.bizMakeOptionList("", CommonUtils.nullToEmpty((String)paramMap.get("customer_objid")), "common.getsupplyselect"));
|
||||
|
||||
// WBS 템플릿 목록 (Machine 제품용)
|
||||
List wbsTemplateList = commonService.selectList("productionplanning.getWbsTemplateOptionList", request, paramMap);
|
||||
StringBuilder wbsTemplateSb = new StringBuilder();
|
||||
if(wbsTemplateList != null) {
|
||||
for(int i=0; i<wbsTemplateList.size(); i++) {
|
||||
Map row = (Map)wbsTemplateList.get(i);
|
||||
wbsTemplateSb.append("<option value=\"").append(row.get("OBJID")).append("\">").append(row.get("TITLE")).append("</option>");
|
||||
}
|
||||
}
|
||||
code_map.put("wbs_template", wbsTemplateSb.toString());
|
||||
|
||||
request.setAttribute("code_map", code_map);
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "/productionplanning/prodPlanResultMgmtEquipList";
|
||||
}
|
||||
|
||||
/**
|
||||
* 생산관리 -> 생산계획&실적관리(장비) 그리드 목록
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/productionplanning/prodPlanResultMgmtEquipGridList.do")
|
||||
public Map prodPlanResultMgmtEquipGridList(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
String[] projectNos = request.getParameterValues("search_project_no");
|
||||
if(projectNos != null && projectNos.length > 0) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(int i = 0; i < projectNos.length; i++) {
|
||||
if(i > 0) sb.append(",");
|
||||
sb.append(projectNos[i]);
|
||||
}
|
||||
paramMap.put("search_project_nos", sb.toString());
|
||||
}
|
||||
|
||||
commonService.selectListPagingNew("productionplanning.prodPlanResultMgmtEquipGridList", request, paramMap);
|
||||
return paramMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 장비 WBS할당 팝업
|
||||
*/
|
||||
@RequestMapping("/productionplanning/prodPlanWbsAssignPopup.do")
|
||||
public String prodPlanWbsAssignPopup(HttpServletRequest request, @RequestParam Map paramMap){
|
||||
try{
|
||||
// 프로젝트 정보 조회
|
||||
Map projectInfo = commonService.selectOne("productionplanning.getEquipProjectInfo", request, paramMap);
|
||||
request.setAttribute("projectInfo", projectInfo);
|
||||
|
||||
// WBS 템플릿 목록
|
||||
List templateList = commonService.selectList("productionplanning.getWbsTemplateOptionList", request, paramMap);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if(templateList != null){
|
||||
for(int i=0; i<templateList.size(); i++){
|
||||
Map row = (Map)templateList.get(i);
|
||||
sb.append("<option value=\"").append(row.get("OBJID")).append("\">").append(row.get("TITLE")).append("</option>");
|
||||
}
|
||||
}
|
||||
request.setAttribute("wbsTemplateOptions", sb.toString());
|
||||
|
||||
// 사용자 목록
|
||||
List userList = commonService.selectList("common.getUserselect6", request, new HashMap());
|
||||
request.setAttribute("userList", userList);
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "/productionplanning/prodPlanWbsAssignPopup";
|
||||
}
|
||||
|
||||
/**
|
||||
* 장비 WBS 템플릿 태스크 목록 조회
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/productionplanning/getWbsTemplateTasks.do")
|
||||
public Map getWbsTemplateTasks(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
Map result = new HashMap();
|
||||
try{
|
||||
List list = commonService.selectList("productionplanning.getWbsTemplateTasks", request, paramMap);
|
||||
result.put("list", list);
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
result.put("list", new ArrayList());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 장비 프로젝트의 기존 WBS 태스크 목록 조회
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/productionplanning/getEquipWbsTaskList.do")
|
||||
public Map getEquipWbsTaskList(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
Map result = new HashMap();
|
||||
try{
|
||||
List list = commonService.selectList("productionplanning.getEquipWbsTaskList", request, paramMap);
|
||||
result.put("list", list);
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
result.put("list", new ArrayList());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 장비 WBS 할당 저장
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/productionplanning/saveEquipWbsAssign.do")
|
||||
public Map saveEquipWbsAssign(HttpServletRequest request, @RequestBody Map<String, Object> paramMap){
|
||||
try{
|
||||
HttpSession session = request.getSession();
|
||||
PersonBean loginUser = (PersonBean)session.getAttribute(Constants.PERSON_BEAN);
|
||||
if(loginUser != null){
|
||||
paramMap.put("writer", loginUser.getUserId());
|
||||
} else {
|
||||
paramMap.put("writer", "");
|
||||
}
|
||||
|
||||
List<Map<String, Object>> tasks = (List<Map<String, Object>>)paramMap.get("tasks");
|
||||
if(tasks == null || tasks.isEmpty()){
|
||||
Map result = new HashMap();
|
||||
result.put("success", false);
|
||||
result.put("message", "저장할 태스크가 없습니다.");
|
||||
return result;
|
||||
}
|
||||
|
||||
return productionPlanningService.saveEquipWbsAssign(paramMap);
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
Map result = new HashMap();
|
||||
result.put("success", false);
|
||||
result.put("message", e.getMessage());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 생산계획 생성 팝업
|
||||
* @param request
|
||||
|
||||
@@ -863,6 +863,180 @@ public class PurchaseOrderController {
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 영문 발주서 양식 팝업
|
||||
*/
|
||||
@RequestMapping("/purchaseOrder/purchaseOrderFormPopup_english.do")
|
||||
public String purchaseOrderFormPopup_english(HttpSession session, HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
Map code_map = new HashMap();
|
||||
Map info = new HashMap();
|
||||
List detailList = new ArrayList();
|
||||
HashMap oemInfo = new HashMap();
|
||||
|
||||
PersonBean person = (PersonBean)session.getAttribute(Constants.PERSON_BEAN);
|
||||
String objId = CommonUtils.checkNull(paramMap.get("PURCHASE_ORDER_MASTER_OBJID"), "");
|
||||
String proposalObjId = CommonUtils.checkNull(paramMap.get("PROPOSAL_OBJID"), "");
|
||||
String writer = CommonUtils.checkNull(person.getUserId());
|
||||
String writerName = person.getUserName();
|
||||
|
||||
try{
|
||||
oemInfo = (HashMap)adminService.getSupMngInfo("-1130201617");
|
||||
|
||||
if(objId.equals("")){
|
||||
request.setAttribute("actType", "C");
|
||||
objId = CommonUtils.createObjId();
|
||||
info.put("actType", "C");
|
||||
info.put("OBJID", objId);
|
||||
info.put("PROPOSAL_OBJID", proposalObjId);
|
||||
info.put("SALES_MNG_USER_ID", writer);
|
||||
info.put("PURCHASE_ORDER_NO", "RPS" + new java.text.SimpleDateFormat("yy").format(new java.util.Date()) + "-" + new java.text.SimpleDateFormat("MMdd").format(new java.util.Date()) + "-rev1");
|
||||
info.put("PURCHASE_DATE", new java.text.SimpleDateFormat("yyyy-MM-dd").format(new java.util.Date()));
|
||||
info.put("SHIPMENT", "OCS");
|
||||
info.put("PACKING", "Export Standard");
|
||||
info.put("MANAGER_NAME", "An-Dong-Yoon");
|
||||
info.put("MANAGER_POSITION", "Team Manager");
|
||||
info.put("MANAGER_PHONE", "+82-42-602-3300");
|
||||
info.put("MANAGER_EMAIL", "ady1225@rps-korea.com");
|
||||
|
||||
// 품의서 마스터 정보 조회 (프로젝트번호, 품의서OBJID 등)
|
||||
if(!"".equals(proposalObjId)){
|
||||
Map proposalInfoParam = new HashMap();
|
||||
proposalInfoParam.put("PROPOSAL_OBJID", proposalObjId);
|
||||
Map proposalMaster = (Map) commonService.selectOne("salesMng.getProposalInfo", request, proposalInfoParam);
|
||||
if(proposalMaster != null){
|
||||
info.put("SALES_REQUEST_OBJID", proposalObjId);
|
||||
String projectNo = CommonUtils.checkNull(proposalMaster.get("PROJECT_NO"));
|
||||
if("".equals(projectNo)) projectNo = CommonUtils.checkNull(proposalMaster.get("project_no"));
|
||||
if(!"".equals(projectNo)) info.put("CONTRACT_MGMT_OBJID", projectNo);
|
||||
}
|
||||
}
|
||||
|
||||
if(!"".equals(proposalObjId)){
|
||||
Map proposalParam = new HashMap();
|
||||
proposalParam.put("PROPOSAL_OBJID", proposalObjId);
|
||||
List proposalPartList = commonService.selectList("salesMng.getProposalPartList", request, proposalParam);
|
||||
if(proposalPartList != null && proposalPartList.size() > 0){
|
||||
for(int i = 0; i < proposalPartList.size(); i++){
|
||||
Map partRow = (Map)proposalPartList.get(i);
|
||||
Map detailRow = new HashMap();
|
||||
detailRow.put("OBJID", "");
|
||||
|
||||
String partObjId = CommonUtils.checkNull(partRow.get("PART_OBJID"));
|
||||
if("".equals(partObjId)) partObjId = CommonUtils.checkNull(partRow.get("part_objid"));
|
||||
detailRow.put("PART_OBJID", partObjId);
|
||||
|
||||
String partNo = CommonUtils.checkNull(partRow.get("PART_NO"));
|
||||
if("".equals(partNo)) partNo = CommonUtils.checkNull(partRow.get("part_no"));
|
||||
detailRow.put("PART_NO", partNo);
|
||||
|
||||
String partName = CommonUtils.checkNull(partRow.get("PART_NAME"));
|
||||
if("".equals(partName)) partName = CommonUtils.checkNull(partRow.get("part_name"));
|
||||
detailRow.put("PART_NAME", partName);
|
||||
|
||||
String spec = CommonUtils.checkNull(partRow.get("SPEC"));
|
||||
if("".equals(spec)) spec = CommonUtils.checkNull(partRow.get("spec"));
|
||||
detailRow.put("SPEC", spec);
|
||||
|
||||
Object qtyObj = partRow.get("QTY");
|
||||
if(qtyObj == null) qtyObj = partRow.get("qty");
|
||||
String qtyStr = CommonUtils.checkNull(qtyObj, "0").toString().replaceAll(",", "");
|
||||
int qty = 0;
|
||||
try { qty = (int)Double.parseDouble(qtyStr.equals("") ? "0" : qtyStr); } catch(Exception e) { qty = 0; }
|
||||
detailRow.put("ORDER_QTY", qty);
|
||||
|
||||
// 단위: 품의서의 DB 코드값 사용
|
||||
String unit = CommonUtils.checkNull(partRow.get("UNIT"));
|
||||
if("".equals(unit)) unit = CommonUtils.checkNull(partRow.get("unit"));
|
||||
detailRow.put("UNIT", "".equals(unit) ? "0001400" : unit);
|
||||
|
||||
// 환종: 기본 USD
|
||||
detailRow.put("CURRENCY", "USD");
|
||||
|
||||
Object priceObj = partRow.get("UNIT_PRICE");
|
||||
if(priceObj == null) priceObj = partRow.get("unit_price");
|
||||
String priceStr = CommonUtils.checkNull(priceObj, "0").toString().replaceAll(",", "");
|
||||
double unitPrice = 0;
|
||||
try { unitPrice = Double.parseDouble(priceStr.equals("") ? "0" : priceStr); } catch(Exception e) { unitPrice = 0; }
|
||||
detailRow.put("PARTNER_PRICE", unitPrice);
|
||||
|
||||
detailRow.put("SUPPLY_UNIT_PRICE", qty * unitPrice);
|
||||
|
||||
// 입고요청일
|
||||
Object deliveryDateObj = partRow.get("DELIVERY_REQUEST_DATE");
|
||||
detailRow.put("DELIVERY_REQUEST_DATE", deliveryDateObj != null ? String.valueOf(deliveryDateObj).trim() : "");
|
||||
|
||||
detailList.add(detailRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
info = purchaseOrderService.getPurchaseOrderMasterInfo(request, paramMap);
|
||||
paramMap.put("MULTI_MASTER_OBJID", objId);
|
||||
detailList = commonService.selectList("purchaseOrder.getPURCHASE_ORDER_PART", request, paramMap);
|
||||
}
|
||||
|
||||
code_map.put("partner_cd", commonService.bizMakeOptionList("", (String)info.get("PARTNER_OBJID"),"common.getClientMngSupplySelect"));
|
||||
|
||||
// 단위 코드 (그리드 select용)
|
||||
Map param = new HashMap();
|
||||
param.put("code","0001399");
|
||||
code_map.put("unit_cd", commonService.getJqGridSelectBoxJsonData2("common.getCodeselect", param, "Select", "CODE", "NAME"));
|
||||
|
||||
// 환종 코드 (그리드 select용)
|
||||
Map currencyParam = new HashMap();
|
||||
currencyParam.put("code","0001533");
|
||||
code_map.put("currency_cd", commonService.getJqGridSelectBoxJsonData2("common.getCodeselect", currencyParam, "Select", "CODE", "NAME"));
|
||||
|
||||
code_map.put("payment_terms_cd", commonService.bizMakeOptionList("0001074", (String)info.get("PAYMENT_TERMS"),"common.getCodeselect"));
|
||||
|
||||
request.setAttribute("oemInfo", oemInfo);
|
||||
request.setAttribute("info", info);
|
||||
request.setAttribute("gridDetailList", JsonUtil.ListToJson(detailList));
|
||||
request.setAttribute("code_map", code_map);
|
||||
request.setAttribute("objId", objId);
|
||||
request.setAttribute("writer", writer);
|
||||
request.setAttribute("writerName", writerName);
|
||||
|
||||
Map userParam = new HashMap();
|
||||
List userList = commonService.selectList("common.getUserList", request, userParam);
|
||||
request.setAttribute("userList", userList);
|
||||
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if(CommonUtils.checkNull(paramMap.get("actType")).equals("DOWN")){
|
||||
request.setAttribute("detailList", detailList);
|
||||
Map apprParam = new HashMap();
|
||||
apprParam.put("objId", objId);
|
||||
request.setAttribute("apprList", commonService.getApprovalLine(apprParam));
|
||||
return "/purchaseOrder/purchaseOrderFormPopup_englishDOWN";
|
||||
}else{
|
||||
return "/purchaseOrder/purchaseOrderFormPopup_english";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 영문 발주서 저장
|
||||
*/
|
||||
@RequestMapping("/purchaseOrder/purchaseOrderFormPopup_englishSave.do")
|
||||
@ResponseBody
|
||||
public Map purchaseOrderFormPopup_englishSave(HttpSession session, HttpServletRequest request, @RequestParam Map paramMap){
|
||||
Map resultMap = new HashMap();
|
||||
try{
|
||||
PersonBean person = (PersonBean)session.getAttribute(Constants.PERSON_BEAN);
|
||||
paramMap.put("WRITER", CommonUtils.checkNull(person.getUserId()));
|
||||
paramMap.put("FORM_TYPE", "english");
|
||||
|
||||
purchaseOrderService.savePurchaseOrder_new(request, paramMap);
|
||||
CommonUtils.setReqResult(request, "", "S", null, resultMap);
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
CommonUtils.setReqResult(request, "", "F", e, resultMap);
|
||||
}
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 외주가공 발주서 양식 팝업
|
||||
*/
|
||||
|
||||
@@ -9417,7 +9417,8 @@ select
|
||||
from
|
||||
PART_MNG
|
||||
WHERE STATUS = 'release'
|
||||
AND ODRFG = '2'
|
||||
AND ACCTFG = '0'
|
||||
-- AND ODRFG = '2'
|
||||
ORDER BY PART_NAME
|
||||
</select>
|
||||
|
||||
@@ -9443,7 +9444,8 @@ ORDER BY PART_NAME
|
||||
FROM PART_MNG
|
||||
WHERE PART_NAME = #{materialCode}
|
||||
AND STATUS = 'release'
|
||||
AND ODRFG = '2'
|
||||
AND ACCTFG = '0'
|
||||
-- AND ODRFG = '2'
|
||||
ORDER BY SPEC
|
||||
</select>
|
||||
|
||||
@@ -9474,7 +9476,8 @@ ORDER BY PART_NAME
|
||||
WHERE PART_NAME = #{materialCode}
|
||||
AND SPEC = #{sizeSpec}
|
||||
AND STATUS = 'release'
|
||||
AND ODRFG = '2'
|
||||
AND ACCTFG = '0'
|
||||
-- AND ODRFG = '2'
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
|
||||
@@ -4603,6 +4603,7 @@
|
||||
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 != ''
|
||||
AND PM.PRODUCT != '0000928'
|
||||
|
||||
UNION ALL
|
||||
|
||||
@@ -4712,6 +4713,276 @@
|
||||
</if>
|
||||
ORDER BY T.SORT_DATE DESC, T.PROJECT_NO DESC
|
||||
</select>
|
||||
|
||||
<!-- 장비 WBS 템플릿 옵션 목록 -->
|
||||
<select id="getWbsTemplateOptionList" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
SELECT OBJID, TITLE
|
||||
FROM PMS_WBS_TEMPLATE
|
||||
WHERE 1=1
|
||||
ORDER BY TITLE
|
||||
</select>
|
||||
|
||||
<!-- 장비 프로젝트 기본정보 조회 -->
|
||||
<select id="getEquipProjectInfo" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
SELECT
|
||||
PM.OBJID,
|
||||
PM.PROJECT_NO,
|
||||
COALESCE(CI.PART_NO, PM.PART_NO, '') AS PART_NO,
|
||||
COALESCE(CI.PART_NAME, PM.PART_NAME, '') AS PART_NAME
|
||||
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'
|
||||
WHERE PM.OBJID::VARCHAR = #{projectObjid}::VARCHAR
|
||||
</select>
|
||||
|
||||
<!-- 장비 WBS 템플릿 태스크 목록 조회 -->
|
||||
<select id="getWbsTemplateTasks" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
SELECT
|
||||
T.OBJID,
|
||||
T.PARENT_OBJID,
|
||||
T.TASK_NAME,
|
||||
T.TASK_SEQ,
|
||||
T.TASK_LEVEL,
|
||||
T.USER_ID,
|
||||
T.UNIT_NO,
|
||||
T.UPPER_TASK_OBJID
|
||||
FROM PMS_WBS_TASK_STANDARD T
|
||||
WHERE T.PARENT_OBJID = #{templateObjid}
|
||||
ORDER BY CAST(T.TASK_SEQ AS INTEGER)
|
||||
</select>
|
||||
|
||||
<!-- 장비 프로젝트의 기존 WBS 태스크 목록 조회 -->
|
||||
<select id="getEquipWbsTaskList" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
SELECT
|
||||
T.OBJID,
|
||||
T.CONTRACT_OBJID,
|
||||
T.PARENT_OBJID,
|
||||
T.TASK_NAME,
|
||||
T.TASK_SEQ,
|
||||
T.UNIT_NO,
|
||||
COALESCE(T.TASK_LEVEL, '') AS TASK_LEVEL,
|
||||
COALESCE(T.UPPER_TASK_OBJID, '') AS UPPER_TASK_OBJID,
|
||||
COALESCE(T.TEMPLATE_TASK_OBJID, '') AS TEMPLATE_TASK_OBJID,
|
||||
CASE WHEN #{wbsType} = 'PRODUCE' THEN COALESCE(T.PRODUCE_USER_ID, '')
|
||||
ELSE COALESCE(T.SHIP_USER_ID, '') END AS USER_ID,
|
||||
CASE WHEN #{wbsType} = 'PRODUCE' THEN COALESCE(T.PRODUCE_PLAN_START, '')
|
||||
ELSE COALESCE(T.SHIP_PLAN_START, '') END AS PLAN_START,
|
||||
CASE WHEN #{wbsType} = 'PRODUCE' THEN COALESCE(T.PRODUCE_PLAN_END, '')
|
||||
ELSE COALESCE(T.SHIP_PLAN_END, '') END AS PLAN_END,
|
||||
CASE WHEN #{wbsType} = 'PRODUCE' THEN COALESCE(T.PRODUCE_ACT_START, '')
|
||||
ELSE COALESCE(T.SHIP_ACT_START, '') END AS ACT_START,
|
||||
CASE WHEN #{wbsType} = 'PRODUCE' THEN COALESCE(T.PRODUCE_ACT_END, '')
|
||||
ELSE COALESCE(T.SHIP_ACT_END, '') END AS ACT_END,
|
||||
COALESCE(T.REMARK, '') AS REMARK,
|
||||
COALESCE(T.PROGRESS, '') AS PROGRESS
|
||||
FROM PMS_WBS_TASK T
|
||||
WHERE T.CONTRACT_OBJID = #{projectObjid}
|
||||
AND COALESCE(T.WBS_TYPE, '') = #{wbsType}
|
||||
ORDER BY CAST(COALESCE(NULLIF(T.TASK_SEQ,''), '0') AS INTEGER)
|
||||
</select>
|
||||
|
||||
<!-- 장비 WBS 태스크 삭제 -->
|
||||
<delete id="deleteEquipWbsTasks" parameterType="map">
|
||||
DELETE FROM PMS_WBS_TASK
|
||||
WHERE CONTRACT_OBJID = #{projectObjid}
|
||||
AND COALESCE(WBS_TYPE, '') = #{wbsType}
|
||||
</delete>
|
||||
|
||||
<!-- 장비 WBS 태스크 INSERT -->
|
||||
<insert id="insertEquipWbsTask" parameterType="map">
|
||||
INSERT INTO PMS_WBS_TASK (
|
||||
OBJID,
|
||||
CONTRACT_OBJID,
|
||||
PARENT_OBJID,
|
||||
TASK_NAME,
|
||||
TASK_SEQ,
|
||||
TASK_LEVEL,
|
||||
UNIT_NO,
|
||||
UPPER_TASK_OBJID,
|
||||
TEMPLATE_TASK_OBJID,
|
||||
WBS_TYPE,
|
||||
<if test="wbsType == 'PRODUCE'">
|
||||
PRODUCE_USER_ID,
|
||||
PRODUCE_PLAN_START,
|
||||
PRODUCE_PLAN_END,
|
||||
PRODUCE_ACT_START,
|
||||
PRODUCE_ACT_END,
|
||||
</if>
|
||||
<if test="wbsType == 'SHIP'">
|
||||
SHIP_USER_ID,
|
||||
SHIP_PLAN_START,
|
||||
SHIP_PLAN_END,
|
||||
SHIP_ACT_START,
|
||||
SHIP_ACT_END,
|
||||
</if>
|
||||
REMARK,
|
||||
PROGRESS,
|
||||
WRITER
|
||||
) VALUES (
|
||||
#{newObjid},
|
||||
#{projectObjid},
|
||||
'',
|
||||
#{taskName},
|
||||
#{taskSeq},
|
||||
#{taskLevel},
|
||||
#{unitNo},
|
||||
#{upperTaskObjid},
|
||||
#{templateTaskObjid},
|
||||
#{wbsType},
|
||||
<if test="wbsType == 'PRODUCE'">
|
||||
#{userId},
|
||||
#{planStart},
|
||||
#{planEnd},
|
||||
#{actStart},
|
||||
#{actEnd},
|
||||
</if>
|
||||
<if test="wbsType == 'SHIP'">
|
||||
#{userId},
|
||||
#{planStart},
|
||||
#{planEnd},
|
||||
#{actStart},
|
||||
#{actEnd},
|
||||
</if>
|
||||
#{remark},
|
||||
#{progress},
|
||||
#{writer}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<!-- 생산계획&실적관리(장비) 그리드 목록 조회 - Machine 제품만 -->
|
||||
<select id="prodPlanResultMgmtEquipGridList" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
SELECT * FROM (
|
||||
SELECT
|
||||
PM.OBJID,
|
||||
PM.PROJECT_NO,
|
||||
CM.PRODUCT,
|
||||
COALESCE(
|
||||
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.PRODUCT LIMIT 1),
|
||||
''
|
||||
) AS PRODUCT_NAME,
|
||||
CM.CATEGORY_CD AS CATEGORY_CODE,
|
||||
COALESCE(
|
||||
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.CATEGORY_CD LIMIT 1),
|
||||
CM.CATEGORY_CD
|
||||
) 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,
|
||||
CM.CUSTOMER_OBJID,
|
||||
COALESCE(
|
||||
CASE
|
||||
WHEN CM.CUSTOMER_OBJID LIKE 'C_%' THEN
|
||||
(SELECT CLIENT_NM FROM CLIENT_MNG AS C WHERE 'C_' || C.OBJID::VARCHAR = CM.CUSTOMER_OBJID LIMIT 1)
|
||||
ELSE
|
||||
(SELECT SUPPLY_NAME FROM SUPPLY_MNG WHERE OBJID::VARCHAR = CM.CUSTOMER_OBJID::VARCHAR LIMIT 1)
|
||||
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,
|
||||
(SELECT
|
||||
CASE
|
||||
WHEN COUNT(*) = 0 THEN ''
|
||||
WHEN COUNT(*) = 1 THEN MIN(CIS.SERIAL_NO)
|
||||
ELSE MIN(CIS.SERIAL_NO) || ' 외 ' || (COUNT(*) - 1)::TEXT || '건'
|
||||
END
|
||||
FROM CONTRACT_ITEM_SERIAL CIS
|
||||
WHERE CIS.ITEM_OBJID = CI.OBJID
|
||||
AND UPPER(CIS.STATUS) = 'ACTIVE'
|
||||
AND CIS.SERIAL_NO IS NOT NULL) AS SERIAL_NO,
|
||||
-- 생산WBS: WBS_TYPE='PRODUCE'인 태스크 존재 여부
|
||||
(SELECT COUNT(1) FROM PMS_WBS_TASK AS O
|
||||
WHERE O.CONTRACT_OBJID = PM.OBJID
|
||||
AND O.WBS_TYPE = 'PRODUCE'
|
||||
) AS PROD_WBS_CNT,
|
||||
-- 생산진척율: Level1 PROGRESS 평균 (계층별 집계 결과)
|
||||
CASE
|
||||
WHEN (SELECT COUNT(1) FROM PMS_WBS_TASK AS O
|
||||
WHERE O.CONTRACT_OBJID = PM.OBJID
|
||||
AND O.WBS_TYPE = 'PRODUCE' AND O.TASK_LEVEL = '1') = 0 THEN 0
|
||||
ELSE ROUND(
|
||||
(SELECT COALESCE(AVG(CASE WHEN O.PROGRESS IS NOT NULL AND O.PROGRESS != ''
|
||||
THEN CAST(O.PROGRESS AS numeric) ELSE 0 END), 0)
|
||||
FROM PMS_WBS_TASK AS O
|
||||
WHERE O.CONTRACT_OBJID = PM.OBJID
|
||||
AND O.WBS_TYPE = 'PRODUCE' AND O.TASK_LEVEL = '1')
|
||||
, 1)
|
||||
END AS PROD_PROGRESS_RATE,
|
||||
-- 납품WBS: WBS_TYPE='SHIP'인 태스크 존재 여부
|
||||
(SELECT COUNT(1) FROM PMS_WBS_TASK AS O
|
||||
WHERE O.CONTRACT_OBJID = PM.OBJID
|
||||
AND O.WBS_TYPE = 'SHIP'
|
||||
) AS DELV_WBS_CNT,
|
||||
-- 납품진척율: Level1 PROGRESS 평균 (계층별 집계 결과)
|
||||
CASE
|
||||
WHEN (SELECT COUNT(1) FROM PMS_WBS_TASK AS O
|
||||
WHERE O.CONTRACT_OBJID = PM.OBJID
|
||||
AND O.WBS_TYPE = 'SHIP' AND O.TASK_LEVEL = '1') = 0 THEN 0
|
||||
ELSE ROUND(
|
||||
(SELECT COALESCE(AVG(CASE WHEN O.PROGRESS IS NOT NULL AND O.PROGRESS != ''
|
||||
THEN CAST(O.PROGRESS AS numeric) ELSE 0 END), 0)
|
||||
FROM PMS_WBS_TASK AS O
|
||||
WHERE O.CONTRACT_OBJID = PM.OBJID
|
||||
AND O.WBS_TYPE = 'SHIP' AND O.TASK_LEVEL = '1')
|
||||
, 1)
|
||||
END AS DELV_PROGRESS_RATE,
|
||||
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 != ''
|
||||
AND PM.PRODUCT = '0000928'
|
||||
) T
|
||||
WHERE 1=1
|
||||
<if test="search_project_nos != null and search_project_nos != ''">
|
||||
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 T.PRODUCT = #{search_product_code}
|
||||
</if>
|
||||
<if test="search_category_code != null and search_category_code != ''">
|
||||
AND T.CATEGORY_CODE = #{search_category_code}
|
||||
</if>
|
||||
<if test="search_production_type != null and search_production_type != ''">
|
||||
AND T.PRODUCTION_TYPE = #{search_production_type}
|
||||
</if>
|
||||
<if test="search_customer_objid != null and search_customer_objid != ''">
|
||||
AND (
|
||||
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 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 T.REQ_DEL_DATE <= #{search_req_del_date_to}
|
||||
</if>
|
||||
<if test="search_part_no != null and 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(T.PART_NAME) LIKE '%' || UPPER(#{search_part_name}) || '%'
|
||||
</if>
|
||||
<if test="search_serial_no != null and search_serial_no != ''">
|
||||
AND UPPER(T.SERIAL_NO) LIKE '%' || UPPER(#{search_serial_no}) || '%'
|
||||
</if>
|
||||
ORDER BY T.SORT_DATE DESC, T.PROJECT_NO DESC
|
||||
</select>
|
||||
|
||||
<!-- 프로젝트 정보 조회 (생산계획 폼용) - PROJECT_MGMT 또는 PRODUCTION_PLAN에서 조회 -->
|
||||
<select id="getProdPlanProjectInfo" parameterType="map" resultType="map">
|
||||
|
||||
@@ -583,6 +583,10 @@
|
||||
,DELIVERY_PLAN_DATE
|
||||
,DELIVERY_PLAN_QTY
|
||||
,PURCHASE_ORDER_NO_ORG
|
||||
,SHIPMENT
|
||||
,PACKING
|
||||
,VALIDITY
|
||||
,ATTN_TO
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@@ -640,6 +644,10 @@
|
||||
,#{DELIVERY_PLAN_DATE}
|
||||
,#{DELIVERY_PLAN_QTY}
|
||||
,#{PURCHASE_ORDER_NO_ORG}
|
||||
,#{SHIPMENT}
|
||||
,#{PACKING}
|
||||
,#{VALIDITY}
|
||||
,#{ATTN_TO}
|
||||
) ON CONFLICT (OBJID) DO
|
||||
UPDATE
|
||||
SET
|
||||
@@ -699,6 +707,10 @@
|
||||
,MULTI_YN = #{MULTI_YN}
|
||||
,MULTI_MASTER_YN = #{MULTI_MASTER_YN}
|
||||
,PURCHASE_ORDER_NO_ORG = #{PURCHASE_ORDER_NO_ORG}
|
||||
,SHIPMENT = #{SHIPMENT}
|
||||
,PACKING = #{PACKING}
|
||||
,VALIDITY = #{VALIDITY}
|
||||
,ATTN_TO = #{ATTN_TO}
|
||||
</update>
|
||||
<!--
|
||||
<update id="mergePurchaseOrderMulti" parameterType="map">
|
||||
@@ -1218,6 +1230,7 @@
|
||||
,PRODUCT_NAME
|
||||
,WORK_ORDER_NO
|
||||
,DELIVERY_REQUEST_DATE
|
||||
,CURRENCY
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@@ -1261,6 +1274,7 @@
|
||||
,#{PRODUCT_NAME}
|
||||
,#{WORK_ORDER_NO}
|
||||
,#{DELIVERY_REQUEST_DATE}
|
||||
,#{CURRENCY}
|
||||
) ON CONFLICT (OBJID) DO
|
||||
UPDATE
|
||||
SET
|
||||
@@ -1292,6 +1306,7 @@
|
||||
,PRODUCT_NAME = #{PRODUCT_NAME}
|
||||
,WORK_ORDER_NO = #{WORK_ORDER_NO}
|
||||
,DELIVERY_REQUEST_DATE = #{DELIVERY_REQUEST_DATE}
|
||||
,CURRENCY = #{CURRENCY}
|
||||
</update>
|
||||
|
||||
<select id="getMyCompanyInfo" parameterType="map" resultType="map">
|
||||
@@ -1462,8 +1477,14 @@
|
||||
|
||||
-- 요청사항
|
||||
,POM.REQUEST_CONTENT
|
||||
|
||||
-- 양식 타입 (general/outsourcing)
|
||||
|
||||
-- 영문발주서 전용 필드
|
||||
,POM.SHIPMENT
|
||||
,POM.PACKING
|
||||
,POM.VALIDITY
|
||||
,POM.ATTN_TO
|
||||
|
||||
-- 양식 타입 (general/outsourcing/english)
|
||||
,COALESCE(POM.FORM_TYPE, 'general') AS FORM_TYPE
|
||||
FROM
|
||||
PURCHASE_ORDER_MASTER POM
|
||||
|
||||
@@ -3913,6 +3913,7 @@ ORDER BY V.PATH2
|
||||
PO_QTY = COALESCE(NULLIF(TRIM(#{PO_QTY}::TEXT), '')::NUMERIC, 0),
|
||||
VENDOR = #{VENDOR_PM},
|
||||
PROCESSING_VENDOR = #{PROCESSING_VENDOR},
|
||||
CURRENCY = #{CURRENCY},
|
||||
UNIT_PRICE = COALESCE(NULLIF(TRIM(#{UNIT_PRICE}::TEXT), '')::NUMERIC, 0),
|
||||
TOTAL_PRICE = COALESCE(NULLIF(TRIM(#{TOTAL_PRICE}::TEXT), '')::NUMERIC, 0),
|
||||
PROCESSING_UNIT_PRICE = COALESCE(NULLIF(TRIM(#{PROCESSING_UNIT_PRICE}::TEXT), '')::NUMERIC, 0),
|
||||
|
||||
@@ -579,28 +579,32 @@
|
||||
-- 최근 차수 견적서 합계 정보
|
||||
,(SELECT TOTAL_AMOUNT FROM ESTIMATE_TEMPLATE WHERE CONTRACT_OBJID = T.OBJID ORDER BY REGDATE DESC LIMIT 1) AS EST_TOTAL_AMOUNT
|
||||
,CASE
|
||||
WHEN T.EXCHANGE_RATE IS NOT NULL AND T.EXCHANGE_RATE != '' AND CAST(T.EXCHANGE_RATE AS NUMERIC) != 0
|
||||
WHEN T.EXCHANGE_RATE IS NOT NULL AND T.EXCHANGE_RATE != ''
|
||||
AND REPLACE(T.EXCHANGE_RATE, ',', '') ~ '^\d+\.?\d*$'
|
||||
AND CAST(REPLACE(T.EXCHANGE_RATE, ',', '') AS NUMERIC) != 0
|
||||
THEN ROUND(
|
||||
CAST(COALESCE((SELECT TOTAL_AMOUNT FROM ESTIMATE_TEMPLATE WHERE CONTRACT_OBJID = T.OBJID ORDER BY REGDATE DESC LIMIT 1), '0') AS NUMERIC)
|
||||
* CAST(T.EXCHANGE_RATE AS NUMERIC), 2
|
||||
CAST(REPLACE(COALESCE((SELECT TOTAL_AMOUNT FROM ESTIMATE_TEMPLATE WHERE CONTRACT_OBJID = T.OBJID ORDER BY REGDATE DESC LIMIT 1), '0'), ',', '') AS NUMERIC)
|
||||
* CAST(REPLACE(T.EXCHANGE_RATE, ',', '') AS NUMERIC), 2
|
||||
)
|
||||
ELSE CAST(COALESCE((SELECT TOTAL_AMOUNT_KRW FROM ESTIMATE_TEMPLATE WHERE CONTRACT_OBJID = T.OBJID ORDER BY REGDATE DESC LIMIT 1), '0') AS NUMERIC)
|
||||
ELSE CAST(REPLACE(COALESCE((SELECT TOTAL_AMOUNT_KRW FROM ESTIMATE_TEMPLATE WHERE CONTRACT_OBJID = T.OBJID ORDER BY REGDATE DESC LIMIT 1), '0'), ',', '') AS NUMERIC)
|
||||
END AS EST_TOTAL_AMOUNT_KRW
|
||||
-- 견적수량 (ESTIMATE_TEMPLATE_ITEM의 수량 합계)
|
||||
,(SELECT COALESCE(SUM(CAST(QUANTITY AS NUMERIC)), 0) FROM ESTIMATE_TEMPLATE_ITEM WHERE TEMPLATE_OBJID = (SELECT objid FROM ESTIMATE_TEMPLATE WHERE CONTRACT_OBJID = T.OBJID ORDER BY REGDATE DESC LIMIT 1)) AS ESTIMATE_QUANTITY
|
||||
,(SELECT COALESCE(SUM(CAST(REPLACE(QUANTITY, ',', '') AS NUMERIC)), 0) FROM ESTIMATE_TEMPLATE_ITEM WHERE TEMPLATE_OBJID = (SELECT objid FROM ESTIMATE_TEMPLATE WHERE CONTRACT_OBJID = T.OBJID ORDER BY REGDATE DESC LIMIT 1)) AS ESTIMATE_QUANTITY
|
||||
-- 수주 합계 정보 (CONTRACT_MGMT 테이블에 저장된 값 사용)
|
||||
,T.ORDER_SUPPLY_PRICE AS ORDER_SUPPLY_PRICE_SUM
|
||||
,T.ORDER_VAT AS ORDER_VAT_SUM
|
||||
,T.ORDER_TOTAL_AMOUNT AS ORDER_TOTAL_AMOUNT_SUM
|
||||
-- 수주수량 (CONTRACT_MGMT의 QUANTITY 또는 CONTRACT_ITEM 합계)
|
||||
,COALESCE(
|
||||
NULLIF(T.QUANTITY, '')::NUMERIC,
|
||||
(SELECT COALESCE(SUM(CAST(ORDER_QUANTITY AS NUMERIC)), 0) FROM CONTRACT_ITEM WHERE CONTRACT_OBJID = T.OBJID AND STATUS = 'ACTIVE')
|
||||
NULLIF(REPLACE(T.QUANTITY, ',', ''), '')::NUMERIC,
|
||||
(SELECT COALESCE(SUM(CAST(REPLACE(ORDER_QUANTITY, ',', '') AS NUMERIC)), 0) FROM CONTRACT_ITEM WHERE CONTRACT_OBJID = T.OBJID AND STATUS = 'ACTIVE')
|
||||
) AS ORDER_QUANTITY
|
||||
,CASE
|
||||
WHEN T.ORDER_TOTAL_AMOUNT IS NOT NULL AND T.ORDER_TOTAL_AMOUNT != ''
|
||||
,CASE
|
||||
WHEN T.ORDER_TOTAL_AMOUNT IS NOT NULL AND T.ORDER_TOTAL_AMOUNT != ''
|
||||
AND T.EXCHANGE_RATE IS NOT NULL AND T.EXCHANGE_RATE != ''
|
||||
THEN CAST(T.ORDER_TOTAL_AMOUNT AS NUMERIC) * CAST(T.EXCHANGE_RATE AS NUMERIC)
|
||||
AND REPLACE(T.ORDER_TOTAL_AMOUNT, ',', '') ~ '^\d+\.?\d*$'
|
||||
AND REPLACE(T.EXCHANGE_RATE, ',', '') ~ '^\d+\.?\d*$'
|
||||
THEN CAST(REPLACE(T.ORDER_TOTAL_AMOUNT, ',', '') AS NUMERIC) * CAST(REPLACE(T.EXCHANGE_RATE, ',', '') AS NUMERIC)
|
||||
ELSE 0
|
||||
END AS ORDER_TOTAL_AMOUNT_KRW
|
||||
-- 품목 정보 요약
|
||||
@@ -5732,7 +5736,7 @@ WHERE
|
||||
SELECT
|
||||
ETI.PART_OBJID,
|
||||
PM.PART_NO,
|
||||
CAST(COALESCE(NULLIF(ETI.UNIT_PRICE, ''), '0') AS NUMERIC) AS CURRENT_PRICE
|
||||
CAST(REPLACE(COALESCE(NULLIF(ETI.UNIT_PRICE, ''), '0'), ',', '') AS NUMERIC) AS CURRENT_PRICE
|
||||
FROM ESTIMATE_TEMPLATE ET
|
||||
INNER JOIN ESTIMATE_TEMPLATE_ITEM ETI ON ET.OBJID = ETI.TEMPLATE_OBJID
|
||||
LEFT JOIN PART_MNG PM ON ETI.PART_OBJID = PM.OBJID
|
||||
@@ -5747,7 +5751,7 @@ WHERE
|
||||
SELECT
|
||||
CI.PART_OBJID,
|
||||
COALESCE(PM.PART_NO, CI.PART_NO) AS PART_NO,
|
||||
MAX(CAST(COALESCE(NULLIF(ETI.UNIT_PRICE, ''), '0') AS NUMERIC)) AS PREV_MAX_PRICE
|
||||
MAX(CAST(REPLACE(COALESCE(NULLIF(ETI.UNIT_PRICE, ''), '0'), ',', '') AS NUMERIC)) AS PREV_MAX_PRICE
|
||||
FROM CONTRACT_MGMT CM
|
||||
INNER JOIN CONTRACT_ITEM CI ON CM.OBJID = CI.CONTRACT_OBJID AND CI.STATUS = 'ACTIVE'
|
||||
LEFT JOIN PART_MNG PM ON CI.PART_OBJID = PM.OBJID
|
||||
|
||||
@@ -860,7 +860,7 @@
|
||||
AND CIS.SERIAL_NO IS NOT NULL),
|
||||
SR.serial_no
|
||||
) AS SERIAL_NO,
|
||||
COALESCE(T.QUANTITY::numeric, 0) AS ORDER_QUANTITY,
|
||||
COALESCE(NULLIF(REPLACE(T.QUANTITY, ',', ''), '')::numeric, 0) AS ORDER_QUANTITY,
|
||||
-- 요청납기: CONTRACT_ITEM 우선, 없으면 PROJECT_MGMT, 없으면 CONTRACT_MGMT
|
||||
COALESCE(
|
||||
(SELECT CI.DUE_DATE
|
||||
@@ -897,12 +897,15 @@
|
||||
COALESCE(SR.sales_total_amount, 0) AS SALES_TOTAL_AMOUNT,
|
||||
COALESCE(SR.sales_total_amount, 0) AS SALES_TOTAL_AMOUNT_KRW,
|
||||
-- 잔량 계산: 수주수량 - sales_registration.sales_quantity
|
||||
COALESCE(T.QUANTITY::numeric, 0) - COALESCE(SR.sales_quantity, 0) AS REMAINING_QUANTITY,
|
||||
COALESCE(NULLIF(REPLACE(T.QUANTITY, ',', ''), '')::numeric, 0) - COALESCE(SR.sales_quantity, 0) AS REMAINING_QUANTITY,
|
||||
-- 잔량원화총액 계산: 잔량 * 판매단가
|
||||
(COALESCE(T.QUANTITY::numeric, 0) - COALESCE(SR.sales_quantity, 0)) * COALESCE(SR.sales_unit_price, 0) AS REMAINING_AMOUNT_KRW,
|
||||
(COALESCE(NULLIF(REPLACE(T.QUANTITY, ',', ''), '')::numeric, 0) - COALESCE(SR.sales_quantity, 0)) * COALESCE(SR.sales_unit_price, 0) AS REMAINING_AMOUNT_KRW,
|
||||
COALESCE(SR.sales_currency, T.CONTRACT_CURRENCY) AS SALES_CURRENCY,
|
||||
CODE_NAME(COALESCE(SR.sales_currency, T.CONTRACT_CURRENCY)) AS SALES_CURRENCY_NAME,
|
||||
COALESCE(SR.sales_exchange_rate, T.CONTRACT_PRICE_CURRENCY::numeric, 0) AS SALES_EXCHANGE_RATE,
|
||||
COALESCE(SR.sales_exchange_rate,
|
||||
CASE WHEN REPLACE(COALESCE(T.CONTRACT_PRICE_CURRENCY, ''), ',', '') ~ '^\d+\.?\d*$'
|
||||
THEN REPLACE(T.CONTRACT_PRICE_CURRENCY, ',', '')::numeric ELSE 0 END,
|
||||
0) AS SALES_EXCHANGE_RATE,
|
||||
COALESCE(TO_CHAR(SR.shipping_date, 'YYYY-MM-DD'), '') AS SHIPPING_DATE,
|
||||
-- 출하일 (분할출하 포함): 엑셀 다운로드용
|
||||
COALESCE(
|
||||
@@ -928,10 +931,10 @@
|
||||
CASE
|
||||
WHEN COALESCE((SELECT SUM(sales_quantity) FROM sales_registration WHERE project_no LIKE T.PROJECT_NO || '%'), 0) = 0
|
||||
THEN '미판매'
|
||||
WHEN COALESCE((SELECT SUM(sales_quantity) FROM sales_registration WHERE project_no LIKE T.PROJECT_NO || '%'), 0) >= COALESCE(T.QUANTITY::numeric, 0)
|
||||
WHEN COALESCE((SELECT SUM(sales_quantity) FROM sales_registration WHERE project_no LIKE T.PROJECT_NO || '%'), 0) >= COALESCE(NULLIF(REPLACE(T.QUANTITY, ',', ''), '')::numeric, 0)
|
||||
THEN '완판'
|
||||
WHEN COALESCE((SELECT SUM(sales_quantity) FROM sales_registration WHERE project_no LIKE T.PROJECT_NO || '%'), 0) > 0
|
||||
AND COALESCE((SELECT SUM(sales_quantity) FROM sales_registration WHERE project_no LIKE T.PROJECT_NO || '%'), 0) <![CDATA[<]]> COALESCE(T.QUANTITY::numeric, 0)
|
||||
AND COALESCE((SELECT SUM(sales_quantity) FROM sales_registration WHERE project_no LIKE T.PROJECT_NO || '%'), 0) <![CDATA[<]]> COALESCE(NULLIF(REPLACE(T.QUANTITY, ',', ''), '')::numeric, 0)
|
||||
THEN '분할판매'
|
||||
ELSE ''
|
||||
END AS SALES_STATUS,
|
||||
@@ -1085,13 +1088,13 @@
|
||||
<foreach item="item" collection="salesStatus">
|
||||
<!-- 완판: 0900208 -->
|
||||
<if test="'0900208'.equals(item)">
|
||||
OR (COALESCE((SELECT SUM(sales_quantity) FROM sales_registration WHERE project_no LIKE T.PROJECT_NO || '%'), 0) >= COALESCE(T.QUANTITY::numeric, 0)
|
||||
AND COALESCE(T.QUANTITY::numeric, 0) > 0)
|
||||
OR (COALESCE((SELECT SUM(sales_quantity) FROM sales_registration WHERE project_no LIKE T.PROJECT_NO || '%'), 0) >= COALESCE(NULLIF(REPLACE(T.QUANTITY, ',', ''), '')::numeric, 0)
|
||||
AND COALESCE(NULLIF(REPLACE(T.QUANTITY, ',', ''), '')::numeric, 0) > 0)
|
||||
</if>
|
||||
<!-- 분할판매: 0900209 -->
|
||||
<if test="'0900209'.equals(item)">
|
||||
OR (COALESCE((SELECT SUM(sales_quantity) FROM sales_registration WHERE project_no LIKE T.PROJECT_NO || '%'), 0) > 0
|
||||
AND COALESCE((SELECT SUM(sales_quantity) FROM sales_registration WHERE project_no LIKE T.PROJECT_NO || '%'), 0) <![CDATA[<]]> COALESCE(T.QUANTITY::numeric, 0))
|
||||
AND COALESCE((SELECT SUM(sales_quantity) FROM sales_registration WHERE project_no LIKE T.PROJECT_NO || '%'), 0) <![CDATA[<]]> COALESCE(NULLIF(REPLACE(T.QUANTITY, ',', ''), '')::numeric, 0))
|
||||
</if>
|
||||
<!-- 미판매: 0900210 -->
|
||||
<if test="'0900210'.equals(item)">
|
||||
@@ -1276,13 +1279,13 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
<foreach item="item" collection="salesStatus">
|
||||
<!-- 완판: 0900208 -->
|
||||
<if test="'0900208'.equals(item)">
|
||||
OR (COALESCE((SELECT SUM(sales_quantity) FROM sales_registration WHERE project_no LIKE T.PROJECT_NO || '%'), 0) >= COALESCE(T.QUANTITY::numeric, 0)
|
||||
AND COALESCE(T.QUANTITY::numeric, 0) > 0)
|
||||
OR (COALESCE((SELECT SUM(sales_quantity) FROM sales_registration WHERE project_no LIKE T.PROJECT_NO || '%'), 0) >= COALESCE(NULLIF(REPLACE(T.QUANTITY, ',', ''), '')::numeric, 0)
|
||||
AND COALESCE(NULLIF(REPLACE(T.QUANTITY, ',', ''), '')::numeric, 0) > 0)
|
||||
</if>
|
||||
<!-- 분할판매: 0900209 -->
|
||||
<if test="'0900209'.equals(item)">
|
||||
OR (COALESCE((SELECT SUM(sales_quantity) FROM sales_registration WHERE project_no LIKE T.PROJECT_NO || '%'), 0) > 0
|
||||
AND COALESCE((SELECT SUM(sales_quantity) FROM sales_registration WHERE project_no LIKE T.PROJECT_NO || '%'), 0) <![CDATA[<]]> COALESCE(T.QUANTITY::numeric, 0))
|
||||
AND COALESCE((SELECT SUM(sales_quantity) FROM sales_registration WHERE project_no LIKE T.PROJECT_NO || '%'), 0) <![CDATA[<]]> COALESCE(NULLIF(REPLACE(T.QUANTITY, ',', ''), '')::numeric, 0))
|
||||
</if>
|
||||
<!-- 미판매: 0900210 -->
|
||||
<if test="'0900210'.equals(item)">
|
||||
@@ -1566,7 +1569,7 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
AND CIS.SERIAL_NO IS NOT NULL),
|
||||
SR.serial_no
|
||||
) AS SERIAL_NO,
|
||||
COALESCE(T.QUANTITY::numeric, 0) AS ORDER_QUANTITY,
|
||||
COALESCE(NULLIF(REPLACE(T.QUANTITY, ',', ''), '')::numeric, 0) AS ORDER_QUANTITY,
|
||||
-- 요청납기: CONTRACT_ITEM 우선, 없으면 PROJECT_MGMT, 없으면 CONTRACT_MGMT
|
||||
COALESCE(
|
||||
(SELECT CI.DUE_DATE
|
||||
@@ -1598,7 +1601,7 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
COALESCE(SR.shipping_order_status, '') AS SHIPPING_ORDER_STATUS,
|
||||
|
||||
-- 주문수량 (PROJECT_MGMT에서 가져오기) - 잔량 계산용
|
||||
COALESCE(T.QUANTITY::NUMERIC, 0) AS ORDER_QUANTITY,
|
||||
COALESCE(NULLIF(REPLACE(T.QUANTITY, ',', ''), '')::NUMERIC, 0) AS ORDER_QUANTITY,
|
||||
|
||||
-- 판매수량 (sales_registration에서 가져오기) - 이미 판매한 수량
|
||||
COALESCE(SR.sales_quantity, 0) AS SALES_QUANTITY,
|
||||
@@ -1609,7 +1612,10 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
COALESCE(SR.sales_total_amount, 0) AS SALES_TOTAL_AMOUNT_KRW,
|
||||
COALESCE(NULLIF(SR.sales_currency, ''), CM.CONTRACT_CURRENCY) AS SALES_CURRENCY,
|
||||
CODE_NAME(COALESCE(NULLIF(SR.sales_currency, ''), CM.CONTRACT_CURRENCY)) AS SALES_CURRENCY_NAME,
|
||||
COALESCE(NULLIF(SR.sales_exchange_rate, 0), NULLIF(CM.EXCHANGE_RATE, '')::numeric, 0) AS SALES_EXCHANGE_RATE,
|
||||
COALESCE(NULLIF(SR.sales_exchange_rate, 0),
|
||||
CASE WHEN REPLACE(COALESCE(CM.EXCHANGE_RATE, ''), ',', '') ~ '^\d+\.?\d*$'
|
||||
THEN REPLACE(CM.EXCHANGE_RATE, ',', '')::numeric ELSE 0 END,
|
||||
0) AS SALES_EXCHANGE_RATE,
|
||||
COALESCE(TO_CHAR(SR.shipping_date, 'YYYY-MM-DD'), '') AS SHIPPING_DATE,
|
||||
COALESCE(SR.shipping_method, '') AS SHIPPING_METHOD,
|
||||
COALESCE(SR.manager_user_id, T.PM_USER_ID) AS MANAGER,
|
||||
@@ -1649,7 +1655,8 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
-- 환종 정보
|
||||
CM.CONTRACT_CURRENCY AS SALES_CURRENCY,
|
||||
CODE_NAME(CM.CONTRACT_CURRENCY) AS SALES_CURRENCY_NAME,
|
||||
COALESCE(CM.EXCHANGE_RATE::NUMERIC, 0) AS SALES_EXCHANGE_RATE,
|
||||
COALESCE(CASE WHEN REPLACE(COALESCE(CM.EXCHANGE_RATE, ''), ',', '') ~ '^\d+\.?\d*$'
|
||||
THEN REPLACE(CM.EXCHANGE_RATE, ',', '')::NUMERIC ELSE 0 END, 0) AS SALES_EXCHANGE_RATE,
|
||||
|
||||
-- 출하일 기본값: 오늘 날짜
|
||||
TO_CHAR(CURRENT_DATE, 'YYYY-MM-DD') AS SHIPPING_DATE,
|
||||
@@ -1696,7 +1703,8 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
-- 환종 정보
|
||||
CM.CONTRACT_CURRENCY AS SALES_CURRENCY,
|
||||
CODE_NAME(CM.CONTRACT_CURRENCY) AS SALES_CURRENCY_NAME,
|
||||
COALESCE(NULLIF(CM.EXCHANGE_RATE, '')::NUMERIC, 0) AS SALES_EXCHANGE_RATE,
|
||||
COALESCE(CASE WHEN REPLACE(COALESCE(CM.EXCHANGE_RATE, ''), ',', '') ~ '^\d+\.?\d*$'
|
||||
THEN REPLACE(CM.EXCHANGE_RATE, ',', '')::NUMERIC ELSE 0 END, 0) AS SALES_EXCHANGE_RATE,
|
||||
|
||||
-- 출하일 기본값: 오늘 날짜
|
||||
TO_CHAR(CURRENT_DATE, 'YYYY-MM-DD') AS SHIPPING_DATE,
|
||||
@@ -2202,7 +2210,7 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
COALESCE(T.PART_NO, '') AS PART_NO,
|
||||
COALESCE(T.PART_NAME, '') AS PART_NAME,
|
||||
T.PART_OBJID,
|
||||
COALESCE(T.QUANTITY::NUMERIC, 0) AS QUANTITY,
|
||||
COALESCE(NULLIF(REPLACE(T.QUANTITY, ',', ''), '')::NUMERIC, 0) AS QUANTITY,
|
||||
CODE_NAME(T.CATEGORY_CD) AS ORDER_TYPE,
|
||||
CODE_NAME(T.PRODUCT) AS PRODUCT_TYPE,
|
||||
CODE_NAME(T.AREA_CD) AS NATION,
|
||||
@@ -2215,9 +2223,10 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
COALESCE(CM.PO_NO, '') AS PO_NO,
|
||||
COALESCE(CM.ORDER_DATE, '') AS ORDER_DATE,
|
||||
COALESCE((SELECT SUM(SR.SALES_QUANTITY) FROM SALES_REGISTRATION SR WHERE SR.PROJECT_NO = T.PROJECT_NO), 0) AS SALES_QUANTITY,
|
||||
COALESCE(T.QUANTITY::NUMERIC, 0) - COALESCE((SELECT SUM(SR.SALES_QUANTITY) FROM SALES_REGISTRATION SR WHERE SR.PROJECT_NO = T.PROJECT_NO), 0) AS REMAINING_QUANTITY,
|
||||
COALESCE(NULLIF(CM.ORDER_UNIT_PRICE, '')::NUMERIC, 0) AS ORDER_UNIT_PRICE,
|
||||
COALESCE(NULLIF(CM.EXCHANGE_RATE, '')::NUMERIC, 1) AS EXCHANGE_RATE,
|
||||
COALESCE(NULLIF(REPLACE(T.QUANTITY, ',', ''), '')::NUMERIC, 0) - COALESCE((SELECT SUM(SR.SALES_QUANTITY) FROM SALES_REGISTRATION SR WHERE SR.PROJECT_NO = T.PROJECT_NO), 0) AS REMAINING_QUANTITY,
|
||||
COALESCE(NULLIF(REPLACE(CM.ORDER_UNIT_PRICE, ',', ''), '')::NUMERIC, 0) AS ORDER_UNIT_PRICE,
|
||||
COALESCE(CASE WHEN REPLACE(COALESCE(CM.EXCHANGE_RATE, ''), ',', '') ~ '^\d+\.?\d*$'
|
||||
THEN REPLACE(CM.EXCHANGE_RATE, ',', '')::NUMERIC ELSE 1 END, 1) AS EXCHANGE_RATE,
|
||||
COALESCE(CM.CONTRACT_CURRENCY, '') AS CONTRACT_CURRENCY
|
||||
FROM PROJECT_MGMT T
|
||||
LEFT JOIN CONTRACT_MGMT CM ON CM.OBJID = T.CONTRACT_OBJID
|
||||
@@ -2393,7 +2402,7 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
WHERE CI.CONTRACT_OBJID = T.CONTRACT_OBJID
|
||||
AND CI.PART_OBJID = T.PART_OBJID AND CI.STATUS = 'ACTIVE'
|
||||
), '') AS SERIAL_NO,
|
||||
COALESCE(T.QUANTITY::numeric, 0) AS ORDER_QUANTITY,
|
||||
COALESCE(NULLIF(REPLACE(T.QUANTITY, ',', ''), '')::numeric, 0) AS ORDER_QUANTITY,
|
||||
(SELECT CM.PO_NO FROM CONTRACT_MGMT CM WHERE CM.OBJID = T.CONTRACT_OBJID) AS PO_NO,
|
||||
COALESCE(T.CONTRACT_DATE, (SELECT CM.order_date FROM CONTRACT_MGMT CM WHERE CM.OBJID = T.CONTRACT_OBJID)) AS ORDER_DATE,
|
||||
COALESCE(SL.split_quantity, 0) AS SALES_QUANTITY,
|
||||
|
||||
@@ -2415,4 +2415,45 @@ public class ProductionPlanningService {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 장비 WBS 할당 저장
|
||||
*/
|
||||
public Map saveEquipWbsAssign(Map<String, Object> paramMap){
|
||||
Map resultMap = new HashMap();
|
||||
SqlSession sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
|
||||
try{
|
||||
String projectObjid = (String)paramMap.get("projectObjid");
|
||||
String wbsType = (String)paramMap.get("wbsType");
|
||||
String writer = (String)paramMap.get("writer");
|
||||
List<Map<String, Object>> tasks = (List<Map<String, Object>>)paramMap.get("tasks");
|
||||
|
||||
// 기존 WBS 태스크 삭제
|
||||
Map deleteParam = new HashMap();
|
||||
deleteParam.put("projectObjid", projectObjid);
|
||||
deleteParam.put("wbsType", wbsType);
|
||||
sqlSession.delete("productionplanning.deleteEquipWbsTasks", deleteParam);
|
||||
|
||||
// 태스크 INSERT
|
||||
for(int i=0; i<tasks.size(); i++){
|
||||
Map<String, Object> task = tasks.get(i);
|
||||
task.put("projectObjid", projectObjid);
|
||||
task.put("wbsType", wbsType);
|
||||
task.put("writer", writer);
|
||||
task.put("newObjid", CommonUtils.createObjId());
|
||||
sqlSession.insert("productionplanning.insertEquipWbsTask", task);
|
||||
}
|
||||
|
||||
sqlSession.commit();
|
||||
resultMap.put("success", true);
|
||||
}catch(Exception e){
|
||||
sqlSession.rollback();
|
||||
resultMap.put("success", false);
|
||||
resultMap.put("message", e.getMessage());
|
||||
e.printStackTrace();
|
||||
}finally{
|
||||
if(sqlSession != null) sqlSession.close();
|
||||
}
|
||||
return resultMap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1570,11 +1570,14 @@ public class PurchaseOrderService {
|
||||
sqlParamMap.clear();
|
||||
sqlParamMap.put("project_objid", CONTRACT_MGMT_OBJID);
|
||||
sqlParamMap.put("unitCode", UNIT_CODE);
|
||||
List<Map<String, Object>> resultListUnit = (ArrayList)sqlSession.selectList("common.getUnitCodeList", sqlParamMap); //unit 조회
|
||||
if(resultListUnit == null || resultListUnit.isEmpty()) {
|
||||
throw new Exception("UNIT이 존재하지 않습니다.");
|
||||
}{
|
||||
UNIT_NAME = (String)resultListUnit.get(0).get("task_name");
|
||||
// 프로젝트/유닛 정보가 있는 경우에만 UNIT 검증 (영문발주서 등 프로젝트 미연결 시 건너뜀)
|
||||
if(StringUtils.isNotBlank(CONTRACT_MGMT_OBJID) && StringUtils.isNotBlank(UNIT_CODE)) {
|
||||
List<Map<String, Object>> resultListUnit = (ArrayList)sqlSession.selectList("common.getUnitCodeList", sqlParamMap); //unit 조회
|
||||
if(resultListUnit == null || resultListUnit.isEmpty()) {
|
||||
throw new Exception("UNIT이 존재하지 않습니다.");
|
||||
}{
|
||||
UNIT_NAME = (String)resultListUnit.get(0).get("task_name");
|
||||
}
|
||||
}
|
||||
|
||||
//동시발주
|
||||
@@ -3137,8 +3140,9 @@ public class PurchaseOrderService {
|
||||
fromUser = CommonUtils.checkNull((String)masterInfo.get("WRITER"));
|
||||
}
|
||||
|
||||
// 발주서 메일은 PURCHASE 계정 사용
|
||||
boolean sendResult = MailUtil.sendMailWithAttachFile(fromUser, fromEmail, toUserIdList, toEmailList, ccEmailList, null, null, subject, mailContents, attachFileList, "PURCHASE_ORDER", Constants.Mail.ACCOUNT_TYPE_PURCHASE);
|
||||
// 발주서 메일 발송 (PURCHASE 계정 수신 불가 이슈로 SALES 계정 임시 사용 - TODO: PURCHASE 계정 정상화 후 원복)
|
||||
boolean sendResult = MailUtil.sendMailWithAttachFile(fromUser, fromEmail, toUserIdList, toEmailList, ccEmailList, null, null, subject, mailContents, attachFileList, "PURCHASE_ORDER", Constants.Mail.ACCOUNT_TYPE_SALES);
|
||||
//boolean sendResult = MailUtil.sendMailWithAttachFile(fromUser, fromEmail, toUserIdList, toEmailList, ccEmailList, null, null, subject, mailContents, attachFileList, "PURCHASE_ORDER", Constants.Mail.ACCOUNT_TYPE_PURCHASE);
|
||||
|
||||
if(sendResult) {
|
||||
// 메일 발송 성공 시 DB 업데이트
|
||||
|
||||
Reference in New Issue
Block a user