Merge pull request 'V2025111901' (#86) from V2025111901 into main
Reviewed-on: #86
This commit was merged in pull request #86.
This commit is contained in:
@@ -39,6 +39,11 @@ body {
|
||||
.tabulator-row.level-8 { background-color: #dce6f1 !important; }
|
||||
.tabulator-row.level-9 { background-color: #FFFFEB !important; }
|
||||
.tabulator-row.level-10 { background-color: #ffffff !important; }
|
||||
|
||||
/* 편집 가능한 컬럼 헤더 스타일 */
|
||||
.editable-header {
|
||||
background-color: #fff9c4 !important;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var _tabulGrid;
|
||||
@@ -308,6 +313,7 @@ function fn_initGrid() {
|
||||
width: 100,
|
||||
title: '자급/사급',
|
||||
field: 'SUPPLY_TYPE',
|
||||
titleFormatter: function() { return '<span class="editable-header">자급/사급</span>'; },
|
||||
editor: 'list',
|
||||
editorParams: {
|
||||
values: ['자급', '사급']
|
||||
@@ -340,6 +346,7 @@ function fn_initGrid() {
|
||||
width: 100,
|
||||
title: '소재',
|
||||
field: 'RAW_MATERIAL',
|
||||
titleFormatter: function() { return '<span class="editable-header">소재</span>'; },
|
||||
editor: 'list',
|
||||
editorParams: {
|
||||
values: materialList // 로드된 소재 목록 사용
|
||||
@@ -367,6 +374,7 @@ function fn_initGrid() {
|
||||
width: 100,
|
||||
title: '사이즈',
|
||||
field: 'SIZE',
|
||||
titleFormatter: function() { return '<span class="editable-header">사이즈</span>'; },
|
||||
editor: 'list',
|
||||
editorParams: function(cell) {
|
||||
// 선택된 소재에 따라 동적으로 사이즈 목록 로드
|
||||
@@ -446,6 +454,7 @@ function fn_initGrid() {
|
||||
width: 100,
|
||||
title: '소재소요량',
|
||||
field: 'REQUIRED_QTY',
|
||||
titleFormatter: function() { return '<span class="editable-header">소재소요량</span>'; },
|
||||
editor: 'number',
|
||||
editorParams: {
|
||||
min: 0,
|
||||
@@ -495,6 +504,7 @@ function fn_initGrid() {
|
||||
width: 100,
|
||||
title: '제작수량',
|
||||
field: 'PRODUCTION_QTY',
|
||||
titleFormatter: function() { return '<span class="editable-header">제작수량</span>'; },
|
||||
editor: 'number',
|
||||
editorParams: {
|
||||
min: 0,
|
||||
@@ -521,6 +531,7 @@ function fn_initGrid() {
|
||||
width: 150,
|
||||
title: '가공업체',
|
||||
field: 'PROCESSING_VENDOR',
|
||||
titleFormatter: function() { return '<span class="editable-header">가공업체</span>'; },
|
||||
editor: 'list',
|
||||
editorParams: {
|
||||
values: ['업체A', '업체B', '업체C'] // TODO: 실제 가공업체 목록으로 교체
|
||||
@@ -532,6 +543,7 @@ function fn_initGrid() {
|
||||
width: 100,
|
||||
title: '가공납기',
|
||||
field: 'PROCESSING_DEADLINE',
|
||||
titleFormatter: function() { return '<span class="editable-header">가공납기</span>'; },
|
||||
editor: 'date'
|
||||
},
|
||||
{
|
||||
@@ -540,6 +552,7 @@ function fn_initGrid() {
|
||||
width: 100,
|
||||
title: '연삭납기',
|
||||
field: 'GRINDING_DEADLINE',
|
||||
titleFormatter: function() { return '<span class="editable-header">연삭납기</span>'; },
|
||||
editor: 'date'
|
||||
},
|
||||
{
|
||||
|
||||
@@ -6,6 +6,11 @@
|
||||
<%@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>
|
||||
@@ -75,44 +80,44 @@ $(document).ready(function(){
|
||||
var columns = [
|
||||
|
||||
/* {headerHozAlign : 'center', hozAlign : 'center', width : '50', title : '년도', field : 'CM_YEAR' }, */
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '110', title : '고객사', field : 'CUSTOMER_NAME' },
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '150', title : '프로젝트명', field : 'CUSTOMER_PROJECT_NAME' },
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '200', title : '유닛명', field : 'UNIT_NAME' },
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '프로젝트번호', field : 'PROJECT_NO',
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '120', title : '고객사', field : 'CUSTOMER_NAME' },
|
||||
//{headerHozAlign : 'center', hozAlign : 'left', width : '150', title : '프로젝트명', field : 'CUSTOMER_PROJECT_NAME' },
|
||||
//{headerHozAlign : 'center', hozAlign : 'left', width : '200', title : '유닛명', field : 'UNIT_NAME' },
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '130', title : '프로젝트번호', field : 'PROJECT_NO',
|
||||
/* formatter:fnc_createGridAnchorTag,
|
||||
cellClick:function(e, cell){
|
||||
var objid = fnc_checkNull(cell.getData().CONTRACT_OBJID);
|
||||
openProjectFormPopUp(objid);
|
||||
} */
|
||||
},
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '발주번호', field : 'PURCHASE_ORDER_NO',
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '130', title : '발주번호', field : 'PURCHASE_ORDER_NO',
|
||||
formatter:fnc_createGridAnchorTag,
|
||||
cellClick:function(e, cell){
|
||||
var objId = fnc_checkNull(cell.getData().OBJID);
|
||||
fn_formPopUp(objId);
|
||||
}
|
||||
},
|
||||
{headerHozAlign : 'center', hozAlign : 'center', /*width : '73',*/ title : '동시', field : "MULTI_YN" },
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '150', title : '발주서_제목', field : 'TITLE' },
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '85', title : '입고요청일', field : 'DELIVERY_DATE' },
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '120', title : '구매/제작업체명', field : 'PARTNER_NAME' },
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '78', title : '구매담당', field : 'SALES_MNG_USER_NAME' },
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '78', title : '발주일', field : 'REGDATE' },
|
||||
{headerHozAlign : 'center', hozAlign : 'right', width : '78', title : '발주수량', field : 'TOTAL_PO_QTY',
|
||||
//{headerHozAlign : 'center', hozAlign : 'center', /*width : '73',*/ title : '동시', field : "MULTI_YN" },
|
||||
{headerHozAlign : 'center', hozAlign : 'left', /* width : '180',*/ title : '발주서_제목', field : 'TITLE' },
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '입고요청일', field : 'DELIVERY_DATE' },
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '170', title : '구매/제작업체명', field : 'PARTNER_NAME' },
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '구매담당', field : 'SALES_MNG_USER_NAME' },
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '발주일', field : 'REGDATE' },
|
||||
{headerHozAlign : 'center', hozAlign : 'right', width : '100', title : '발주수량', field : 'TOTAL_PO_QTY',
|
||||
formatter:"money", formatterParams:{thousand:",", symbolAfter:"p", precision:false }
|
||||
},
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '78', title : '입고일', field : 'CUR_DELIVERY_DATE' },
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '70', title : '입고자', field : 'CUR_RECEIVER_NAME' },
|
||||
{headerHozAlign : 'center', hozAlign : 'right', width : '75', title : '입고수량', field : 'TOTAL_DELIVERY_QTY',
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '입고일', field : 'CUR_DELIVERY_DATE' },
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '입고자', field : 'CUR_RECEIVER_NAME' },
|
||||
{headerHozAlign : 'center', hozAlign : 'right', width : '100', title : '입고수량', field : 'TOTAL_DELIVERY_QTY',
|
||||
formatter:"money", formatterParams:{thousand:",", symbolAfter:"p", precision:false }
|
||||
},
|
||||
{headerHozAlign : 'center', hozAlign : 'right', width : '85', title : '미입고수량', field : 'NON_DELIVERY_QTY',
|
||||
{headerHozAlign : 'center', hozAlign : 'right', width : '100', title : '미입고수량', field : 'NON_DELIVERY_QTY',
|
||||
formatter:"money", formatterParams:{thousand:",", symbolAfter:"p", precision:false }
|
||||
},
|
||||
/* {headerHozAlign : 'center', hozAlign : 'right', width : '90', title : '부적합수량', field : 'TOTAL_DEFECT_QTY',
|
||||
formatter:"money", formatterParams:{thousand:",", symbolAfter:"p", precision:false }
|
||||
}, */
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '75', title : '입고결과', field : 'DELIVERY_STATUS',
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '입고결과', field : 'DELIVERY_STATUS',
|
||||
formatter:fnc_createGridAnchorTag,
|
||||
cellClick:function(e, cell){
|
||||
var objId = fnc_checkNull(cell.getData().OBJID);
|
||||
@@ -293,7 +298,7 @@ function fn_formPopUp(objId){
|
||||
<div class="content-box-s">
|
||||
<div class="plm_menu_name_gdnsi">
|
||||
<h2>
|
||||
<span>입고관리_입고결과등록</span>
|
||||
<span><%=menuName%></span>
|
||||
</h2>
|
||||
<div class="btnArea">
|
||||
<input type="button" class="plm_btns" value="조회" id="btnSearch">
|
||||
|
||||
@@ -1806,8 +1806,8 @@ function fn_price_save(){
|
||||
<div class="plm_btn_wrap" style="padding:0 8 0 8; text-align: right;">
|
||||
<% if(isModify){ %>
|
||||
<c:if test="${empty info || empty info.MULTI_YN || info.MULTI_YN eq 'Y' and info.MULTI_MASTER_YN eq 'Y'}">
|
||||
<input type="button" value="행추가" class="plm_btns" id="btnAdd" name="btnAdd" style="background:#dfeffc">
|
||||
<input type="button" value="행삭제" class="plm_btns" id="btnDel" name="btnDel" style="background:#dfeffc">
|
||||
<!-- <input type="button" value="행추가" class="plm_btns" id="btnAdd" name="btnAdd" style="background:#dfeffc">
|
||||
<input type="button" value="행삭제" class="plm_btns" id="btnDel" name="btnDel" style="background:#dfeffc"> -->
|
||||
<input type="button" value="저장" class="plm_btns" id="btnSave" name="btnSave" style="background:#dfeffc">
|
||||
<c:if test="${!empty info && !empty info.OBJID && !empty info.WRITER }">
|
||||
<!-- 240305 막음(목록에서만 상신)
|
||||
|
||||
@@ -390,7 +390,7 @@ function fn_search(){
|
||||
var _sum=0;
|
||||
var _sum2=0;
|
||||
var text =" <font size='2px' color='red'>총발주금액(원) : ";
|
||||
var text2 =" <font size='2px' color='red'>단일발주금액(원) : ";
|
||||
//var text2 =" <font size='2px' color='red'>단일발주금액(원) : ";
|
||||
$.ajax({
|
||||
url:"/purchaseOrder/purchaseOrderMasterListSum.do",
|
||||
type:"POST",
|
||||
@@ -398,16 +398,17 @@ function fn_search(){
|
||||
dataType:"json",
|
||||
async:false,
|
||||
success:function(data){
|
||||
_sum = numberWithCommas(data.TOTAL_REAL_SUPPLY_PRICE);
|
||||
_sum2 = numberWithCommas(data.TOTAL_SUPPLY_PRICE);
|
||||
_sum = numberWithCommas(data.TOTAL_SUPPLY_PRICE);
|
||||
//_sum2 = numberWithCommas(data.TOTAL_SUPPLY_PRICE);
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
}
|
||||
});
|
||||
text +=_sum+"</font> ";
|
||||
text2 +=_sum2+"</font>";
|
||||
//text2 +=_sum2+"</font>";
|
||||
//text2 = '';
|
||||
$(".purchaseOrderSum").html(text+text2);
|
||||
//$(".purchaseOrderSum").html(text+text2);
|
||||
$(".purchaseOrderSum").html(text);
|
||||
}
|
||||
|
||||
function rowSelectionControl (data, rows) {
|
||||
|
||||
893
WebContent/WEB-INF/view/salesMng/proposalFormPopUp.jsp
Normal file
893
WebContent/WEB-INF/view/salesMng/proposalFormPopUp.jsp
Normal file
@@ -0,0 +1,893 @@
|
||||
<%@ 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"%>
|
||||
<%
|
||||
// 결재 정보 매핑
|
||||
List approvalList = (List)request.getAttribute("approvalList");
|
||||
Map<Integer, Map> approvalMap = new HashMap<Integer, Map>();
|
||||
Map<Integer, Map> referenceMap = new HashMap<Integer, Map>();
|
||||
|
||||
if(approvalList != null) {
|
||||
for(Object obj : approvalList) {
|
||||
Map item = (Map)obj;
|
||||
Integer seq = null;
|
||||
Object seqObj = item.get("SEQ");
|
||||
if(seqObj != null) {
|
||||
if(seqObj instanceof Number) {
|
||||
seq = ((Number)seqObj).intValue();
|
||||
} else {
|
||||
seq = Integer.parseInt(seqObj.toString());
|
||||
}
|
||||
}
|
||||
if(seq != null) {
|
||||
approvalMap.put(seq, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 결재자 정보 (직급별)
|
||||
String[] approvalNames = new String[10];
|
||||
String[] approvalDates = new String[10];
|
||||
String[] approvalStatus = new String[10];
|
||||
|
||||
for(int i = 1; i <= 9; i++) {
|
||||
Map approver = approvalMap.get(i);
|
||||
if(approver != null) {
|
||||
approvalNames[i] = CommonUtils.checkNull(approver.get("TARGET_USER_NAME"));
|
||||
approvalDates[i] = CommonUtils.checkNull(approver.get("PROC_DATE"));
|
||||
approvalStatus[i] = CommonUtils.checkNull(approver.get("STATUS"));
|
||||
} else {
|
||||
approvalNames[i] = "";
|
||||
approvalDates[i] = "";
|
||||
approvalStatus[i] = "";
|
||||
}
|
||||
}
|
||||
%>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title><%=Constants.SYSTEM_NAME%> - 구매품의서</title>
|
||||
<c:set var="now" value="<%=new java.util.Date() %>"/>
|
||||
<c:set var="sysYear"><fmt:formatDate value="${now}" pattern="yyyy" /></c:set>
|
||||
<style>
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 10mm;
|
||||
}
|
||||
|
||||
@media print {
|
||||
body {
|
||||
-webkit-print-color-adjust: exact !important;
|
||||
print-color-adjust: exact !important;
|
||||
}
|
||||
.no-print {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Malgun Gothic', '맑은 고딕', sans-serif;
|
||||
font-size: 12px;
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
background: #fff;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.proposal-container {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
border: none;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.proposal-title {
|
||||
text-align: center;
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
letter-spacing: 20px;
|
||||
padding: 15px 0;
|
||||
border-bottom: 2px solid #000;
|
||||
}
|
||||
|
||||
.header-section {
|
||||
display: flex;
|
||||
border-bottom: 1px solid #000;
|
||||
border-inline: 2px solid #000;
|
||||
}
|
||||
|
||||
.header-left {
|
||||
flex: 0 0 auto;
|
||||
width: 35%;
|
||||
min-width: 200px;
|
||||
border-right: 1px solid #000;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* 하단 기본정보 섹션 (수신및참조 ~ 제목) */
|
||||
.sub-info-section {
|
||||
border-bottom: 1px solid #000;
|
||||
border-inline: 2px solid #000;
|
||||
}
|
||||
|
||||
.sub-info-section .info-table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sub-info-section .info-table td.label {
|
||||
width: 90px;
|
||||
min-width: 90px;
|
||||
}
|
||||
|
||||
.sub-info-section .info-table td.value {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.info-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.info-table td {
|
||||
border: 1px solid #999;
|
||||
padding: 2px 4px;
|
||||
height: 26px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.info-table .label {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: bold;
|
||||
width: 90px;
|
||||
min-width: 90px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info-table .value {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* 결재란 스타일 */
|
||||
.approval-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.approval-table td, .approval-table th {
|
||||
border: 1px solid #999;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.approval-table .header-row td {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: bold;
|
||||
height: 22px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.approval-table .sign-cell {
|
||||
height: 50px;
|
||||
min-width: 45px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.approval-table .sign-cell .sign-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.approval-table .sign-cell .sign-number {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 4px;
|
||||
font-size: 10px;
|
||||
color: #ff0066;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.approval-table .sign-cell .sign-name {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.approval-table .sign-cell .sign-image {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
border: 2px solid #ff0066;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 2px auto;
|
||||
}
|
||||
|
||||
.approval-table .date-cell {
|
||||
height: 40px;
|
||||
font-size: 10px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.approval-table .type-cell {
|
||||
width: 25px;
|
||||
min-width: 25px;
|
||||
background-color: #f5f5f5;
|
||||
font-weight: bold;
|
||||
writing-mode: vertical-rl;
|
||||
text-orientation: mixed;
|
||||
}
|
||||
|
||||
.approval-table .position-cell {
|
||||
width: 30px;
|
||||
background-color: #f5f5f5;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 중간 정보 섹션 */
|
||||
.middle-section {
|
||||
border-bottom: 1px solid #000;
|
||||
border-inline: 2px solid #000;
|
||||
}
|
||||
|
||||
.middle-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.middle-table td, .middle-table th {
|
||||
border: 1px solid #999;
|
||||
padding: 5px 8px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.middle-table .header-cell {
|
||||
background-color: #ebf1de;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.middle-table .date-header {
|
||||
background-color: #ffff99;
|
||||
}
|
||||
|
||||
.middle-table .total-header {
|
||||
background-color: #dce6f1;
|
||||
}
|
||||
|
||||
.middle-table .total-value {
|
||||
background-color: #ffffcc;
|
||||
font-weight: bold;
|
||||
text-align: right;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 품목 테이블 */
|
||||
.item-section {
|
||||
border-bottom: 1px solid #000;
|
||||
border-inline: 2px solid #000;
|
||||
}
|
||||
|
||||
.item-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.item-table th, .item-table td {
|
||||
border: 1px solid #999;
|
||||
padding: 1px 2px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.item-table th {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: bold;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.item-table td {
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
.item-table .text-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.item-table .text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.item-table .total-row td {
|
||||
background-color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.reference-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.reference-table td {
|
||||
border: 1px solid #999;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.reference-table .label {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: bold;
|
||||
width: 80px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 버튼 영역 */
|
||||
.btn-area {
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
background: #f5f5f5;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: right;
|
||||
}
|
||||
|
||||
.btn-area .plm_btns {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
/* 개정 정보 */
|
||||
.revision-info {
|
||||
text-align: right;
|
||||
font-size: 11px;
|
||||
color: #ff0000;
|
||||
padding: 5px 10px;
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
|
||||
/* 수신및참조 버튼 */
|
||||
.edit-btn {
|
||||
background: #e0e0e0;
|
||||
border: 1px solid #999;
|
||||
padding: 2px 8px;
|
||||
font-size: 11px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 입력 필드 스타일 */
|
||||
.no-print-border {
|
||||
border: 1px solid #ccc;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@media print {
|
||||
.no-print-border {
|
||||
border: none !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
select.no-print-border {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
// 닫기 버튼
|
||||
$("#btnClose").click(function(){
|
||||
self.close();
|
||||
});
|
||||
|
||||
// 인쇄 버튼
|
||||
$("#btnPrint").click(function(){
|
||||
window.print();
|
||||
});
|
||||
|
||||
// 저장 버튼
|
||||
$("#btnSave").click(function(){
|
||||
fn_save();
|
||||
});
|
||||
|
||||
// 날짜 피커 초기화
|
||||
$(".date_icon").datepicker({
|
||||
dateFormat: 'yy-mm-dd',
|
||||
changeMonth: true,
|
||||
changeYear: true
|
||||
});
|
||||
});
|
||||
|
||||
// 숫자 포맷팅
|
||||
function formatNumber(num) {
|
||||
if(num == null || num == '') return '0';
|
||||
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
|
||||
// 저장 함수
|
||||
function fn_save(){
|
||||
// 품목 정보 수집
|
||||
var partList = [];
|
||||
$(".part-row").each(function(){
|
||||
// data-part-objid를 문자열로 가져옴 (attr 사용)
|
||||
var partObjId = $(this).attr("data-part-objid");
|
||||
var remark = $(this).find(".part-remark").val();
|
||||
var deliveryDate = $(this).find(".part-delivery-date").val();
|
||||
var unit = $(this).find(".part-unit").val();
|
||||
|
||||
partList.push({
|
||||
PART_OBJID: String(partObjId),
|
||||
REMARK: remark,
|
||||
DELIVERY_REQUEST_DATE: deliveryDate,
|
||||
UNIT: unit
|
||||
});
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
url: "/salesMng/saveProposal.do",
|
||||
type: "POST",
|
||||
data: {
|
||||
PROPOSAL_OBJID: $("#OBJID").val(),
|
||||
RECIPIENT_REF: $("#RECIPIENT_REF").val(),
|
||||
EXECUTOR: $("#EXECUTOR").val(),
|
||||
EXECUTION_DATE: $("#EXECUTION_DATE").val(),
|
||||
TITLE: $("#TITLE").val(),
|
||||
PART_LIST: JSON.stringify(partList)
|
||||
},
|
||||
dataType: "json",
|
||||
success: function(data){
|
||||
if(data.resultFlag == "S"){
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: '저장 완료',
|
||||
text: data.message
|
||||
});
|
||||
} else {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: '저장 실패',
|
||||
text: data.message
|
||||
});
|
||||
}
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: '오류',
|
||||
text: '저장 중 오류가 발생했습니다.'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<form name="form1" id="form1" method="post">
|
||||
<input type="hidden" name="OBJID" id="OBJID" value="${resultMap.OBJID}" />
|
||||
|
||||
<div class="proposal-container">
|
||||
<!-- 제목 -->
|
||||
<div class="proposal-title">구 매 품 의 서</div>
|
||||
|
||||
<!-- 상단 섹션: 기본정보 + 결재란 (품의번호~기안자까지만) -->
|
||||
<div class="header-section">
|
||||
<!-- 왼쪽: 기본 정보 (품의번호, 작성일자, 기안부서, 기안자) -->
|
||||
<div class="header-left">
|
||||
<table class="info-table" style="height:100%">
|
||||
<tr>
|
||||
<td class="label">품 의 번 호</td>
|
||||
<td class="value" colspan="3">${resultMap.PROPOSAL_NO}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label">작 성 일 자</td>
|
||||
<td class="value" colspan="3">${resultMap.REGDATE_TITLE} <c:if test="${not empty resultMap.REGDATE}"><fmt:formatDate value="${resultMap.REGDATE}" pattern="HH:mm"/></c:if></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label">기 안 부 서</td>
|
||||
<td class="value" colspan="3">
|
||||
<c:choose>
|
||||
<c:when test="${not empty resultMap.WRITER_NAME}">
|
||||
<%
|
||||
String writerDeptName = (String)((Map)request.getAttribute("resultMap")).get("WRITER_NAME");
|
||||
if(writerDeptName != null && writerDeptName.contains(" ")) {
|
||||
out.print(writerDeptName.substring(0, writerDeptName.indexOf(" ")));
|
||||
} else {
|
||||
out.print(writerDeptName != null ? writerDeptName : "-");
|
||||
}
|
||||
%>
|
||||
</c:when>
|
||||
<c:otherwise>-</c:otherwise>
|
||||
</c:choose>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label">기 안 자</td>
|
||||
<td class="value" colspan="3">
|
||||
<c:choose>
|
||||
<c:when test="${not empty resultMap.WRITER_NAME}">
|
||||
<%
|
||||
String writerName = (String)((Map)request.getAttribute("resultMap")).get("WRITER_NAME");
|
||||
if(writerName != null && writerName.contains(" ")) {
|
||||
out.print(writerName.substring(writerName.lastIndexOf(" ") + 1));
|
||||
} else {
|
||||
out.print(writerName != null ? writerName : "-");
|
||||
}
|
||||
%>
|
||||
</c:when>
|
||||
<c:otherwise>-</c:otherwise>
|
||||
</c:choose>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 오른쪽: 결재란 -->
|
||||
<div class="header-right">
|
||||
<table class="approval-table">
|
||||
<!-- 결재 헤더 -->
|
||||
<tr class="header-row">
|
||||
<td rowspan="3" class="type-cell">결재</td>
|
||||
<td>직장</td>
|
||||
<td>대리</td>
|
||||
<td>팀장</td>
|
||||
<td>이사</td>
|
||||
<td>상무이<br/>사</td>
|
||||
<td>부사장</td>
|
||||
<td>대표이<br/>사</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="sign-cell">
|
||||
<c:if test="${not empty approvalList[0]}">
|
||||
<span class="sign-number">1</span>
|
||||
<div class="sign-image">
|
||||
<span class="sign-name">${approvalList[0].TARGET_USER_NAME}</span>
|
||||
</div>
|
||||
</c:if>
|
||||
</td>
|
||||
<td class="sign-cell">
|
||||
<c:if test="${not empty approvalList[1]}">
|
||||
<span class="sign-number">2</span>
|
||||
<div class="sign-image">
|
||||
<span class="sign-name">${approvalList[1].TARGET_USER_NAME}</span>
|
||||
</div>
|
||||
</c:if>
|
||||
</td>
|
||||
<td class="sign-cell">
|
||||
<c:if test="${not empty approvalList[2]}">
|
||||
<span class="sign-number">3</span>
|
||||
<div class="sign-image">
|
||||
<span class="sign-name">${approvalList[2].TARGET_USER_NAME}</span>
|
||||
</div>
|
||||
</c:if>
|
||||
</td>
|
||||
<td class="sign-cell">
|
||||
<c:if test="${not empty approvalList[3]}">
|
||||
<span class="sign-number">4</span>
|
||||
<div class="sign-image">
|
||||
<span class="sign-name">${approvalList[3].TARGET_USER_NAME}</span>
|
||||
</div>
|
||||
</c:if>
|
||||
</td>
|
||||
<td class="sign-cell">
|
||||
<c:if test="${not empty approvalList[4]}">
|
||||
<span class="sign-number">5</span>
|
||||
<div class="sign-image">
|
||||
<span class="sign-name">${approvalList[4].TARGET_USER_NAME}</span>
|
||||
</div>
|
||||
</c:if>
|
||||
</td>
|
||||
<td class="sign-cell">
|
||||
<c:if test="${not empty approvalList[5]}">
|
||||
<span class="sign-number">6</span>
|
||||
<div class="sign-image">
|
||||
<span class="sign-name">${approvalList[5].TARGET_USER_NAME}</span>
|
||||
</div>
|
||||
</c:if>
|
||||
</td>
|
||||
<td class="sign-cell">
|
||||
<c:if test="${not empty approvalList[6]}">
|
||||
<span class="sign-number">7</span>
|
||||
<div class="sign-image">
|
||||
<span class="sign-name">${approvalList[6].TARGET_USER_NAME}</span>
|
||||
</div>
|
||||
</c:if>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="date-cell">
|
||||
<c:if test="${not empty approvalList[0].PROC_DATE}">
|
||||
${approvalList[0].PROC_DATE}
|
||||
</c:if>
|
||||
</td>
|
||||
<td class="date-cell">
|
||||
<c:if test="${not empty approvalList[1].PROC_DATE}">
|
||||
${approvalList[1].PROC_DATE}
|
||||
</c:if>
|
||||
</td>
|
||||
<td class="date-cell">
|
||||
<c:if test="${not empty approvalList[2].PROC_DATE}">
|
||||
${approvalList[2].PROC_DATE}
|
||||
</c:if>
|
||||
</td>
|
||||
<td class="date-cell">
|
||||
<c:if test="${not empty approvalList[3].PROC_DATE}">
|
||||
${approvalList[3].PROC_DATE}
|
||||
</c:if>
|
||||
</td>
|
||||
<td class="date-cell">
|
||||
<c:if test="${not empty approvalList[4].PROC_DATE}">
|
||||
${approvalList[4].PROC_DATE}
|
||||
</c:if>
|
||||
</td>
|
||||
<td class="date-cell">
|
||||
<c:if test="${not empty approvalList[5].PROC_DATE}">
|
||||
${approvalList[5].PROC_DATE}
|
||||
</c:if>
|
||||
</td>
|
||||
<td class="date-cell">
|
||||
<c:if test="${not empty approvalList[6].PROC_DATE}">
|
||||
${approvalList[6].PROC_DATE}
|
||||
</c:if>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- 합의 헤더 -->
|
||||
<tr class="header-row">
|
||||
<td rowspan="3" class="type-cell">합의</td>
|
||||
<td>주임</td>
|
||||
<td>팀장</td>
|
||||
<td colspan="5"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="sign-cell">
|
||||
<c:if test="${fn:length(approvalList) > 7 and not empty approvalList[7]}">
|
||||
<span class="sign-number">8</span>
|
||||
<div class="sign-image">
|
||||
<span class="sign-name">${approvalList[7].TARGET_USER_NAME}</span>
|
||||
</div>
|
||||
</c:if>
|
||||
</td>
|
||||
<td class="sign-cell">
|
||||
<c:if test="${fn:length(approvalList) > 8 and not empty approvalList[8]}">
|
||||
<span class="sign-number">9</span>
|
||||
<div class="sign-image">
|
||||
<span class="sign-name">${approvalList[8].TARGET_USER_NAME}</span>
|
||||
</div>
|
||||
</c:if>
|
||||
</td>
|
||||
<td colspan="5"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="date-cell">
|
||||
<c:if test="${fn:length(approvalList) > 7 and not empty approvalList[7].PROC_DATE}">
|
||||
${approvalList[7].PROC_DATE}
|
||||
</c:if>
|
||||
</td>
|
||||
<td class="date-cell">
|
||||
<c:if test="${fn:length(approvalList) > 8 and not empty approvalList[8].PROC_DATE}">
|
||||
${approvalList[8].PROC_DATE}
|
||||
</c:if>
|
||||
</td>
|
||||
<td colspan="5"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 하단 기본정보 (수신및참조, 시행자, 시행일자, 제목) - 입력 가능 -->
|
||||
<div class="sub-info-section">
|
||||
<table class="info-table" style="border-top: none;">
|
||||
<tr>
|
||||
<td class="label">수신및참조</td>
|
||||
<td class="value" colspan="3">
|
||||
<input type="text" name="RECIPIENT_REF" id="RECIPIENT_REF" value="${resultMap.RECIPIENT_REF}" style="width:100%; box-sizing:border-box;" placeholder="구매자재팀,제조관리팀" class="no-print-border"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label">시 행 자</td>
|
||||
<td class="value" colspan="3">
|
||||
<input type="text" name="EXECUTOR" id="EXECUTOR" value="${resultMap.EXECUTOR}" style="width:100%; box-sizing:border-box;" class="no-print-border"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label">시행일자</td>
|
||||
<td class="value" colspan="3">
|
||||
<input type="text" name="EXECUTION_DATE" id="EXECUTION_DATE" value="${resultMap.EXECUTION_DATE_TITLE}" style="width:120px;" class="date_icon no-print-border" autocomplete="off"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label">제 목</td>
|
||||
<td class="value" colspan="3">
|
||||
<input type="text" name="TITLE" id="TITLE" value="${resultMap.TITLE}" style="width:100%; box-sizing:border-box;" placeholder="[일반] 구매품의서(${resultMap.WRITER_DEPT})" class="no-print-border"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 개정 정보 -->
|
||||
<div class="revision-info">[구매품의서 개정 : 22.05.17]</div>
|
||||
|
||||
<!-- 중간 정보 섹션 -->
|
||||
<div class="middle-section">
|
||||
<table class="middle-table">
|
||||
<tr>
|
||||
<th rowspan="2" class="header-cell" style="width:50px;">구<br/>분</th>
|
||||
<th class="header-cell" style="width:100px;">부 서</th>
|
||||
<th class="header-cell" style="width:100px;">소속팀</th>
|
||||
<th class="header-cell" style="width:100px;">날 짜</th>
|
||||
<th class="" style="width:150px;">${resultMap.REGDATE_TITLE}</th>
|
||||
<th class="total-header" style="width:100px;">총 합 계</th>
|
||||
</tr>
|
||||
<tr style="height: 50px;">
|
||||
<td>
|
||||
<c:choose>
|
||||
<c:when test="${not empty resultMap.WRITER_NAME}">
|
||||
<%
|
||||
String writerDept = (String)((Map)request.getAttribute("resultMap")).get("WRITER_NAME");
|
||||
if(writerDept != null && writerDept.contains(" ")) {
|
||||
out.print(writerDept.substring(0, writerDept.indexOf(" ")));
|
||||
} else {
|
||||
out.print("-");
|
||||
}
|
||||
%>
|
||||
</c:when>
|
||||
<c:otherwise>-</c:otherwise>
|
||||
</c:choose>
|
||||
</td>
|
||||
<td>
|
||||
<c:choose>
|
||||
<c:when test="${not empty resultMap.WRITER_NAME}">
|
||||
<%
|
||||
String writerTeam = (String)((Map)request.getAttribute("resultMap")).get("WRITER_NAME");
|
||||
if(writerTeam != null && writerTeam.contains(" ")) {
|
||||
out.print(writerTeam.substring(0, writerTeam.indexOf(" ")));
|
||||
} else {
|
||||
out.print("-");
|
||||
}
|
||||
%>
|
||||
</c:when>
|
||||
<c:otherwise>-</c:otherwise>
|
||||
</c:choose>
|
||||
</td>
|
||||
<td class="header-cell">기 안 자</td>
|
||||
<td>
|
||||
<c:choose>
|
||||
<c:when test="${not empty resultMap.WRITER_NAME}">
|
||||
<%
|
||||
String writerOnly = (String)((Map)request.getAttribute("resultMap")).get("WRITER_NAME");
|
||||
if(writerOnly != null && writerOnly.contains(" ")) {
|
||||
out.print(writerOnly.substring(writerOnly.lastIndexOf(" ") + 1));
|
||||
} else {
|
||||
out.print(writerOnly != null ? writerOnly : "-");
|
||||
}
|
||||
%>
|
||||
</c:when>
|
||||
<c:otherwise>-</c:otherwise>
|
||||
</c:choose>
|
||||
</td>
|
||||
<td class="total-value">
|
||||
<c:set var="totalAmount" value="0"/>
|
||||
<c:forEach var="item" items="${partList}">
|
||||
<c:set var="totalAmount" value="${totalAmount + (empty item.TOTAL_PRICE ? 0 : item.TOTAL_PRICE)}"/>
|
||||
</c:forEach>
|
||||
<fmt:formatNumber value="${totalAmount}" pattern="#,###"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 품목 테이블 -->
|
||||
<div class="item-section">
|
||||
<table class="item-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:40px;">No.</th>
|
||||
<th style="width:150px;">목 적</th>
|
||||
<th style="width:250px;">품명 / 규격</th>
|
||||
<th style="width:100px;">납 기 일</th>
|
||||
<th style="width:100px;">업 체 명</th>
|
||||
<th style="width:60px;">수량</th>
|
||||
<th style="width:50px;">단위</th>
|
||||
<th style="width:80px;">단가</th>
|
||||
<th style="width:100px;">합 계</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<c:choose>
|
||||
<c:when test="${not empty partList}">
|
||||
<c:forEach var="item" items="${partList}" varStatus="status">
|
||||
<tr class="part-row" data-part-objid="${item.OBJID}">
|
||||
<td>${status.count}</td>
|
||||
<td class="text-left">
|
||||
<input type="text" name="REMARK_${item.OBJID}" class="part-remark no-print-border" value="${item.REMARK}" style="width:100%; box-sizing:border-box;"/>
|
||||
</td>
|
||||
<td class="text-left">
|
||||
${item.PART_NAME}
|
||||
<c:if test="${not empty item.SPEC}">
|
||||
<br/>(${item.SPEC})
|
||||
</c:if>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<input type="text" name="DELIVERY_DATE_${item.OBJID}" class="part-delivery-date date_icon no-print-border" value="${item.DELIVERY_REQUEST_DATE_TITLE}" style="width:100%; box-sizing:border-box;" autocomplete="off"/>
|
||||
</td>
|
||||
<td class="text-left">${item.VENDOR_NAME}</td>
|
||||
<td class="text-right"><fmt:formatNumber value="${item.QTY}" pattern="#,###"/></td>
|
||||
<td>
|
||||
<select name="UNIT_${item.OBJID}" class="part-unit no-print-border" style="width:100%; box-sizing:border-box;">
|
||||
<option value="">선택</option>
|
||||
${code_map.unit_list}
|
||||
</select>
|
||||
<script>
|
||||
$(function(){ $("select[name='UNIT_${item.OBJID}']").val("${item.UNIT}"); });
|
||||
</script>
|
||||
</td>
|
||||
<td class="text-right"><fmt:formatNumber value="${item.UNIT_PRICE}" pattern="#,###"/></td>
|
||||
<td class="text-right"><fmt:formatNumber value="${item.TOTAL_PRICE}" pattern="#,###"/></td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<tr>
|
||||
<td colspan="9" style="height:100px;">등록된 품목이 없습니다.</td>
|
||||
</tr>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
<!-- 빈 행 추가 (최소 4행 유지) -->
|
||||
<c:if test="${fn:length(partList) < 4}">
|
||||
<c:forEach begin="${fn:length(partList) + 1}" end="4">
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</c:if>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 참조문서 섹션 -->
|
||||
<div class="reference-section">
|
||||
<table class="reference-table">
|
||||
<tr style="height: 50px;">
|
||||
<td class="label" style="vertical-align: middle; width: 150px;">참 조 문 서</td>
|
||||
<td style="vertical-align: top; padding: 10px;">선택된 문서가 없습니다.</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 버튼 영역 -->
|
||||
<div class="btn-area no-print">
|
||||
<input type="button" value="저장" class="plm_btns" id="btnSave" style="background:#28a745; color:white;">
|
||||
<input type="button" value="인쇄" class="plm_btns" id="btnPrint" style="background:#17a2b8; color:white;">
|
||||
<input type="button" value="닫기" class="plm_btns" id="btnClose">
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -200,7 +200,7 @@ function fn_search(){
|
||||
// 품의서 상세 팝업
|
||||
function fn_openProposalFormPopUp(objId){
|
||||
var url = "/salesMng/proposalFormPopUp.do?PROPOSAL_OBJID=" + fnc_checkNull(objId);
|
||||
window.open(url, "proposalFormPopUp", "width=1200,height=700,scrollbars=yes,resizable=yes");
|
||||
window.open(url, "proposalFormPopUp", "width=1200,height=900,scrollbars=yes,resizable=yes");
|
||||
}
|
||||
|
||||
function _fnc_datepick(){
|
||||
|
||||
@@ -721,10 +721,12 @@ function fn_save() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 품의서작성일 자동 설정 (현재 날짜)
|
||||
// 저장 전 데이터 가공
|
||||
gridData.forEach(function(item) {
|
||||
// PROPOSAL_DATE는 품의서 생성 시에만 자동 설정되므로 여기서는 제거
|
||||
// (기존에 저장된 값이 있으면 유지, 없으면 NULL로 유지)
|
||||
// TOTAL_PRICE 계산 (PO_QTY * UNIT_PRICE)
|
||||
var poQty = parseFloat(item.PO_QTY) || 0;
|
||||
var unitPrice = parseFloat(item.UNIT_PRICE) || 0;
|
||||
item.TOTAL_PRICE = poQty * unitPrice;
|
||||
|
||||
// 사용여부 변환: 사용/미사용 → Y/N
|
||||
if(item.USE_YN === '사용') {
|
||||
|
||||
@@ -506,12 +506,13 @@ function fn_createProposal() {
|
||||
success: function(response) {
|
||||
if(response.resultFlag === "S") {
|
||||
var targetParts = response.data;
|
||||
var excludedParts = response.excludedParts || []; // 공급업체 미입력 품목
|
||||
|
||||
// 3. 대상 품목 확인
|
||||
if(!targetParts || targetParts.length == 0) {
|
||||
Swal.fire({
|
||||
title: '알림',
|
||||
text: '품의서를 생성할 품목이 없습니다.\n(단가가 입력되고 품의서가 생성되지 않은 품목만 대상)',
|
||||
text: '품의서를 생성할 품목이 없습니다.\n(단가와 공급업체가 모두 입력되고 품의서가 생성되지 않은 품목만 대상)',
|
||||
icon: 'info'
|
||||
});
|
||||
return;
|
||||
@@ -519,17 +520,33 @@ function fn_createProposal() {
|
||||
|
||||
// 4. 품의서 생성 확인
|
||||
var partCount = targetParts.length;
|
||||
var partList = targetParts.map(function(part) {
|
||||
var partListHtml = targetParts.map(function(part) {
|
||||
return '- ' + fnc_checkNull(part.PART_NO) + ' / ' + fnc_checkNull(part.PART_NAME);
|
||||
}).join('\n');
|
||||
}).join('<br/>');
|
||||
|
||||
// 공급업체 미입력으로 제외된 품목이 있는 경우 알림 추가
|
||||
var excludedHtml = '';
|
||||
if(excludedParts && excludedParts.length > 0) {
|
||||
var excludedListHtml = excludedParts.map(function(part) {
|
||||
return '- ' + fnc_checkNull(part.PART_NO) + ' / ' + fnc_checkNull(part.PART_NAME);
|
||||
}).join('<br/>');
|
||||
|
||||
excludedHtml = '<div style="margin-top:15px; padding:10px; background-color:#fff3cd; border:1px solid #ffc107; border-radius:4px;">' +
|
||||
'<p style="color:#856404; font-weight:bold; margin-bottom:5px;">⚠️ 공급업체 미입력으로 제외된 품목 (' + excludedParts.length + '건)</p>' +
|
||||
'<div style="max-height:100px; overflow-y:auto; font-size:11px; color:#856404;">' +
|
||||
excludedListHtml +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
title: '품의서 생성',
|
||||
html: '<div style="text-align:left;">' +
|
||||
'<p>총 <strong>' + partCount + '건</strong>의 품목으로 품의서를 생성합니다.</p>' +
|
||||
'<div style="max-height:200px; overflow-y:auto; border:1px solid #ddd; padding:10px; margin-top:10px; font-size:12px;">' +
|
||||
partList +
|
||||
'<div style="max-height:150px; overflow-y:auto; border:1px solid #ddd; padding:10px; margin-top:10px; font-size:12px;">' +
|
||||
partListHtml +
|
||||
'</div>' +
|
||||
excludedHtml +
|
||||
'</div>',
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
@@ -541,10 +558,27 @@ function fn_createProposal() {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 실패 시에도 공급업체 미입력 품목 정보 표시
|
||||
var excludedParts = response.excludedParts || [];
|
||||
var excludedHtml = '';
|
||||
|
||||
if(excludedParts && excludedParts.length > 0) {
|
||||
var excludedListHtml = excludedParts.map(function(part) {
|
||||
return '- ' + fnc_checkNull(part.PART_NO) + ' / ' + fnc_checkNull(part.PART_NAME);
|
||||
}).join('<br/>');
|
||||
|
||||
excludedHtml = '<br/><br/><div style="text-align:left; padding:10px; background-color:#fff3cd; border:1px solid #ffc107; border-radius:4px;">' +
|
||||
'<p style="color:#856404; font-weight:bold; margin-bottom:5px;">⚠️ 공급업체 미입력 품목 (' + excludedParts.length + '건)</p>' +
|
||||
'<div style="max-height:150px; overflow-y:auto; font-size:11px; color:#856404;">' +
|
||||
excludedListHtml +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
title: '오류',
|
||||
text: response.message || '품목 조회 중 오류가 발생했습니다.',
|
||||
icon: 'error'
|
||||
title: '알림',
|
||||
html: (response.message || '품목 조회 중 오류가 발생했습니다.') + excludedHtml,
|
||||
icon: 'info'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -3833,12 +3833,50 @@
|
||||
WHERE OBJID = #{mbomHeaderObjid}
|
||||
</update>
|
||||
|
||||
<!-- MBOM_DETAIL 삭제 (수정 시 기존 데이터 삭제 후 재삽입) -->
|
||||
<!-- MBOM_DETAIL 전체 삭제 (신규 저장 시 사용 - 기존 호환성 유지) -->
|
||||
<delete id="deleteMbomDetail" parameterType="map">
|
||||
DELETE FROM MBOM_DETAIL
|
||||
WHERE MBOM_HEADER_OBJID = #{mbomHeaderObjid}
|
||||
</delete>
|
||||
|
||||
<!-- MBOM_DETAIL 개별 삭제 (UPSERT용) -->
|
||||
<delete id="deleteMbomDetailByObjid" parameterType="map">
|
||||
DELETE FROM MBOM_DETAIL
|
||||
WHERE OBJID = #{objid}
|
||||
</delete>
|
||||
|
||||
<!-- MBOM_DETAIL 업데이트 (UPSERT용) -->
|
||||
<update id="updateMbomDetail" parameterType="map">
|
||||
UPDATE MBOM_DETAIL
|
||||
SET
|
||||
PARENT_OBJID = NULLIF(#{parentObjid}, ''),
|
||||
SEQ = NULLIF(#{seq}::TEXT, '')::INTEGER,
|
||||
LEVEL = NULLIF(#{level}::TEXT, '')::INTEGER,
|
||||
PART_OBJID = NULLIF(#{partObjid}, ''),
|
||||
PART_NO = NULLIF(#{partNo}, ''),
|
||||
PART_NAME = NULLIF(#{partName}, ''),
|
||||
QTY = NULLIF(#{qty}::TEXT, '')::NUMERIC,
|
||||
UNIT = NULLIF(#{unit}, ''),
|
||||
SUPPLY_TYPE = NULLIF(#{supplyType}, ''),
|
||||
MAKE_OR_BUY = NULLIF(#{makeOrBuy}, ''),
|
||||
RAW_MATERIAL_PART_NO = NULLIF(#{rawMaterialPartNo}, ''),
|
||||
RAW_MATERIAL_SPEC = NULLIF(#{rawMaterialSpec}, ''),
|
||||
RAW_MATERIAL = NULLIF(#{rawMaterial}, ''),
|
||||
RAW_MATERIAL_SIZE = NULLIF(#{rawMaterialSize}, ''),
|
||||
PROCESSING_VENDOR = NULLIF(#{processingVendor}, ''),
|
||||
PROCESSING_DEADLINE = NULLIF(#{processingDeadline}, ''),
|
||||
GRINDING_DEADLINE = NULLIF(#{grindingDeadline}, ''),
|
||||
REQUIRED_QTY = NULLIF(#{requiredQty}::TEXT, '')::NUMERIC,
|
||||
ORDER_QTY = NULLIF(#{orderQty}::TEXT, '')::NUMERIC,
|
||||
PRODUCTION_QTY = NULLIF(#{productionQty}::TEXT, '')::NUMERIC,
|
||||
STOCK_QTY = NULLIF(#{stockQty}::TEXT, '')::NUMERIC,
|
||||
SHORTAGE_QTY = NULLIF(#{shortageQty}::TEXT, '')::NUMERIC,
|
||||
EDITER = #{sessionUserId},
|
||||
EDIT_DATE = NOW(),
|
||||
REMARK = NULLIF(#{remark}, '')
|
||||
WHERE OBJID = #{objid}
|
||||
</update>
|
||||
|
||||
<!-- MBOM_HISTORY 삽입 -->
|
||||
<insert id="insertMbomHistory" parameterType="map">
|
||||
INSERT INTO MBOM_HISTORY (
|
||||
|
||||
@@ -2863,8 +2863,102 @@ WHERE OBJID = (SELECT PURCHASE_ORDER_MASTER_OBJID FROM PURCHASE_ORDER_PART POP W
|
||||
WHERE OBJID = #{PURCHASE_ORDER_MASTER_OBJID}
|
||||
</select>
|
||||
|
||||
|
||||
<select id="purchaseOrderMasterListSum" parameterType="map" resultType="map">
|
||||
SELECT
|
||||
SUM(NVL(POM.TOTAL_PRICE_ALL, '0')::NUMERIC) AS TOTAL_PRICE_ALL
|
||||
,SUM(NVL(POM.TOTAL_SUPPLY_PRICE, '0')::NUMERIC) AS TOTAL_SUPPLY_PRICE
|
||||
,SUM(NVL(POM.TOTAL_REAL_SUPPLY_PRICE, '0')::NUMERIC) AS TOTAL_REAL_SUPPLY_PRICE
|
||||
,SUM(NVL(POM.TOTAL_SUPPLY_UNIT_PRICE, '0')::NUMERIC) AS TOTAL_SUPPLY_UNIT_PRICE
|
||||
FROM
|
||||
PURCHASE_ORDER_MASTER AS POM
|
||||
WHERE 1=1
|
||||
<if test="Year !=null and Year != '' ">
|
||||
AND TO_CHAR(POM.REGDATE,'YYYY') = #{Year}
|
||||
</if>
|
||||
<if test="customer_cd !=null and customer_cd != '' ">
|
||||
AND EXISTS (
|
||||
SELECT 'E' FROM PROJECT_MGMT AS S_P
|
||||
WHERE POM.CONTRACT_MGMT_OBJID = S_P.OBJID
|
||||
AND S_P.CUSTOMER_OBJID = #{customer_cd}
|
||||
)
|
||||
</if>
|
||||
<if test="customer_project_name !=null and customer_project_name != '' ">
|
||||
AND CM.CUSTOMER_PROJECT_NAME = #{customer_project_name}
|
||||
</if>
|
||||
<if test="project_no !=null and project_no != '' ">
|
||||
AND POM.CONTRACT_MGMT_OBJID = #{project_no}
|
||||
</if>
|
||||
<if test="unit_code !=null and unit_code != '' ">
|
||||
AND POM.UNIT_CODE LIKE '%'||#{unit_code}||'%'
|
||||
</if>
|
||||
<if test="purchase_order_no !=null and purchase_order_no != '' ">
|
||||
AND POM.PURCHASE_ORDER_NO LIKE '%'||#{purchase_order_no}||'%'
|
||||
</if>
|
||||
<if test="type !=null and type != '' ">
|
||||
AND POM.TYPE = #{type}
|
||||
</if>
|
||||
<if test="order_type_cd !=null and order_type_cd != '' ">
|
||||
AND POM.ORDER_TYPE_CD = #{order_type_cd}
|
||||
</if>
|
||||
<if test="delivery_start_date !=null and delivery_start_date != '' ">
|
||||
AND TO_DATE(POM.DELIVERY_DATE ,'YYYY-MM-DD') <![CDATA[ >= ]]> TO_DATE(#{delivery_start_date}, 'YYYY-MM-DD')
|
||||
</if>
|
||||
<if test="delivery_end_date !=null and delivery_end_date != '' ">
|
||||
AND TO_DATE(POM.DELIVERY_DATE ,'YYYY-MM-DD') <![CDATA[ <= ]]> TO_DATE(#{delivery_end_date}, 'YYYY-MM-DD')
|
||||
</if>
|
||||
<if test="partner_objid !=null and partner_objid != '' ">
|
||||
AND POM.PARTNER_OBJID = #{partner_objid}
|
||||
</if>
|
||||
<if test="sales_mng_user_id !=null and sales_mng_user_id != '' ">
|
||||
AND POM.SALES_MNG_USER_ID = #{sales_mng_user_id}
|
||||
</if>
|
||||
<if test="reg_start_date !=null and reg_start_date != '' ">
|
||||
AND TO_DATE(TO_CHAR(POM.REGDATE,'YYYY-MM-DD') ,'YYYY-MM-DD') <![CDATA[ >= ]]> TO_DATE(#{reg_start_date}, 'YYYY-MM-DD')
|
||||
</if>
|
||||
<if test="reg_end_date !=null and reg_end_date != '' ">
|
||||
AND TO_DATE(TO_CHAR(POM.REGDATE,'YYYY-MM-DD') ,'YYYY-MM-DD') <![CDATA[ <= ]]> TO_DATE(#{reg_end_date}, 'YYYY-MM-DD')
|
||||
</if>
|
||||
<if test="appr_status !=null and appr_status != '' ">
|
||||
<choose>
|
||||
<when test="'cancel'.equals(appr_status)">
|
||||
AND POM.STATUS = #{appr_status}
|
||||
</when>
|
||||
<when test="'complete'.equals(appr_status)">
|
||||
AND POM.STATUS = 'approvalComplete'
|
||||
</when>
|
||||
<when test="'create'.equals(appr_status)">
|
||||
AND ( POM.STATUS = #{appr_status}
|
||||
AND NOT EXISTS (SELECT 1 FROM APPROVAL AT
|
||||
WHERE AT.TARGET_OBJID::VARCHAR = POM.OBJID::VARCHAR
|
||||
)
|
||||
AND NOT EXISTS (SELECT 1 FROM APPROVAL_TARGET AT
|
||||
WHERE AT.TARGET_OBJID::VARCHAR = POM.OBJID::VARCHAR
|
||||
OR AT.MASTER_TARGET_OBJID::VARCHAR = POM.OBJID::VARCHAR
|
||||
)
|
||||
)
|
||||
</when>
|
||||
<otherwise>
|
||||
AND A.APPR_STATUS = #{appr_status}
|
||||
</otherwise>
|
||||
</choose>
|
||||
</if>
|
||||
<if test="SEARCH_PART_NO !=null and SEARCH_PART_NO != '' ">
|
||||
AND EXISTS (SELECT 1
|
||||
FROM PURCHASE_ORDER_PART POP
|
||||
WHERE POP.PURCHASE_ORDER_MASTER_OBJID = POM.OBJID
|
||||
AND TRIM(UPPER(POP.PART_NO)) LIKE '%'||TRIM(UPPER(#{SEARCH_PART_NO}))||'%'
|
||||
)
|
||||
</if>
|
||||
<if test="SEARCH_PART_NAME !=null and SEARCH_PART_NAME != '' ">
|
||||
AND EXISTS (SELECT 1
|
||||
FROM PURCHASE_ORDER_PART POP
|
||||
WHERE POP.PURCHASE_ORDER_MASTER_OBJID = POM.OBJID
|
||||
AND TRIM(UPPER(POP.PART_NAME)) LIKE '%'||TRIM(UPPER(#{SEARCH_PART_NAME}))||'%'
|
||||
)
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="purchaseOrderMasterListSum_old" parameterType="map" resultType="map">
|
||||
SELECT
|
||||
<!--
|
||||
SUM(CASE WHEN (SUPPLY_UNIT_VAT_SUM_PRICE IS NULL OR SUPPLY_UNIT_VAT_SUM_PRICE='')
|
||||
@@ -4097,8 +4191,8 @@ SELECT POM.OBJID
|
||||
,POM.MULTI_YN
|
||||
,CASE WHEN POM.MULTI_MASTER_YN = 'Y' THEN '' ELSE POM.MULTI_YN END MULTI_YN_MAKED
|
||||
<!-- ,S1.TOTAL_PO_QTY -->
|
||||
<!-- ,(SELECT SUM(ORDER_QTY::NUMERIC) FROM PURCHASE_ORDER_PART AS O WHERE POM.OBJID::VARCHAR = O.PURCHASE_ORDER_MASTER_OBJID) AS TOTAL_PO_QTY -->
|
||||
,(SELECT SUM(REAL_ORDER_QTY::NUMERIC) FROM PURCHASE_ORDER_PART AS O WHERE POM.OBJID::VARCHAR = O.PURCHASE_ORDER_MASTER_OBJID) AS TOTAL_PO_QTY
|
||||
,(SELECT SUM(ORDER_QTY::NUMERIC) FROM PURCHASE_ORDER_PART AS O WHERE POM.OBJID::VARCHAR = O.PURCHASE_ORDER_MASTER_OBJID) AS TOTAL_PO_QTY
|
||||
<!--,(SELECT SUM(REAL_ORDER_QTY::NUMERIC) FROM PURCHASE_ORDER_PART AS O WHERE POM.OBJID::VARCHAR = O.PURCHASE_ORDER_MASTER_OBJID) AS TOTAL_PO_QTY -->
|
||||
,S1.CUR_DELIVERY_DATE
|
||||
,S1.TOTAL_DELIVERY_QTY
|
||||
<!-- ,(S1.TOTAL_PO_QTY - S1.TOTAL_DELIVERY_QTY - S1.TOTAL_DEFECT_QTY) AS NON_DELIVERY_QTY -->
|
||||
@@ -4167,7 +4261,8 @@ SELECT POM.OBJID
|
||||
ON POM.CONTRACT_MGMT_OBJID = CM.OBJID
|
||||
<!-- ,PROJECT_MGMT AS CM -->
|
||||
<!-- WHERE POM.CONTRACT_MGMT_OBJID = CM.OBJID -->
|
||||
WHERE POM.STATUS = 'approvalComplete' <!-- A.APPR_STATUS = 'complete' -->/*결재완료*/
|
||||
WHERE 1=1
|
||||
<!-- AND POM.STATUS = 'approvalComplete' --> <!-- A.APPR_STATUS = 'complete' -->/*결재완료*/
|
||||
<!-- AND POM.SALES_STATUS = 'OK' -->
|
||||
<!-- AND (POM.SALES_STATUS = 'OK' OR POM.TYPE = '0001538' ) -->
|
||||
AND (MULTI_MASTER_YN = 'Y' OR NVL(MULTI_MASTER_YN, '') != 'Y' AND NVL(MULTI_YN, '') != 'Y')
|
||||
|
||||
@@ -3447,6 +3447,35 @@ ORDER BY V.PATH2
|
||||
-- 단가가 입력되어 있고
|
||||
AND MD.UNIT_PRICE IS NOT NULL
|
||||
AND MD.UNIT_PRICE > 0
|
||||
-- 공급업체가 입력되어 있고
|
||||
AND MD.VENDOR IS NOT NULL
|
||||
AND MD.VENDOR != ''
|
||||
-- 품의서가 생성되지 않은 품목만
|
||||
AND MD.PROPOSAL_DATE IS NULL
|
||||
ORDER BY MD.REGDATE
|
||||
</select>
|
||||
|
||||
<!-- 품의서 대상 제외 품목 조회 - M-BOM 기반 (단가O, 공급업체X) -->
|
||||
<select id="getProposalExcludedPartsFromMBom" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
SELECT
|
||||
MD.OBJID,
|
||||
MD.PART_OBJID,
|
||||
PM.PART_NO,
|
||||
PM.PART_NAME,
|
||||
MD.QTY,
|
||||
MD.UNIT_PRICE,
|
||||
MD.TOTAL_PRICE,
|
||||
'MBOM' AS DATA_SOURCE
|
||||
FROM
|
||||
MBOM_DETAIL MD
|
||||
LEFT JOIN PART_MNG PM ON MD.PART_OBJID::VARCHAR = PM.OBJID::VARCHAR
|
||||
WHERE
|
||||
MD.MBOM_HEADER_OBJID = #{MBOM_HEADER_OBJID}
|
||||
-- 단가가 입력되어 있고
|
||||
AND MD.UNIT_PRICE IS NOT NULL
|
||||
AND MD.UNIT_PRICE > 0
|
||||
-- 공급업체가 미입력
|
||||
AND (MD.VENDOR IS NULL OR MD.VENDOR = '')
|
||||
-- 품의서가 생성되지 않은 품목만
|
||||
AND MD.PROPOSAL_DATE IS NULL
|
||||
ORDER BY MD.REGDATE
|
||||
@@ -3475,6 +3504,35 @@ ORDER BY V.PATH2
|
||||
-- 단가가 입력되어 있고
|
||||
AND SRP.UNIT_PRICE IS NOT NULL
|
||||
AND SRP.UNIT_PRICE > 0
|
||||
-- 공급업체가 입력되어 있고
|
||||
AND SRP.VENDOR_PM IS NOT NULL
|
||||
AND SRP.VENDOR_PM != ''
|
||||
-- 품의서가 생성되지 않은 품목만
|
||||
AND SRP.PROPOSAL_DATE IS NULL
|
||||
ORDER BY SRP.REGDATE
|
||||
</select>
|
||||
|
||||
<!-- 품의서 대상 제외 품목 조회 - 수동 작성 (단가O, 공급업체X) -->
|
||||
<select id="getProposalExcludedPartsFromManual" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
SELECT
|
||||
SRP.OBJID,
|
||||
SRP.PART_OBJID,
|
||||
PM.PART_NO,
|
||||
PM.PART_NAME,
|
||||
SRP.QTY,
|
||||
SRP.UNIT_PRICE,
|
||||
SRP.TOTAL_PRICE,
|
||||
'MANUAL' AS DATA_SOURCE
|
||||
FROM
|
||||
SALES_REQUEST_PART SRP
|
||||
LEFT JOIN PART_MNG PM ON SRP.PART_OBJID::VARCHAR = PM.OBJID::VARCHAR
|
||||
WHERE
|
||||
SRP.SALES_REQUEST_MASTER_OBJID = #{SALES_REQUEST_MASTER_OBJID}
|
||||
-- 단가가 입력되어 있고
|
||||
AND SRP.UNIT_PRICE IS NOT NULL
|
||||
AND SRP.UNIT_PRICE > 0
|
||||
-- 공급업체가 미입력
|
||||
AND (SRP.VENDOR_PM IS NULL OR SRP.VENDOR_PM = '')
|
||||
-- 품의서가 생성되지 않은 품목만
|
||||
AND SRP.PROPOSAL_DATE IS NULL
|
||||
ORDER BY SRP.REGDATE
|
||||
@@ -3828,14 +3886,72 @@ ORDER BY V.PATH2
|
||||
END AS STATUS_TITLE,
|
||||
SRM.WRITER,
|
||||
(SELECT DEPT_NAME||' '||USER_NAME FROM USER_INFO WHERE USER_ID = SRM.WRITER) AS WRITER_NAME,
|
||||
(SELECT DEPT_NAME FROM USER_INFO WHERE USER_ID = SRM.WRITER) AS WRITER_DEPT,
|
||||
SRM.REGDATE,
|
||||
TO_CHAR(SRM.REGDATE,'YYYY-MM-DD') AS REGDATE_TITLE,
|
||||
TO_CHAR(SRM.REGDATE,'YYYY-MM-DD HH24:MI') AS REGDATE_TIME,
|
||||
SRM.REMARK,
|
||||
SRM.DOC_TYPE
|
||||
SRM.DOC_TYPE,
|
||||
-- 품의서 추가 컬럼
|
||||
SRM.RECIPIENT_REF,
|
||||
SRM.EXECUTOR,
|
||||
SRM.EXECUTION_DATE,
|
||||
TO_CHAR(SRM.EXECUTION_DATE, 'YYYY-MM-DD') AS EXECUTION_DATE_TITLE,
|
||||
SRM.TITLE
|
||||
FROM
|
||||
SALES_REQUEST_MASTER SRM
|
||||
WHERE
|
||||
SRM.OBJID = #{PROPOSAL_OBJID}
|
||||
</select>
|
||||
|
||||
<!-- 품의서 품목 리스트 조회 -->
|
||||
<select id="getProposalPartList" parameterType="map" resultType="map">
|
||||
SELECT
|
||||
ROW_NUMBER() OVER(ORDER BY SRP.REGDATE) AS RNUM,
|
||||
SRP.OBJID,
|
||||
SRP.PART_OBJID,
|
||||
PM.PART_NO,
|
||||
PM.PART_NAME,
|
||||
PM.SPEC,
|
||||
PM.MATERIAL,
|
||||
SRP.UNIT,
|
||||
COALESCE(
|
||||
(SELECT CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = SRP.UNIT),
|
||||
(SELECT CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = PM.UNIT)
|
||||
) AS UNIT_TITLE,
|
||||
SRP.QTY,
|
||||
SRP.UNIT_PRICE,
|
||||
SRP.TOTAL_PRICE,
|
||||
SRP.VENDOR_PM,
|
||||
(SELECT SUPPLY_NAME FROM ADMIN_SUPPLY_MNG WHERE OBJID::VARCHAR = SRP.VENDOR_PM) AS VENDOR_NAME,
|
||||
SRP.REMARK,
|
||||
SRP.DELIVERY_REQUEST_DATE,
|
||||
SRP.DELIVERY_REQUEST_DATE AS DELIVERY_REQUEST_DATE_TITLE
|
||||
FROM
|
||||
SALES_REQUEST_PART SRP
|
||||
LEFT JOIN PART_MNG PM ON SRP.PART_OBJID::VARCHAR = PM.OBJID::VARCHAR
|
||||
WHERE
|
||||
SRP.SALES_REQUEST_MASTER_OBJID = #{PROPOSAL_OBJID}
|
||||
ORDER BY SRP.REGDATE
|
||||
</select>
|
||||
|
||||
<!-- 품의서 마스터 정보 수정 (수신및참조, 시행자, 시행일자, 제목) -->
|
||||
<update id="updateProposalMaster" parameterType="map">
|
||||
UPDATE SALES_REQUEST_MASTER SET
|
||||
RECIPIENT_REF = #{RECIPIENT_REF},
|
||||
EXECUTOR = #{EXECUTOR},
|
||||
EXECUTION_DATE = CASE WHEN #{EXECUTION_DATE} IS NOT NULL AND #{EXECUTION_DATE} != '' THEN #{EXECUTION_DATE}::DATE ELSE NULL END,
|
||||
TITLE = #{TITLE}
|
||||
WHERE OBJID = #{PROPOSAL_OBJID}
|
||||
</update>
|
||||
|
||||
<!-- 품의서 품목 정보 수정 (납기일, 단위, 목적) -->
|
||||
<update id="updateProposalPart" parameterType="map">
|
||||
UPDATE SALES_REQUEST_PART SET
|
||||
DELIVERY_REQUEST_DATE = CASE WHEN #{DELIVERY_REQUEST_DATE} IS NOT NULL AND #{DELIVERY_REQUEST_DATE} != '' THEN #{DELIVERY_REQUEST_DATE} ELSE NULL END,
|
||||
UNIT = #{UNIT},
|
||||
REMARK = #{REMARK}
|
||||
WHERE OBJID = #{PART_OBJID}
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
@@ -1276,12 +1276,24 @@ public class SalesMngController {
|
||||
public String proposalFormPopUp(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
Map resultMap = new HashMap();
|
||||
Map code_map = new HashMap();
|
||||
ArrayList approvalList = new ArrayList();
|
||||
List<Map> partList = new ArrayList();
|
||||
|
||||
try {
|
||||
String proposalObjId = CommonUtils.checkNull(paramMap.get("PROPOSAL_OBJID"));
|
||||
|
||||
if(!"".equals(proposalObjId)){
|
||||
resultMap = commonService.selectOne("salesMng.getProposalInfo", request, paramMap);
|
||||
|
||||
// 결재 정보 조회
|
||||
Map approvalParam = new HashMap();
|
||||
approvalParam.put("OBJID", proposalObjId);
|
||||
approvalList = approvalService.getApprovalLine(request, approvalParam);
|
||||
|
||||
// 품의서 품목 리스트 조회
|
||||
Map partParam = new HashMap();
|
||||
partParam.put("PROPOSAL_OBJID", proposalObjId);
|
||||
partList = commonService.selectList("salesMng.getProposalPartList", request, partParam);
|
||||
} else {
|
||||
resultMap.put("OBJID", CommonUtils.createObjId());
|
||||
resultMap.put("STATUS", "create");
|
||||
@@ -1293,6 +1305,8 @@ public class SalesMngController {
|
||||
code_map.put("order_type", commonService.bizMakeOptionList("0001822", (String)resultMap.get("ORDER_TYPE"), "common.getCodeselect"));
|
||||
// 제품구분
|
||||
code_map.put("product_name", commonService.bizMakeOptionList("0000016", (String)resultMap.get("PRODUCT_NAME"), "common.getCodeselect"));
|
||||
// 단위 코드 목록 (UNIT_CD: 단위)
|
||||
code_map.put("unit_list", commonService.bizMakeOptionList("0001399", "", "common.getCodeselect"));
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -1300,6 +1314,8 @@ public class SalesMngController {
|
||||
|
||||
request.setAttribute("resultMap", resultMap);
|
||||
request.setAttribute("code_map", code_map);
|
||||
request.setAttribute("approvalList", approvalList);
|
||||
request.setAttribute("partList", partList);
|
||||
return "/salesMng/proposalFormPopUp";
|
||||
}
|
||||
|
||||
@@ -1345,13 +1361,22 @@ public class SalesMngController {
|
||||
// Service의 공통 메서드 사용
|
||||
Map partsInfo = salesMngService.getProposalTargetPartsWithInfo(sqlSession, salesRequestMasterObjid);
|
||||
List<Map> targetParts = (List<Map>)partsInfo.get("targetParts");
|
||||
List<Map> excludedParts = (List<Map>)partsInfo.get("excludedParts"); // 공급업체 미입력 품목
|
||||
|
||||
if(targetParts != null && !targetParts.isEmpty()) {
|
||||
resultMap.put("resultFlag", "S");
|
||||
resultMap.put("data", targetParts);
|
||||
resultMap.put("excludedParts", excludedParts); // 공급업체 미입력 품목도 함께 반환
|
||||
} else {
|
||||
resultMap.put("resultFlag", "F");
|
||||
resultMap.put("message", "품의서 생성 대상 품목이 없습니다.\n(단가가 입력되고 품의서가 생성되지 않은 품목만 가능)");
|
||||
// 대상 품목이 없는 경우, 공급업체 미입력 품목이 있는지 확인
|
||||
if(excludedParts != null && !excludedParts.isEmpty()) {
|
||||
resultMap.put("resultFlag", "F");
|
||||
resultMap.put("message", "품의서 생성 대상 품목이 없습니다.\n(단가와 공급업체가 모두 입력된 품목만 가능)");
|
||||
resultMap.put("excludedParts", excludedParts);
|
||||
} else {
|
||||
resultMap.put("resultFlag", "F");
|
||||
resultMap.put("message", "품의서 생성 대상 품목이 없습니다.\n(단가가 입력되고 품의서가 생성되지 않은 품목만 가능)");
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
@@ -1388,4 +1413,47 @@ public class SalesMngController {
|
||||
public Map createProposalFromPurchaseList(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
return createProposal(request, paramMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 품의서 저장 (마스터 + 품목)
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/salesMng/saveProposal.do")
|
||||
public Map saveProposal(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
Map resultMap = new HashMap();
|
||||
SqlSession sqlSession = null;
|
||||
|
||||
try {
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
|
||||
|
||||
// 1. 마스터 정보 저장
|
||||
sqlSession.update("salesMng.updateProposalMaster", paramMap);
|
||||
|
||||
// 2. 품목 정보 저장 (JSON 배열로 전달받음)
|
||||
String partListJson = CommonUtils.checkNull(paramMap.get("PART_LIST"));
|
||||
if(!"".equals(partListJson)) {
|
||||
List<Map<String, Object>> partList = JsonUtil.JsonToList(partListJson);
|
||||
for(Map part : partList) {
|
||||
sqlSession.update("salesMng.updateProposalPart", part);
|
||||
}
|
||||
}
|
||||
|
||||
sqlSession.commit();
|
||||
resultMap.put("resultFlag", "S");
|
||||
resultMap.put("message", "저장되었습니다.");
|
||||
|
||||
} catch (Exception e) {
|
||||
if(sqlSession != null) sqlSession.rollback();
|
||||
e.printStackTrace();
|
||||
resultMap.put("resultFlag", "F");
|
||||
resultMap.put("message", "저장 중 오류가 발생했습니다: " + e.getMessage());
|
||||
} finally {
|
||||
if(sqlSession != null) sqlSession.close();
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1927,21 +1927,26 @@ public class SalesMngService {
|
||||
|
||||
// 2. 품의서 대상 품목 조회 (M-BOM 기반 여부에 따라 분기)
|
||||
List<Map> targetParts = null;
|
||||
List<Map> excludedParts = null; // 공급업체 미입력으로 제외된 품목
|
||||
|
||||
if(!mbomHeaderObjid.isEmpty()) {
|
||||
// M-BOM 기반 -> MBOM_DETAIL에서 조회
|
||||
Map mbomParam = new HashMap();
|
||||
mbomParam.put("MBOM_HEADER_OBJID", mbomHeaderObjid);
|
||||
targetParts = sqlSession.selectList("salesMng.getProposalTargetPartsFromMBom", mbomParam);
|
||||
excludedParts = sqlSession.selectList("salesMng.getProposalExcludedPartsFromMBom", mbomParam);
|
||||
} else {
|
||||
// 수동 작성 -> SALES_REQUEST_PART에서 조회
|
||||
targetParts = sqlSession.selectList("salesMng.getProposalTargetPartsFromManual", paramMap);
|
||||
excludedParts = sqlSession.selectList("salesMng.getProposalExcludedPartsFromManual", paramMap);
|
||||
}
|
||||
|
||||
targetParts = CommonUtils.keyChangeUpperList(targetParts);
|
||||
excludedParts = CommonUtils.keyChangeUpperList(excludedParts);
|
||||
|
||||
// 3. 결과 반환
|
||||
result.put("targetParts", targetParts);
|
||||
result.put("excludedParts", excludedParts); // 공급업체 미입력 품목
|
||||
result.put("mbomHeaderObjid", mbomHeaderObjid);
|
||||
result.put("purchaseRequestInfo", purchaseRequestInfo);
|
||||
|
||||
|
||||
@@ -1361,107 +1361,100 @@ public class ProductionPlanningService {
|
||||
}
|
||||
}
|
||||
|
||||
// M-BOM 업데이트
|
||||
// M-BOM 헤더 업데이트
|
||||
paramMap.put("mbomHeaderObjid", existingMbom.get("OBJID"));
|
||||
sqlSession.update("productionplanning.updateMbomHeader", paramMap);
|
||||
|
||||
// 삭제 전에 기존 데이터 백업 (PROPOSAL_DATE, VENDOR, NET_QTY, PO_QTY 등 보존)
|
||||
// 기존 데이터 조회
|
||||
Map<String, Object> queryParam = new HashMap<>();
|
||||
queryParam.put("mbomHeaderObjid", existingMbom.get("OBJID")); // camelCase로 수정
|
||||
queryParam.put("mbomHeaderObjid", existingMbom.get("OBJID"));
|
||||
List<Map> oldMbomDetails = sqlSession.selectList("productionplanning.getMbomDetailList", queryParam);
|
||||
|
||||
// OBJID를 키로 하는 맵 생성 (빠른 조회)
|
||||
// 기존 OBJID Set 생성
|
||||
java.util.Set<String> existingObjids = new java.util.HashSet<>();
|
||||
Map<String, Map> existingDataMap = new HashMap<>();
|
||||
if(oldMbomDetails != null) {
|
||||
for(Map detail : oldMbomDetails) {
|
||||
detail = CommonUtils.toUpperCaseMapKey(detail);
|
||||
String objid = CommonUtils.checkNull(detail.get("OBJID"));
|
||||
if(!objid.isEmpty()) {
|
||||
existingObjids.add(objid);
|
||||
existingDataMap.put(objid, detail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sqlSession.delete("productionplanning.deleteMbomDetail", paramMap);
|
||||
// JSP에서 넘어온 OBJID Set 생성
|
||||
java.util.Set<String> newObjids = new java.util.HashSet<>();
|
||||
|
||||
|
||||
// 새 상세 데이터 삽입
|
||||
// UPSERT 처리
|
||||
if(mbomData != null && !mbomData.isEmpty()) {
|
||||
for(Map<String, Object> item : mbomData) {
|
||||
item.put("mbomHeaderObjid", existingMbom.get("OBJID"));
|
||||
item.put("sessionUserId", userId);
|
||||
|
||||
// SEQ가 없으면 기존 SEQ 유지 (JSP에서 전송된 seq 사용)
|
||||
// 없는 경우에만 새로 부여
|
||||
// SEQ 기본값
|
||||
if(item.get("seq") == null || "".equals(item.get("seq"))) {
|
||||
item.put("seq", 999); // 임시값 (나중에 정렬 필요)
|
||||
item.put("seq", 999);
|
||||
}
|
||||
|
||||
// 기존 항목인 경우 objid와 childObjid 유지
|
||||
// 새 항목인 경우에만 생성
|
||||
String objid = CommonUtils.checkNull(item.get("objid"));
|
||||
String childObjid = CommonUtils.checkNull(item.get("childObjid"));
|
||||
|
||||
// 신규 항목: objid가 비어있을 때만
|
||||
if("".equals(objid)) {
|
||||
objid = CommonUtils.createObjId();
|
||||
item.put("objid", objid);
|
||||
}
|
||||
|
||||
if("".equals(childObjid)) {
|
||||
childObjid = objid; // 새 항목은 objid와 동일
|
||||
childObjid = objid;
|
||||
item.put("childObjid", childObjid);
|
||||
}
|
||||
|
||||
// 기존 데이터에서 보존해야 할 값들 복원
|
||||
newObjids.add(objid);
|
||||
|
||||
// 기존 데이터에서 보존할 값 복원
|
||||
Map existingData = existingDataMap.get(objid);
|
||||
if(existingData != null) {
|
||||
// PROPOSAL_DATE가 JSP에서 안 넘어왔으면 기존 값 사용
|
||||
if(item.get("proposalDate") == null || "".equals(item.get("proposalDate"))) {
|
||||
Object proposalDate = existingData.get("PROPOSAL_DATE");
|
||||
if(proposalDate != null) {
|
||||
item.put("proposalDate", proposalDate);
|
||||
System.out.println("PROPOSAL_DATE 복원: " + objid + " -> " + proposalDate);
|
||||
}
|
||||
Object val = existingData.get("PROPOSAL_DATE");
|
||||
if(val != null) item.put("proposalDate", val);
|
||||
}
|
||||
|
||||
// VENDOR가 JSP에서 안 넘어왔으면 기존 값 사용
|
||||
if(item.get("vendor") == null || "".equals(item.get("vendor"))) {
|
||||
Object vendor = existingData.get("VENDOR");
|
||||
if(vendor != null) {
|
||||
item.put("vendor", vendor);
|
||||
System.out.println("VENDOR 복원: " + objid + " -> " + vendor);
|
||||
}
|
||||
Object val = existingData.get("VENDOR");
|
||||
if(val != null) item.put("vendor", val);
|
||||
}
|
||||
|
||||
// NET_QTY가 JSP에서 안 넘어왔으면 기존 값 사용
|
||||
if(item.get("netQty") == null || "".equals(item.get("netQty"))) {
|
||||
Object netQty = existingData.get("NET_QTY");
|
||||
if(netQty != null) {
|
||||
item.put("netQty", netQty);
|
||||
}
|
||||
Object val = existingData.get("NET_QTY");
|
||||
if(val != null) item.put("netQty", val);
|
||||
}
|
||||
|
||||
// PO_QTY가 JSP에서 안 넘어왔으면 기존 값 사용
|
||||
if(item.get("poQty") == null || "".equals(item.get("poQty"))) {
|
||||
Object poQty = existingData.get("PO_QTY");
|
||||
if(poQty != null) {
|
||||
item.put("poQty", poQty);
|
||||
}
|
||||
Object val = existingData.get("PO_QTY");
|
||||
if(val != null) item.put("poQty", val);
|
||||
}
|
||||
}
|
||||
|
||||
// LEVEL이 없으면 기본값 1 설정
|
||||
// LEVEL 기본값
|
||||
if(item.get("level") == null || "".equals(item.get("level"))) {
|
||||
item.put("level", 1);
|
||||
}
|
||||
|
||||
System.out.println("UPDATE M-BOM DETAIL: seq=" + item.get("seq") +
|
||||
", level=" + item.get("level") +
|
||||
", partNo=" + item.get("partNo") +
|
||||
", parentObjid=" + item.get("parentObjid") +
|
||||
", childObjid=" + childObjid);
|
||||
|
||||
sqlSession.insert("productionplanning.insertMbomDetail", item);
|
||||
// UPSERT: 기존 항목이면 UPDATE, 신규면 INSERT
|
||||
if(existingObjids.contains(objid)) {
|
||||
sqlSession.update("productionplanning.updateMbomDetail", item);
|
||||
} else {
|
||||
sqlSession.insert("productionplanning.insertMbomDetail", item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE: DB에 있는데 JSP에 없는 항목 삭제
|
||||
for(String existingObjid : existingObjids) {
|
||||
if(!newObjids.contains(existingObjid)) {
|
||||
Map<String, Object> deleteParam = new HashMap<>();
|
||||
deleteParam.put("objid", existingObjid);
|
||||
sqlSession.delete("productionplanning.deleteMbomDetailByObjid", deleteParam);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user