견적요청서관리 기능 개발
This commit is contained in:
@@ -75,6 +75,7 @@ body, html {
|
||||
<div class="header">
|
||||
<h3 style="margin: 0 0 10px 0; float: left;">구매리스트</h3>
|
||||
<div style="float: right;">
|
||||
<input type="button" value="견적요청서 생성" class="plm_btns" onclick="fn_createQuotationRequest();" style="margin-right: 5px; background-color: #4CAF50; border-color: #4CAF50;">
|
||||
<input type="button" value="저장" class="plm_btns" onclick="fn_save();" style="margin-right: 5px;">
|
||||
<input type="button" value="닫기" class="plm_btns" onclick="window.close();" style="margin-right: 5px;">
|
||||
</div>
|
||||
@@ -216,22 +217,15 @@ function fn_loadInitialData(){
|
||||
var hasMbomHeader = mbomHeaderObjid && mbomHeaderObjid !== "" && mbomHeaderObjid !== "null";
|
||||
var hasMaster = salesRequestMasterObjid && salesRequestMasterObjid !== "" && salesRequestMasterObjid !== "null";
|
||||
|
||||
// M-BOM에서 생성된 경우만 M-BOM 데이터를 로드 (MBOM_HEADER_OBJID가 있어야 함)
|
||||
// M-BOM에서만 데이터를 로드 (MBOM_HEADER_OBJID가 있어야 함)
|
||||
if(hasMbomHeader){
|
||||
logDebug("purchaseListFormPopUp :: M-BOM에서 생성된 구매리스트 - MBOM 로드");
|
||||
fn_loadFromMBom(function(mbomList){
|
||||
if(hasMaster){
|
||||
// M-BOM 데이터가 있으면 merge, 없으면 SALES_REQUEST_PART만 로드
|
||||
var hasMbomData = mbomList && mbomList.length > 0;
|
||||
logDebug("purchaseListFormPopUp :: MBOM data count:", mbomList ? mbomList.length : 0);
|
||||
fn_loadPurchaseList(hasMbomData); // M-BOM 있으면 merge, 없으면 단독 로드
|
||||
}
|
||||
// M-BOM 데이터만 사용 (SALES_REQUEST_PART 조회 안 함)
|
||||
logDebug("purchaseListFormPopUp :: MBOM data count:", mbomList ? mbomList.length : 0);
|
||||
});
|
||||
} else if(hasMaster){
|
||||
logDebug("purchaseListFormPopUp :: 수동 작성된 구매리스트 - SALES_REQUEST_PART만 로드");
|
||||
fn_loadPurchaseList(false);
|
||||
} else {
|
||||
logDebug("purchaseListFormPopUp :: no data to load");
|
||||
logDebug("purchaseListFormPopUp :: MBOM_HEADER_OBJID 없음 - 데이터 로드 안 함");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1009,6 +1003,196 @@ function fn_save() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 견적요청서 생성
|
||||
function fn_createQuotationRequest() {
|
||||
// 체크된 행 가져오기
|
||||
var checkedRows = [];
|
||||
$('.rowCheck:checked').each(function() {
|
||||
var row = $(this).closest('.tabulator-row');
|
||||
var rowData = _tabulGrid.getRow(row.attr('data-row')).getData();
|
||||
checkedRows.push(rowData);
|
||||
});
|
||||
|
||||
// 체크된 항목이 없으면 전체 데이터 사용
|
||||
if(checkedRows.length === 0) {
|
||||
checkedRows = _tabulGrid.getData();
|
||||
}
|
||||
|
||||
if(checkedRows.length === 0) {
|
||||
Swal.fire({
|
||||
title: '알림',
|
||||
text: '견적요청서를 생성할 데이터가 없습니다.',
|
||||
icon: 'warning'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 공급업체/가공업체가 입력된 항목 분류
|
||||
var supplyItems = []; // 공급업체가 입력된 항목
|
||||
var processingItems = []; // 가공업체가 입력된 항목
|
||||
|
||||
checkedRows.forEach(function(item) {
|
||||
var vendorPm = item.VENDOR_PM || '';
|
||||
var processingVendor = item.PROCESSING_VENDOR || '';
|
||||
|
||||
if(vendorPm && vendorPm !== '') {
|
||||
supplyItems.push({
|
||||
objid: item.OBJID,
|
||||
vendorObjid: vendorPm,
|
||||
partNo: item.PART_NO,
|
||||
partName: item.PART_NAME
|
||||
});
|
||||
}
|
||||
|
||||
if(processingVendor && processingVendor !== '') {
|
||||
processingItems.push({
|
||||
objid: item.OBJID,
|
||||
vendorObjid: processingVendor,
|
||||
partNo: item.PART_NO,
|
||||
partName: item.PART_NAME
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if(supplyItems.length === 0 && processingItems.length === 0) {
|
||||
Swal.fire({
|
||||
title: '알림',
|
||||
text: '공급업체 또는 가공업체가 입력된 항목이 없습니다.\n업체를 먼저 입력해주세요.',
|
||||
icon: 'warning'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 업체별로 그룹화
|
||||
var supplyVendorGroups = {};
|
||||
var processingVendorGroups = {};
|
||||
|
||||
supplyItems.forEach(function(item) {
|
||||
if(!supplyVendorGroups[item.vendorObjid]) {
|
||||
supplyVendorGroups[item.vendorObjid] = [];
|
||||
}
|
||||
supplyVendorGroups[item.vendorObjid].push(item.objid);
|
||||
});
|
||||
|
||||
processingItems.forEach(function(item) {
|
||||
if(!processingVendorGroups[item.vendorObjid]) {
|
||||
processingVendorGroups[item.vendorObjid] = [];
|
||||
}
|
||||
processingVendorGroups[item.vendorObjid].push(item.objid);
|
||||
});
|
||||
|
||||
// 생성할 견적요청서 목록 표시
|
||||
var supplyCount = Object.keys(supplyVendorGroups).length;
|
||||
var processingCount = Object.keys(processingVendorGroups).length;
|
||||
var totalCount = supplyCount + processingCount;
|
||||
|
||||
var confirmMsg = '견적요청서를 생성하시겠습니까?\n\n';
|
||||
if(supplyCount > 0) {
|
||||
confirmMsg += '- 공급업체: ' + supplyCount + '개 업체\n';
|
||||
}
|
||||
if(processingCount > 0) {
|
||||
confirmMsg += '- 가공업체: ' + processingCount + '개 업체\n';
|
||||
}
|
||||
confirmMsg += '\n총 ' + totalCount + '개의 견적요청서가 생성됩니다.';
|
||||
|
||||
Swal.fire({
|
||||
title: '견적요청서 생성',
|
||||
text: confirmMsg,
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: '생성',
|
||||
cancelButtonText: '취소'
|
||||
}).then((result) => {
|
||||
if(result.isConfirmed) {
|
||||
fn_executeCreateQuotationRequest(supplyVendorGroups, processingVendorGroups);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 견적요청서 생성 실행
|
||||
function fn_executeCreateQuotationRequest(supplyVendorGroups, processingVendorGroups) {
|
||||
var createPromises = [];
|
||||
|
||||
// 공급업체별 견적요청서 생성
|
||||
for(var vendorObjid in supplyVendorGroups) {
|
||||
var partObjids = supplyVendorGroups[vendorObjid];
|
||||
createPromises.push(
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/salesMng/createQuotationRequest.do",
|
||||
data: {
|
||||
SALES_REQUEST_MASTER_OBJID: salesRequestMasterObjid,
|
||||
VENDOR_OBJID: vendorObjid,
|
||||
VENDOR_TYPE: 'SUPPLY',
|
||||
PART_OBJIDS: JSON.stringify(partObjids)
|
||||
},
|
||||
dataType: "json"
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// 가공업체별 견적요청서 생성
|
||||
for(var vendorObjid in processingVendorGroups) {
|
||||
var partObjids = processingVendorGroups[vendorObjid];
|
||||
createPromises.push(
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/salesMng/createQuotationRequest.do",
|
||||
data: {
|
||||
SALES_REQUEST_MASTER_OBJID: salesRequestMasterObjid,
|
||||
VENDOR_OBJID: vendorObjid,
|
||||
VENDOR_TYPE: 'PROCESSING',
|
||||
PART_OBJIDS: JSON.stringify(partObjids)
|
||||
},
|
||||
dataType: "json"
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
Promise.all(createPromises).then(function(results) {
|
||||
var successCount = 0;
|
||||
var failCount = 0;
|
||||
var createdNos = [];
|
||||
|
||||
results.forEach(function(result) {
|
||||
if(result.resultFlag === 'S') {
|
||||
successCount++;
|
||||
if(result.QUOTATION_REQUEST_NO) {
|
||||
createdNos.push(result.QUOTATION_REQUEST_NO);
|
||||
}
|
||||
} else {
|
||||
failCount++;
|
||||
}
|
||||
});
|
||||
|
||||
if(successCount > 0) {
|
||||
var msg = successCount + '개의 견적요청서가 생성되었습니다.';
|
||||
if(createdNos.length > 0) {
|
||||
msg += '\n\n생성된 번호:\n' + createdNos.join('\n');
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
title: '완료',
|
||||
text: msg,
|
||||
icon: 'success'
|
||||
});
|
||||
} else {
|
||||
Swal.fire({
|
||||
title: '실패',
|
||||
text: '견적요청서 생성에 실패했습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
}
|
||||
}).catch(function(error) {
|
||||
console.error("견적요청서 생성 오류:", error);
|
||||
Swal.fire({
|
||||
title: '오류',
|
||||
text: '견적요청서 생성 중 오류가 발생했습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
447
WebContent/WEB-INF/view/salesMng/quotationRequestFormPopup.jsp
Normal file
447
WebContent/WEB-INF/view/salesMng/quotationRequestFormPopup.jsp
Normal file
@@ -0,0 +1,447 @@
|
||||
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||||
<%@ 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>
|
||||
<script type="text/javascript" src="/js/tabulator/tabulator_custom.js"></script>
|
||||
<style>
|
||||
body, html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
.header {
|
||||
padding: 15px 20px;
|
||||
background: #f5f5f5;
|
||||
border-bottom: 2px solid #ddd;
|
||||
}
|
||||
.header h3 {
|
||||
margin: 0 0 10px 0;
|
||||
color: #333;
|
||||
}
|
||||
.info-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
.info-table td {
|
||||
padding: 8px 15px;
|
||||
border: 1px solid #eee;
|
||||
}
|
||||
.info-table label {
|
||||
font-weight: bold;
|
||||
color: #555;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.info-table span {
|
||||
color: #333;
|
||||
}
|
||||
.content {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
overflow: auto;
|
||||
}
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
padding: 3px 10px;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.status-create { background: #e3f2fd; color: #1976d2; }
|
||||
.status-sent { background: #fff3e0; color: #f57c00; }
|
||||
.status-received { background: #e8f5e9; color: #388e3c; }
|
||||
.status-completed { background: #f3e5f5; color: #7b1fa2; }
|
||||
.vendor-type-badge {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 3px;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.vendor-supply { background: #e3f2fd; color: #1976d2; }
|
||||
.vendor-processing { background: #e8f5e9; color: #388e3c; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<div style="float: left;">
|
||||
<h3 style="margin: 0;">
|
||||
견적요청서
|
||||
<c:if test="${not empty resultMap.QUOTATION_REQUEST_NO}">
|
||||
- ${resultMap.QUOTATION_REQUEST_NO}
|
||||
</c:if>
|
||||
<c:choose>
|
||||
<c:when test="${resultMap.STATUS eq 'create'}">
|
||||
<span class="status-badge status-create">작성중</span>
|
||||
</c:when>
|
||||
<c:when test="${resultMap.STATUS eq 'sent'}">
|
||||
<span class="status-badge status-sent">발송완료</span>
|
||||
</c:when>
|
||||
<c:when test="${resultMap.STATUS eq 'received'}">
|
||||
<span class="status-badge status-received">견적수신</span>
|
||||
</c:when>
|
||||
<c:when test="${resultMap.STATUS eq 'completed'}">
|
||||
<span class="status-badge status-completed">완료</span>
|
||||
</c:when>
|
||||
</c:choose>
|
||||
</h3>
|
||||
</div>
|
||||
<div style="float: right;">
|
||||
<input type="button" value="저장" class="plm_btns" onclick="fn_save();" style="margin-right: 5px;">
|
||||
<input type="button" value="닫기" class="plm_btns" onclick="window.close();">
|
||||
</div>
|
||||
<div style="clear: both;"></div>
|
||||
|
||||
<!-- 프로젝트/업체 정보 -->
|
||||
<table class="info-table" style="margin-top: 15px;">
|
||||
<tr>
|
||||
<td style="width:25%;">
|
||||
<label>프로젝트번호:</label>
|
||||
<span id="infoProjectNo">${resultMap.PROJECT_NO}</span>
|
||||
</td>
|
||||
<td style="width:25%;">
|
||||
<label>구매유형:</label>
|
||||
<span id="infoPurchaseType">${resultMap.PURCHASE_TYPE_NAME}</span>
|
||||
</td>
|
||||
<td style="width:25%;">
|
||||
<label>주문유형:</label>
|
||||
<span id="infoOrderType">${resultMap.ORDER_TYPE_NAME}</span>
|
||||
</td>
|
||||
<td style="width:25%;">
|
||||
<label>제품구분:</label>
|
||||
<span id="infoProductName">${resultMap.PRODUCT_NAME_TITLE}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label>요청번호:</label>
|
||||
<span id="infoRequestNo">${resultMap.REQUEST_MNG_NO}</span>
|
||||
</td>
|
||||
<td colspan="2">
|
||||
<label>업체명:</label>
|
||||
<span id="infoVendorName" style="font-weight: bold; color: #1976d2;">${resultMap.VENDOR_NAME}</span>
|
||||
<c:choose>
|
||||
<c:when test="${resultMap.VENDOR_TYPE eq 'SUPPLY'}">
|
||||
<span class="vendor-type-badge vendor-supply">공급업체</span>
|
||||
</c:when>
|
||||
<c:when test="${resultMap.VENDOR_TYPE eq 'PROCESSING'}">
|
||||
<span class="vendor-type-badge vendor-processing">가공업체</span>
|
||||
</c:when>
|
||||
</c:choose>
|
||||
</td>
|
||||
<td>
|
||||
<label>업체 이메일:</label>
|
||||
<span id="infoVendorEmail">${resultMap.VENDOR_EMAIL}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<c:if test="${not empty resultMap.MAIL_SEND_DATE_TITLE}">
|
||||
<tr>
|
||||
<td colspan="4">
|
||||
<label>메일발송일:</label>
|
||||
<span id="infoMailSendDate" style="color: green;">${resultMap.MAIL_SEND_DATE_TITLE}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</c:if>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div style="margin-bottom: 20px;">
|
||||
<%-- 업체유형 설명 주석처리
|
||||
<c:choose>
|
||||
<c:when test="${resultMap.VENDOR_TYPE eq 'SUPPLY'}">
|
||||
<span style="font-weight: bold; color: #1976d2;">공급업체 견적 - 품번/품명/제작수량 기준</span>
|
||||
</c:when>
|
||||
<c:when test="${resultMap.VENDOR_TYPE eq 'PROCESSING'}">
|
||||
<span style="font-weight: bold; color: #388e3c;">가공업체 견적 - 소재품번/소재재질/규격/발주수량 기준</span>
|
||||
</c:when>
|
||||
</c:choose>
|
||||
--%>
|
||||
<span style="float: right; color: #666; font-size: 12px;">
|
||||
* 단가 입력 후 저장하면 구매리스트에 자동 반영됩니다.
|
||||
</span>
|
||||
</div>
|
||||
<div id="quotationDetailTable"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var _tabulGrid;
|
||||
var quotationRequestMasterObjid = "${resultMap.OBJID}";
|
||||
var vendorType = "${resultMap.VENDOR_TYPE}";
|
||||
var currentStatus = "${resultMap.STATUS}";
|
||||
|
||||
$(document).ready(function(){
|
||||
fn_initGrid();
|
||||
fn_loadDetailList();
|
||||
});
|
||||
|
||||
// 그리드 초기화
|
||||
function fn_initGrid() {
|
||||
var columns = [];
|
||||
|
||||
// 공통 컬럼
|
||||
columns.push({title:'OBJID', field:'OBJID', visible:false});
|
||||
columns.push({title:'SALES_REQUEST_PART_OBJID', field:'SALES_REQUEST_PART_OBJID', visible:false});
|
||||
columns.push({title:'PART_OBJID', field:'PART_OBJID', visible:false});
|
||||
|
||||
// No
|
||||
columns.push({
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 50,
|
||||
title: 'No',
|
||||
field: 'ROW_NUM',
|
||||
formatter: "rownum"
|
||||
});
|
||||
|
||||
// 업체유형에 따라 다른 컬럼 표시
|
||||
if(vendorType === 'PROCESSING') {
|
||||
// 가공업체: 품번, 품명, 규격(없음), 제작수량
|
||||
columns.push({
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
widthGrow: 2,
|
||||
title: '품번',
|
||||
field: 'PART_NO'
|
||||
});
|
||||
columns.push({
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
widthGrow: 3,
|
||||
title: '품명',
|
||||
field: 'PART_NAME'
|
||||
});
|
||||
columns.push({
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 100,
|
||||
title: '규격',
|
||||
field: 'SIZE',
|
||||
formatter: function(cell) {
|
||||
return '-';
|
||||
}
|
||||
});
|
||||
columns.push({
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'right',
|
||||
width: 100,
|
||||
title: '제작수량',
|
||||
field: 'QTY',
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
return value ? Number(value).toLocaleString() : '0';
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 공급업체: 소재품번, 소재재질, 규격, 발주수량
|
||||
columns.push({
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
widthGrow: 2,
|
||||
title: '소재품번',
|
||||
field: 'PART_NO'
|
||||
});
|
||||
columns.push({
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
widthGrow: 2,
|
||||
title: '소재재질',
|
||||
field: 'RAW_MATERIAL'
|
||||
});
|
||||
columns.push({
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 120,
|
||||
title: '규격',
|
||||
field: 'SIZE'
|
||||
});
|
||||
columns.push({
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'right',
|
||||
width: 100,
|
||||
title: '발주수량',
|
||||
field: 'QTY',
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
return value ? Number(value).toLocaleString() : '0';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 업체명
|
||||
columns.push({
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
widthGrow: 1.5,
|
||||
title: vendorType === 'PROCESSING' ? '가공업체' : '공급업체',
|
||||
field: 'VENDOR_NAME'
|
||||
});
|
||||
|
||||
// 단가 (수정가능)
|
||||
columns.push({
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'right',
|
||||
width: 120,
|
||||
title: '<span style="background-color: #FFFF00; padding: 2px 5px;">단가</span>',
|
||||
field: 'UNIT_PRICE',
|
||||
editor: 'number',
|
||||
editable: true,
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
return value ? Number(value).toLocaleString() : '0';
|
||||
}
|
||||
});
|
||||
|
||||
// // 총단가 (자동계산) - 주석처리
|
||||
// columns.push({
|
||||
// headerHozAlign: 'center',
|
||||
// hozAlign: 'right',
|
||||
// width: 120,
|
||||
// title: '총단가',
|
||||
// field: 'TOTAL_PRICE',
|
||||
// formatter: function(cell) {
|
||||
// var data = cell.getRow().getData();
|
||||
// var qty = parseFloat(data.QTY) || 0;
|
||||
// var unitPrice = parseFloat(data.UNIT_PRICE) || 0;
|
||||
// var totalPrice = qty * unitPrice;
|
||||
// return totalPrice > 0 ? totalPrice.toLocaleString() : '0';
|
||||
// }
|
||||
// });
|
||||
|
||||
// // 비고 - 주석처리
|
||||
// columns.push({
|
||||
// headerHozAlign: 'center',
|
||||
// hozAlign: 'left',
|
||||
// widthGrow: 2,
|
||||
// title: '비고',
|
||||
// field: 'REMARK',
|
||||
// editor: 'input',
|
||||
// editable: true
|
||||
// });
|
||||
|
||||
_tabulGrid = new Tabulator("#quotationDetailTable", {
|
||||
layout: "fitColumns",
|
||||
height: "calc(100vh - 300px)",
|
||||
columns: columns,
|
||||
data: [],
|
||||
placeholder: "데이터가 없습니다."
|
||||
});
|
||||
|
||||
// 셀 편집 이벤트 (총단가 자동 계산)
|
||||
_tabulGrid.on("cellEdited", function(cell) {
|
||||
var field = cell.getField();
|
||||
var row = cell.getRow();
|
||||
|
||||
if(field === 'UNIT_PRICE') {
|
||||
row.reformat();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 상세 목록 조회
|
||||
function fn_loadDetailList() {
|
||||
if(!quotationRequestMasterObjid || quotationRequestMasterObjid === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: "/salesMng/getQuotationRequestDetailList.do",
|
||||
method: 'post',
|
||||
data: {
|
||||
QUOTATION_REQUEST_MASTER_OBJID: quotationRequestMasterObjid
|
||||
},
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
if(data && data.list) {
|
||||
_tabulGrid.setData(data.list);
|
||||
}
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
console.error("상세 목록 조회 오류:", error);
|
||||
Swal.fire({
|
||||
title: '오류',
|
||||
text: '상세 목록 조회 중 오류가 발생했습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 저장
|
||||
function fn_save() {
|
||||
var gridData = _tabulGrid.getData();
|
||||
|
||||
if(!gridData || gridData.length === 0) {
|
||||
Swal.fire({
|
||||
title: '알림',
|
||||
text: '저장할 데이터가 없습니다.',
|
||||
icon: 'warning'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
title: '확인',
|
||||
text: '저장하시겠습니까?\n단가가 구매리스트에 자동 반영됩니다.',
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: '확인',
|
||||
cancelButtonText: '취소'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
$.ajax({
|
||||
url: "/salesMng/saveQuotationRequestPrice.do",
|
||||
method: 'post',
|
||||
data: {
|
||||
QUOTATION_REQUEST_MASTER_OBJID: quotationRequestMasterObjid,
|
||||
DETAIL_LIST: JSON.stringify(gridData)
|
||||
},
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
if(data && (data.resultFlag === 'S' || data.RESULTFLAG === 'S')) {
|
||||
Swal.fire({
|
||||
title: '성공',
|
||||
text: data.message || '저장되었습니다.',
|
||||
icon: 'success'
|
||||
}).then(() => {
|
||||
if(opener && opener.fn_search) {
|
||||
opener.fn_search();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Swal.fire({
|
||||
title: '실패',
|
||||
text: data.message || data.MESSAGE || '저장에 실패했습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
}
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
console.error("저장 오류:", error);
|
||||
Swal.fire({
|
||||
title: '오류',
|
||||
text: '저장 중 오류가 발생했습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
322
WebContent/WEB-INF/view/salesMng/quotationRequestList.jsp
Normal file
322
WebContent/WEB-INF/view/salesMng/quotationRequestList.jsp
Normal file
@@ -0,0 +1,322 @@
|
||||
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||||
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
|
||||
<%@ 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;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<link rel="stylesheet" href="/css/selectMulti.css">
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function(){
|
||||
|
||||
$("input").keyup(function(e){
|
||||
if(e.keyCode == 13){
|
||||
$("#page").val("1");
|
||||
fn_search();
|
||||
}
|
||||
});
|
||||
|
||||
$('.select2').select2();
|
||||
fnc_datepick();
|
||||
|
||||
// 조회 버튼
|
||||
$("#btnSearch").click(function(){
|
||||
$("#page").val("1");
|
||||
fn_search();
|
||||
});
|
||||
|
||||
// 삭제 버튼
|
||||
$("#btnDelete").click(function(){
|
||||
fn_delete();
|
||||
});
|
||||
|
||||
// 메일발송 버튼
|
||||
$("#btnSend").click(function(){
|
||||
fn_sendMail();
|
||||
});
|
||||
|
||||
fn_search();
|
||||
|
||||
setTimeout(() => fnc_calculateContentHeight("gridDiv", 15), 50);
|
||||
$("#gridDiv").off("fnc_calculateContentHeight");
|
||||
$(window).resize(function() {
|
||||
fnc_calculateContentHeight("gridDiv", 15);
|
||||
});
|
||||
});
|
||||
|
||||
// 그리드 컬럼 정의
|
||||
var columns = [
|
||||
{title:'OBJID', field:'OBJID', visible:false},
|
||||
{title:'SALES_REQUEST_MASTER_OBJID', field:'SALES_REQUEST_MASTER_OBJID', visible:false},
|
||||
{title:'PROJECT_MGMT_OBJID', field:'PROJECT_MGMT_OBJID', visible:false},
|
||||
{title:'VENDOR_OBJID', field:'VENDOR_OBJID', visible:false},
|
||||
{title:'VENDOR_TYPE', field:'VENDOR_TYPE', visible:false},
|
||||
|
||||
{headerHozAlign:'center', hozAlign:'center', width:140, title:'견적번호', field:'QUOTATION_REQUEST_NO', frozen:true,
|
||||
formatter: function(cell, formatterParams, onRendered){
|
||||
var value = fnc_checkNull(cell.getValue());
|
||||
return "<a href='#none' style='color:#0000EE'>" + value + "</a>";
|
||||
},
|
||||
cellClick: function(e, cell){
|
||||
var objId = fnc_checkNull(cell.getData().OBJID);
|
||||
fn_formPopUp(objId);
|
||||
}
|
||||
},
|
||||
{headerHozAlign:'center', hozAlign:'center', widthGrow:1, title:'요청번호', field:'REQUEST_MNG_NO'},
|
||||
{headerHozAlign:'center', hozAlign:'center', widthGrow:0.8, title:'구매유형', field:'PURCHASE_TYPE_NAME'},
|
||||
{headerHozAlign:'center', hozAlign:'center', widthGrow:1.2, title:'프로젝트번호', field:'PROJECT_NUMBER'},
|
||||
{headerHozAlign:'center', hozAlign:'center', widthGrow:0.7, title:'주문유형', field:'ORDER_TYPE_NAME'},
|
||||
{headerHozAlign:'center', hozAlign:'center', widthGrow:0.7, title:'제품구분', field:'PRODUCT_NAME_TITLE'},
|
||||
{headerHozAlign:'center', hozAlign:'left', widthGrow:1.2, title:'품번', field:'PART_NO'},
|
||||
{headerHozAlign:'center', hozAlign:'left', widthGrow:1.5, title:'품명', field:'PART_NAME'},
|
||||
{headerHozAlign:'center', hozAlign:'left', widthGrow:1.2, title:'업체명', field:'VENDOR_NAME',
|
||||
formatter: function(cell, formatterParams, onRendered){
|
||||
var value = fnc_checkNull(cell.getValue());
|
||||
var vendorType = fnc_checkNull(cell.getData().VENDOR_TYPE);
|
||||
var badge = '';
|
||||
if(vendorType === 'SUPPLY') {
|
||||
badge = ' <span style="font-size:10px; color:#2196F3;">[공급]</span>';
|
||||
} else if(vendorType === 'PROCESSING') {
|
||||
badge = ' <span style="font-size:10px; color:#4CAF50;">[가공]</span>';
|
||||
}
|
||||
return value + badge;
|
||||
}
|
||||
},
|
||||
{headerHozAlign:'center', hozAlign:'center', widthGrow:0.6, title:'견적요청서', field:'QUOTATION_REQUEST_NO',
|
||||
formatter: function(cell, formatterParams, onRendered){
|
||||
return '<a href="#" class="File file_icon" style="width:20px; height:20px; display:inline-block;"></a>';
|
||||
},
|
||||
cellClick: function(e, cell){
|
||||
var objId = fnc_checkNull(cell.getData().OBJID);
|
||||
fn_formPopUp(objId);
|
||||
}
|
||||
},
|
||||
{headerHozAlign:'center', hozAlign:'center', widthGrow:0.9, title:'메일발송', field:'MAIL_SEND_DATE_TITLE',
|
||||
formatter: function(cell, formatterParams, onRendered){
|
||||
var sendYn = fnc_checkNull(cell.getData().MAIL_SEND_YN);
|
||||
var sendDate = fnc_checkNull(cell.getValue());
|
||||
if(sendYn === 'Y' && sendDate !== ''){
|
||||
return '<span style="color:green;">' + sendDate + '</span>';
|
||||
} else {
|
||||
return '<span style="color:#999;">미발송</span>';
|
||||
}
|
||||
}
|
||||
},
|
||||
{headerHozAlign:'center', hozAlign:'center', widthGrow:0.6, title:'수신견적서', field:'ATTACH_FILE_CNT',
|
||||
formatter: function(cell, formatterParams, onRendered){
|
||||
var cnt = cell.getValue() || 0;
|
||||
var iconClass = cnt > 0 ? 'file_icon' : 'file_empty_icon';
|
||||
return '<a href="#" class="File ' + iconClass + '" style="width:20px; height:20px; display:inline-block;"></a>';
|
||||
},
|
||||
cellClick: function(e, cell){
|
||||
var objId = fnc_checkNull(cell.getData().OBJID);
|
||||
fn_openAttachFile(objId);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
// 조회
|
||||
function fn_search(){
|
||||
_tabulGrid = fnc_tabul_search(_tabul_layout_fitColumns, _tabulGrid, "/salesMng/quotationRequestListPaging.do", columns, true);
|
||||
}
|
||||
|
||||
// 상세 팝업
|
||||
function fn_formPopUp(objId){
|
||||
var popup_width = 1200;
|
||||
var popup_height = 800;
|
||||
var url = "/salesMng/quotationRequestFormPopup.do?QUOTATION_REQUEST_MASTER_OBJID=" + objId;
|
||||
|
||||
window.open(url, "quotationRequestFormPopup", "width="+popup_width+",height="+popup_height+",menubar=no,scrollbars=yes,resizable=yes");
|
||||
}
|
||||
|
||||
// 수신견적서 첨부파일 팝업
|
||||
function fn_openAttachFile(objId){
|
||||
var popup_width = 800;
|
||||
var popup_height = 600;
|
||||
var url = "/common/attachFilePopup.do?TARGET_OBJID=" + objId + "&DOC_TYPE=QUOTATION_RECEIVED&TITLE=수신견적서";
|
||||
|
||||
window.open(url, "attachFilePopup", "width="+popup_width+",height="+popup_height+",menubar=no,scrollbars=yes,resizable=yes");
|
||||
}
|
||||
|
||||
// 삭제
|
||||
function fn_delete(){
|
||||
var selectedData = _tabulGrid.getSelectedData();
|
||||
|
||||
if(selectedData.length < 1){
|
||||
Swal.fire("삭제할 행을 선택해주세요.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 발송완료 상태 확인
|
||||
for(var i = 0; i < selectedData.length; i++){
|
||||
var status = fnc_checkNull(selectedData[i].STATUS);
|
||||
if(status === 'sent' || status === 'received' || status === 'completed'){
|
||||
Swal.fire("발송완료/견적수신/완료 상태는 삭제할 수 없습니다.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
title: '확인',
|
||||
text: '선택한 ' + selectedData.length + '건을 삭제하시겠습니까?',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: '삭제',
|
||||
cancelButtonText: '취소'
|
||||
}).then((result) => {
|
||||
if(result.isConfirmed){
|
||||
var deletePromises = [];
|
||||
|
||||
for(var i = 0; i < selectedData.length; i++){
|
||||
var objId = fnc_checkNull(selectedData[i].OBJID);
|
||||
deletePromises.push(
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/salesMng/deleteQuotationRequest.do",
|
||||
data: { QUOTATION_REQUEST_MASTER_OBJID: objId },
|
||||
dataType: "json"
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
Promise.all(deletePromises).then(function(results){
|
||||
Swal.fire({
|
||||
title: '완료',
|
||||
text: '삭제되었습니다.',
|
||||
icon: 'success'
|
||||
}).then(() => {
|
||||
fn_search();
|
||||
});
|
||||
}).catch(function(error){
|
||||
Swal.fire({
|
||||
title: '오류',
|
||||
text: '삭제 중 오류가 발생했습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 메일 발송
|
||||
function fn_sendMail(){
|
||||
var selectedData = _tabulGrid.getSelectedData();
|
||||
|
||||
if(selectedData.length < 1){
|
||||
Swal.fire("메일을 발송할 행을 선택해주세요.");
|
||||
return false;
|
||||
} else if(selectedData.length > 1){
|
||||
Swal.fire("한번에 한 개의 견적요청서만 발송 가능합니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var objId = fnc_checkNull(selectedData[0].OBJID);
|
||||
var mailSendYn = fnc_checkNull(selectedData[0].MAIL_SEND_YN);
|
||||
|
||||
// 이미 발송된 경우 재발송 확인
|
||||
if(mailSendYn === 'Y'){
|
||||
Swal.fire({
|
||||
title: '이미 발송된 견적요청서입니다.',
|
||||
text: '다시 발송하시겠습니까?',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: '재발송',
|
||||
cancelButtonText: '취소'
|
||||
}).then((result) => {
|
||||
if(result.isConfirmed){
|
||||
fn_openMailFormPopup(objId);
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
fn_openMailFormPopup(objId);
|
||||
}
|
||||
|
||||
// 메일 발송 팝업
|
||||
function fn_openMailFormPopup(quotationRequestObjId){
|
||||
var popup_width = 900;
|
||||
var popup_height = 750;
|
||||
var url = "/salesMng/quotationRequestMailFormPopup.do?QUOTATION_REQUEST_MASTER_OBJID=" + quotationRequestObjId;
|
||||
|
||||
window.open(url, "quotationRequestMailForm", "width="+popup_width+",height="+popup_height+",menubar=no,scrollbars=yes,resizable=yes");
|
||||
}
|
||||
|
||||
</script>
|
||||
<body>
|
||||
<form name="form1" id="form1" action="" method="post">
|
||||
<input type="hidden" name="actionType" id="actionType">
|
||||
<input type="hidden" name="SALES_REQUEST_MASTER_OBJID" id="SALES_REQUEST_MASTER_OBJID" value="${param.SALES_REQUEST_MASTER_OBJID}">
|
||||
|
||||
<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="btnSend">
|
||||
<input type="button" class="plm_btns" value="삭제" id="btnDelete" style="background-color:#dc3545; border-color:#dc3545;">
|
||||
<input type="button" class="plm_btns" value="조회" id="btnSearch">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="plmSearchZon">
|
||||
<table class="">
|
||||
|
||||
<tr>
|
||||
<td><label for="Year">년도</label></td>
|
||||
<td>
|
||||
<select name="Year" id="Year" class="select2" autocomplete="off">
|
||||
<option value="">선택</option>
|
||||
<c:forEach begin="${sysYear-4}" end="${sysYear}" var="req_year">
|
||||
<option value="${req_year}"${param.Year eq req_year ? 'selected':'' }>${req_year}</option>
|
||||
</c:forEach>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
<td><label for="">프로젝트번호</label></td>
|
||||
<td><select name="PROJECT_NO" id="PROJECT_NO" class="select2" autocomplete="off" style="width:190px;"><option value="">선택</option>${code_map.project_no}</select></td>
|
||||
|
||||
<td><label for="">견적요청서No.</label></td>
|
||||
<td><input type="text" name="QUOTATION_REQUEST_NO" id="QUOTATION_REQUEST_NO" autocomplete="off" value="${param.QUOTATION_REQUEST_NO}" style=""/></td>
|
||||
|
||||
<td><label for="">업체</label></td>
|
||||
<td><select name="VENDOR_OBJID" id="VENDOR_OBJID" class="select2" autocomplete="off" style=""><option value="">선택</option>${code_map.vendor_objid}</select></td>
|
||||
|
||||
<td><label for="">상태</label></td>
|
||||
<td><select name="STATUS" id="STATUS" class="select2" autocomplete="off" style="">${code_map.status}</select></td>
|
||||
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<%@include file= "/WEB-INF/view/common/common_gridArea.jsp" %>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -116,6 +116,11 @@ $(document).ready(function(){
|
||||
fn_createProposal();
|
||||
});
|
||||
|
||||
// 견적요청서 생성
|
||||
$("#btnQuotationRequest").click(function(){
|
||||
fn_openQuotationRequestPopup();
|
||||
});
|
||||
|
||||
$("#btnOrderBOMReg").click(function(){
|
||||
fn_salesRequestTargetBOMListPopUp();
|
||||
});
|
||||
@@ -196,21 +201,25 @@ var columns = [
|
||||
,{headerHozAlign : 'center', hozAlign : 'center', title : "유/무상", field :"PAID_TYPE_NAME" , widthGrow:0.9 }
|
||||
,{headerHozAlign : 'center', hozAlign : 'left', title : "품번", field :"PART_NO" , widthGrow:1.4}
|
||||
,{headerHozAlign : 'center', hozAlign : 'left' , title : "품명", field :"PART_NAME" , widthGrow:1.8 }
|
||||
,{headerHozAlign : 'center', hozAlign : 'center', title : "견적요청서", field :"HAS_PURCHASE_REQUEST" , widthGrow:1.1,
|
||||
,{headerHozAlign : 'center', hozAlign : 'center', title : "견적요청서", field :"HAS_QUOTATION_REQUEST" , widthGrow:1.1,
|
||||
formatter: function(cell, formatterParams, onRendered){
|
||||
// 구매요청서 작성 여부: HAS_PURCHASE_REQUEST가 'Y'이면 구매요청서 작성됨
|
||||
// 견적요청서 존재 여부: HAS_QUOTATION_REQUEST가 'Y'이면 견적요청서 있음
|
||||
var data = cell.getData();
|
||||
var hasPurchaseRequest = fnc_checkNull(data.HAS_PURCHASE_REQUEST);
|
||||
var iconClass = (hasPurchaseRequest == 'Y') ? 'file_icon' : 'file_empty_icon';
|
||||
return '<a href="#" class="File ' + iconClass + '" style="width:20px; height:20px; display:inline-block;"></a>';
|
||||
var hasQuotationRequest = fnc_checkNull(data.HAS_QUOTATION_REQUEST);
|
||||
var quotationCount = parseInt(data.QUOTATION_REQUEST_COUNT) || 0;
|
||||
var iconClass = (hasQuotationRequest == 'Y') ? 'file_icon' : 'file_empty_icon';
|
||||
var countText = quotationCount > 0 ? ' (' + quotationCount + ')' : '';
|
||||
return '<a href="#" class="File ' + iconClass + '" style="width:20px; height:20px; display:inline-block;"></a>' + countText;
|
||||
},
|
||||
cellClick : function(e, cell) {
|
||||
var data = cell.getData();
|
||||
var hasPurchaseRequest = fnc_checkNull(data.HAS_PURCHASE_REQUEST);
|
||||
var hasQuotationRequest = fnc_checkNull(data.HAS_QUOTATION_REQUEST);
|
||||
|
||||
// 구매요청서가 작성된 경우(파란색 아이콘)만 팝업 열기
|
||||
if(hasPurchaseRequest == 'Y') {
|
||||
fn_openSalesRequestFormPopUp(data.OBJID);
|
||||
// 견적요청서가 있는 경우 견적요청서관리 페이지로 이동 (해당 요청번호로 필터링)
|
||||
if(hasQuotationRequest == 'Y') {
|
||||
// 견적요청서관리 페이지 팝업으로 열기
|
||||
var salesRequestObjid = fnc_checkNull(data.OBJID);
|
||||
window.open("/salesMng/quotationRequestList.do?SALES_REQUEST_MASTER_OBJID=" + salesRequestObjid, "quotationRequestList", "width=1400,height=800,menubar=no,scrollbars=yes,resizable=yes");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -698,6 +707,250 @@ function fn_executeCreateProposal(salesRequestObjid, targetParts) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적요청서 자동 생성
|
||||
* - 선택된 구매요청서의 구매리스트에서 공급업체/가공업체가 입력된 항목으로 견적요청서 자동 생성
|
||||
*/
|
||||
function fn_openQuotationRequestPopup() {
|
||||
var selectedData = _tabulGrid.getSelectedData();
|
||||
|
||||
if(selectedData.length < 1) {
|
||||
Swal.fire({
|
||||
title: '알림',
|
||||
text: '견적요청서를 생성할 행을 선택해주세요.',
|
||||
icon: 'warning'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
if(selectedData.length > 1) {
|
||||
Swal.fire({
|
||||
title: '알림',
|
||||
text: '한번에 한 건만 선택해주세요.',
|
||||
icon: 'warning'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
var salesRequestObjid = fnc_checkNull(selectedData[0].OBJID);
|
||||
var hasPurchaseRequest = fnc_checkNull(selectedData[0].HAS_PURCHASE_REQUEST);
|
||||
|
||||
// 구매리스트가 작성되지 않은 경우
|
||||
if(hasPurchaseRequest !== 'Y') {
|
||||
Swal.fire({
|
||||
title: '알림',
|
||||
text: '먼저 구매리스트를 작성해주세요.\n(견적요청서 아이콘 클릭하여 구매리스트 작성)',
|
||||
icon: 'warning'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
// 구매리스트에서 견적요청서 생성 대상 조회
|
||||
$.ajax({
|
||||
url: "/salesMng/getPurchaseListForQuotation.do",
|
||||
type: "POST",
|
||||
data: {
|
||||
SALES_REQUEST_MASTER_OBJID: salesRequestObjid
|
||||
},
|
||||
dataType: "json",
|
||||
success: function(response) {
|
||||
if(response.resultFlag === "S" && response.list && response.list.length > 0) {
|
||||
fn_processQuotationRequestCreation(salesRequestObjid, response.list);
|
||||
} else {
|
||||
Swal.fire({
|
||||
title: '알림',
|
||||
text: '견적요청서를 생성할 대상이 없습니다.\n(공급업체 또는 가공업체가 입력된 항목이 필요합니다)',
|
||||
icon: 'warning'
|
||||
});
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error("구매리스트 조회 오류:", error);
|
||||
Swal.fire({
|
||||
title: '오류',
|
||||
text: '구매리스트 조회 중 오류가 발생했습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적요청서 생성 처리
|
||||
*/
|
||||
function fn_processQuotationRequestCreation(salesRequestObjid, purchaseList) {
|
||||
// 공급업체/가공업체별로 그룹화
|
||||
var supplyVendorGroups = {}; // 공급업체별 그룹
|
||||
var processingVendorGroups = {}; // 가공업체별 그룹
|
||||
|
||||
purchaseList.forEach(function(item) {
|
||||
// 대소문자 모두 처리 (서버에서 소문자로 반환될 수 있음)
|
||||
var vendorPm = fnc_checkNull(item.VENDOR_PM || item.vendor_pm);
|
||||
var processingVendor = fnc_checkNull(item.PROCESSING_VENDOR || item.processing_vendor);
|
||||
var objid = fnc_checkNull(item.OBJID || item.objid);
|
||||
var vendorName = fnc_checkNull(item.VENDOR_NAME || item.vendor_name);
|
||||
var processingVendorName = fnc_checkNull(item.PROCESSING_VENDOR_NAME || item.processing_vendor_name);
|
||||
// 견적요청서 생성 가능 여부 플래그
|
||||
var canCreateSupply = fnc_checkNull(item.CAN_CREATE_SUPPLY || item.can_create_supply);
|
||||
var canCreateProcessing = fnc_checkNull(item.CAN_CREATE_PROCESSING || item.can_create_processing);
|
||||
|
||||
// 공급업체 견적요청서 생성 가능한 경우
|
||||
if(vendorPm !== '' && canCreateSupply === 'Y') {
|
||||
if(!supplyVendorGroups[vendorPm]) {
|
||||
supplyVendorGroups[vendorPm] = {
|
||||
vendorName: vendorName,
|
||||
parts: []
|
||||
};
|
||||
}
|
||||
supplyVendorGroups[vendorPm].parts.push(objid);
|
||||
}
|
||||
|
||||
// 가공업체 견적요청서 생성 가능한 경우
|
||||
if(processingVendor !== '' && canCreateProcessing === 'Y') {
|
||||
if(!processingVendorGroups[processingVendor]) {
|
||||
processingVendorGroups[processingVendor] = {
|
||||
vendorName: processingVendorName,
|
||||
parts: []
|
||||
};
|
||||
}
|
||||
processingVendorGroups[processingVendor].parts.push(objid);
|
||||
}
|
||||
});
|
||||
|
||||
var supplyCount = Object.keys(supplyVendorGroups).length;
|
||||
var processingCount = Object.keys(processingVendorGroups).length;
|
||||
var totalCount = supplyCount + processingCount;
|
||||
|
||||
if(totalCount === 0) {
|
||||
Swal.fire({
|
||||
title: '알림',
|
||||
text: '견적요청서를 생성할 대상이 없습니다.\n(공급업체 또는 가공업체가 입력된 항목이 필요합니다)',
|
||||
icon: 'warning'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 생성 확인 메시지
|
||||
var confirmHtml = '<div style="text-align:left; margin-top:10px;">';
|
||||
if(supplyCount > 0) {
|
||||
confirmHtml += '<p><strong>공급업체:</strong> ' + supplyCount + '개 업체</p>';
|
||||
for(var vendorId in supplyVendorGroups) {
|
||||
confirmHtml += '<span style="margin-left:20px; color:#1976d2;">- ' + supplyVendorGroups[vendorId].vendorName + ' (' + supplyVendorGroups[vendorId].parts.length + '건)</span><br/>';
|
||||
}
|
||||
}
|
||||
if(processingCount > 0) {
|
||||
confirmHtml += '<p><strong>가공업체:</strong> ' + processingCount + '개 업체</p>';
|
||||
for(var vendorId in processingVendorGroups) {
|
||||
confirmHtml += '<span style="margin-left:20px; color:#388e3c;">- ' + processingVendorGroups[vendorId].vendorName + ' (' + processingVendorGroups[vendorId].parts.length + '건)</span><br/>';
|
||||
}
|
||||
}
|
||||
confirmHtml += '</div>';
|
||||
|
||||
Swal.fire({
|
||||
title: '견적요청서 생성',
|
||||
html: '<p>총 <strong>' + totalCount + '개</strong>의 견적요청서가 생성됩니다.</p>' + confirmHtml,
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: '생성',
|
||||
cancelButtonText: '취소',
|
||||
width: '500px'
|
||||
}).then((result) => {
|
||||
if(result.isConfirmed) {
|
||||
fn_executeCreateQuotationRequests(salesRequestObjid, supplyVendorGroups, processingVendorGroups);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적요청서 생성 실행
|
||||
*/
|
||||
function fn_executeCreateQuotationRequests(salesRequestObjid, supplyVendorGroups, processingVendorGroups) {
|
||||
var createPromises = [];
|
||||
|
||||
// 공급업체별 견적요청서 생성
|
||||
for(var vendorObjid in supplyVendorGroups) {
|
||||
var partObjids = supplyVendorGroups[vendorObjid].parts;
|
||||
createPromises.push(
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/salesMng/createQuotationRequest.do",
|
||||
data: {
|
||||
SALES_REQUEST_MASTER_OBJID: salesRequestObjid,
|
||||
VENDOR_OBJID: vendorObjid,
|
||||
VENDOR_TYPE: 'SUPPLY',
|
||||
PART_OBJIDS: JSON.stringify(partObjids)
|
||||
},
|
||||
dataType: "json"
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// 가공업체별 견적요청서 생성
|
||||
for(var vendorObjid in processingVendorGroups) {
|
||||
var partObjids = processingVendorGroups[vendorObjid].parts;
|
||||
createPromises.push(
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/salesMng/createQuotationRequest.do",
|
||||
data: {
|
||||
SALES_REQUEST_MASTER_OBJID: salesRequestObjid,
|
||||
VENDOR_OBJID: vendorObjid,
|
||||
VENDOR_TYPE: 'PROCESSING',
|
||||
PART_OBJIDS: JSON.stringify(partObjids)
|
||||
},
|
||||
dataType: "json"
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
Promise.all(createPromises).then(function(results) {
|
||||
var successCount = 0;
|
||||
var failCount = 0;
|
||||
var createdNos = [];
|
||||
|
||||
results.forEach(function(result) {
|
||||
if(result.resultFlag === 'S') {
|
||||
successCount++;
|
||||
if(result.QUOTATION_REQUEST_NO) {
|
||||
createdNos.push(result.QUOTATION_REQUEST_NO);
|
||||
}
|
||||
} else {
|
||||
failCount++;
|
||||
}
|
||||
});
|
||||
|
||||
if(successCount > 0) {
|
||||
var msgHtml = '<p>' + successCount + '개의 견적요청서가 생성되었습니다.</p>';
|
||||
if(createdNos.length > 0) {
|
||||
msgHtml += '<div style="margin-top:10px; text-align:left;"><strong>생성된 번호:</strong><br/>';
|
||||
msgHtml += createdNos.map(function(no) { return '- ' + no; }).join('<br/>');
|
||||
msgHtml += '</div>';
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
title: '완료',
|
||||
html: msgHtml,
|
||||
icon: 'success'
|
||||
}).then(() => {
|
||||
fn_search();
|
||||
});
|
||||
} else {
|
||||
Swal.fire({
|
||||
title: '실패',
|
||||
text: '견적요청서 생성에 실패했습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
}
|
||||
}).catch(function(error) {
|
||||
console.error("견적요청서 생성 오류:", error);
|
||||
Swal.fire({
|
||||
title: '오류',
|
||||
text: '견적요청서 생성 중 오류가 발생했습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="backcolor">
|
||||
@@ -716,6 +969,7 @@ function fn_executeCreateProposal(salesRequestObjid, targetParts) {
|
||||
<div class="btnArea">
|
||||
<input type="button" value="조회" class="plm_btns" id="btnSearch">
|
||||
<!-- <input type="button" value="구매요청서작성" class="plm_btns" id="btnOrderReg"> -->
|
||||
<input type="button" value="견적요청서생성" class="plm_btns" id="btnQuotationRequest" style="background-color: #4CAF50; border-color: #4CAF50;">
|
||||
<input type="button" value="품의서생성" class="plm_btns" id="btnReg">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -989,11 +989,24 @@ VALUES
|
||||
-- 문서유형 (PURCHASE_REQUEST: 구매요청서, PROPOSAL: 품의서)
|
||||
SRM.DOC_TYPE,
|
||||
|
||||
-- 구매요청서 작성 여부 (SALES_REQUEST_PART에 DOC_TYPE이 PURCHASE_REQUEST인 데이터가 있으면 'Y')
|
||||
(SELECT CASE WHEN COUNT(*) > 0 THEN 'Y' ELSE 'N' END
|
||||
FROM SALES_REQUEST_PART
|
||||
WHERE SALES_REQUEST_MASTER_OBJID = SRM.OBJID
|
||||
AND (DOC_TYPE = 'PURCHASE_REQUEST' OR DOC_TYPE IS NULL)) AS HAS_PURCHASE_REQUEST,
|
||||
-- 구매요청서 작성 여부
|
||||
-- M-BOM 기반이면 MBOM_HEADER_OBJID가 있으므로 'Y'
|
||||
-- 수동 작성이면 SALES_REQUEST_PART에 데이터가 있으면 'Y'
|
||||
CASE
|
||||
WHEN SRM.MBOM_HEADER_OBJID IS NOT NULL AND SRM.MBOM_HEADER_OBJID::VARCHAR != '' THEN 'Y'
|
||||
WHEN (SELECT COUNT(*) FROM SALES_REQUEST_PART WHERE SALES_REQUEST_MASTER_OBJID = SRM.OBJID AND (DOC_TYPE = 'PURCHASE_REQUEST' OR DOC_TYPE IS NULL)) > 0 THEN 'Y'
|
||||
ELSE 'N'
|
||||
END AS HAS_PURCHASE_REQUEST,
|
||||
|
||||
-- 견적요청서 존재 여부 (QUOTATION_REQUEST_MASTER에 데이터가 있으면 'Y')
|
||||
COALESCE((SELECT CASE WHEN COUNT(*) > 0 THEN 'Y' ELSE 'N' END
|
||||
FROM QUOTATION_REQUEST_MASTER
|
||||
WHERE SALES_REQUEST_MASTER_OBJID::VARCHAR = SRM.OBJID::VARCHAR), 'N') AS HAS_QUOTATION_REQUEST,
|
||||
|
||||
-- 견적요청서 개수
|
||||
COALESCE((SELECT COUNT(*)
|
||||
FROM QUOTATION_REQUEST_MASTER
|
||||
WHERE SALES_REQUEST_MASTER_OBJID::VARCHAR = SRM.OBJID::VARCHAR), 0) AS QUOTATION_REQUEST_COUNT,
|
||||
|
||||
-- M-BOM 관련 컬럼
|
||||
SRM.MBOM_HEADER_OBJID,
|
||||
@@ -3075,7 +3088,7 @@ UPDATE SET
|
||||
TOTAL_PRICE = #{TOTAL_PRICE}
|
||||
</update>
|
||||
|
||||
<!-- 구매리스트 상세 조회 (기존 저장된 데이터) -->
|
||||
<!-- 구매리스트 상세 조회 (기존 저장된 데이터) - 이 쿼리는 사용하지 않음, M-BOM 기반으로만 동작 -->
|
||||
<select id="getPurchaseListDetail" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
<!-- SALES_REQUEST_PART에서 저장된 데이터 조회, PART_MNG에서 품목정보 가져옴 -->
|
||||
SELECT
|
||||
@@ -3114,11 +3127,11 @@ UPDATE SET
|
||||
COALESCE(SRP.VENDOR_PM, SRP.PARTNER_OBJID) AS VENDOR_PM,
|
||||
COALESCE(SRP.UNIT_PRICE, NULLIF(SRP.PARTNER_PRICE, '')::numeric, 0) AS UNIT_PRICE,
|
||||
COALESCE(SRP.TOTAL_PRICE, 0) AS TOTAL_PRICE,
|
||||
COALESCE(SRP.PROCESSING_UNIT_PRICE, 0) AS PROCESSING_UNIT_PRICE,
|
||||
COALESCE(SRP.PROCESSING_TOTAL_PRICE, 0) AS PROCESSING_TOTAL_PRICE,
|
||||
COALESCE(SRP.GRAND_TOTAL_PRICE, 0) AS GRAND_TOTAL_PRICE,
|
||||
0 AS PROCESSING_UNIT_PRICE,
|
||||
0 AS PROCESSING_TOTAL_PRICE,
|
||||
0 AS GRAND_TOTAL_PRICE,
|
||||
SRP.PROPOSAL_DATE,
|
||||
SRP.PROCESSING_PROPOSAL_DATE,
|
||||
NULL AS PROCESSING_PROPOSAL_DATE,
|
||||
'SRP' AS DATA_SOURCE -- 데이터 소스 구분용
|
||||
FROM
|
||||
SALES_REQUEST_PART SRP
|
||||
@@ -4264,4 +4277,412 @@ ORDER BY V.PATH2
|
||||
WHERE OBJID = #{PART_OBJID}
|
||||
</update>
|
||||
|
||||
<!-- 구매리스트 품목 단일 조회 (MBOM_DETAIL에서 조회) -->
|
||||
<select id="getSalesRequestPartInfo" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
SELECT
|
||||
MD.OBJID,
|
||||
MD.MBOM_HEADER_OBJID,
|
||||
MD.PART_OBJID,
|
||||
PM.PART_NO,
|
||||
PM.PART_NAME,
|
||||
MD.RAW_MATERIAL,
|
||||
MD.RAW_MATERIAL_PART_NO AS RAW_MATERIAL_NO,
|
||||
MD.RAW_MATERIAL_SIZE AS SIZE,
|
||||
MD.PO_QTY,
|
||||
MD.PRODUCTION_QTY,
|
||||
MD.UNIT_PRICE,
|
||||
MD.PROCESSING_UNIT_PRICE,
|
||||
MD.VENDOR AS VENDOR_PM,
|
||||
(SELECT CLIENT_NM FROM CLIENT_MNG WHERE OBJID::VARCHAR = MD.VENDOR) AS VENDOR_NAME,
|
||||
MD.PROCESSING_VENDOR,
|
||||
(SELECT CLIENT_NM FROM CLIENT_MNG WHERE OBJID::VARCHAR = MD.PROCESSING_VENDOR) AS PROCESSING_VENDOR_NAME
|
||||
FROM MBOM_DETAIL MD
|
||||
LEFT JOIN PART_MNG PM ON MD.PART_OBJID::VARCHAR = PM.OBJID::VARCHAR
|
||||
WHERE MD.OBJID = #{OBJID}
|
||||
</select>
|
||||
|
||||
<!-- =====================================================
|
||||
견적요청서 관리 쿼리
|
||||
===================================================== -->
|
||||
|
||||
<!-- 견적요청서 목록 조회 (페이징) -->
|
||||
<select id="getQuotationRequestListCount" parameterType="map" resultType="int">
|
||||
SELECT COUNT(*)
|
||||
FROM QUOTATION_REQUEST_MASTER QRM
|
||||
LEFT JOIN SALES_REQUEST_MASTER SRM ON QRM.SALES_REQUEST_MASTER_OBJID::VARCHAR = SRM.OBJID::VARCHAR
|
||||
LEFT JOIN PROJECT_MGMT PM ON PM.OBJID = SRM.PROJECT_NO
|
||||
LEFT JOIN CLIENT_MNG CM ON QRM.VENDOR_OBJID::VARCHAR = CM.OBJID::VARCHAR
|
||||
WHERE 1=1
|
||||
<if test="SALES_REQUEST_MASTER_OBJID != null and SALES_REQUEST_MASTER_OBJID != ''">
|
||||
AND QRM.SALES_REQUEST_MASTER_OBJID::VARCHAR = #{SALES_REQUEST_MASTER_OBJID}
|
||||
</if>
|
||||
<if test="Year != null and Year != ''">
|
||||
AND TO_CHAR(QRM.REG_DATE, 'YYYY') = #{Year}
|
||||
</if>
|
||||
<if test="QUOTATION_REQUEST_NO != null and QUOTATION_REQUEST_NO != ''">
|
||||
AND QRM.QUOTATION_REQUEST_NO LIKE '%' || #{QUOTATION_REQUEST_NO} || '%'
|
||||
</if>
|
||||
<if test="PROJECT_NO != null and PROJECT_NO != ''">
|
||||
AND PM.PROJECT_NO LIKE '%' || #{PROJECT_NO} || '%'
|
||||
</if>
|
||||
<if test="VENDOR_OBJID != null and VENDOR_OBJID != ''">
|
||||
AND QRM.VENDOR_OBJID::VARCHAR = #{VENDOR_OBJID}
|
||||
</if>
|
||||
<if test="STATUS != null and STATUS != ''">
|
||||
AND QRM.STATUS = #{STATUS}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="getQuotationRequestList" parameterType="map" resultType="map">
|
||||
SELECT
|
||||
QRM.OBJID,
|
||||
QRM.QUOTATION_REQUEST_NO,
|
||||
QRM.SALES_REQUEST_MASTER_OBJID,
|
||||
QRM.PROJECT_MGMT_OBJID,
|
||||
QRM.VENDOR_OBJID,
|
||||
QRM.VENDOR_TYPE,
|
||||
QRM.STATUS,
|
||||
CASE
|
||||
WHEN QRM.STATUS = 'create' THEN '작성중'
|
||||
WHEN QRM.STATUS = 'sent' THEN '발송완료'
|
||||
WHEN QRM.STATUS = 'received' THEN '견적수신'
|
||||
WHEN QRM.STATUS = 'completed' THEN '완료'
|
||||
ELSE QRM.STATUS
|
||||
END AS STATUS_NAME,
|
||||
QRM.MAIL_SEND_DATE,
|
||||
TO_CHAR(QRM.MAIL_SEND_DATE, 'YYYY-MM-DD') AS MAIL_SEND_DATE_TITLE,
|
||||
QRM.MAIL_SEND_YN,
|
||||
QRM.DUE_DATE,
|
||||
TO_CHAR(QRM.DUE_DATE, 'YYYY-MM-DD') AS DUE_DATE_TITLE,
|
||||
QRM.REMARK,
|
||||
QRM.WRITER,
|
||||
QRM.REG_DATE,
|
||||
TO_CHAR(QRM.REG_DATE, 'YYYY-MM-DD') AS REG_DATE_TITLE,
|
||||
-- 구매요청서 정보
|
||||
SRM.REQUEST_MNG_NO,
|
||||
SRM.PURCHASE_TYPE,
|
||||
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = SRM.PURCHASE_TYPE) AS PURCHASE_TYPE_NAME,
|
||||
-- 주문유형
|
||||
COALESCE(PM.CATEGORY_CD, SRM.ORDER_TYPE) AS ORDER_TYPE,
|
||||
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = COALESCE(PM.CATEGORY_CD, SRM.ORDER_TYPE)) AS ORDER_TYPE_NAME,
|
||||
-- 제품구분
|
||||
COALESCE(
|
||||
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CTM.PRODUCT),
|
||||
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = SRM.PRODUCT_NAME)
|
||||
) AS PRODUCT_NAME_TITLE,
|
||||
-- 프로젝트번호
|
||||
PM.PROJECT_NO AS PROJECT_NUMBER,
|
||||
-- 업체 정보
|
||||
CM.CLIENT_NM AS VENDOR_NAME,
|
||||
-- 품번/품명 (프로젝트 정보)
|
||||
PM.PART_NO,
|
||||
PM.PART_NAME,
|
||||
-- 수신견적서 첨부파일 개수
|
||||
(SELECT COUNT(*) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = QRM.OBJID::VARCHAR AND DOC_TYPE = 'QUOTATION_RECEIVED' AND STATUS = 'Active') AS ATTACH_FILE_CNT
|
||||
FROM QUOTATION_REQUEST_MASTER QRM
|
||||
LEFT JOIN SALES_REQUEST_MASTER SRM ON QRM.SALES_REQUEST_MASTER_OBJID::VARCHAR = SRM.OBJID::VARCHAR
|
||||
LEFT JOIN PROJECT_MGMT PM ON PM.OBJID = SRM.PROJECT_NO
|
||||
LEFT JOIN CONTRACT_MGMT CTM ON CTM.OBJID = PM.CONTRACT_OBJID
|
||||
LEFT JOIN CLIENT_MNG CM ON QRM.VENDOR_OBJID::VARCHAR = CM.OBJID::VARCHAR
|
||||
WHERE 1=1
|
||||
<if test="SALES_REQUEST_MASTER_OBJID != null and SALES_REQUEST_MASTER_OBJID != ''">
|
||||
AND QRM.SALES_REQUEST_MASTER_OBJID::VARCHAR = #{SALES_REQUEST_MASTER_OBJID}
|
||||
</if>
|
||||
<if test="Year != null and Year != ''">
|
||||
AND TO_CHAR(QRM.REG_DATE, 'YYYY') = #{Year}
|
||||
</if>
|
||||
<if test="QUOTATION_REQUEST_NO != null and QUOTATION_REQUEST_NO != ''">
|
||||
AND QRM.QUOTATION_REQUEST_NO LIKE '%' || #{QUOTATION_REQUEST_NO} || '%'
|
||||
</if>
|
||||
<if test="PROJECT_NO != null and PROJECT_NO != ''">
|
||||
AND PM.PROJECT_NO LIKE '%' || #{PROJECT_NO} || '%'
|
||||
</if>
|
||||
<if test="VENDOR_OBJID != null and VENDOR_OBJID != ''">
|
||||
AND QRM.VENDOR_OBJID::VARCHAR = #{VENDOR_OBJID}
|
||||
</if>
|
||||
<if test="STATUS != null and STATUS != ''">
|
||||
AND QRM.STATUS = #{STATUS}
|
||||
</if>
|
||||
ORDER BY QRM.REG_DATE DESC
|
||||
<if test="startRow != null and countPerPage != null">
|
||||
OFFSET #{startRow} LIMIT #{countPerPage}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<!-- 견적요청서 마스터 정보 조회 -->
|
||||
<select id="getQuotationRequestMasterInfo" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
SELECT
|
||||
QRM.OBJID,
|
||||
QRM.QUOTATION_REQUEST_NO,
|
||||
QRM.SALES_REQUEST_MASTER_OBJID,
|
||||
QRM.PROJECT_MGMT_OBJID,
|
||||
QRM.VENDOR_OBJID,
|
||||
QRM.VENDOR_TYPE,
|
||||
QRM.STATUS,
|
||||
QRM.MAIL_SEND_DATE,
|
||||
TO_CHAR(QRM.MAIL_SEND_DATE, 'YYYY-MM-DD') AS MAIL_SEND_DATE_TITLE,
|
||||
QRM.MAIL_SEND_YN,
|
||||
QRM.DUE_DATE,
|
||||
TO_CHAR(QRM.DUE_DATE, 'YYYY-MM-DD') AS DUE_DATE_TITLE,
|
||||
QRM.REMARK,
|
||||
QRM.WRITER,
|
||||
QRM.REG_DATE,
|
||||
TO_CHAR(QRM.REG_DATE, 'YYYY-MM-DD') AS REG_DATE_TITLE,
|
||||
-- 구매요청서 정보
|
||||
SRM.REQUEST_MNG_NO,
|
||||
SRM.PURCHASE_TYPE,
|
||||
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = SRM.PURCHASE_TYPE) AS PURCHASE_TYPE_NAME,
|
||||
-- 주문유형
|
||||
COALESCE(PM.CATEGORY_CD, SRM.ORDER_TYPE) AS ORDER_TYPE,
|
||||
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = COALESCE(PM.CATEGORY_CD, SRM.ORDER_TYPE)) AS ORDER_TYPE_NAME,
|
||||
-- 제품구분
|
||||
COALESCE(
|
||||
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CTM.PRODUCT),
|
||||
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = SRM.PRODUCT_NAME)
|
||||
) AS PRODUCT_NAME_TITLE,
|
||||
-- 프로젝트번호
|
||||
PM.PROJECT_NO,
|
||||
-- 업체 정보
|
||||
CM.CLIENT_NM AS VENDOR_NAME,
|
||||
CM.EMAIL AS VENDOR_EMAIL
|
||||
FROM QUOTATION_REQUEST_MASTER QRM
|
||||
LEFT JOIN SALES_REQUEST_MASTER SRM ON QRM.SALES_REQUEST_MASTER_OBJID::VARCHAR = SRM.OBJID::VARCHAR
|
||||
LEFT JOIN PROJECT_MGMT PM ON PM.OBJID = SRM.PROJECT_NO
|
||||
LEFT JOIN CONTRACT_MGMT CTM ON CTM.OBJID = PM.CONTRACT_OBJID
|
||||
LEFT JOIN CLIENT_MNG CM ON QRM.VENDOR_OBJID::VARCHAR = CM.OBJID::VARCHAR
|
||||
WHERE QRM.OBJID = #{QUOTATION_REQUEST_MASTER_OBJID}::NUMERIC
|
||||
</select>
|
||||
|
||||
<!-- 견적요청서 상세 목록 조회 -->
|
||||
<select id="getQuotationRequestDetailList" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
SELECT
|
||||
QRD.OBJID,
|
||||
QRD.QUOTATION_REQUEST_MASTER_OBJID,
|
||||
QRD.SALES_REQUEST_PART_OBJID,
|
||||
QRD.PART_OBJID,
|
||||
QRD.PART_NO,
|
||||
QRD.PART_NAME,
|
||||
QRD.RAW_MATERIAL,
|
||||
QRD.SIZE,
|
||||
QRD.QTY,
|
||||
QRD.UNIT_PRICE,
|
||||
QRD.REMARK,
|
||||
QRD.REG_DATE,
|
||||
-- 마스터 정보
|
||||
QRM.VENDOR_TYPE,
|
||||
QRM.VENDOR_OBJID,
|
||||
(SELECT CLIENT_NM FROM CLIENT_MNG WHERE OBJID::VARCHAR = QRM.VENDOR_OBJID::VARCHAR) AS VENDOR_NAME
|
||||
FROM QUOTATION_REQUEST_DETAIL QRD
|
||||
LEFT JOIN QUOTATION_REQUEST_MASTER QRM ON QRD.QUOTATION_REQUEST_MASTER_OBJID = QRM.OBJID
|
||||
WHERE QRD.QUOTATION_REQUEST_MASTER_OBJID = #{QUOTATION_REQUEST_MASTER_OBJID}::NUMERIC
|
||||
ORDER BY QRD.OBJID
|
||||
</select>
|
||||
|
||||
<!-- 견적요청서 번호 생성 -->
|
||||
<select id="getNextQuotationRequestNo" parameterType="map" resultType="string">
|
||||
SELECT 'Q' || TO_CHAR(NOW(), 'YYYYMMDD') || '-' || LPAD(NEXTVAL('SEQ_QUOTATION_REQUEST_NO')::VARCHAR, 3, '0')
|
||||
</select>
|
||||
|
||||
<!-- 견적요청서 마스터 생성 -->
|
||||
<insert id="insertQuotationRequestMaster" parameterType="map">
|
||||
INSERT INTO QUOTATION_REQUEST_MASTER (
|
||||
OBJID,
|
||||
QUOTATION_REQUEST_NO,
|
||||
SALES_REQUEST_MASTER_OBJID,
|
||||
PROJECT_MGMT_OBJID,
|
||||
VENDOR_OBJID,
|
||||
VENDOR_TYPE,
|
||||
STATUS,
|
||||
DUE_DATE,
|
||||
REMARK,
|
||||
WRITER,
|
||||
REG_DATE
|
||||
) VALUES (
|
||||
#{OBJID}::NUMERIC,
|
||||
#{QUOTATION_REQUEST_NO},
|
||||
#{SALES_REQUEST_MASTER_OBJID}::NUMERIC,
|
||||
#{PROJECT_MGMT_OBJID}::NUMERIC,
|
||||
#{VENDOR_OBJID}::NUMERIC,
|
||||
#{VENDOR_TYPE},
|
||||
'create',
|
||||
<if test="DUE_DATE != null and DUE_DATE != ''">#{DUE_DATE}::DATE</if>
|
||||
<if test="DUE_DATE == null or DUE_DATE == ''">NULL</if>,
|
||||
#{REMARK},
|
||||
#{WRITER},
|
||||
NOW()
|
||||
)
|
||||
</insert>
|
||||
|
||||
<!-- 견적요청서 상세 생성 -->
|
||||
<insert id="insertQuotationRequestDetail" parameterType="map">
|
||||
INSERT INTO QUOTATION_REQUEST_DETAIL (
|
||||
OBJID,
|
||||
QUOTATION_REQUEST_MASTER_OBJID,
|
||||
SALES_REQUEST_PART_OBJID,
|
||||
PART_OBJID,
|
||||
PART_NO,
|
||||
PART_NAME,
|
||||
RAW_MATERIAL,
|
||||
SIZE,
|
||||
QTY,
|
||||
UNIT_PRICE,
|
||||
REMARK,
|
||||
REG_DATE
|
||||
) VALUES (
|
||||
#{OBJID}::NUMERIC,
|
||||
#{QUOTATION_REQUEST_MASTER_OBJID}::NUMERIC,
|
||||
#{SALES_REQUEST_PART_OBJID}::NUMERIC,
|
||||
#{PART_OBJID}::NUMERIC,
|
||||
#{PART_NO},
|
||||
#{PART_NAME},
|
||||
#{RAW_MATERIAL},
|
||||
#{SIZE},
|
||||
COALESCE(#{QTY}::NUMERIC, 0),
|
||||
COALESCE(#{UNIT_PRICE}::NUMERIC, 0),
|
||||
#{REMARK},
|
||||
NOW()
|
||||
)
|
||||
</insert>
|
||||
|
||||
<!-- 견적요청서 상세 단가 업데이트 -->
|
||||
<update id="updateQuotationRequestDetailPrice" parameterType="map">
|
||||
UPDATE QUOTATION_REQUEST_DETAIL SET
|
||||
UNIT_PRICE = #{UNIT_PRICE}::NUMERIC,
|
||||
TOTAL_PRICE = #{QTY}::NUMERIC * #{UNIT_PRICE}::NUMERIC,
|
||||
EDIT_DATE = NOW()
|
||||
WHERE OBJID = #{OBJID}::NUMERIC
|
||||
</update>
|
||||
|
||||
<!-- 견적요청서 마스터 상태 업데이트 -->
|
||||
<update id="updateQuotationRequestMasterStatus" parameterType="map">
|
||||
UPDATE QUOTATION_REQUEST_MASTER SET
|
||||
STATUS = #{STATUS},
|
||||
EDIT_DATE = NOW()
|
||||
<if test="MAIL_SEND_YN != null and MAIL_SEND_YN != ''">
|
||||
, MAIL_SEND_YN = #{MAIL_SEND_YN}
|
||||
, MAIL_SEND_DATE = NOW()
|
||||
</if>
|
||||
WHERE OBJID = #{QUOTATION_REQUEST_MASTER_OBJID}::NUMERIC
|
||||
</update>
|
||||
|
||||
<!-- MBOM_DETAIL 단가 업데이트 (견적 수신 후) -->
|
||||
<update id="updatePurchaseListPriceFromQuotation" parameterType="map">
|
||||
UPDATE MBOM_DETAIL SET
|
||||
<if test="VENDOR_TYPE == 'SUPPLY'">
|
||||
UNIT_PRICE = #{UNIT_PRICE}::NUMERIC
|
||||
</if>
|
||||
<if test="VENDOR_TYPE == 'PROCESSING'">
|
||||
PROCESSING_UNIT_PRICE = #{UNIT_PRICE}::NUMERIC
|
||||
</if>
|
||||
, EDIT_DATE = NOW()
|
||||
WHERE OBJID = #{SALES_REQUEST_PART_OBJID}
|
||||
</update>
|
||||
|
||||
<!-- 구매리스트에서 견적요청서 생성 대상 조회 - M-BOM 기반 (MBOM_DETAIL에서 조회) -->
|
||||
<!-- 공급업체/가공업체별로 견적요청서 생성 가능 여부 플래그 포함 -->
|
||||
<select id="getPurchaseListForQuotationFromMBom" parameterType="map" resultType="map">
|
||||
SELECT
|
||||
MD.OBJID,
|
||||
#{SALES_REQUEST_MASTER_OBJID} AS SALES_REQUEST_MASTER_OBJID,
|
||||
MD.PART_OBJID,
|
||||
PM.PART_NO,
|
||||
PM.PART_NAME,
|
||||
MD.RAW_MATERIAL,
|
||||
MD.RAW_MATERIAL_SIZE AS SIZE,
|
||||
MD.PO_QTY,
|
||||
MD.PRODUCTION_QTY,
|
||||
MD.UNIT_PRICE,
|
||||
MD.PROCESSING_UNIT_PRICE,
|
||||
MD.VENDOR AS VENDOR_PM,
|
||||
(SELECT CLIENT_NM FROM CLIENT_MNG WHERE OBJID::VARCHAR = MD.VENDOR) AS VENDOR_NAME,
|
||||
MD.PROCESSING_VENDOR,
|
||||
(SELECT CLIENT_NM FROM CLIENT_MNG WHERE OBJID::VARCHAR = MD.PROCESSING_VENDOR) AS PROCESSING_VENDOR_NAME,
|
||||
MD.RAW_MATERIAL_PART_NO AS RAW_MATERIAL_NO,
|
||||
'MBOM' AS DATA_SOURCE,
|
||||
-- 공급업체 견적요청서 생성 가능 여부
|
||||
CASE WHEN MD.VENDOR IS NOT NULL AND MD.VENDOR != '' AND NOT EXISTS (
|
||||
SELECT 1 FROM QUOTATION_REQUEST_DETAIL QRD
|
||||
INNER JOIN QUOTATION_REQUEST_MASTER QRM ON QRD.QUOTATION_REQUEST_MASTER_OBJID = QRM.OBJID
|
||||
WHERE QRD.SALES_REQUEST_PART_OBJID::VARCHAR = MD.OBJID::VARCHAR
|
||||
AND QRM.VENDOR_TYPE = 'SUPPLY'
|
||||
AND QRM.VENDOR_OBJID::VARCHAR = MD.VENDOR
|
||||
) THEN 'Y' ELSE 'N' END AS CAN_CREATE_SUPPLY,
|
||||
-- 가공업체 견적요청서 생성 가능 여부
|
||||
CASE WHEN MD.PROCESSING_VENDOR IS NOT NULL AND MD.PROCESSING_VENDOR != '' AND NOT EXISTS (
|
||||
SELECT 1 FROM QUOTATION_REQUEST_DETAIL QRD
|
||||
INNER JOIN QUOTATION_REQUEST_MASTER QRM ON QRD.QUOTATION_REQUEST_MASTER_OBJID = QRM.OBJID
|
||||
WHERE QRD.SALES_REQUEST_PART_OBJID::VARCHAR = MD.OBJID::VARCHAR
|
||||
AND QRM.VENDOR_TYPE = 'PROCESSING'
|
||||
AND QRM.VENDOR_OBJID::VARCHAR = MD.PROCESSING_VENDOR
|
||||
) THEN 'Y' ELSE 'N' END AS CAN_CREATE_PROCESSING
|
||||
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.VENDOR IS NOT NULL AND MD.VENDOR != '')
|
||||
OR (MD.PROCESSING_VENDOR IS NOT NULL AND MD.PROCESSING_VENDOR != '')
|
||||
)
|
||||
-- 공급업체 또는 가공업체 중 하나라도 견적요청서 생성 가능해야 함
|
||||
AND (
|
||||
-- 공급업체 견적요청서 생성 가능
|
||||
(MD.VENDOR IS NOT NULL AND MD.VENDOR != '' AND NOT EXISTS (
|
||||
SELECT 1 FROM QUOTATION_REQUEST_DETAIL QRD
|
||||
INNER JOIN QUOTATION_REQUEST_MASTER QRM ON QRD.QUOTATION_REQUEST_MASTER_OBJID = QRM.OBJID
|
||||
WHERE QRD.SALES_REQUEST_PART_OBJID::VARCHAR = MD.OBJID::VARCHAR
|
||||
AND QRM.VENDOR_TYPE = 'SUPPLY'
|
||||
AND QRM.VENDOR_OBJID::VARCHAR = MD.VENDOR
|
||||
))
|
||||
OR
|
||||
-- 가공업체 견적요청서 생성 가능
|
||||
(MD.PROCESSING_VENDOR IS NOT NULL AND MD.PROCESSING_VENDOR != '' AND NOT EXISTS (
|
||||
SELECT 1 FROM QUOTATION_REQUEST_DETAIL QRD
|
||||
INNER JOIN QUOTATION_REQUEST_MASTER QRM ON QRD.QUOTATION_REQUEST_MASTER_OBJID = QRM.OBJID
|
||||
WHERE QRD.SALES_REQUEST_PART_OBJID::VARCHAR = MD.OBJID::VARCHAR
|
||||
AND QRM.VENDOR_TYPE = 'PROCESSING'
|
||||
AND QRM.VENDOR_OBJID::VARCHAR = MD.PROCESSING_VENDOR
|
||||
))
|
||||
)
|
||||
ORDER BY MD.REGDATE
|
||||
</select>
|
||||
|
||||
<!-- 구매리스트에서 견적요청서 생성 대상 조회 - 수동 작성 (SALES_REQUEST_PART에서 조회) -->
|
||||
<select id="getPurchaseListForQuotationFromManual" parameterType="map" resultType="map">
|
||||
SELECT
|
||||
SRP.OBJID,
|
||||
SRP.SALES_REQUEST_MASTER_OBJID,
|
||||
SRP.PART_OBJID,
|
||||
PM.PART_NO,
|
||||
PM.PART_NAME,
|
||||
SRP.RAW_MATERIAL,
|
||||
SRP.SIZE,
|
||||
SRP.PO_QTY,
|
||||
SRP.PRODUCTION_QTY,
|
||||
SRP.UNIT_PRICE,
|
||||
SRP.PROCESSING_UNIT_PRICE,
|
||||
SRP.VENDOR_PM,
|
||||
(SELECT CLIENT_NM FROM CLIENT_MNG WHERE OBJID::VARCHAR = SRP.VENDOR_PM) AS VENDOR_NAME,
|
||||
SRP.PROCESSING_VENDOR,
|
||||
(SELECT CLIENT_NM FROM CLIENT_MNG WHERE OBJID::VARCHAR = SRP.PROCESSING_VENDOR) AS PROCESSING_VENDOR_NAME,
|
||||
SRP.RAW_MATERIAL_NO,
|
||||
'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}::NUMERIC
|
||||
AND (
|
||||
(SRP.VENDOR_PM IS NOT NULL AND SRP.VENDOR_PM != '')
|
||||
OR (SRP.PROCESSING_VENDOR IS NOT NULL AND SRP.PROCESSING_VENDOR != '')
|
||||
)
|
||||
ORDER BY SRP.OBJID
|
||||
</select>
|
||||
|
||||
<!-- 견적요청서 삭제 (마스터) -->
|
||||
<delete id="deleteQuotationRequestMaster" parameterType="map">
|
||||
DELETE FROM QUOTATION_REQUEST_MASTER WHERE OBJID = #{QUOTATION_REQUEST_MASTER_OBJID}::NUMERIC
|
||||
</delete>
|
||||
|
||||
<!-- 견적요청서 삭제 (상세) -->
|
||||
<delete id="deleteQuotationRequestDetail" parameterType="map">
|
||||
DELETE FROM QUOTATION_REQUEST_DETAIL WHERE QUOTATION_REQUEST_MASTER_OBJID = #{QUOTATION_REQUEST_MASTER_OBJID}::NUMERIC
|
||||
</delete>
|
||||
|
||||
</mapper>
|
||||
@@ -1538,4 +1538,222 @@ public class SalesMngController {
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// 견적요청서 관리 컨트롤러
|
||||
// =====================================================
|
||||
|
||||
/**
|
||||
* 견적요청서 목록 페이지
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping("/salesMng/quotationRequestList.do")
|
||||
public String quotationRequestList(HttpServletRequest request, @RequestParam Map paramMap){
|
||||
String returnUrl = "/salesMng/quotationRequestList";
|
||||
Map code_map = new HashMap();
|
||||
|
||||
try {
|
||||
// 프로젝트번호
|
||||
code_map.put("project_no", commonService.bizMakeOptionList("", (String)paramMap.get("project_no"), "common.getProjectNameList"));
|
||||
// 업체 목록
|
||||
code_map.put("vendor_objid", commonService.bizMakeOptionList("", (String)paramMap.get("vendor_objid"), "common.getsupplyselect"));
|
||||
// 상태
|
||||
String statusOptions = "";
|
||||
statusOptions += "<option value=''>전체</option>";
|
||||
statusOptions += "<option value='create'" + ("create".equals(paramMap.get("status")) ? " selected" : "") + ">작성중</option>";
|
||||
statusOptions += "<option value='sent'" + ("sent".equals(paramMap.get("status")) ? " selected" : "") + ">발송완료</option>";
|
||||
statusOptions += "<option value='received'" + ("received".equals(paramMap.get("status")) ? " selected" : "") + ">견적수신</option>";
|
||||
statusOptions += "<option value='completed'" + ("completed".equals(paramMap.get("status")) ? " selected" : "") + ">완료</option>";
|
||||
code_map.put("status", statusOptions);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
request.setAttribute("code_map", code_map);
|
||||
return returnUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적요청서 목록 조회 (페이징)
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/salesMng/quotationRequestListPaging.do")
|
||||
public Map getQuotationRequestListPaging(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
commonService.selectListPagingNew("salesMng.getQuotationRequestList", request, paramMap);
|
||||
return paramMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적요청서 상세 팝업
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping("/salesMng/quotationRequestFormPopup.do")
|
||||
public String quotationRequestFormPopup(HttpServletRequest request, @RequestParam Map paramMap){
|
||||
Map resultMap = new HashMap();
|
||||
Map code_map = new HashMap();
|
||||
|
||||
try {
|
||||
String quotationRequestMasterObjid = CommonUtils.checkNull(paramMap.get("QUOTATION_REQUEST_MASTER_OBJID"));
|
||||
|
||||
if(!"".equals(quotationRequestMasterObjid)){
|
||||
// 기존 견적요청서 조회
|
||||
resultMap = salesMngService.getQuotationRequestMasterInfo(request, paramMap);
|
||||
} else {
|
||||
// 신규 생성 (구매리스트에서 호출 시)
|
||||
resultMap.put("OBJID", CommonUtils.createObjId());
|
||||
resultMap.put("STATUS", "create");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
request.setAttribute("code_map", code_map);
|
||||
request.setAttribute("resultMap", resultMap);
|
||||
return "/salesMng/quotationRequestFormPopup";
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적요청서 상세 목록 조회
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/salesMng/getQuotationRequestDetailList.do")
|
||||
public Map getQuotationRequestDetailList(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
Map resultMap = new HashMap();
|
||||
|
||||
try {
|
||||
List<Map> detailList = salesMngService.getQuotationRequestDetailList(request, paramMap);
|
||||
resultMap.put("list", detailList);
|
||||
resultMap.put("resultFlag", "S");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
resultMap.put("resultFlag", "F");
|
||||
resultMap.put("message", "조회 중 오류가 발생했습니다.");
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적요청서 생성 (구매리스트에서)
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/salesMng/createQuotationRequest.do")
|
||||
public Map createQuotationRequest(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
Map resultMap = new HashMap();
|
||||
|
||||
try {
|
||||
resultMap = salesMngService.createQuotationRequest(request, paramMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
resultMap.put("resultFlag", "F");
|
||||
resultMap.put("message", "견적요청서 생성 중 오류가 발생했습니다: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적요청서 단가 저장
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/salesMng/saveQuotationRequestPrice.do")
|
||||
public Map saveQuotationRequestPrice(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
Map resultMap = new HashMap();
|
||||
|
||||
try {
|
||||
resultMap = salesMngService.saveQuotationRequestPrice(request, paramMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
resultMap.put("resultFlag", "F");
|
||||
resultMap.put("message", "저장 중 오류가 발생했습니다: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적요청서 메일 발송 후 상태 업데이트
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/salesMng/updateQuotationRequestMailSent.do")
|
||||
public Map updateQuotationRequestMailSent(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
Map resultMap = new HashMap();
|
||||
|
||||
try {
|
||||
resultMap = salesMngService.updateQuotationRequestMailSent(request, paramMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
resultMap.put("resultFlag", "F");
|
||||
resultMap.put("message", "상태 업데이트 중 오류가 발생했습니다: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적요청서 삭제
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/salesMng/deleteQuotationRequest.do")
|
||||
public Map deleteQuotationRequest(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
Map resultMap = new HashMap();
|
||||
|
||||
try {
|
||||
resultMap = salesMngService.deleteQuotationRequest(request, paramMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
resultMap.put("resultFlag", "F");
|
||||
resultMap.put("message", "삭제 중 오류가 발생했습니다: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 구매리스트에서 견적요청서 생성 대상 조회
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/salesMng/getPurchaseListForQuotation.do")
|
||||
public Map getPurchaseListForQuotation(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
Map resultMap = new HashMap();
|
||||
|
||||
try {
|
||||
List<Map> list = salesMngService.getPurchaseListForQuotation(request, paramMap);
|
||||
resultMap.put("list", list);
|
||||
resultMap.put("resultFlag", "S");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
resultMap.put("resultFlag", "F");
|
||||
resultMap.put("message", "조회 중 오류가 발생했습니다.");
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2194,4 +2194,391 @@ public class SalesMngService {
|
||||
|
||||
return proposalNo;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// 견적요청서 관리 메서드
|
||||
// =====================================================
|
||||
|
||||
/**
|
||||
* 견적요청서 목록 조회
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
public List<Map> getQuotationRequestList(HttpServletRequest request, Map paramMap) {
|
||||
SqlSession sqlSession = null;
|
||||
List<Map> resultList = new ArrayList<Map>();
|
||||
try {
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession();
|
||||
resultList = sqlSession.selectList("salesMng.getQuotationRequestList", paramMap);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if(sqlSession != null) sqlSession.close();
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적요청서 마스터 정보 조회
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
public Map getQuotationRequestMasterInfo(HttpServletRequest request, Map paramMap) {
|
||||
SqlSession sqlSession = null;
|
||||
Map resultMap = new HashMap();
|
||||
try {
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession();
|
||||
resultMap = (Map)sqlSession.selectOne("salesMng.getQuotationRequestMasterInfo", paramMap);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if(sqlSession != null) sqlSession.close();
|
||||
}
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적요청서 상세 목록 조회
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
public List<Map> getQuotationRequestDetailList(HttpServletRequest request, Map paramMap) {
|
||||
SqlSession sqlSession = null;
|
||||
List<Map> resultList = new ArrayList<Map>();
|
||||
try {
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession();
|
||||
resultList = sqlSession.selectList("salesMng.getQuotationRequestDetailList", paramMap);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if(sqlSession != null) sqlSession.close();
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적요청서 생성 (구매리스트에서)
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
public Map createQuotationRequest(HttpServletRequest request, Map paramMap) {
|
||||
SqlSession sqlSession = null;
|
||||
Map resultMap = new HashMap();
|
||||
|
||||
try {
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
|
||||
|
||||
String salesRequestMasterObjid = CommonUtils.checkNull(paramMap.get("SALES_REQUEST_MASTER_OBJID"));
|
||||
String vendorObjid = CommonUtils.checkNull(paramMap.get("VENDOR_OBJID"));
|
||||
String vendorType = CommonUtils.checkNull(paramMap.get("VENDOR_TYPE")); // SUPPLY 또는 PROCESSING
|
||||
String partObjidsJson = CommonUtils.checkNull(paramMap.get("PART_OBJIDS")); // 선택된 품목 OBJID 목록
|
||||
|
||||
HttpSession session = request.getSession();
|
||||
PersonBean personBean = (PersonBean)session.getAttribute(Constants.PERSON_BEAN);
|
||||
String userId = personBean.getUserId();
|
||||
|
||||
// 1. 견적요청서 번호 생성
|
||||
String quotationRequestNo = (String)sqlSession.selectOne("salesMng.getNextQuotationRequestNo");
|
||||
|
||||
// 2. 구매요청서 마스터 정보 조회 (프로젝트 정보 등)
|
||||
Map masterParam = new HashMap();
|
||||
masterParam.put("SALES_REQUEST_MASTER_OBJID", salesRequestMasterObjid);
|
||||
Map purchaseRequestInfo = (Map)sqlSession.selectOne("salesMng.getSalesRequestMasterInfo", masterParam);
|
||||
|
||||
// 3. 견적요청서 마스터 생성
|
||||
String quotationMasterObjid = CommonUtils.createObjId();
|
||||
Map quotationMaster = new HashMap();
|
||||
quotationMaster.put("OBJID", quotationMasterObjid);
|
||||
quotationMaster.put("QUOTATION_REQUEST_NO", quotationRequestNo);
|
||||
quotationMaster.put("SALES_REQUEST_MASTER_OBJID", salesRequestMasterObjid);
|
||||
// 대소문자 모두 처리 (MyBatis에서 소문자로 반환될 수 있음)
|
||||
Object projectMgmtObjid = null;
|
||||
Object dueDate = null;
|
||||
if(purchaseRequestInfo != null) {
|
||||
projectMgmtObjid = purchaseRequestInfo.get("PROJECT_MGMT_OBJID") != null ?
|
||||
purchaseRequestInfo.get("PROJECT_MGMT_OBJID") : purchaseRequestInfo.get("project_mgmt_objid");
|
||||
dueDate = purchaseRequestInfo.get("DUE_DATE") != null ?
|
||||
purchaseRequestInfo.get("DUE_DATE") : purchaseRequestInfo.get("due_date");
|
||||
}
|
||||
quotationMaster.put("PROJECT_MGMT_OBJID", projectMgmtObjid);
|
||||
quotationMaster.put("VENDOR_OBJID", vendorObjid);
|
||||
quotationMaster.put("VENDOR_TYPE", vendorType);
|
||||
quotationMaster.put("DUE_DATE", dueDate);
|
||||
quotationMaster.put("WRITER", userId);
|
||||
|
||||
sqlSession.insert("salesMng.insertQuotationRequestMaster", quotationMaster);
|
||||
|
||||
// 4. 선택된 품목들로 견적요청서 상세 생성
|
||||
List<String> partObjids = new ArrayList<String>();
|
||||
if(partObjidsJson != null && !partObjidsJson.isEmpty()) {
|
||||
org.codehaus.jackson.map.ObjectMapper mapper = new org.codehaus.jackson.map.ObjectMapper();
|
||||
partObjids = mapper.readValue(partObjidsJson, List.class);
|
||||
}
|
||||
|
||||
for(String partObjid : partObjids) {
|
||||
// 구매리스트 품목 정보 조회
|
||||
Map partParam = new HashMap();
|
||||
partParam.put("OBJID", partObjid);
|
||||
Map partInfo = (Map)sqlSession.selectOne("salesMng.getSalesRequestPartInfo", partParam);
|
||||
|
||||
if(partInfo != null) {
|
||||
Map detailParam = new HashMap();
|
||||
detailParam.put("OBJID", CommonUtils.createObjId());
|
||||
detailParam.put("QUOTATION_REQUEST_MASTER_OBJID", quotationMasterObjid);
|
||||
detailParam.put("SALES_REQUEST_PART_OBJID", partObjid); // MBOM_DETAIL.OBJID
|
||||
detailParam.put("PART_OBJID", partInfo.get("PART_OBJID"));
|
||||
|
||||
// 업체유형에 따라 다른 정보 저장 (단가는 0으로, 견적 수신 후 입력)
|
||||
if("PROCESSING".equals(vendorType)) {
|
||||
// 가공업체: 품번, 품명, 제작수량
|
||||
detailParam.put("PART_NO", partInfo.get("PART_NO"));
|
||||
detailParam.put("PART_NAME", partInfo.get("PART_NAME"));
|
||||
detailParam.put("RAW_MATERIAL", "");
|
||||
detailParam.put("SIZE", "");
|
||||
detailParam.put("QTY", partInfo.get("PRODUCTION_QTY"));
|
||||
} else {
|
||||
// 공급업체: 소재품번, 소재재질, 규격, 발주수량
|
||||
detailParam.put("PART_NO", partInfo.get("RAW_MATERIAL_NO"));
|
||||
detailParam.put("PART_NAME", partInfo.get("RAW_MATERIAL"));
|
||||
detailParam.put("RAW_MATERIAL", partInfo.get("RAW_MATERIAL"));
|
||||
detailParam.put("SIZE", partInfo.get("SIZE"));
|
||||
detailParam.put("QTY", partInfo.get("PO_QTY"));
|
||||
}
|
||||
detailParam.put("UNIT_PRICE", 0); // 단가는 견적 수신 후 입력
|
||||
detailParam.put("REMARK", "");
|
||||
|
||||
sqlSession.insert("salesMng.insertQuotationRequestDetail", detailParam);
|
||||
}
|
||||
}
|
||||
|
||||
sqlSession.commit();
|
||||
|
||||
resultMap.put("resultFlag", "S");
|
||||
resultMap.put("QUOTATION_REQUEST_MASTER_OBJID", quotationMasterObjid);
|
||||
resultMap.put("QUOTATION_REQUEST_NO", quotationRequestNo);
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적요청서 단가 저장 및 구매리스트 업데이트
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
public Map saveQuotationRequestPrice(HttpServletRequest request, Map paramMap) {
|
||||
SqlSession sqlSession = null;
|
||||
Map resultMap = new HashMap();
|
||||
|
||||
try {
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
|
||||
|
||||
String quotationMasterObjid = CommonUtils.checkNull(paramMap.get("QUOTATION_REQUEST_MASTER_OBJID"));
|
||||
String detailListJson = CommonUtils.checkNull(paramMap.get("DETAIL_LIST"));
|
||||
|
||||
// JSON 파싱
|
||||
List<Map> detailList = new ArrayList<Map>();
|
||||
if(detailListJson != null && !detailListJson.isEmpty()) {
|
||||
org.codehaus.jackson.map.ObjectMapper mapper = new org.codehaus.jackson.map.ObjectMapper();
|
||||
detailList = mapper.readValue(detailListJson, List.class);
|
||||
}
|
||||
|
||||
// 견적요청서 마스터 정보 조회 (VENDOR_TYPE 확인)
|
||||
Map masterParam = new HashMap();
|
||||
masterParam.put("QUOTATION_REQUEST_MASTER_OBJID", quotationMasterObjid);
|
||||
Map masterInfo = (Map)sqlSession.selectOne("salesMng.getQuotationRequestMasterInfo", masterParam);
|
||||
String vendorType = CommonUtils.checkNull(masterInfo.get("VENDOR_TYPE"));
|
||||
|
||||
// 각 상세 항목 업데이트
|
||||
for(Map detail : detailList) {
|
||||
String detailObjid = CommonUtils.checkNull(detail.get("OBJID"));
|
||||
String salesRequestPartObjid = CommonUtils.checkNull(detail.get("SALES_REQUEST_PART_OBJID"));
|
||||
String unitPrice = CommonUtils.checkNull(detail.get("UNIT_PRICE"));
|
||||
String qty = CommonUtils.checkNull(detail.get("QTY"));
|
||||
|
||||
// 1. 견적요청서 상세 단가 업데이트
|
||||
Map updateParam = new HashMap();
|
||||
updateParam.put("OBJID", detailObjid);
|
||||
updateParam.put("UNIT_PRICE", unitPrice);
|
||||
updateParam.put("QTY", qty);
|
||||
sqlSession.update("salesMng.updateQuotationRequestDetailPrice", updateParam);
|
||||
|
||||
// 2. 구매리스트 단가 업데이트
|
||||
Map purchaseUpdateParam = new HashMap();
|
||||
purchaseUpdateParam.put("SALES_REQUEST_PART_OBJID", salesRequestPartObjid);
|
||||
purchaseUpdateParam.put("UNIT_PRICE", unitPrice);
|
||||
purchaseUpdateParam.put("VENDOR_TYPE", vendorType);
|
||||
sqlSession.update("salesMng.updatePurchaseListPriceFromQuotation", purchaseUpdateParam);
|
||||
}
|
||||
|
||||
// 3. 견적요청서 마스터 상태 업데이트 (received: 견적수신)
|
||||
Map statusParam = new HashMap();
|
||||
statusParam.put("QUOTATION_REQUEST_MASTER_OBJID", quotationMasterObjid);
|
||||
statusParam.put("STATUS", "received");
|
||||
sqlSession.update("salesMng.updateQuotationRequestMasterStatus", statusParam);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적요청서 메일 발송 후 상태 업데이트
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
public Map updateQuotationRequestMailSent(HttpServletRequest request, Map paramMap) {
|
||||
SqlSession sqlSession = null;
|
||||
Map resultMap = new HashMap();
|
||||
|
||||
try {
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
|
||||
|
||||
String quotationMasterObjid = CommonUtils.checkNull(paramMap.get("QUOTATION_REQUEST_MASTER_OBJID"));
|
||||
|
||||
Map statusParam = new HashMap();
|
||||
statusParam.put("QUOTATION_REQUEST_MASTER_OBJID", quotationMasterObjid);
|
||||
statusParam.put("STATUS", "sent");
|
||||
statusParam.put("MAIL_SEND_YN", "Y");
|
||||
sqlSession.update("salesMng.updateQuotationRequestMasterStatus", statusParam);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적요청서 삭제
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
public Map deleteQuotationRequest(HttpServletRequest request, Map paramMap) {
|
||||
SqlSession sqlSession = null;
|
||||
Map resultMap = new HashMap();
|
||||
|
||||
try {
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
|
||||
|
||||
String quotationMasterObjid = CommonUtils.checkNull(paramMap.get("QUOTATION_REQUEST_MASTER_OBJID"));
|
||||
|
||||
Map deleteParam = new HashMap();
|
||||
deleteParam.put("QUOTATION_REQUEST_MASTER_OBJID", quotationMasterObjid);
|
||||
|
||||
// 상세 먼저 삭제
|
||||
sqlSession.delete("salesMng.deleteQuotationRequestDetail", deleteParam);
|
||||
// 마스터 삭제
|
||||
sqlSession.delete("salesMng.deleteQuotationRequestMaster", deleteParam);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 구매리스트에서 견적요청서 생성 대상 조회
|
||||
* - MBOM_DETAIL에서만 조회 (구매리스트관리는 M-BOM 기반으로만 동작)
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
public List<Map> getPurchaseListForQuotation(HttpServletRequest request, Map paramMap) {
|
||||
SqlSession sqlSession = null;
|
||||
List<Map> resultList = new ArrayList<Map>();
|
||||
try {
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession();
|
||||
|
||||
String salesRequestMasterObjid = CommonUtils.checkNull(paramMap.get("SALES_REQUEST_MASTER_OBJID"));
|
||||
System.out.println("========== getPurchaseListForQuotation ==========");
|
||||
System.out.println("SALES_REQUEST_MASTER_OBJID: " + salesRequestMasterObjid);
|
||||
|
||||
// SALES_REQUEST_MASTER에서 MBOM_HEADER_OBJID 조회
|
||||
Map masterParam = new HashMap();
|
||||
masterParam.put("SALES_REQUEST_MASTER_OBJID", salesRequestMasterObjid);
|
||||
Map masterInfo = (Map)sqlSession.selectOne("salesMng.getSalesRequestMasterInfo", masterParam);
|
||||
|
||||
System.out.println("masterInfo: " + masterInfo);
|
||||
|
||||
if(masterInfo != null) {
|
||||
// 대소문자 구분 없이 MBOM_HEADER_OBJID 조회
|
||||
String mbomHeaderObjid = "";
|
||||
if(masterInfo.get("MBOM_HEADER_OBJID") != null) {
|
||||
mbomHeaderObjid = CommonUtils.checkNull(masterInfo.get("MBOM_HEADER_OBJID"));
|
||||
} else if(masterInfo.get("mbom_header_objid") != null) {
|
||||
mbomHeaderObjid = CommonUtils.checkNull(masterInfo.get("mbom_header_objid"));
|
||||
}
|
||||
|
||||
System.out.println("MBOM_HEADER_OBJID: " + mbomHeaderObjid);
|
||||
|
||||
if(!mbomHeaderObjid.isEmpty()) {
|
||||
// MBOM_DETAIL에서 조회
|
||||
Map queryParam = new HashMap();
|
||||
queryParam.put("MBOM_HEADER_OBJID", mbomHeaderObjid);
|
||||
queryParam.put("SALES_REQUEST_MASTER_OBJID", salesRequestMasterObjid);
|
||||
resultList = sqlSession.selectList("salesMng.getPurchaseListForQuotationFromMBom", queryParam);
|
||||
System.out.println("조회 결과 건수: " + resultList.size());
|
||||
} else {
|
||||
System.out.println("MBOM_HEADER_OBJID가 비어있음");
|
||||
}
|
||||
} else {
|
||||
System.out.println("masterInfo가 null");
|
||||
}
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if(sqlSession != null) sqlSession.close();
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user