판매관리 원상복구
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -201,7 +201,6 @@ function fn_search(){
|
||||
// 그리드 초기화
|
||||
_tabulGrid = new Tabulator("#mainGrid", {
|
||||
layout: _tabul_layout_fitColumns,
|
||||
height: "auto",
|
||||
columns: columns,
|
||||
data: response.RESULTLIST || []
|
||||
});
|
||||
|
||||
@@ -13,44 +13,6 @@
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title><%=Constants.SYSTEM_NAME%></title>
|
||||
|
||||
<style>
|
||||
/* 분할출하 행 스타일 */
|
||||
.tabulator-row .split-row {
|
||||
background-color: #E3F2FD !important;
|
||||
}
|
||||
.tabulator-row:hover .split-row {
|
||||
background-color: #BBDEFB !important;
|
||||
}
|
||||
|
||||
/* 분할출하 부모 행 클릭 가능 표시 */
|
||||
.has-children-row {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
/* Tabulator 기본 트리 아이콘 숨김 */
|
||||
.tabulator-row .tabulator-data-tree-branch,
|
||||
.tabulator-row .tabulator-data-tree-control {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* 트리 토글 아이콘 커스텀 */
|
||||
.tabulator-tree-toggle {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 자식 행(분할출하 데이터) 들여쓰기 */
|
||||
.tabulator-row.tabulator-tree-level-1 {
|
||||
background-color: #F5F5F5 !important;
|
||||
}
|
||||
.tabulator-row.tabulator-tree-level-1:hover {
|
||||
background-color: #EEEEEE !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
_fnc_datepick(); // 날짜 선택기 초기화
|
||||
@@ -63,14 +25,12 @@
|
||||
}
|
||||
});
|
||||
|
||||
$("#btnSearch").click(function(){
|
||||
$("#btnSearch").click(function(){
|
||||
fn_search();
|
||||
});
|
||||
|
||||
// 초기 데이터 조회 (DOM이 완전히 로드된 후 실행)
|
||||
setTimeout(function(){
|
||||
fn_search();
|
||||
}, 100);
|
||||
// 초기 데이터 조회
|
||||
fn_search();
|
||||
|
||||
// 출하지시/판매등록 버튼
|
||||
$("#btnBulkRegister").click(function(){
|
||||
@@ -110,49 +70,8 @@
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
// 새로운 테이블 구조에 맞게 컬럼 정의 수정 (분할출하 구분 추가)
|
||||
// 새로운 테이블 구조에 맞게 컬럼 정의 수정
|
||||
var columns = [
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '150', title : '출하구분', field : 'RECORD_TYPE',
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
var data = cell.getData();
|
||||
var hasSplit = data.HAS_SPLIT_SHIPMENT;
|
||||
var hasChildren = data._children && data._children.length > 0;
|
||||
var row = cell.getRow();
|
||||
var treeLevel = row.getTreeParent() ? 1 : 0;
|
||||
|
||||
var html = '';
|
||||
|
||||
// 출하구분 뱃지
|
||||
if (value === 'SPLIT') {
|
||||
// 자식 행: 더 큰 들여쓰기 + 뱃지
|
||||
html += '<span style="display:inline-block; width:40px;"></span>';
|
||||
html += '<span style="display:inline-block; padding:3px 8px; background:#E3F2FD; color:#1976D2; border-radius:3px; font-size:11px; font-weight:bold;">분할</span>';
|
||||
} else if (hasSplit === true || hasSplit === 'true' || hasSplit === 't') {
|
||||
// 분할출하 부모 행: 화살표 + 뱃지
|
||||
var isExpanded = row.isTreeExpanded();
|
||||
var toggleIcon = isExpanded ? '▼' : '▶';
|
||||
html += '<span class="tabulator-tree-toggle" style="font-size:10px; color:#666; margin-right:5px;">' + toggleIcon + '</span>';
|
||||
html += '<span style="display:inline-block; padding:3px 8px; background:#FFF3E0; color:#F57C00; border-radius:3px; font-size:11px; font-weight:bold;">분할출하</span>';
|
||||
} else {
|
||||
// 일반 행: 들여쓰기(화살표 크기만큼) + 뱃지
|
||||
html += '<span style="display:inline-block; width:21px;"></span>';
|
||||
html += '<span style="display:inline-block; padding:3px 8px; background:#E8F5E9; color:#388E3C; border-radius:3px; font-size:11px; font-weight:bold;">일반</span>';
|
||||
}
|
||||
|
||||
return html;
|
||||
},
|
||||
cellClick: function(e, cell) {
|
||||
// 분할출하 행 클릭 시 펼치기/접기
|
||||
var row = cell.getRow();
|
||||
var data = cell.getData();
|
||||
var hasChildren = data._children && data._children.length > 0;
|
||||
|
||||
if (hasChildren) {
|
||||
row.treeToggle();
|
||||
}
|
||||
}
|
||||
},
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '120', title : '프로젝트번호', field : 'PROJECT_NO', frozen : true},
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '주문유형', field : 'ORDER_TYPE'},
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '제품구분', field : 'PRODUCT_TYPE'},
|
||||
@@ -162,17 +81,7 @@ var columns = [
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '80', title : '유/무상', field : 'PAYMENT_TYPE'},
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '120', title : '품번', field : 'PRODUCT_NO'},
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '180', title : '품명', field : 'PRODUCT_NAME'},
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '120', title : 'S/N', field : 'SPLIT_SERIAL_NO',
|
||||
formatter: function(cell) {
|
||||
var splitSn = cell.getValue();
|
||||
var recordType = cell.getData().RECORD_TYPE;
|
||||
// 분할인 경우 분할 S/N, 원본인 경우 계약 S/N
|
||||
if(recordType === 'SPLIT' && splitSn) {
|
||||
return splitSn;
|
||||
}
|
||||
return cell.getData().SERIAL_NO_ORIGINAL || '';
|
||||
}
|
||||
},
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '120', title : 'S/N', field : 'SERIAL_NO'},
|
||||
{headerHozAlign : 'center', hozAlign : 'right', width : '100', title : '수주수량', field : 'ORDER_QUANTITY',
|
||||
formatter: "money", formatterParams: {thousand: ",", symbolAfter: "", precision: false}
|
||||
},
|
||||
@@ -192,7 +101,7 @@ var columns = [
|
||||
},
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '생산 상태', field : 'PRODUCTION_STATUS'},
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '출하지시 상태', field : 'SHIPPING_ORDER_STATUS'},
|
||||
{headerHozAlign : 'center', hozAlign : 'right', width : '100', title : '출하수량', field : 'SALES_QUANTITY',
|
||||
{headerHozAlign : 'center', hozAlign : 'right', width : '100', title : '판매수량', field : 'SALES_QUANTITY',
|
||||
formatter: "money", formatterParams: {thousand: ",", symbolAfter: "", precision: false}
|
||||
},
|
||||
{headerHozAlign : 'center', hozAlign : 'right', width : '120', title : '판매단가', field : 'SALES_UNIT_PRICE',
|
||||
@@ -217,139 +126,14 @@ var columns = [
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '출하일', field : 'SHIPPING_DATE'},
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '출하방법', field : 'SHIPPING_METHOD'},
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '담당자', field : 'MANAGER'},
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '인도조건', field : 'INCOTERMS'},
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '150', title : '비고', field : 'SPLIT_REMARK',
|
||||
visible: false // 기본적으로 숨김, 필요시 표시
|
||||
}
|
||||
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '인도조건', field : 'INCOTERMS'}
|
||||
];
|
||||
|
||||
// 데이터 조회 함수 (트리 구조 적용)
|
||||
// 데이터 조회 함수
|
||||
function fn_search(){
|
||||
// 원본 데이터 조회 (페이지네이션 포함)
|
||||
var originalSearch = function(){
|
||||
return fnc_tabul_search(_tabul_layout_fitColumns, null, "/salesMgmt/salesMgmtGridList.do", columns, true);
|
||||
};
|
||||
|
||||
// 초기 로드
|
||||
fn_loadData();
|
||||
_tabulGrid = fnc_tabul_search(_tabul_layout_fitColumns, _tabulGrid, "/salesMgmt/salesMgmtGridList.do", columns, true);
|
||||
}
|
||||
|
||||
// 데이터 로드 함수 (페이지네이션에서도 사용)
|
||||
function fn_loadData() {
|
||||
console.log("fn_loadData 호출됨, PAGE_T:", $("#PAGE_T").val());
|
||||
$.ajax({
|
||||
url: "/salesMgmt/salesMgmtGridList.do",
|
||||
type: "POST",
|
||||
data: $("#form1").serialize(),
|
||||
dataType: "json",
|
||||
success: function(response){
|
||||
console.log("서버에서 받은 데이터 개수:", response.RESULTLIST ? response.RESULTLIST.length : 0);
|
||||
|
||||
// TOTAL_CNT 찾기 (PAGE_HTML에서 파싱)
|
||||
var totalCnt = 0;
|
||||
if(response.PAGE_HTML) {
|
||||
// PAGE_HTML에서 "119 건" 같은 패턴 찾기
|
||||
var match = response.PAGE_HTML.match(/<b id="bTableStatus">(\d+)<\/b>/);
|
||||
if(match && match[1]) {
|
||||
totalCnt = parseInt(match[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// 못 찾으면 다른 곳에서 찾기
|
||||
if(!totalCnt) {
|
||||
totalCnt = response.TOTAL_CNT || response.totalCnt ||
|
||||
(response.pagingMap && response.pagingMap.TOTAL_CNT) ||
|
||||
(response.RESULTLIST ? response.RESULTLIST.length : 0);
|
||||
}
|
||||
|
||||
console.log("파싱된 TOTAL_CNT:", totalCnt);
|
||||
|
||||
// 트리 구조로 데이터 변환
|
||||
var treeData = fn_convertToTreeData(response.RESULTLIST || []);
|
||||
console.log("트리 구조 변환 후 개수:", treeData.length);
|
||||
|
||||
// 기존 그리드 제거 (매번 재생성)
|
||||
if(_tabulGrid && _tabulGrid.element){
|
||||
try {
|
||||
_tabulGrid.destroy();
|
||||
} catch(e) {
|
||||
console.warn("그리드 destroy 중 오류:", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Tabulator 그리드 생성 (dataTree 옵션 활성화)
|
||||
_tabulGrid = new Tabulator("#mainGrid", {
|
||||
layout: "fitColumns",
|
||||
height: "auto",
|
||||
data: treeData,
|
||||
columns: columns,
|
||||
dataTree: true,
|
||||
dataTreeStartExpanded: false,
|
||||
dataTreeChildField: "_children",
|
||||
dataTreeChildIndent: 20,
|
||||
selectable: true,
|
||||
rowFormatter: function(row) {
|
||||
var data = row.getData();
|
||||
if (data._children && data._children.length > 0) {
|
||||
row.getElement().classList.add("has-children-row");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 페이지네이션 HTML 업데이트 (매출관리와 동일한 방식)
|
||||
if(response.PAGE_HTML){
|
||||
$(".table_paging_wrap").html(response.PAGE_HTML);
|
||||
}
|
||||
|
||||
// 전체 개수 표시
|
||||
$(".totalCntArea").html("전체 <strong>" + totalCnt + "</strong>건");
|
||||
},
|
||||
error: function(xhr, status, error){
|
||||
alert("데이터 조회 중 오류가 발생했습니다.");
|
||||
console.error("Error:", error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 플랫 데이터를 트리 구조로 변환하는 함수
|
||||
function fn_convertToTreeData(flatData){
|
||||
var treeData = [];
|
||||
var parentMap = {}; // PROJECT_NO를 키로 하는 부모 맵
|
||||
|
||||
// 1단계: 모든 데이터를 순회하며 부모와 자식 구분
|
||||
for(var i = 0; i < flatData.length; i++){
|
||||
var item = flatData[i];
|
||||
|
||||
if(item.RECORD_TYPE === 'ORIGINAL'){
|
||||
// 원본 데이터: 부모로 등록
|
||||
item._children = []; // 자식 배열 초기화
|
||||
parentMap[item.PROJECT_NO] = item;
|
||||
treeData.push(item);
|
||||
} else if(item.RECORD_TYPE === 'SPLIT'){
|
||||
// 분할 데이터: 부모를 찾아서 자식으로 추가
|
||||
var parent = parentMap[item.PROJECT_NO];
|
||||
if(parent){
|
||||
parent._children.push(item);
|
||||
} else {
|
||||
// 부모가 없는 경우 (이론적으로는 발생하지 않아야 함)
|
||||
console.warn("부모를 찾을 수 없습니다:", item.PROJECT_NO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2단계: 자식이 없는 부모의 _children 제거
|
||||
for(var j = 0; j < treeData.length; j++){
|
||||
if(treeData[j]._children && treeData[j]._children.length === 0){
|
||||
delete treeData[j]._children;
|
||||
}
|
||||
}
|
||||
|
||||
return treeData;
|
||||
}
|
||||
|
||||
// 페이지 이동 함수는 common.js의 기본 구현 사용
|
||||
// common.js에서 이미 정의된 fnc_goPage가 PAGE_T를 설정하고 fn_search()를 호출함
|
||||
|
||||
// 출하지시/판매등록 함수 (1건만 선택 가능)
|
||||
function fn_bulkRegister(){
|
||||
if(!_tabulGrid){
|
||||
@@ -374,12 +158,6 @@ function fn_bulkRegister(){
|
||||
// 선택한 1건의 항목 가져오기
|
||||
var selectedRow = selectedRows[0];
|
||||
|
||||
// 분할출하 건은 편집 불가 알림
|
||||
if(selectedRow.RECORD_TYPE === 'SPLIT'){
|
||||
alert("분할출하 건은 원본 데이터에서만 수정할 수 있습니다.\n프로젝트번호: " + selectedRow.PROJECT_NO + "의 원본 행을 선택해주세요.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 판매등록 팝업 열기
|
||||
fn_openSaleRegPopup(selectedRow.PROJECT_NO, selectedRow.SALE_NO);
|
||||
}
|
||||
|
||||
@@ -17,11 +17,6 @@
|
||||
// S/N 관리 전역 변수
|
||||
var snList = [];
|
||||
var snCounter = 1;
|
||||
var currentSnField = null; // 현재 클릭된 S/N 필드 추적
|
||||
|
||||
// 분할출하 관련 전역 변수
|
||||
var splitCounter = 1;
|
||||
var splitShipments = [];
|
||||
|
||||
$(function() {
|
||||
$('.select2').select2();
|
||||
@@ -38,9 +33,8 @@
|
||||
// 판매환종 초기값 설정 (견적환종과 동기화)
|
||||
initializeSalesCurrency();
|
||||
|
||||
// S/N 필드 클릭 이벤트 (기본 모드)
|
||||
// S/N 필드 클릭 이벤트
|
||||
$("#serialNo").click(function() {
|
||||
currentSnField = $(this); // 현재 필드 저장
|
||||
fn_openSnManagePopup();
|
||||
});
|
||||
|
||||
@@ -69,42 +63,11 @@
|
||||
self.close();
|
||||
});
|
||||
|
||||
// 저장 버튼 (분할출하 포함)
|
||||
// 저장 버튼
|
||||
$("#btnSave").click(function() {
|
||||
fn_saveWithSplit();
|
||||
fn_save();
|
||||
});
|
||||
|
||||
// 분할 추가 버튼
|
||||
$("#btnAddSplit").click(function() {
|
||||
fn_addSplitRow();
|
||||
});
|
||||
|
||||
// 분할출하 모드 토글
|
||||
$("#enableSplitShipment").change(function() {
|
||||
fn_toggleSplitShipmentMode();
|
||||
});
|
||||
|
||||
// 기존 분할출하 데이터 로드
|
||||
var saleNo = "${param.saleNo}";
|
||||
if(saleNo && saleNo.trim() != '') {
|
||||
fn_loadSplitShipments(saleNo);
|
||||
}
|
||||
});
|
||||
|
||||
// 분할출하 모드 토글 함수
|
||||
function fn_toggleSplitShipmentMode() {
|
||||
var isEnabled = $("#enableSplitShipment").is(':checked');
|
||||
|
||||
if(isEnabled) {
|
||||
// 분할 모드 ON: 기본 섹션 숨기고 분할출하 섹션만 표시
|
||||
$(".single-shipment-section").hide();
|
||||
$(".split-shipment-section").show();
|
||||
} else {
|
||||
// 분할 모드 OFF: 기본 섹션 표시하고 분할출하 섹션 숨김
|
||||
$(".single-shipment-section").show();
|
||||
$(".split-shipment-section").hide();
|
||||
}
|
||||
}
|
||||
|
||||
// 판매공급가액 계산 함수
|
||||
function fn_calculateSupplyPrice() {
|
||||
@@ -204,57 +167,29 @@
|
||||
// S/N 화면 표시 업데이트
|
||||
function fn_updateSnDisplay() {
|
||||
var count = snList.length;
|
||||
var displayValue = '';
|
||||
|
||||
if(count > 0) {
|
||||
// 모든 S/N을 쉼표로 연결
|
||||
var snValues = [];
|
||||
for(var i = 0; i < snList.length; i++) {
|
||||
snValues.push(snList[i].value);
|
||||
}
|
||||
displayValue = snValues.join(', ');
|
||||
}
|
||||
|
||||
// 현재 클릭된 필드가 있으면 해당 필드에 값 설정
|
||||
if(currentSnField && currentSnField.length > 0) {
|
||||
currentSnField.val(displayValue);
|
||||
$("#serialNo").val(snValues.join(', '));
|
||||
} else {
|
||||
// 기본 필드에 값 설정 (하위 호환성)
|
||||
$("#serialNo").val(displayValue);
|
||||
$("#serialNo").val('');
|
||||
}
|
||||
}
|
||||
|
||||
// S/N 관리 팝업 열기
|
||||
function fn_openSnManagePopup() {
|
||||
// 현재 클릭된 필드의 값 가져오기
|
||||
var serialNoValue = currentSnField ? currentSnField.val() : $("#serialNo").val();
|
||||
// 최신 데이터 다시 로드 (display 업데이트 없이)
|
||||
var serialNoValue = $("#serialNo").val();
|
||||
var serialNoListValue = $("#serialNoList").val();
|
||||
|
||||
console.log("팝업 열기 시작");
|
||||
console.log("현재 필드:", currentSnField ? "분할 S/N" : "기본 S/N");
|
||||
console.log("serialNoValue:", serialNoValue);
|
||||
console.log("serialNoList 값:", serialNoListValue);
|
||||
|
||||
// 분할 S/N 필드인 경우 (빈 값이든 아니든 독립적으로 처리)
|
||||
if(currentSnField && currentSnField.hasClass('split-sn')) {
|
||||
console.log("분할 S/N 필드에서 파싱");
|
||||
snList = [];
|
||||
snCounter = 1; // 분할 S/N은 독립적으로 카운터 시작
|
||||
|
||||
if(serialNoValue && serialNoValue.trim() != '') {
|
||||
var snArray = serialNoValue.split(',');
|
||||
for(var i = 0; i < snArray.length; i++) {
|
||||
if(snArray[i].trim() != '') {
|
||||
snList.push({
|
||||
id: snCounter++,
|
||||
value: snArray[i].trim()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 기본 모드이고 hidden 필드에 JSON 데이터가 있으면 파싱
|
||||
else if(serialNoListValue && serialNoListValue.trim() != '') {
|
||||
// 데이터가 있을 때만 로드
|
||||
if(serialNoListValue && serialNoListValue.trim() != '') {
|
||||
// JSON 형태로 저장된 데이터가 있으면 파싱
|
||||
try {
|
||||
snList = JSON.parse(serialNoListValue);
|
||||
@@ -596,359 +531,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================
|
||||
// 분할출하 관련 함수들
|
||||
// ======================================
|
||||
|
||||
// 분할출하 카드 추가 (기본 정보 + 금액 정보 레이아웃 그대로 복제)
|
||||
function fn_addSplitRow() {
|
||||
// 기본값 가져오기
|
||||
var serialNo = $("#serialNo").val() || '';
|
||||
var salesQuantity = $("#salesQuantity").val() || 0;
|
||||
var shippingDate = $("#shippingDate").val() || '';
|
||||
var shippingMethod = $("#shippingMethod").val() || '';
|
||||
var manager = $("#manager").val() || '';
|
||||
var unitPrice = $("#salesUnitPrice").val() || 0;
|
||||
var salesCurrency = $("#salesCurrency").val() || '';
|
||||
var exchangeRate = $("#salesExchangeRate").val() || 0;
|
||||
var incoterms = $("#incoterms").val() || '';
|
||||
|
||||
var html = '<div class="split-card" data-split-id="' + splitCounter + '" style="border:1px solid #ddd; border-radius:5px; padding:15px; margin-bottom:15px; background:#f9f9f9;">';
|
||||
html += ' <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:10px; padding-bottom:10px; border-bottom:2px solid #4CAF50;">';
|
||||
html += ' <h4 style="margin:0; color:#4CAF50;">분할 출하 #' + splitCounter + '</h4>';
|
||||
html += ' <button type="button" class="plm_btns" onclick="fn_removeSplitRow(' + splitCounter + ')" style="padding:5px 10px; background:#f44336; color:white;">삭제</button>';
|
||||
html += ' </div>';
|
||||
|
||||
// === 기본 정보 섹션 ===
|
||||
html += ' <div style="background:#fff; padding:10px; border-radius:3px; margin-bottom:10px;">';
|
||||
html += ' <h5 style="margin:0 0 10px 0; color:#666; font-size:13px; border-bottom:1px solid #eee; padding-bottom:5px;">기본 정보</h5>';
|
||||
html += ' <table class="pmsPopuptable">';
|
||||
html += ' <colgroup>';
|
||||
html += ' <col width="15%" />';
|
||||
html += ' <col width="35%" />';
|
||||
html += ' <col width="15%" />';
|
||||
html += ' <col width="35%" />';
|
||||
html += ' </colgroup>';
|
||||
|
||||
// S/N
|
||||
html += ' <tr>';
|
||||
html += ' <td class="input_title"><label>S/N</label></td>';
|
||||
html += ' <td colspan="3"><input type="text" class="split-sn" name="splitSn_' + splitCounter + '" placeholder="클릭하여 S/N 추가" style="width:100%; cursor:pointer; background-color:#f8f9fa; color:#333 !important;" value="' + serialNo + '" readonly /></td>';
|
||||
html += ' </tr>';
|
||||
|
||||
// 판매수량, 출하일
|
||||
html += ' <tr>';
|
||||
html += ' <td class="input_title"><label>판매수량</label></td>';
|
||||
html += ' <td><input type="number" class="split-qty" name="splitQty_' + splitCounter + '" value="' + salesQuantity + '" onchange="fn_calculateSplitRowAmount(this)" /></td>';
|
||||
html += ' <td class="input_title"><label>출하일</label></td>';
|
||||
html += ' <td><input type="text" class="date_icon split-date" name="splitDate_' + splitCounter + '" value="' + shippingDate + '" autocomplete="off" /></td>';
|
||||
html += ' </tr>';
|
||||
|
||||
// 출하방법, 담당자
|
||||
html += ' <tr>';
|
||||
html += ' <td class="input_title"><label>출하방법</label></td>';
|
||||
html += ' <td>';
|
||||
html += ' <select class="select2 split-method" name="splitMethod_' + splitCounter + '">';
|
||||
html += ' <option value="">선택</option>';
|
||||
html += ' <option value="내수/직납"' + (shippingMethod == '내수/직납' ? ' selected' : '') + '>내수/직납</option>';
|
||||
html += ' <option value="내수/택배"' + (shippingMethod == '내수/택배' ? ' selected' : '') + '>내수/택배</option>';
|
||||
html += ' <option value="내수/기타"' + (shippingMethod == '내수/기타' ? ' selected' : '') + '>내수/기타</option>';
|
||||
html += ' <option value="수출"' + (shippingMethod == '수출' ? ' selected' : '') + '>수출</option>';
|
||||
html += ' </select>';
|
||||
html += ' </td>';
|
||||
html += ' <td class="input_title"><label>담당자</label></td>';
|
||||
html += ' <td>';
|
||||
html += ' <select class="select2 split-manager" name="splitManager_' + splitCounter + '">';
|
||||
// 담당자 옵션 복사 (동적으로 생성, "선택" 옵션 제거 없이 그대로 복사)
|
||||
$("#manager option").each(function() {
|
||||
var val = $(this).val();
|
||||
var text = $(this).text();
|
||||
var selected = (val == manager) ? ' selected' : '';
|
||||
html += ' <option value="' + val + '"' + selected + '>' + text + '</option>';
|
||||
});
|
||||
html += ' </select>';
|
||||
html += ' </td>';
|
||||
html += ' </tr>';
|
||||
|
||||
html += ' </table>';
|
||||
html += ' </div>';
|
||||
|
||||
// === 금액 정보 섹션 ===
|
||||
html += ' <div style="background:#fff; padding:10px; border-radius:3px;">';
|
||||
html += ' <h5 style="margin:0 0 10px 0; color:#666; font-size:13px; border-bottom:1px solid #eee; padding-bottom:5px;">금액 정보</h5>';
|
||||
html += ' <table class="pmsPopuptable">';
|
||||
html += ' <colgroup>';
|
||||
html += ' <col width="15%" />';
|
||||
html += ' <col width="35%" />';
|
||||
html += ' <col width="15%" />';
|
||||
html += ' <col width="35%" />';
|
||||
html += ' </colgroup>';
|
||||
|
||||
// 판매단가, 판매공급가액
|
||||
html += ' <tr>';
|
||||
html += ' <td class="input_title"><label>판매단가</label></td>';
|
||||
html += ' <td><input type="number" class="split-unit-price" name="splitUnitPrice_' + splitCounter + '" value="' + unitPrice + '" onchange="fn_calculateSplitRowAmount(this)" /></td>';
|
||||
html += ' <td class="input_title"><label>판매공급가액</label></td>';
|
||||
html += ' <td><input type="number" class="split-supply-price" name="splitSupplyPrice_' + splitCounter + '" readonly style="background-color:#f5f5f5;" /></td>';
|
||||
html += ' </tr>';
|
||||
|
||||
// 판매부가세, 판매총액
|
||||
html += ' <tr>';
|
||||
html += ' <td class="input_title"><label>판매부가세</label></td>';
|
||||
html += ' <td><input type="number" class="split-vat" name="splitVat_' + splitCounter + '" readonly style="background-color:#f5f5f5;" /></td>';
|
||||
html += ' <td class="input_title"><label>판매총액</label></td>';
|
||||
html += ' <td><input type="number" class="split-total-amount" name="splitTotalAmount_' + splitCounter + '" readonly style="background-color:#f5f5f5;" /></td>';
|
||||
html += ' </tr>';
|
||||
|
||||
// 판매환종, 판매환율
|
||||
html += ' <tr>';
|
||||
html += ' <td class="input_title"><label>판매환종</label></td>';
|
||||
html += ' <td>';
|
||||
html += ' <select class="select2 split-currency" name="splitCurrency_' + splitCounter + '" onchange="fn_calculateSplitRowAmount(this)">';
|
||||
// 환종 옵션 복사 ("선택" 옵션 포함하여 그대로 복사)
|
||||
$("#salesCurrency option").each(function() {
|
||||
var val = $(this).val();
|
||||
var text = $(this).text();
|
||||
var selected = (val == salesCurrency) ? ' selected' : '';
|
||||
html += ' <option value="' + val + '"' + selected + '>' + text + '</option>';
|
||||
});
|
||||
html += ' </select>';
|
||||
html += ' </td>';
|
||||
html += ' <td class="input_title"><label>판매환율</label></td>';
|
||||
html += ' <td><input type="number" class="split-exchange-rate" name="splitExchangeRate_' + splitCounter + '" step="0.01" value="' + exchangeRate + '" onchange="fn_calculateSplitRowAmount(this)" /></td>';
|
||||
html += ' </tr>';
|
||||
|
||||
// 인도조건
|
||||
html += ' <tr>';
|
||||
html += ' <td class="input_title"><label>인도조건</label></td>';
|
||||
html += ' <td colspan="3">';
|
||||
html += ' <select class="select2 split-incoterms" name="splitIncoterms_' + splitCounter + '">';
|
||||
html += ' <option value="">선택</option>';
|
||||
html += ' <option value="FOB"' + (incoterms == 'FOB' ? ' selected' : '') + '>FOB</option>';
|
||||
html += ' <option value="EXW"' + (incoterms == 'EXW' ? ' selected' : '') + '>EXW</option>';
|
||||
html += ' <option value="CIF"' + (incoterms == 'CIF' ? ' selected' : '') + '>CIF</option>';
|
||||
html += ' <option value="DDP"' + (incoterms == 'DDP' ? ' selected' : '') + '>DDP</option>';
|
||||
html += ' <option value="DAP"' + (incoterms == 'DAP' ? ' selected' : '') + '>DAP</option>';
|
||||
html += ' </select>';
|
||||
html += ' </td>';
|
||||
html += ' </tr>';
|
||||
|
||||
html += ' </table>';
|
||||
html += ' </div>';
|
||||
|
||||
html += '</div>';
|
||||
|
||||
$("#splitShipmentContainer").append(html);
|
||||
|
||||
// 새로 추가된 카드 선택
|
||||
var newCard = $(".split-card[data-split-id='" + splitCounter + "']");
|
||||
|
||||
// 날짜 선택기 초기화
|
||||
newCard.find(".split-date").datepicker({
|
||||
changeMonth: true,
|
||||
changeYear: true,
|
||||
dateFormat: 'yy-mm-dd'
|
||||
});
|
||||
|
||||
// select2 초기화 (드롭다운 스타일 적용)
|
||||
newCard.find('.select2').select2();
|
||||
|
||||
// S/N 클릭 이벤트 추가 (분할 모드)
|
||||
newCard.find(".split-sn").click(function() {
|
||||
currentSnField = $(this); // 현재 필드 저장
|
||||
fn_openSnManagePopup();
|
||||
});
|
||||
|
||||
// 초기 금액 계산
|
||||
fn_calculateSplitRowAmount(newCard.find(".split-qty")[0]);
|
||||
|
||||
splitCounter++;
|
||||
}
|
||||
|
||||
// 분할 행의 금액 계산
|
||||
function fn_calculateSplitRowAmount(input) {
|
||||
// 카드 전체를 기준으로 필드 찾기
|
||||
var card = $(input).closest('.split-card');
|
||||
|
||||
// 기본 값 가져오기
|
||||
var qty = parseFloat(card.find('.split-qty').val()) || 0;
|
||||
var unitPrice = parseFloat(card.find('.split-unit-price').val()) || 0;
|
||||
var currency = card.find('.split-currency').val();
|
||||
var exchangeRate = parseFloat(card.find('.split-exchange-rate').val()) || 1;
|
||||
|
||||
// 외화 기준 금액 계산
|
||||
var foreignSupplyPrice = qty * unitPrice;
|
||||
|
||||
// KRW가 아니고 환율이 있으면 환율 적용 (기본 모드 로직과 동일)
|
||||
var supplyPrice;
|
||||
if(currency && currency !== 'KRW' && exchangeRate > 0) {
|
||||
supplyPrice = Math.round(foreignSupplyPrice * exchangeRate);
|
||||
} else {
|
||||
supplyPrice = Math.round(foreignSupplyPrice);
|
||||
}
|
||||
|
||||
// 부가세 = 공급가액 * 0.1
|
||||
var vat = Math.round(supplyPrice * 0.1);
|
||||
|
||||
// 총액 = 공급가액 + 부가세
|
||||
var totalAmount = supplyPrice + vat;
|
||||
|
||||
// 값 설정
|
||||
card.find('.split-supply-price').val(supplyPrice);
|
||||
card.find('.split-vat').val(vat);
|
||||
card.find('.split-total-amount').val(totalAmount);
|
||||
}
|
||||
|
||||
// 분할출하 카드 삭제
|
||||
function fn_removeSplitRow(id) {
|
||||
if (confirm("이 분할출하를 삭제하시겠습니까?")) {
|
||||
$(".split-card[data-split-id='" + id + "']").remove();
|
||||
fn_reorderSplitRows();
|
||||
}
|
||||
}
|
||||
|
||||
// 분할출하 카드 번호 재정렬
|
||||
function fn_reorderSplitRows() {
|
||||
$("#splitShipmentContainer .split-card").each(function(index) {
|
||||
$(this).find("h4").text("분할 출하 #" + (index + 1));
|
||||
});
|
||||
}
|
||||
|
||||
// 분할출하 데이터 수집
|
||||
function fn_collectSplitData() {
|
||||
var splits = [];
|
||||
var isSplitMode = $("#enableSplitShipment").is(':checked');
|
||||
|
||||
// 분할 모드가 아니면 빈 배열 반환
|
||||
if(!isSplitMode) {
|
||||
return splits;
|
||||
}
|
||||
|
||||
// 분할 모드일 때만 수량 합계 검증 (원본 수량 없음)
|
||||
var totalSplitQty = 0;
|
||||
|
||||
$("#splitShipmentContainer .split-card").each(function() {
|
||||
var card = $(this);
|
||||
var shippingDate = card.find(".split-date").val();
|
||||
var qty = parseInt(card.find(".split-qty").val()) || 0;
|
||||
|
||||
// 필수값 체크
|
||||
if(!shippingDate || qty <= 0) {
|
||||
return true; // continue
|
||||
}
|
||||
|
||||
splits.push({
|
||||
shippingDate: shippingDate,
|
||||
splitQuantity: qty,
|
||||
serialNo: card.find(".split-sn").val() || '',
|
||||
salesUnitPrice: parseFloat(card.find(".split-unit-price").val()) || 0,
|
||||
salesSupplyPrice: parseFloat(card.find(".split-supply-price").val()) || 0,
|
||||
salesVat: parseFloat(card.find(".split-vat").val()) || 0,
|
||||
salesTotalAmount: parseFloat(card.find(".split-total-amount").val()) || 0,
|
||||
salesCurrency: card.find(".split-currency").val() || '',
|
||||
salesExchangeRate: parseFloat(card.find(".split-exchange-rate").val()) || 0,
|
||||
shippingMethod: card.find(".split-method").val() || '',
|
||||
managerUserId: card.find(".split-manager").val() || '',
|
||||
incoterms: card.find(".split-incoterms").val() || ''
|
||||
});
|
||||
|
||||
totalSplitQty += qty;
|
||||
});
|
||||
|
||||
// 분할 모드에서는 최소 1개 이상의 분할 데이터가 있어야 함
|
||||
if (isSplitMode && splits.length === 0) {
|
||||
alert("분할출하 모드에서는 최소 1개 이상의 분할 데이터를 입력해야 합니다.");
|
||||
return null;
|
||||
}
|
||||
|
||||
return splits;
|
||||
}
|
||||
|
||||
// 저장 (분할출하 포함)
|
||||
function fn_saveWithSplit() {
|
||||
// 체크박스 상태에 따라 출하지시 상태 값 설정
|
||||
var isChecked = $("#isShippingOrder").is(":checked");
|
||||
$("#shippingOrderStatus").val(isChecked ? "출하지시" : "");
|
||||
|
||||
// S/N 데이터 처리
|
||||
var serialNoListValue = $("#serialNoList").val();
|
||||
if(serialNoListValue && serialNoListValue.trim() != '') {
|
||||
try {
|
||||
var snArray = JSON.parse(serialNoListValue);
|
||||
var snValues = [];
|
||||
for(var i = 0; i < snArray.length; i++) {
|
||||
if(snArray[i].value) {
|
||||
snValues.push(snArray[i].value);
|
||||
}
|
||||
}
|
||||
$("#serialNo").val(snValues.join(','));
|
||||
} catch(e) {
|
||||
console.error("S/N JSON 파싱 오류:", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 분할출하 데이터 수집
|
||||
var splits = fn_collectSplitData();
|
||||
if (splits === null) return; // 검증 실패
|
||||
|
||||
if (confirm("저장하시겠습니까?")) {
|
||||
var formData = $("#form1").serialize();
|
||||
|
||||
// 분할출하 데이터 추가
|
||||
if(splits && splits.length > 0) {
|
||||
formData += "&splitShipments=" + encodeURIComponent(JSON.stringify(splits));
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: "/salesMgmt/saveSplitShipments.do",
|
||||
type: "POST",
|
||||
data: formData,
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
alert(data.msg);
|
||||
if (data.result && opener && opener.fn_search) {
|
||||
opener.fn_search();
|
||||
}
|
||||
if (data.result) {
|
||||
self.close();
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
alert("저장 중 오류가 발생했습니다.");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 기존 분할출하 로드
|
||||
function fn_loadSplitShipments(saleNo) {
|
||||
if(!saleNo) return;
|
||||
|
||||
$.ajax({
|
||||
url: "/salesMgmt/getSplitShipments.do",
|
||||
type: "POST",
|
||||
data: { saleNo: saleNo },
|
||||
dataType: "json",
|
||||
success: function(response) {
|
||||
if (response.result && response.data && response.data.length > 0) {
|
||||
$.each(response.data, function(i, item) {
|
||||
fn_addSplitRow();
|
||||
var row = $("#splitShipmentBody tr:last");
|
||||
row.find(".split-date").val(item.SHIPPING_DATE || '');
|
||||
row.find(".split-qty").val(item.SPLIT_QUANTITY || '');
|
||||
row.find(".split-sn").val(item.SERIAL_NO || '');
|
||||
row.find(".split-method").val(item.SHIPPING_METHOD || '');
|
||||
row.find(".split-remark").val(item.REMARK || '');
|
||||
row.attr("data-log-id", item.LOG_ID);
|
||||
});
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
console.error("분할출하 데이터 로드 실패");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
@@ -998,13 +580,10 @@
|
||||
</table>
|
||||
|
||||
<!-- 기본 정보 영역 -->
|
||||
<div class="form_popup_title" style="margin-top:15px; display:flex; justify-content:space-between; align-items:center;">
|
||||
<span class="single-shipment-section">기본 정보</span>
|
||||
<label style="font-weight:normal; display:inline-flex; align-items:center; margin-left:auto; margin-right:10px;">
|
||||
<input type="checkbox" id="enableSplitShipment" style="margin-right:5px;" >분할출하 모드</label>
|
||||
</label>
|
||||
<div class="form_popup_title" style="margin-top:15px;">
|
||||
<span>기본 정보</span>
|
||||
</div>
|
||||
<table class="single-shipment-section">
|
||||
<table class="">
|
||||
<colgroup>
|
||||
<col width="100%" />
|
||||
</colgroup>
|
||||
@@ -1018,7 +597,7 @@
|
||||
<col width="35%" />
|
||||
</colgroup>
|
||||
|
||||
<!-- 첫번째 행: S/N (항상 표시) -->
|
||||
<!-- 첫번째 행: S/N -->
|
||||
<tr>
|
||||
<td class="input_title"><label for="serialNo">S/N</label></td>
|
||||
<td colspan="3">
|
||||
@@ -1030,7 +609,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- 두번째 행: 판매수량, 출하일 (항상 표시) -->
|
||||
<!-- 두번째 행: 판매수량, 출하일 -->
|
||||
<tr>
|
||||
<td class="input_title"><label for="salesQuantity">판매수량</label></td>
|
||||
<td>
|
||||
@@ -1042,7 +621,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- 세번째 행: 출하방법, 담당자 (항상 표시) -->
|
||||
<!-- 세번째 행: 출하방법, 담당자 -->
|
||||
<tr>
|
||||
<td class="input_title"><label for="shippingMethod">출하방법</label></td>
|
||||
<td>
|
||||
@@ -1068,11 +647,11 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- 금액 정보 영역 (항상 표시) -->
|
||||
<div class="form_popup_title single-shipment-section" style="margin-top:15px;">
|
||||
<!-- 금액 정보 영역 -->
|
||||
<div class="form_popup_title" style="margin-top:15px;">
|
||||
<span>금액 정보</span>
|
||||
</div>
|
||||
<table class="single-shipment-section">
|
||||
<table class="">
|
||||
<colgroup>
|
||||
<col width="100%" />
|
||||
</colgroup>
|
||||
@@ -1145,21 +724,6 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- 분할출하 관리 섹션 (분할 모드 ON시만 표시) -->
|
||||
<div class="split-shipment-section" style="display:none;">
|
||||
<div class="form_popup_title" style="margin-top:15px;">
|
||||
<span>분할출하 관리</span>
|
||||
<button type="button" class="plm_btns" id="btnAddSplit" style="float:right; margin-left:5px;">
|
||||
분할 추가
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 분할출하 카드들이 추가될 컨테이너 -->
|
||||
<div id="splitShipmentContainer" style="margin-top:10px;">
|
||||
<!-- 동적으로 카드 추가 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="btn_wrap">
|
||||
|
||||
@@ -281,11 +281,8 @@ public class SalesNcollectMgmtController {
|
||||
@RequestMapping(value = "/salesMgmt/salesMgmtGridList.do", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public Map<String, Object> getSalesMgmtGridList(HttpServletRequest request, @RequestParam Map<String, Object> paramMap) {
|
||||
// 기본 쿼리 사용 (분할출하 VIEW는 나중에 필요시 활성화)
|
||||
String queryId = "salesNcollectMgmt.getSalesMgmtGridList";
|
||||
|
||||
// commonService.selectListPagingNew를 사용하여 페이지네이션 HTML 생성
|
||||
commonService.selectListPagingNew(queryId, request, paramMap);
|
||||
commonService.selectListPagingNew("salesNcollectMgmt.getSalesMgmtGridList", request, paramMap);
|
||||
return paramMap;
|
||||
}
|
||||
|
||||
@@ -729,49 +726,4 @@ public class SalesNcollectMgmtController {
|
||||
Map resultMap = salesNcollectMgmtService.salesDeadlineConfirm(request, paramMap);
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 분할출하 저장
|
||||
* </pre>
|
||||
* @param request
|
||||
* @param paramMap - 분할출하 정보
|
||||
* @return Map
|
||||
*/
|
||||
@RequestMapping(value = "/salesMgmt/saveSplitShipments.do", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public Map<String, Object> saveSplitShipments(HttpServletRequest request,
|
||||
@RequestParam Map<String, Object> paramMap) {
|
||||
return salesNcollectMgmtService.saveSplitShipments(request, paramMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 분할출하 목록 조회
|
||||
* </pre>
|
||||
* @param paramMap - 조회 조건 (saleNo)
|
||||
* @return Map
|
||||
*/
|
||||
@RequestMapping(value = "/salesMgmt/getSplitShipments.do", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public Map<String, Object> getSplitShipments(@RequestParam Map<String, Object> paramMap) {
|
||||
List<Map<String, Object>> list = salesNcollectMgmtService.getSplitShipmentList(paramMap);
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
resultMap.put("data", list);
|
||||
resultMap.put("result", true);
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 분할출하 삭제
|
||||
* </pre>
|
||||
* @param paramMap - 삭제 조건 (logId)
|
||||
* @return Map
|
||||
*/
|
||||
@RequestMapping(value = "/salesMgmt/deleteSplitShipment.do", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public Map<String, Object> deleteSplitShipment(@RequestParam Map<String, Object> paramMap) {
|
||||
return salesNcollectMgmtService.deleteSplitShipment(paramMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -835,267 +835,4 @@ public class SalesNcollectMgmtService {
|
||||
}
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 분할출하 저장 (여러 건)
|
||||
* </pre>
|
||||
* @param request
|
||||
* @param paramMap - 분할출하 정보 (JSON 배열)
|
||||
* @return Map
|
||||
*/
|
||||
public Map<String, Object> saveSplitShipments(HttpServletRequest request, Map<String, Object> paramMap) {
|
||||
Map<String, Object> resultMap = new HashMap<String, Object>();
|
||||
SqlSession sqlSession = null;
|
||||
|
||||
try {
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
|
||||
PersonBean person = (PersonBean) request.getSession().getAttribute(Constants.PERSON_BEAN);
|
||||
String userId = person.getUserId();
|
||||
|
||||
// 분할출하 데이터 JSON 파싱
|
||||
String splitDataJson = CommonUtils.checkNull(paramMap.get("splitShipments"));
|
||||
if (StringUtils.isBlank(splitDataJson) || "[]".equals(splitDataJson)) {
|
||||
// 분할출하 데이터가 없으면 일반 저장만 수행
|
||||
return saveSaleRegistration(request, paramMap);
|
||||
}
|
||||
|
||||
// JSON 파싱 (간단한 파싱 - 실제로는 Jackson 등 사용 권장)
|
||||
List<Map<String, Object>> splitList = parseSplitShipments(splitDataJson);
|
||||
|
||||
// 원본 sales_registration 데이터 조회 또는 생성
|
||||
String projectNo = CommonUtils.checkNull(paramMap.get("orderNo"));
|
||||
Map<String, Object> saleInfo = sqlSession.selectOne("salesNcollectMgmt.getSaleInfo", paramMap);
|
||||
|
||||
Integer saleNo = null;
|
||||
int originalQuantity = 0;
|
||||
BigDecimal salesUnitPrice = BigDecimal.ZERO;
|
||||
String salesCurrency = "";
|
||||
BigDecimal salesExchangeRate = BigDecimal.ONE;
|
||||
String incoterms = "";
|
||||
|
||||
if (saleInfo != null && saleInfo.get("SALE_NO") != null) {
|
||||
// 기존 판매 정보가 있는 경우
|
||||
saleNo = Integer.parseInt(saleInfo.get("SALE_NO").toString());
|
||||
originalQuantity = Integer.parseInt(CommonUtils.checkNull(saleInfo.get("SALES_QUANTITY"), "0"));
|
||||
salesUnitPrice = new BigDecimal(CommonUtils.checkNull(saleInfo.get("SALES_UNIT_PRICE"), "0"));
|
||||
salesCurrency = CommonUtils.checkNull(saleInfo.get("SALES_CURRENCY"));
|
||||
salesExchangeRate = new BigDecimal(CommonUtils.checkNull(saleInfo.get("SALES_EXCHANGE_RATE"), "1"));
|
||||
incoterms = CommonUtils.checkNull(saleInfo.get("INCOTERMS"));
|
||||
} else {
|
||||
// 신규 판매 정보 생성
|
||||
sqlSession.insert("salesNcollectMgmt.insertSaleRegistration", paramMap);
|
||||
|
||||
// INSERT 후 반환된 saleNo 사용 (useGeneratedKeys로 자동 설정됨)
|
||||
if (paramMap.get("saleNo") == null) {
|
||||
resultMap.put("result", false);
|
||||
resultMap.put("msg", "판매 정보 저장 후 sale_no 생성 실패");
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
saleNo = Integer.parseInt(paramMap.get("saleNo").toString());
|
||||
originalQuantity = Integer.parseInt(CommonUtils.checkNull(paramMap.get("salesQuantity"), "0"));
|
||||
salesUnitPrice = new BigDecimal(CommonUtils.checkNull(paramMap.get("salesUnitPrice"), "0"));
|
||||
salesCurrency = CommonUtils.checkNull(paramMap.get("salesCurrency"));
|
||||
salesExchangeRate = new BigDecimal(CommonUtils.checkNull(paramMap.get("salesExchangeRate"), "1"));
|
||||
incoterms = CommonUtils.checkNull(paramMap.get("incoterms"));
|
||||
}
|
||||
|
||||
// 분할 수량 합계 검증
|
||||
int totalSplitQty = 0;
|
||||
for (Map<String, Object> split : splitList) {
|
||||
String qtyStr = CommonUtils.checkNull(split.get("splitQuantity"), "0");
|
||||
totalSplitQty += Integer.parseInt(qtyStr);
|
||||
}
|
||||
|
||||
if (totalSplitQty > originalQuantity) {
|
||||
resultMap.put("result", false);
|
||||
resultMap.put("msg", "분할 수량 합계(" + totalSplitQty + ")가 원본 수량(" + originalQuantity + ")을 초과했습니다.");
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
// 기존 분할출하 삭제 (재저장 방식)
|
||||
sqlSession.delete("salesNcollectMgmt.deleteAllSplitShipments", paramMap);
|
||||
|
||||
// 분할출하 데이터 저장
|
||||
for (Map<String, Object> split : splitList) {
|
||||
split.put("saleNo", saleNo);
|
||||
split.put("projectNo", projectNo);
|
||||
split.put("originalQuantity", originalQuantity);
|
||||
split.put("regUserId", userId);
|
||||
|
||||
// 금액 계산
|
||||
int splitQty = Integer.parseInt(CommonUtils.checkNull(split.get("splitQuantity"), "0"));
|
||||
BigDecimal supplyPrice = salesUnitPrice.multiply(new BigDecimal(splitQty));
|
||||
BigDecimal vat = supplyPrice.multiply(new BigDecimal("0.1"));
|
||||
BigDecimal totalAmount = supplyPrice.add(vat);
|
||||
|
||||
split.put("salesUnitPrice", salesUnitPrice);
|
||||
split.put("salesSupplyPrice", supplyPrice);
|
||||
split.put("salesVat", vat);
|
||||
split.put("salesTotalAmount", totalAmount);
|
||||
split.put("salesCurrency", salesCurrency);
|
||||
split.put("salesExchangeRate", salesExchangeRate);
|
||||
|
||||
// incoterms가 없으면 원본 값 사용
|
||||
if (StringUtils.isBlank(CommonUtils.checkNull(split.get("incoterms")))) {
|
||||
split.put("incoterms", incoterms);
|
||||
}
|
||||
|
||||
// managerUserId가 없으면 현재 사용자
|
||||
if (StringUtils.isBlank(CommonUtils.checkNull(split.get("managerUserId")))) {
|
||||
split.put("managerUserId", userId);
|
||||
}
|
||||
|
||||
sqlSession.insert("salesNcollectMgmt.insertSplitShipment", split);
|
||||
}
|
||||
|
||||
// sales_registration의 has_split_shipment 플래그 업데이트
|
||||
paramMap.put("saleNo", saleNo);
|
||||
paramMap.put("updUserId", userId);
|
||||
sqlSession.update("salesNcollectMgmt.updateSplitFlag", paramMap);
|
||||
|
||||
sqlSession.commit();
|
||||
|
||||
resultMap.put("result", true);
|
||||
resultMap.put("msg", "분할출하가 저장되었습니다.");
|
||||
|
||||
} catch (Exception e) {
|
||||
if (sqlSession != null) {
|
||||
sqlSession.rollback();
|
||||
}
|
||||
resultMap.put("result", false);
|
||||
resultMap.put("msg", "저장 중 오류가 발생했습니다: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (sqlSession != null) {
|
||||
sqlSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 분할출하 목록 조회
|
||||
* </pre>
|
||||
* @param paramMap - 조회 조건
|
||||
* @return List
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public List<Map<String, Object>> getSplitShipmentList(Map<String, Object> paramMap) {
|
||||
List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
|
||||
SqlSession sqlSession = null;
|
||||
|
||||
try {
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession();
|
||||
resultList = (ArrayList) sqlSession.selectList("salesNcollectMgmt.getSplitShipmentList", paramMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (sqlSession != null) {
|
||||
sqlSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
return CommonUtils.toUpperCaseMapKey(resultList);
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 분할출하 삭제
|
||||
* </pre>
|
||||
* @param paramMap - 삭제 조건
|
||||
* @return Map
|
||||
*/
|
||||
public Map<String, Object> deleteSplitShipment(Map<String, Object> paramMap) {
|
||||
Map<String, Object> resultMap = new HashMap<String, Object>();
|
||||
SqlSession sqlSession = null;
|
||||
|
||||
try {
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
|
||||
|
||||
int cnt = sqlSession.delete("salesNcollectMgmt.deleteSplitShipment", paramMap);
|
||||
|
||||
if (cnt > 0) {
|
||||
// has_split_shipment 플래그 업데이트
|
||||
sqlSession.update("salesNcollectMgmt.updateSplitFlag", paramMap);
|
||||
|
||||
sqlSession.commit();
|
||||
resultMap.put("result", true);
|
||||
resultMap.put("msg", "삭제되었습니다.");
|
||||
} else {
|
||||
resultMap.put("result", false);
|
||||
resultMap.put("msg", "삭제할 데이터가 없습니다.");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
if (sqlSession != null) {
|
||||
sqlSession.rollback();
|
||||
}
|
||||
resultMap.put("result", false);
|
||||
resultMap.put("msg", "삭제 중 오류가 발생했습니다.");
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (sqlSession != null) {
|
||||
sqlSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 분할출하 JSON 문자열 파싱
|
||||
* </pre>
|
||||
* @param jsonStr - JSON 문자열
|
||||
* @return List
|
||||
*/
|
||||
private List<Map<String, Object>> parseSplitShipments(String jsonStr) {
|
||||
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
|
||||
|
||||
try {
|
||||
// 간단한 JSON 파싱 (실제로는 Jackson 또는 Gson 사용 권장)
|
||||
// 형식: [{"shippingDate":"2024-01-01","splitQuantity":"10",...},...]
|
||||
jsonStr = jsonStr.trim();
|
||||
if (jsonStr.startsWith("[")) {
|
||||
jsonStr = jsonStr.substring(1);
|
||||
}
|
||||
if (jsonStr.endsWith("]")) {
|
||||
jsonStr = jsonStr.substring(0, jsonStr.length() - 1);
|
||||
}
|
||||
|
||||
// 각 객체를 분리
|
||||
String[] objects = jsonStr.split("\\},\\{");
|
||||
|
||||
for (String obj : objects) {
|
||||
obj = obj.replace("{", "").replace("}", "").trim();
|
||||
if (obj.isEmpty()) continue;
|
||||
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
|
||||
// 각 속성을 파싱
|
||||
String[] pairs = obj.split("\",\"");
|
||||
for (String pair : pairs) {
|
||||
pair = pair.replace("\"", "").trim();
|
||||
String[] keyValue = pair.split(":");
|
||||
if (keyValue.length == 2) {
|
||||
String key = keyValue[0].trim();
|
||||
String value = keyValue[1].trim();
|
||||
map.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
if (!map.isEmpty()) {
|
||||
result.add(map);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user