분할출하 S/N 선택 기능 추가
This commit is contained in:
@@ -523,7 +523,61 @@ var columns = [
|
||||
formatter: "money", formatterParams: {thousand: ",", symbolAfter: "", precision: 2}
|
||||
},
|
||||
// 19. S/N
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '100', title : 'S/N', field : 'SERIAL_NO'},
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '100', title : 'S/N', field : 'SERIAL_NO',
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
if(!value || value.trim() === '') return '';
|
||||
var snArr = value.split(',');
|
||||
for(var i = snArr.length - 1; i >= 0; i--) { if(snArr[i].trim() === '') snArr.splice(i, 1); }
|
||||
if(snArr.length === 0) return '';
|
||||
if(snArr.length === 1) return snArr[0].trim();
|
||||
return '<a href="javascript:void(0);" style="color:#2196F3;">' + snArr[0].trim() + ' 외 ' + (snArr.length - 1) + '건</a>';
|
||||
},
|
||||
cellClick: function(e, cell) {
|
||||
var value = cell.getValue();
|
||||
if(!value || value.trim() === '') return;
|
||||
var snArr = value.split(',');
|
||||
var validSns = [];
|
||||
for(var i = 0; i < snArr.length; i++) { if(snArr[i].trim() !== '') validSns.push(snArr[i].trim()); }
|
||||
if(validSns.length <= 1) return;
|
||||
var html = '<table style="width:100%; border-collapse:collapse; border:1px solid #ddd;">';
|
||||
html += '<thead><tr style="background:#f5f5f5;"><th style="padding:8px; border:1px solid #ddd; text-align:center; width:50px;">번호</th><th style="padding:8px; border:1px solid #ddd; text-align:center;">S/N</th></tr></thead><tbody>';
|
||||
for(var i = 0; i < validSns.length; i++) { html += '<tr><td style="text-align:center; padding:6px; border:1px solid #ddd;">' + (i+1) + '</td><td style="padding:6px; border:1px solid #ddd;">' + validSns[i] + '</td></tr>'; }
|
||||
html += '</tbody></table>';
|
||||
Swal.fire({title: 'S/N 목록 (' + validSns.length + '건)', html: html, width: '500px', confirmButtonText: '닫기'});
|
||||
}
|
||||
},
|
||||
// 19-1. 분할S/N
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '120', title : '분할S/N', field : 'SPLIT_SERIAL_NO',
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
if(!value || value.trim() === '') return '';
|
||||
var snArr = value.split(',');
|
||||
for(var i = snArr.length - 1; i >= 0; i--) {
|
||||
if(snArr[i].trim() === '') snArr.splice(i, 1);
|
||||
}
|
||||
if(snArr.length === 0) return '';
|
||||
if(snArr.length === 1) return snArr[0].trim();
|
||||
return '<a href="javascript:void(0);" style="color:#2196F3;">' + snArr[0].trim() + ' 외 ' + (snArr.length - 1) + '건</a>';
|
||||
},
|
||||
cellClick: function(e, cell) {
|
||||
var value = cell.getValue();
|
||||
if(!value || value.trim() === '') return;
|
||||
var snArr = value.split(',');
|
||||
var validSns = [];
|
||||
for(var i = 0; i < snArr.length; i++) {
|
||||
if(snArr[i].trim() !== '') validSns.push(snArr[i].trim());
|
||||
}
|
||||
if(validSns.length === 0) return;
|
||||
var html = '<table style="width:100%; border-collapse:collapse; border:1px solid #ddd;">';
|
||||
html += '<thead><tr style="background:#f5f5f5;"><th style="padding:8px; border:1px solid #ddd; text-align:center; width:50px;">번호</th><th style="padding:8px; border:1px solid #ddd; text-align:center;">S/N</th></tr></thead><tbody>';
|
||||
for(var i = 0; i < validSns.length; i++) {
|
||||
html += '<tr><td style="text-align:center; padding:6px; border:1px solid #ddd;">' + (i+1) + '</td><td style="padding:6px; border:1px solid #ddd;">' + validSns[i] + '</td></tr>';
|
||||
}
|
||||
html += '</tbody></table>';
|
||||
Swal.fire({title: '분할S/N 목록 (' + validSns.length + '건)', html: html, width: '500px', confirmButtonText: '닫기'});
|
||||
}
|
||||
},
|
||||
// 20. 품번
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '100', title : '품번', field : 'PRODUCT_NO'},
|
||||
// 21. 과세구분
|
||||
|
||||
@@ -442,7 +442,61 @@ var columns = [
|
||||
formatter: "money", formatterParams: {thousand: ",", symbolAfter: "", precision: 2}
|
||||
},
|
||||
// 24. S/N
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '100', title : 'S/N', field : 'SERIAL_NO'},
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '100', title : 'S/N', field : 'SERIAL_NO',
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
if(!value || value.trim() === '') return '';
|
||||
var snArr = value.split(',');
|
||||
for(var i = snArr.length - 1; i >= 0; i--) { if(snArr[i].trim() === '') snArr.splice(i, 1); }
|
||||
if(snArr.length === 0) return '';
|
||||
if(snArr.length === 1) return snArr[0].trim();
|
||||
return '<a href="javascript:void(0);" style="color:#2196F3;">' + snArr[0].trim() + ' 외 ' + (snArr.length - 1) + '건</a>';
|
||||
},
|
||||
cellClick: function(e, cell) {
|
||||
var value = cell.getValue();
|
||||
if(!value || value.trim() === '') return;
|
||||
var snArr = value.split(',');
|
||||
var validSns = [];
|
||||
for(var i = 0; i < snArr.length; i++) { if(snArr[i].trim() !== '') validSns.push(snArr[i].trim()); }
|
||||
if(validSns.length <= 1) return;
|
||||
var html = '<table style="width:100%; border-collapse:collapse; border:1px solid #ddd;">';
|
||||
html += '<thead><tr style="background:#f5f5f5;"><th style="padding:8px; border:1px solid #ddd; text-align:center; width:50px;">번호</th><th style="padding:8px; border:1px solid #ddd; text-align:center;">S/N</th></tr></thead><tbody>';
|
||||
for(var i = 0; i < validSns.length; i++) { html += '<tr><td style="text-align:center; padding:6px; border:1px solid #ddd;">' + (i+1) + '</td><td style="padding:6px; border:1px solid #ddd;">' + validSns[i] + '</td></tr>'; }
|
||||
html += '</tbody></table>';
|
||||
Swal.fire({title: 'S/N 목록 (' + validSns.length + '건)', html: html, width: '500px', confirmButtonText: '닫기'});
|
||||
}
|
||||
},
|
||||
// 24-1. 분할S/N
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '120', title : '분할S/N', field : 'SPLIT_SERIAL_NO',
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
if(!value || value.trim() === '') return '';
|
||||
var snArr = value.split(',');
|
||||
for(var i = snArr.length - 1; i >= 0; i--) {
|
||||
if(snArr[i].trim() === '') snArr.splice(i, 1);
|
||||
}
|
||||
if(snArr.length === 0) return '';
|
||||
if(snArr.length === 1) return snArr[0].trim();
|
||||
return '<a href="javascript:void(0);" style="color:#2196F3;">' + snArr[0].trim() + ' 외 ' + (snArr.length - 1) + '건</a>';
|
||||
},
|
||||
cellClick: function(e, cell) {
|
||||
var value = cell.getValue();
|
||||
if(!value || value.trim() === '') return;
|
||||
var snArr = value.split(',');
|
||||
var validSns = [];
|
||||
for(var i = 0; i < snArr.length; i++) {
|
||||
if(snArr[i].trim() !== '') validSns.push(snArr[i].trim());
|
||||
}
|
||||
if(validSns.length === 0) return;
|
||||
var html = '<table style="width:100%; border-collapse:collapse; border:1px solid #ddd;">';
|
||||
html += '<thead><tr style="background:#f5f5f5;"><th style="padding:8px; border:1px solid #ddd; text-align:center; width:50px;">번호</th><th style="padding:8px; border:1px solid #ddd; text-align:center;">S/N</th></tr></thead><tbody>';
|
||||
for(var i = 0; i < validSns.length; i++) {
|
||||
html += '<tr><td style="text-align:center; padding:6px; border:1px solid #ddd;">' + (i+1) + '</td><td style="padding:6px; border:1px solid #ddd;">' + validSns[i] + '</td></tr>';
|
||||
}
|
||||
html += '</tbody></table>';
|
||||
Swal.fire({title: '분할S/N 목록 (' + validSns.length + '건)', html: html, width: '500px', confirmButtonText: '닫기'});
|
||||
}
|
||||
},
|
||||
// 25. 품번
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '100', title : '품번', field : 'PRODUCT_NO'},
|
||||
|
||||
|
||||
@@ -547,7 +547,8 @@ function fn_calculateSelectedItem() {
|
||||
console.log("저장 후 확인:", $("#serialNoList").val());
|
||||
|
||||
fn_updateSnDisplay();
|
||||
|
||||
fn_updateSplitSnDisplay();
|
||||
|
||||
Swal.close();
|
||||
}
|
||||
|
||||
@@ -556,6 +557,169 @@ function fn_calculateSelectedItem() {
|
||||
Swal.close();
|
||||
}
|
||||
|
||||
// === 분할S/N 관련 함수 ===
|
||||
var usedSplitSerialNos = "${usedSplitSerialNos}"; // 이미 다른 출하에서 사용된 S/N
|
||||
var selectedSplitSns = []; // 현재 선택된 분할S/N
|
||||
|
||||
// 페이지 로드 시 기존 분할S/N 초기화
|
||||
$(function() {
|
||||
var existingSplitSn = $("#splitSerialNoHidden").val();
|
||||
if(existingSplitSn && existingSplitSn.trim() !== '') {
|
||||
selectedSplitSns = existingSplitSn.split(',');
|
||||
for(var i = 0; i < selectedSplitSns.length; i++) {
|
||||
selectedSplitSns[i] = selectedSplitSns[i].trim();
|
||||
}
|
||||
}
|
||||
fn_updateSplitSnDisplay();
|
||||
});
|
||||
|
||||
// 사용 가능한 S/N 목록 계산 (전체 S/N - 이미 사용된 S/N + 현재 수정 중인 분할S/N)
|
||||
function fn_getAvailableSns() {
|
||||
var allSns = [];
|
||||
var serialNoVal = $("#serialNo").val();
|
||||
if(serialNoVal && serialNoVal.trim() !== '') {
|
||||
var snArr = serialNoVal.split(',');
|
||||
for(var i = 0; i < snArr.length; i++) {
|
||||
if(snArr[i].trim() !== '') {
|
||||
allSns.push(snArr[i].trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 이미 사용된 S/N 파싱
|
||||
var usedSns = [];
|
||||
if(usedSplitSerialNos && usedSplitSerialNos.trim() !== '') {
|
||||
var usedArr = usedSplitSerialNos.split(',');
|
||||
for(var i = 0; i < usedArr.length; i++) {
|
||||
if(usedArr[i].trim() !== '') {
|
||||
usedSns.push(usedArr[i].trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 사용 가능한 S/N = 전체 - 이미사용(다른 출하)
|
||||
var available = [];
|
||||
for(var i = 0; i < allSns.length; i++) {
|
||||
var isUsed = false;
|
||||
for(var j = 0; j < usedSns.length; j++) {
|
||||
if(allSns[i] === usedSns[j]) {
|
||||
isUsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!isUsed) {
|
||||
available.push(allSns[i]);
|
||||
}
|
||||
}
|
||||
return available;
|
||||
}
|
||||
|
||||
// 분할S/N 선택 팝업
|
||||
function fn_openSplitSnPopup() {
|
||||
var availableSns = fn_getAvailableSns();
|
||||
|
||||
if(availableSns.length === 0) {
|
||||
alert('선택 가능한 S/N이 없습니다.\nS/N을 먼저 등록하거나, 이미 모든 S/N이 다른 출하에 배정되었습니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
var popupHtml = '<div style="padding:10px; color:#333;">';
|
||||
popupHtml += ' <h3 style="margin:0 0 15px 0; text-align:center; color:#333;">분할S/N 선택</h3>';
|
||||
popupHtml += ' <div style="margin-bottom:10px; text-align:right;">';
|
||||
popupHtml += ' <button type="button" onclick="fn_splitSnSelectAll()" class="plm_btns" style="padding:4px 10px; font-size:12px;">전체선택</button>';
|
||||
popupHtml += ' <button type="button" onclick="fn_splitSnDeselectAll()" class="plm_btns" style="padding:4px 10px; font-size:12px;">전체해제</button>';
|
||||
popupHtml += ' </div>';
|
||||
popupHtml += ' <div id="splitSnListContainer" style="max-height:300px; overflow-y:auto;">';
|
||||
popupHtml += ' <table style="width:100%; border-collapse:collapse; border:1px solid #ddd;">';
|
||||
popupHtml += ' <colgroup><col width="15%"><col width="15%"><col width="70%"></colgroup>';
|
||||
popupHtml += ' <thead><tr style="background:#f5f5f5;">';
|
||||
popupHtml += ' <th style="padding:8px; border:1px solid #ddd; text-align:center;">선택</th>';
|
||||
popupHtml += ' <th style="padding:8px; border:1px solid #ddd; text-align:center;">번호</th>';
|
||||
popupHtml += ' <th style="padding:8px; border:1px solid #ddd; text-align:center;">S/N</th>';
|
||||
popupHtml += ' </tr></thead><tbody>';
|
||||
|
||||
for(var i = 0; i < availableSns.length; i++) {
|
||||
var isChecked = false;
|
||||
for(var j = 0; j < selectedSplitSns.length; j++) {
|
||||
if(availableSns[i] === selectedSplitSns[j]) {
|
||||
isChecked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
popupHtml += '<tr>';
|
||||
popupHtml += '<td style="text-align:center; padding:6px; border:1px solid #ddd;">';
|
||||
popupHtml += '<input type="checkbox" class="split-sn-chk" value="' + availableSns[i] + '" ' + (isChecked ? 'checked' : '') + ' />';
|
||||
popupHtml += '</td>';
|
||||
popupHtml += '<td style="text-align:center; padding:6px; border:1px solid #ddd;">' + (i+1) + '</td>';
|
||||
popupHtml += '<td style="padding:6px; border:1px solid #ddd;">' + availableSns[i] + '</td>';
|
||||
popupHtml += '</tr>';
|
||||
}
|
||||
|
||||
popupHtml += ' </tbody></table>';
|
||||
popupHtml += ' </div>';
|
||||
popupHtml += ' <div style="margin-top:10px; text-align:center; color:#666; font-size:12px;">';
|
||||
popupHtml += ' 선택한 S/N 개수가 판매수량에 자동 반영됩니다.';
|
||||
popupHtml += ' </div>';
|
||||
popupHtml += ' <div style="text-align:center; margin-top:15px; display:flex; gap:10px; justify-content:center;">';
|
||||
popupHtml += ' <button type="button" onclick="fn_confirmSplitSn()" class="plm_btns">확인</button>';
|
||||
popupHtml += ' <button type="button" onclick="Swal.close()" class="plm_btns">취소</button>';
|
||||
popupHtml += ' </div>';
|
||||
popupHtml += '</div>';
|
||||
|
||||
Swal.fire({
|
||||
html: popupHtml,
|
||||
width: '500px',
|
||||
showConfirmButton: false,
|
||||
showCloseButton: true
|
||||
});
|
||||
}
|
||||
|
||||
// 전체선택
|
||||
function fn_splitSnSelectAll() {
|
||||
$(".swal2-html-container .split-sn-chk").prop('checked', true);
|
||||
}
|
||||
|
||||
// 전체해제
|
||||
function fn_splitSnDeselectAll() {
|
||||
$(".swal2-html-container .split-sn-chk").prop('checked', false);
|
||||
}
|
||||
|
||||
// 분할S/N 선택 확인
|
||||
function fn_confirmSplitSn() {
|
||||
selectedSplitSns = [];
|
||||
$(".swal2-html-container .split-sn-chk:checked").each(function() {
|
||||
selectedSplitSns.push($(this).val());
|
||||
});
|
||||
|
||||
// hidden 필드에 저장
|
||||
$("#splitSerialNoHidden").val(selectedSplitSns.join(','));
|
||||
|
||||
// 판매수량 자동 업데이트
|
||||
$("#salesQuantity").val(selectedSplitSns.length);
|
||||
fn_calculateSupplyPrice();
|
||||
|
||||
fn_updateSplitSnDisplay();
|
||||
Swal.close();
|
||||
}
|
||||
|
||||
// 분할S/N 표시 업데이트
|
||||
function fn_updateSplitSnDisplay() {
|
||||
if(selectedSplitSns.length > 0) {
|
||||
var displayText = selectedSplitSns.join(', ');
|
||||
if(displayText.length > 80) {
|
||||
displayText = displayText.substring(0, 77) + '... (' + selectedSplitSns.length + '건)';
|
||||
}
|
||||
$("#splitSnDisplay").text(displayText).css('color', '#333');
|
||||
} else {
|
||||
var serialNoVal = $("#serialNo").val();
|
||||
if(serialNoVal && serialNoVal.trim() !== '') {
|
||||
$("#splitSnDisplay").text('클릭하여 분할S/N 선택').css('color', '#999');
|
||||
} else {
|
||||
$("#splitSnDisplay").text('S/N을 먼저 등록하세요').css('color', '#999');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fn_save() {
|
||||
// 출하지시 상태는 자동으로 설정됨 (hidden 필드에 이미 "출하지시" 값 설정)
|
||||
|
||||
@@ -735,7 +899,19 @@ function fn_calculateSelectedItem() {
|
||||
readonly />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<!-- 2-1행: 분할S/N -->
|
||||
<tr>
|
||||
<td class="input_title"><label for="splitSerialNo">분할S/N</label></td>
|
||||
<td colspan="3">
|
||||
<input type="hidden" name="splitSerialNo" id="splitSerialNoHidden" value="${saleInfo.SPLIT_SERIAL_NO}" />
|
||||
<div id="splitSnContainer" style="width:100%; min-height:34px; border:1px solid #ddd; border-radius:4px; padding:5px; background-color:#f8f9fa; cursor:pointer;"
|
||||
onclick="fn_openSplitSnPopup()">
|
||||
<span id="splitSnDisplay" style="color:#999;">S/N을 먼저 등록하세요</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- 3행: 판매수량, 출하일 -->
|
||||
<tr>
|
||||
<td class="input_title">
|
||||
|
||||
@@ -95,13 +95,14 @@ function fn_openEditPopup(logId, orderNo) {
|
||||
<th>출하수량</th>
|
||||
<th>출하지시상태</th>
|
||||
<th>S/N</th>
|
||||
<th>분할S/N</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<c:choose>
|
||||
<c:when test="${empty shippingList}">
|
||||
<tr>
|
||||
<td colspan="4">출하 내역이 없습니다.</td>
|
||||
<td colspan="5">출하 내역이 없습니다.</td>
|
||||
</tr>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
@@ -116,6 +117,7 @@ function fn_openEditPopup(logId, orderNo) {
|
||||
<td>${item.shipping_quantity}</td>
|
||||
<td>${item.shipping_order_status}</td>
|
||||
<td>${item.serial_no}</td>
|
||||
<td>${item.split_serial_no}</td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</c:otherwise>
|
||||
|
||||
@@ -441,7 +441,28 @@ public class SalesNcollectMgmtController {
|
||||
// orderInfo로 견적 정보 전달 (saleInfo가 이미 모든 필요한 정보를 포함)
|
||||
request.setAttribute("orderInfo", saleInfo);
|
||||
}
|
||||
|
||||
|
||||
// 이미 사용된 분할S/N 조회 (현재 수정 중인 logId 제외)
|
||||
if(paramMap.get("orderNo") != null && !paramMap.get("orderNo").equals("")) {
|
||||
Map<String, Object> usedSnParam = new HashMap<String, Object>();
|
||||
usedSnParam.put("projectNo", paramMap.get("orderNo"));
|
||||
if(paramMap.get("logId") != null && !paramMap.get("logId").equals("")) {
|
||||
usedSnParam.put("excludeLogId", paramMap.get("logId"));
|
||||
}
|
||||
List<Map<String, Object>> usedSnList = salesNcollectMgmtService.getUsedSplitSerialNos(usedSnParam);
|
||||
|
||||
// 이미 사용된 S/N들을 하나의 콤마 구분 문자열로 합침
|
||||
StringBuilder usedSnBuilder = new StringBuilder();
|
||||
for(Map<String, Object> usedSn : usedSnList) {
|
||||
String splitSn = (String) usedSn.get("split_serial_no");
|
||||
if(splitSn != null && !splitSn.isEmpty()) {
|
||||
if(usedSnBuilder.length() > 0) usedSnBuilder.append(",");
|
||||
usedSnBuilder.append(splitSn);
|
||||
}
|
||||
}
|
||||
request.setAttribute("usedSplitSerialNos", usedSnBuilder.toString());
|
||||
}
|
||||
|
||||
// 수정 모드: saleInfo에서 담당자 선택값 반영
|
||||
if(saleInfo != null && saleInfo.get("MANAGER") != null) {
|
||||
String selectedManager = saleInfo.get("MANAGER").toString();
|
||||
|
||||
@@ -844,14 +844,9 @@
|
||||
FROM CONTRACT_MGMT CM WHERE CM.OBJID = T.CONTRACT_OBJID) AS PAYMENT_TYPE,
|
||||
T.PART_NO AS PRODUCT_NO,
|
||||
T.PART_NAME AS PRODUCT_NAME,
|
||||
-- S/N: CONTRACT_ITEM_SERIAL(마스터) 우선, 없으면 판매등록 텍스트 fallback (그리드 요약용)
|
||||
-- S/N: CONTRACT_ITEM_SERIAL(마스터) 우선, 없으면 판매등록 텍스트 fallback (콤마 구분 전체 목록)
|
||||
COALESCE(
|
||||
(SELECT
|
||||
CASE
|
||||
WHEN COUNT(*) = 0 THEN NULL
|
||||
WHEN COUNT(*) = 1 THEN MIN(CIS.SERIAL_NO)
|
||||
ELSE MIN(CIS.SERIAL_NO) || ' 외 ' || (COUNT(*) - 1)::TEXT || '건'
|
||||
END
|
||||
(SELECT STRING_AGG(CIS.SERIAL_NO, ',' ORDER BY CIS.SEQ)
|
||||
FROM CONTRACT_ITEM CI
|
||||
LEFT JOIN CONTRACT_ITEM_SERIAL CIS ON CI.OBJID = CIS.ITEM_OBJID AND UPPER(CIS.STATUS) = 'ACTIVE'
|
||||
WHERE CI.CONTRACT_OBJID = T.CONTRACT_OBJID
|
||||
@@ -860,6 +855,15 @@
|
||||
AND CIS.SERIAL_NO IS NOT NULL),
|
||||
SR.serial_no
|
||||
) AS SERIAL_NO,
|
||||
-- 분할S/N: shipment_log에서 해당 프로젝트의 모든 분할S/N 집계
|
||||
COALESCE(
|
||||
(SELECT STRING_AGG(SL_SN.split_serial_no, ',' ORDER BY SL_SN.log_id)
|
||||
FROM shipment_log SL_SN
|
||||
WHERE SL_SN.target_objid = T.PROJECT_NO
|
||||
AND SL_SN.split_serial_no IS NOT NULL
|
||||
AND SL_SN.split_serial_no != ''),
|
||||
''
|
||||
) AS SPLIT_SERIAL_NO,
|
||||
COALESCE(NULLIF(REPLACE(T.QUANTITY, ',', ''), '')::numeric, 0) AS ORDER_QUANTITY,
|
||||
-- 요청납기: CONTRACT_ITEM 우선, 없으면 PROJECT_MGMT, 없으면 CONTRACT_MGMT
|
||||
COALESCE(
|
||||
@@ -1902,7 +1906,7 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
remaining_quantity, shipping_status, shipping_date, shipping_method,
|
||||
sales_unit_price, sales_supply_price, sales_vat, sales_total_amount,
|
||||
sales_currency, sales_exchange_rate, manager_user_id, incoterms,
|
||||
serial_no, parent_sale_no, reg_user_id
|
||||
serial_no, parent_sale_no, reg_user_id, split_serial_no
|
||||
) VALUES (
|
||||
#{targetObjid}, 'SPLIT_SHIPMENT', '분할 출하',
|
||||
#{salesQuantity}::integer, #{originalQuantity}::integer, #{remainingQuantity}::integer,
|
||||
@@ -1916,7 +1920,7 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
#{shippingMethod}, #{salesUnitPrice}::numeric, #{salesSupplyPrice}::numeric,
|
||||
#{salesVat}::numeric, #{salesTotalAmount}::numeric, #{salesCurrency},
|
||||
#{salesExchangeRate}::numeric, #{managerUserId}, #{incoterms}, #{serialNo},
|
||||
#{parentSaleNo}::integer, #{cretEmpNo}
|
||||
#{parentSaleNo}::integer, #{cretEmpNo}, #{splitSerialNo}
|
||||
)
|
||||
</insert>
|
||||
|
||||
@@ -1994,6 +1998,7 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
WHERE PM.PROJECT_NO = SL.target_objid AND CI.STATUS = 'ACTIVE'
|
||||
), '-') AS serial_no,
|
||||
SL.target_objid AS project_no,
|
||||
COALESCE(SL.split_serial_no, '-') AS split_serial_no,
|
||||
TO_CHAR(SL.reg_date, 'YYYY-MM-DD HH24:MI:SS') AS reg_date
|
||||
FROM shipment_log SL
|
||||
WHERE SL.target_objid = #{projectNo}
|
||||
@@ -2025,6 +2030,7 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
COALESCE(SL.sales_exchange_rate, 0) AS SALES_EXCHANGE_RATE,
|
||||
COALESCE(SL.manager_user_id, '') AS MANAGER,
|
||||
COALESCE(SL.incoterms, '') AS INCOTERMS,
|
||||
COALESCE(SL.split_serial_no, '') AS SPLIT_SERIAL_NO,
|
||||
COALESCE(SL.original_quantity, 0) AS ORDER_QUANTITY,
|
||||
COALESCE(SL.remaining_quantity, 0) AS REMAINING_QUANTITY
|
||||
FROM shipment_log SL
|
||||
@@ -2070,6 +2076,9 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
<if test="incoterms != null and incoterms != ''">
|
||||
, incoterms = #{incoterms}
|
||||
</if>
|
||||
<if test="splitSerialNo != null and splitSerialNo != ''">
|
||||
, split_serial_no = #{splitSerialNo}
|
||||
</if>
|
||||
WHERE log_id = #{logId}::integer
|
||||
</update>
|
||||
|
||||
@@ -2406,6 +2415,7 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
WHERE CI.CONTRACT_OBJID = T.CONTRACT_OBJID
|
||||
AND CI.PART_OBJID = T.PART_OBJID AND CI.STATUS = 'ACTIVE'
|
||||
), '') AS SERIAL_NO,
|
||||
COALESCE(SL.split_serial_no, '') AS SPLIT_SERIAL_NO,
|
||||
COALESCE(NULLIF(REPLACE(T.QUANTITY, ',', ''), '')::numeric, 0) AS ORDER_QUANTITY,
|
||||
(SELECT CM.PO_NO FROM CONTRACT_MGMT CM WHERE CM.OBJID = T.CONTRACT_OBJID) AS PO_NO,
|
||||
COALESCE(T.CONTRACT_DATE, (SELECT CM.order_date FROM CONTRACT_MGMT CM WHERE CM.OBJID = T.CONTRACT_OBJID)) AS ORDER_DATE,
|
||||
@@ -2742,6 +2752,22 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
WHERE PROJECT_NO = #{projectNo}
|
||||
</update>
|
||||
|
||||
<!-- 프로젝트의 이미 사용된 분할S/N 목록 조회 -->
|
||||
<select id="getUsedSplitSerialNos" parameterType="map" resultType="map">
|
||||
/* salesNcollectMgmt.getUsedSplitSerialNos - 이미 사용된 분할S/N 조회 */
|
||||
SELECT
|
||||
SL.log_id,
|
||||
COALESCE(SL.split_serial_no, '') AS split_serial_no
|
||||
FROM shipment_log SL
|
||||
WHERE SL.target_objid = #{projectNo}
|
||||
<if test="excludeLogId != null and excludeLogId != ''">
|
||||
AND SL.log_id != #{excludeLogId}::integer
|
||||
</if>
|
||||
AND SL.split_serial_no IS NOT NULL
|
||||
AND SL.split_serial_no != ''
|
||||
ORDER BY SL.log_id
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
|
||||
|
||||
@@ -401,6 +401,10 @@ public Map<String, Object> saveSaleRegistration(HttpServletRequest request, Map<
|
||||
if(logId != null && !"".equals(logId)) {
|
||||
System.out.println("=== shipment_log 수정 모드 (logId: " + logId + ") ===");
|
||||
paramMap.put("shippingOrderStatus", "출하지시");
|
||||
// splitSerialNo가 있으면 전달
|
||||
if(paramMap.get("splitSerialNo") != null) {
|
||||
paramMap.put("splitSerialNo", paramMap.get("splitSerialNo"));
|
||||
}
|
||||
sqlSession.update("salesNcollectMgmt.updateShipmentLog", paramMap);
|
||||
} else {
|
||||
// 신규 등록 → shipment_log에 INSERT
|
||||
@@ -424,6 +428,7 @@ public Map<String, Object> saveSaleRegistration(HttpServletRequest request, Map<
|
||||
logParam.put("managerUserId", paramMap.get("managerUserId"));
|
||||
logParam.put("incoterms", paramMap.get("incoterms"));
|
||||
logParam.put("serialNo", paramMap.get("serialNo"));
|
||||
logParam.put("splitSerialNo", paramMap.get("splitSerialNo"));
|
||||
logParam.put("parentSaleNo", null);
|
||||
logParam.put("cretEmpNo", paramMap.get("cretEmpNo"));
|
||||
|
||||
@@ -518,6 +523,23 @@ public Map<String, Object> saveSaleRegistration(HttpServletRequest request, Map<
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 프로젝트의 이미 사용된 분할S/N 목록 조회
|
||||
*/
|
||||
public List<Map<String, Object>> getUsedSplitSerialNos(Map<String, Object> paramMap) {
|
||||
SqlSession sqlSession = null;
|
||||
List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
|
||||
try {
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession(true);
|
||||
resultList = sqlSession.selectList("salesNcollectMgmt.getUsedSplitSerialNos", paramMap);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if(sqlSession != null) sqlSession.close();
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 분할출하 처리 (로그 기반)
|
||||
|
||||
Reference in New Issue
Block a user