diff --git a/WebContent/WEB-INF/view/salesmgmt/salesMgmt/revenueMgmtList.jsp b/WebContent/WEB-INF/view/salesmgmt/salesMgmt/revenueMgmtList.jsp
index b443c64..7927085 100644
--- a/WebContent/WEB-INF/view/salesmgmt/salesMgmt/revenueMgmtList.jsp
+++ b/WebContent/WEB-INF/view/salesmgmt/salesMgmt/revenueMgmtList.jsp
@@ -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 '' + snArr[0].trim() + ' 외 ' + (snArr.length - 1) + '건';
+ },
+ 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 = '
';
+ html += '| 번호 | S/N |
';
+ for(var i = 0; i < validSns.length; i++) { html += '| ' + (i+1) + ' | ' + validSns[i] + ' |
'; }
+ html += '
';
+ 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 '' + snArr[0].trim() + ' 외 ' + (snArr.length - 1) + '건';
+ },
+ 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 = '';
+ html += '| 번호 | S/N |
';
+ for(var i = 0; i < validSns.length; i++) {
+ html += '| ' + (i+1) + ' | ' + validSns[i] + ' |
';
+ }
+ html += '
';
+ Swal.fire({title: '분할S/N 목록 (' + validSns.length + '건)', html: html, width: '500px', confirmButtonText: '닫기'});
+ }
+ },
// 20. 품번
{headerHozAlign : 'center', hozAlign : 'left', width : '100', title : '품번', field : 'PRODUCT_NO'},
// 21. 과세구분
diff --git a/WebContent/WEB-INF/view/salesmgmt/salesMgmt/salesMgmtList.jsp b/WebContent/WEB-INF/view/salesmgmt/salesMgmt/salesMgmtList.jsp
index e270271..33f1236 100644
--- a/WebContent/WEB-INF/view/salesmgmt/salesMgmt/salesMgmtList.jsp
+++ b/WebContent/WEB-INF/view/salesmgmt/salesMgmt/salesMgmtList.jsp
@@ -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 '' + snArr[0].trim() + ' 외 ' + (snArr.length - 1) + '건';
+ },
+ 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 = '';
+ html += '| 번호 | S/N |
';
+ for(var i = 0; i < validSns.length; i++) { html += '| ' + (i+1) + ' | ' + validSns[i] + ' |
'; }
+ html += '
';
+ 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 '' + snArr[0].trim() + ' 외 ' + (snArr.length - 1) + '건';
+ },
+ 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 = '';
+ html += '| 번호 | S/N |
';
+ for(var i = 0; i < validSns.length; i++) {
+ html += '| ' + (i+1) + ' | ' + validSns[i] + ' |
';
+ }
+ html += '
';
+ Swal.fire({title: '분할S/N 목록 (' + validSns.length + '건)', html: html, width: '500px', confirmButtonText: '닫기'});
+ }
+ },
// 25. 품번
{headerHozAlign : 'center', hozAlign : 'left', width : '100', title : '품번', field : 'PRODUCT_NO'},
diff --git a/WebContent/WEB-INF/view/salesmgmt/salesMgmt/salesRegForm.jsp b/WebContent/WEB-INF/view/salesmgmt/salesMgmt/salesRegForm.jsp
index 27ab276..b79cf3f 100644
--- a/WebContent/WEB-INF/view/salesmgmt/salesMgmt/salesRegForm.jsp
+++ b/WebContent/WEB-INF/view/salesmgmt/salesMgmt/salesRegForm.jsp
@@ -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 = '';
+ popupHtml += '
분할S/N 선택
';
+ popupHtml += '
';
+ popupHtml += ' ';
+ popupHtml += ' ';
+ popupHtml += '
';
+ popupHtml += '
';
+ popupHtml += '
';
+ popupHtml += '
';
+ popupHtml += '
';
+ popupHtml += ' 선택한 S/N 개수가 판매수량에 자동 반영됩니다.';
+ popupHtml += '
';
+ popupHtml += '
';
+ popupHtml += ' ';
+ popupHtml += ' ';
+ popupHtml += '
';
+ popupHtml += '
';
+
+ 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 />
-
+
+
+
+ |
+
+
+
+ S/N을 먼저 등록하세요
+
+ |
+
+
|
diff --git a/WebContent/WEB-INF/view/salesmgmt/salesMgmt/shippingDetailPopup.jsp b/WebContent/WEB-INF/view/salesmgmt/salesMgmt/shippingDetailPopup.jsp
index 3dafa70..7b4cbcc 100644
--- a/WebContent/WEB-INF/view/salesmgmt/salesMgmt/shippingDetailPopup.jsp
+++ b/WebContent/WEB-INF/view/salesmgmt/salesMgmt/shippingDetailPopup.jsp
@@ -95,13 +95,14 @@ function fn_openEditPopup(logId, orderNo) {
| 출하수량 |
출하지시상태 |
S/N |
+ 분할S/N |
- | 출하 내역이 없습니다. |
+ 출하 내역이 없습니다. |
@@ -116,6 +117,7 @@ function fn_openEditPopup(logId, orderNo) {
${item.shipping_quantity} |
${item.shipping_order_status} |
${item.serial_no} |
+ ${item.split_serial_no} |
diff --git a/src/com/pms/salesmgmt/controller/SalesNcollectMgmtController.java b/src/com/pms/salesmgmt/controller/SalesNcollectMgmtController.java
index 0ac0e66..93520cd 100644
--- a/src/com/pms/salesmgmt/controller/SalesNcollectMgmtController.java
+++ b/src/com/pms/salesmgmt/controller/SalesNcollectMgmtController.java
@@ -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 usedSnParam = new HashMap();
+ usedSnParam.put("projectNo", paramMap.get("orderNo"));
+ if(paramMap.get("logId") != null && !paramMap.get("logId").equals("")) {
+ usedSnParam.put("excludeLogId", paramMap.get("logId"));
+ }
+ List