V20260210 #162
@@ -307,7 +307,19 @@ function fn_loadProjectInfo(projectObjid){
|
||||
$("#REQ_DEL_DATE").val(fnc_checkNull(info.req_del_date));
|
||||
|
||||
// S/N
|
||||
$("#SERIAL_NO").val(fnc_checkNull(info.serial_no));
|
||||
var serialNoVal = fnc_checkNull(info.serial_no);
|
||||
$("#SERIAL_NO").val(serialNoVal);
|
||||
// snList 동기화 (AJAX 로드 시에도 팝업 목록 갱신)
|
||||
snList = [];
|
||||
snCounter = 1;
|
||||
if(serialNoVal && serialNoVal.trim() != '') {
|
||||
var snArr = serialNoVal.split(',');
|
||||
for(var si = 0; si < snArr.length; si++) {
|
||||
if(snArr[si].trim() != '') {
|
||||
snList.push({ id: snCounter++, value: snArr[si].trim() });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 수주수량
|
||||
$("#ORDER_QTY").val(fnc_checkNull(info.order_qty) || 0);
|
||||
@@ -479,7 +491,7 @@ function fn_openSnManagePopup() {
|
||||
width: '700px',
|
||||
showConfirmButton: false,
|
||||
showCloseButton: true,
|
||||
didOpen: function() {
|
||||
onOpen: function() {
|
||||
setTimeout(function() {
|
||||
fn_renderSnList();
|
||||
// 엔터키로 추가
|
||||
|
||||
@@ -227,7 +227,21 @@
|
||||
Swal.fire("매출마감 전 데이터만 매출마감 가능합니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// 선택된 항목의 고객사가 모두 동일한지 체크
|
||||
var firstCustomer = fnc_checkNull(targetObj[0].CUSTOMER);
|
||||
var hasDiffCustomer = false;
|
||||
for(var i = 1; i < targetObj.length; i++){
|
||||
if(fnc_checkNull(targetObj[i].CUSTOMER) != firstCustomer){
|
||||
hasDiffCustomer = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(hasDiffCustomer){
|
||||
Swal.fire("동일한 고객사의 데이터만 매출마감할 수 있습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 매출마감일 입력 팝업
|
||||
Swal.fire({
|
||||
title: '매출마감 처리',
|
||||
|
||||
@@ -215,7 +215,16 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// 거래명세서 출력 버튼은 항상 새로 작성 (저장된 데이터 무시)
|
||||
// 이미 거래명세서가 생성된 항목이 있는지 확인
|
||||
var alreadyCreated = selectedData.filter(function(row) {
|
||||
return row.HAS_TRANSACTION_STATEMENT === 'Y';
|
||||
});
|
||||
if(alreadyCreated.length > 0) {
|
||||
var projectNames = alreadyCreated.map(function(row) { return row.PROJECT_NO; }).join(', ');
|
||||
alert("이미 거래명세서가 생성된 항목이 있습니다.\n(" + projectNames + ")\n파란 폴더 아이콘을 클릭하여 확인해주세요.");
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem('loadSavedStatement', 'false');
|
||||
|
||||
// 같은 거래처인지 확인
|
||||
@@ -233,15 +242,19 @@
|
||||
console.log(selectedData);
|
||||
localStorage.setItem('transactionStatementData', JSON.stringify(selectedData));
|
||||
|
||||
// 프로젝트 번호들을 수집
|
||||
// 프로젝트 번호/OBJID 수집
|
||||
var projectNos = selectedData.map(function(row) {
|
||||
return row.PROJECT_NO;
|
||||
}).join(',');
|
||||
var projectObjids = selectedData.map(function(row) {
|
||||
return row.OBJID;
|
||||
}).join(',');
|
||||
|
||||
// 새로 만든 거래명세서 팝업 열기
|
||||
var popup_width = 1000;
|
||||
var popup_height = 800;
|
||||
var url = "/salesMgmt/transactionStatementForm.do?projectNos=" + encodeURIComponent(projectNos);
|
||||
var url = "/salesMgmt/transactionStatementForm.do?projectNos=" + encodeURIComponent(projectNos)
|
||||
+ "&projectObjids=" + encodeURIComponent(projectObjids);
|
||||
fn_centerPopup(popup_width, popup_height, url);
|
||||
}
|
||||
|
||||
@@ -463,8 +476,9 @@ var columns = [
|
||||
cellClick: function(e, cell) {
|
||||
var data = cell.getRow().getData();
|
||||
var projectNo = data.PROJECT_NO;
|
||||
var projectObjid = data.OBJID;
|
||||
var hasStatement = data.HAS_TRANSACTION_STATEMENT === 'Y';
|
||||
if(projectNo) fn_openTransactionStatementPopup(projectNo, hasStatement);
|
||||
if(projectNo) fn_openTransactionStatementPopup(projectNo, projectObjid, hasStatement);
|
||||
}
|
||||
}
|
||||
];
|
||||
@@ -555,9 +569,9 @@ function fn_search(){
|
||||
|
||||
// 출하일 상세 내역 팝업
|
||||
// 거래명세서 팝업 열기 (단일 프로젝트)
|
||||
function fn_openTransactionStatementPopup(projectNo, hasStatement) {
|
||||
function fn_openTransactionStatementPopup(projectNo, projectObjid, hasStatement) {
|
||||
console.log("=== 거래명세서 팝업 열기 ===");
|
||||
console.log("projectNo:", projectNo);
|
||||
console.log("projectNo:", projectNo, "projectObjid:", projectObjid);
|
||||
console.log("hasStatement:", hasStatement);
|
||||
|
||||
if(!projectNo) {
|
||||
@@ -583,11 +597,11 @@ function fn_openTransactionStatementPopup(projectNo, hasStatement) {
|
||||
}
|
||||
|
||||
localStorage.setItem('transactionStatementData', JSON.stringify(projectData));
|
||||
// 파란폴더(저장된 경우)만 여기까지 도달 → DB 데이터 로드
|
||||
localStorage.setItem('loadSavedStatement', 'true');
|
||||
|
||||
// 거래명세서 팝업 열기
|
||||
var url = "/salesMgmt/transactionStatementForm.do?projectNos=" + encodeURIComponent(projectNo);
|
||||
// 거래명세서 팝업 열기 (OBJID 포함)
|
||||
var url = "/salesMgmt/transactionStatementForm.do?projectNos=" + encodeURIComponent(projectNo)
|
||||
+ "&projectObjids=" + encodeURIComponent(projectObjid);
|
||||
var popup_width = 900;
|
||||
var popup_height = 800;
|
||||
var left = (screen.width - popup_width) / 2;
|
||||
@@ -688,8 +702,13 @@ function fn_bulkRegister(){
|
||||
}
|
||||
}
|
||||
|
||||
// 판매등록 팝업 열기 (그리드 데이터 전달)
|
||||
fn_openSaleRegPopupWithData(selectedRow);
|
||||
if(selectedRow.SALES_REG_NO) {
|
||||
// 기존 판매등록 수정 모드
|
||||
fn_openSaleRegPopup(selectedRow.PROJECT_NO, selectedRow.SALES_REG_NO);
|
||||
} else {
|
||||
// 신규 판매등록
|
||||
fn_openSaleRegPopupWithData(selectedRow);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
|
||||
@@ -36,10 +36,24 @@
|
||||
// 날짜 선택기 초기화
|
||||
_fnc_datepick();
|
||||
|
||||
// 출하일: 저장된 값이 없으면 오늘 날짜 설정
|
||||
if(!$("#shippingDate").val() || $("#shippingDate").val().trim() === '') {
|
||||
var today = new Date();
|
||||
var yyyy = today.getFullYear();
|
||||
var mm = String(today.getMonth() + 1).padStart(2, '0');
|
||||
var dd = String(today.getDate()).padStart(2, '0');
|
||||
$("#shippingDate").val(yyyy + '-' + mm + '-' + dd);
|
||||
}
|
||||
|
||||
// 기존 담당자 값 설정
|
||||
var managerValue = "${saleInfo.MANAGER}";
|
||||
console.log("MANAGER 값:", managerValue);
|
||||
console.log("SHIPPING_METHOD:", "${saleInfo.SHIPPING_METHOD}");
|
||||
console.log("INCOTERMS:", "${saleInfo.INCOTERMS}");
|
||||
console.log("SERIAL_NO:", "${saleInfo.SERIAL_NO}");
|
||||
if(managerValue) {
|
||||
$("#manager").val(managerValue).trigger('change');
|
||||
console.log("담당자 설정 후 선택값:", $("#manager").val());
|
||||
}
|
||||
|
||||
// 판매환종 초기값 설정 (견적환종과 동기화)
|
||||
@@ -729,26 +743,17 @@ function fn_calculateSelectedItem() {
|
||||
<tr>
|
||||
<td class="input_title">
|
||||
<label for="salesQuantity">판매수량</label>
|
||||
<c:if test="${param.saleNo == null || param.saleNo == ''}">
|
||||
<c:if test="${true}">
|
||||
<span style="color:#666; font-size:11px; display:block; margin-top:2px;">
|
||||
(잔량: ${saleInfo.REMAINING_QUANTITY != null ? saleInfo.REMAINING_QUANTITY : saleInfo.ORDER_QUANTITY}개)
|
||||
</span>
|
||||
</c:if>
|
||||
</td>
|
||||
<td>
|
||||
<c:choose>
|
||||
<c:when test="${param.saleNo != null && param.saleNo != ''}">
|
||||
<input type="number" name="salesQuantity" id="salesQuantity"
|
||||
value="${saleInfo.SALES_QUANTITY}"
|
||||
readonly style="background-color: #f5f5f5;" />
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<input type="number" name="salesQuantity" id="salesQuantity"
|
||||
value="${saleInfo.SALES_QUANTITY != null && saleInfo.SALES_QUANTITY != '' && saleInfo.SALES_QUANTITY != 0 ? saleInfo.SALES_QUANTITY : ''}"
|
||||
onchange="fn_calculateSupplyPrice()"
|
||||
placeholder="판매할 수량 입력" />
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
<input type="number" name="salesQuantity" id="salesQuantity"
|
||||
value="${saleInfo.SALES_QUANTITY != null && saleInfo.SALES_QUANTITY != '' && saleInfo.SALES_QUANTITY != 0 ? saleInfo.SALES_QUANTITY : ''}"
|
||||
onchange="fn_calculateSupplyPrice()"
|
||||
placeholder="판매할 수량 입력" />
|
||||
</td>
|
||||
<td class="input_title"><label for="shippingDate">출하일</label></td>
|
||||
<td>
|
||||
|
||||
@@ -58,7 +58,7 @@ body {
|
||||
|
||||
.info-table td {
|
||||
border: 1px solid #000;
|
||||
padding: 6px 10px;
|
||||
padding: 6px 8px;
|
||||
font-size: 9pt;
|
||||
vertical-align: middle;
|
||||
}
|
||||
@@ -386,6 +386,43 @@ body {
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
/* 좌우 테두리 겹침 방지 (container 2px + cell 1px = 3px 문제 해결) */
|
||||
.info-table td.date-label-cell,
|
||||
.info-table td.receiver-cell,
|
||||
.info-table td.supply-text-cell {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.info-table tr > td:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.info-table tr:first-child > td {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.items-table tr > th:first-child,
|
||||
.items-table tr > td:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.items-table tr > th:last-child,
|
||||
.items-table tr > td:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.items-table thead tr:first-child > th {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.footer-table tr > td:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.footer-table tr > td:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
/* 버튼 */
|
||||
.button-area {
|
||||
text-align: center;
|
||||
@@ -416,7 +453,7 @@ body {
|
||||
$(document).ready(function(){
|
||||
var today = new Date();
|
||||
var days = ['일', '월', '화', '수', '목', '금', '토'];
|
||||
var dateStr = days[today.getDay()] + "요일, " + (today.getMonth() + 1) + "월 " + today.getDate() + ", " + today.getFullYear();
|
||||
var dateStr = today.getFullYear() + "년 " + (today.getMonth() + 1) + "월 " + today.getDate() + "일 " + days[today.getDay()] + "요일";
|
||||
|
||||
// 표시용 날짜 (한글)
|
||||
$("#deliveryDate").text(dateStr);
|
||||
@@ -435,12 +472,12 @@ $(document).ready(function(){
|
||||
var dateText = $(this).text().trim();
|
||||
// 날짜 파싱 시도
|
||||
try {
|
||||
// "목요일, 11월 15, 2025" 형식 파싱
|
||||
var match = dateText.match(/(\d+)월\s*(\d+),?\s*(\d{4})/);
|
||||
// "2025년 3월 5일 수요일" 형식 파싱
|
||||
var match = dateText.match(/(\d{4})년\s*(\d+)월\s*(\d+)일/);
|
||||
if (match) {
|
||||
var year = match[3];
|
||||
var month = String(match[1]).padStart(2, '0');
|
||||
var day = String(match[2]).padStart(2, '0');
|
||||
var year = match[1];
|
||||
var month = String(match[2]).padStart(2, '0');
|
||||
var day = String(match[3]).padStart(2, '0');
|
||||
var isoDate = year + "-" + month + "-" + day;
|
||||
$("#deliveryDateISO").val(isoDate);
|
||||
console.log("날짜 업데이트: " + dateText + " → " + isoDate);
|
||||
@@ -469,8 +506,10 @@ function fn_loadData() {
|
||||
console.log("저장된 데이터 불러오기:", loadSaved);
|
||||
|
||||
if(loadSaved && gridData.length > 0) {
|
||||
// 저장된 거래명세서 불러오기
|
||||
fn_loadSavedStatement(gridData[0].PROJECT_NO, gridData);
|
||||
// 저장된 거래명세서 불러오기 (OBJID 기반 조회)
|
||||
var objid = fnc_checkNull("${param.projectObjids}").split(",")[0];
|
||||
if(!objid) objid = gridData[0].OBJID;
|
||||
fn_loadSavedStatement(objid, gridData);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -565,14 +604,14 @@ function fn_loadEmptyStatement(gridData) {
|
||||
}
|
||||
|
||||
// 저장된 거래명세서 불러오기
|
||||
function fn_loadSavedStatement(projectNo, gridData) {
|
||||
function fn_loadSavedStatement(projectObjid, gridData) {
|
||||
console.log("=== 저장된 거래명세서 불러오기 ===");
|
||||
console.log("projectNo:", projectNo);
|
||||
|
||||
console.log("projectObjid:", projectObjid);
|
||||
|
||||
$.ajax({
|
||||
url: '/salesMgmt/getSavedTransactionStatement.do',
|
||||
type: 'POST',
|
||||
data: { projectNo: projectNo },
|
||||
data: { projectObjid: projectObjid },
|
||||
success: function(response) {
|
||||
if(response.success && response.data && response.data.length > 0) {
|
||||
console.log("저장된 데이터:", response.data);
|
||||
@@ -603,8 +642,8 @@ function fn_loadSavedStatement(projectNo, gridData) {
|
||||
totalVat += vat;
|
||||
|
||||
var row = $("<tr>");
|
||||
row.append($("<td contenteditable='true' class='text-left'>").text(item.imitemid || item.IMITEMID || ""));
|
||||
row.append($("<td contenteditable='true'>").text(item.prodcd || item.PRODCD || ""));
|
||||
row.append($("<td contenteditable='true' class='text-left'>").text(item.prodcd || item.PRODCD || ""));
|
||||
row.append($("<td contenteditable='true'>").text(item.imitemid || item.IMITEMID || ""));
|
||||
row.append($("<td contenteditable='true'>").text(quantity));
|
||||
row.append($("<td contenteditable='true' class='text-right'>").text(fn_num(item.isprice || item.ISPRICE || 0)));
|
||||
row.append($("<td contenteditable='true' class='text-right'>").text(fn_num(supply)));
|
||||
@@ -755,8 +794,8 @@ function fn_fillData(data) {
|
||||
totalVat += vat;
|
||||
|
||||
var row = $("<tr>");
|
||||
row.append($("<td contenteditable='true' class='text-left'>").text(item.PRODUCTNAME || item.productName || ""));
|
||||
row.append($("<td contenteditable='true'>").text(item.SPEC || item.spec || ""));
|
||||
row.append($("<td contenteditable='true' class='text-left'>").html(" "));
|
||||
row.append($("<td contenteditable='true'>").text(item.PRODUCTNAME || item.productName || ""));
|
||||
row.append($("<td contenteditable='true'>").text(quantity));
|
||||
row.append($("<td contenteditable='true' class='text-right'>").text(fn_num(item.UNITPRICE || item.unitPrice || 0)));
|
||||
row.append($("<td contenteditable='true' class='text-right'>").text(fn_num(supply)));
|
||||
@@ -913,6 +952,7 @@ function fn_save() {
|
||||
// 수정된 데이터 수집
|
||||
var data = {
|
||||
projectNos: "${param.projectNos}",
|
||||
projectObjids: "${param.projectObjids}",
|
||||
deliveryDate: $("#deliveryDateISO").val(),
|
||||
receiverName: $("#receiverName").text(),
|
||||
registrationNo: $("#registrationNo").text(),
|
||||
@@ -1000,7 +1040,7 @@ function fn_close() {
|
||||
<tr class="row-1">
|
||||
<td class="date-label-cell">납품일</td>
|
||||
<td class="date-value-cell" colspan="4">
|
||||
<span id="deliveryDate" contenteditable="true">수요일, 9월 24, 2025</span>
|
||||
<span id="deliveryDate" contenteditable="true">2025년 3월 5일 수요일</span>
|
||||
<input type="hidden" id="deliveryDateISO" value="">
|
||||
</td>
|
||||
<td class="supplier-label-cell" rowspan="5">
|
||||
@@ -1060,7 +1100,7 @@ function fn_close() {
|
||||
</td>
|
||||
<td class="supplier-field-label">전화 번호</td>
|
||||
<td class="supplier-field-value" colspan="4">
|
||||
<span contenteditable="true" id="supplierTel">TEL:042-602-3300 / FAX:042-672</span>
|
||||
<span contenteditable="true" id="supplierTel">TEL:042-602-3300 / FAX:042-672-3399</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
80
src/com/pms/common/utils/SerialNoSyncUtil.java
Normal file
80
src/com/pms/common/utils/SerialNoSyncUtil.java
Normal file
@@ -0,0 +1,80 @@
|
||||
package com.pms.common.utils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.ibatis.session.SqlSession;
|
||||
|
||||
/**
|
||||
* S/N 동기화 유틸리티
|
||||
* - 모든 화면에서 S/N 저장 시 CONTRACT_ITEM_SERIAL(마스터)에 동기화
|
||||
* - 프로젝트 연결이 없는 경우(독립 생산계획 등)는 동기화 skip
|
||||
*/
|
||||
public class SerialNoSyncUtil {
|
||||
|
||||
/**
|
||||
* S/N 텍스트를 파싱하여 CONTRACT_ITEM_SERIAL 테이블에 동기화
|
||||
*
|
||||
* @param sqlSession 현재 트랜잭션의 SqlSession
|
||||
* @param projectNo 프로젝트번호 (PROJECT_MGMT.PROJECT_NO)
|
||||
* @param serialNoText 쉼표 구분 S/N 문자열 (예: "SN001, SN002, SN003")
|
||||
* @param writer 작성자 ID
|
||||
*/
|
||||
public static void syncSerialToContractItemSerial(
|
||||
SqlSession sqlSession, String projectNo, String serialNoText, String writer) {
|
||||
|
||||
if (projectNo == null || projectNo.trim().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 프로젝트번호로 CONTRACT_ITEM 조회
|
||||
Map<String, Object> param = new HashMap<String, Object>();
|
||||
param.put("projectNo", projectNo);
|
||||
|
||||
Map<String, Object> contractItem = sqlSession.selectOne(
|
||||
"contractMgmt.getContractItemByProject", param);
|
||||
|
||||
if (contractItem == null) {
|
||||
// CONTRACT_ITEM이 없으면 동기화 불가 (프로젝트-계약 연결 없음)
|
||||
return;
|
||||
}
|
||||
|
||||
String itemObjId = String.valueOf(contractItem.get("item_objid"));
|
||||
if (itemObjId == null || "null".equals(itemObjId) || itemObjId.trim().isEmpty()) {
|
||||
itemObjId = String.valueOf(contractItem.get("ITEM_OBJID"));
|
||||
}
|
||||
if (itemObjId == null || "null".equals(itemObjId) || itemObjId.trim().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 기존 S/N 비활성화
|
||||
Map<String, Object> deleteParam = new HashMap<String, Object>();
|
||||
deleteParam.put("itemObjId", itemObjId);
|
||||
sqlSession.update("contractMgmt.deleteItemSerials", deleteParam);
|
||||
|
||||
// 3. 새 S/N 삽입
|
||||
if (serialNoText == null || serialNoText.trim().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String[] serialNumbers = serialNoText.split(",");
|
||||
int seq = 1;
|
||||
|
||||
for (String sn : serialNumbers) {
|
||||
String trimmedSn = sn.trim();
|
||||
if (trimmedSn.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Map<String, Object> insertParam = new HashMap<String, Object>();
|
||||
insertParam.put("objId", CommonUtils.createObjId());
|
||||
insertParam.put("itemObjId", itemObjId);
|
||||
insertParam.put("seq", seq);
|
||||
insertParam.put("serialNo", trimmedSn);
|
||||
insertParam.put("writer", writer);
|
||||
|
||||
sqlSession.insert("contractMgmt.insertContractItemSerial", insertParam);
|
||||
seq++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4776,7 +4776,17 @@
|
||||
PP.REQ_DEL_DATE,
|
||||
PP.PART_NO,
|
||||
PP.PART_NAME,
|
||||
PP.SERIAL_NO,
|
||||
-- S/N: CONTRACT_ITEM_SERIAL(마스터) 우선, 없으면 PRODUCTION_PLAN 텍스트 fallback
|
||||
COALESCE(
|
||||
(SELECT STRING_AGG(CIS.SERIAL_NO, ', ' ORDER BY CIS.SERIAL_NO)
|
||||
FROM PROJECT_MGMT PM
|
||||
JOIN CONTRACT_ITEM CI ON CI.CONTRACT_OBJID = PM.CONTRACT_OBJID
|
||||
AND CI.PART_OBJID = PM.PART_OBJID AND CI.STATUS = 'ACTIVE'
|
||||
JOIN CONTRACT_ITEM_SERIAL CIS ON CIS.ITEM_OBJID = CI.OBJID
|
||||
AND UPPER(CIS.STATUS) = 'ACTIVE' AND CIS.SERIAL_NO IS NOT NULL
|
||||
WHERE PM.OBJID::VARCHAR = PP.PROJECT_OBJID),
|
||||
PP.SERIAL_NO
|
||||
) AS SERIAL_NO,
|
||||
PP.ORDER_QTY,
|
||||
PP.EXTRA_PROD_QTY,
|
||||
PP.TOTAL_PROD_QTY,
|
||||
|
||||
@@ -352,25 +352,25 @@ public class SalesNcollectMgmtController {
|
||||
return "/salesmgmt/salesMgmt/projectDetailView";
|
||||
}
|
||||
}
|
||||
// saleNo가 있지만 "detail"이 아니면 프로젝트 기본 정보 조회 모드
|
||||
// saleNo가 있지만 "detail"이 아니면 판매등록 수정 모드 - getSaleInfo로 S/N 포함 조회
|
||||
else if(paramMap.get("saleNo") != null && !paramMap.get("saleNo").equals("")) {
|
||||
System.out.println("=== 프로젝트 기본 정보 조회 모드 ===");
|
||||
Map<String, Object> orderDataParam = new HashMap<String, Object>();
|
||||
orderDataParam.put("orderNo", paramMap.get("orderNo"));
|
||||
saleInfo = salesNcollectMgmtService.getOrderDataByOrderNo(orderDataParam);
|
||||
System.out.println("=== 판매등록 수정 모드 ===");
|
||||
Map<String, Object> saleInfoParam = new HashMap<String, Object>();
|
||||
saleInfoParam.put("orderNo", paramMap.get("orderNo"));
|
||||
saleInfoParam.put("saleNo", paramMap.get("saleNo"));
|
||||
saleInfo = salesNcollectMgmtService.getSaleInfo(saleInfoParam);
|
||||
|
||||
if(saleInfo != null) {
|
||||
salesCurrency = CommonUtils.nullToEmpty((String)saleInfo.get("SALES_CURRENCY"));
|
||||
saleInfo.put("ORDER_QUANTITY", saleInfo.get("SALES_QUANTITY"));
|
||||
|
||||
Map<String, Object> shipmentParam = new HashMap<String, Object>();
|
||||
shipmentParam.put("projectNo", paramMap.get("orderNo"));
|
||||
Integer totalShipped = salesNcollectMgmtService.getTotalShippedQuantity(shipmentParam);
|
||||
saleInfo.put("SALES_QUANTITY", totalShipped != null ? totalShipped : 0);
|
||||
|
||||
System.out.println("=== 프로젝트 기본 정보 조회 완료 ===");
|
||||
System.out.println("ORDER_QUANTITY (수주수량): " + saleInfo.get("ORDER_QUANTITY"));
|
||||
System.out.println("SALES_QUANTITY (총 판매수량): " + saleInfo.get("SALES_QUANTITY"));
|
||||
System.out.println("=== 판매등록 수정 모드 조회 완료 ===");
|
||||
System.out.println("SALE_NO: " + saleInfo.get("SALE_NO"));
|
||||
System.out.println("ORDER_QUANTITY: " + saleInfo.get("ORDER_QUANTITY"));
|
||||
System.out.println("SALES_QUANTITY: " + saleInfo.get("SALES_QUANTITY"));
|
||||
System.out.println("SERIAL_NO: " + saleInfo.get("SERIAL_NO"));
|
||||
System.out.println("MANAGER: " + saleInfo.get("MANAGER"));
|
||||
System.out.println("INCOTERMS: " + saleInfo.get("INCOTERMS"));
|
||||
System.out.println("SHIPPING_METHOD: " + saleInfo.get("SHIPPING_METHOD"));
|
||||
}
|
||||
}
|
||||
// saleNo가 없으면 신규 판매 등록 모드 -> 수주 데이터만 조회
|
||||
@@ -430,6 +430,20 @@ public class SalesNcollectMgmtController {
|
||||
request.setAttribute("orderInfo", saleInfo);
|
||||
}
|
||||
|
||||
// 수정 모드: saleInfo에서 담당자 선택값 반영
|
||||
if(saleInfo != null && saleInfo.get("MANAGER") != null) {
|
||||
String selectedManager = saleInfo.get("MANAGER").toString();
|
||||
System.out.println("=== 담당자 선택값 반영 ===");
|
||||
System.out.println("selectedManager: [" + selectedManager + "]");
|
||||
codeMap.put("managerList", commonService.bizMakeOptionList("", selectedManager, "common.getUserselect"));
|
||||
} else {
|
||||
System.out.println("=== 담당자 선택값 없음 ===");
|
||||
System.out.println("saleInfo null: " + (saleInfo == null));
|
||||
if(saleInfo != null) {
|
||||
System.out.println("MANAGER value: " + saleInfo.get("MANAGER"));
|
||||
}
|
||||
}
|
||||
|
||||
// 환종(통화) - 공통코드 0001533
|
||||
codeMap.put("salesCurrency",
|
||||
commonService.bizMakeOptionList("0001533", salesCurrency, "common.getCodeselect"));
|
||||
|
||||
@@ -5685,12 +5685,11 @@ WHERE
|
||||
WHERE OBJID = #{itemObjId}
|
||||
</update>
|
||||
|
||||
<!-- 특정 품목의 S/N 전체 삭제 -->
|
||||
<update id="deleteItemSerials" parameterType="map">
|
||||
UPDATE CONTRACT_ITEM_SERIAL
|
||||
SET STATUS = 'INACTIVE'
|
||||
<!-- 특정 품목의 S/N 전체 삭제 (hard delete: 유니크 제약조건 충돌 방지) -->
|
||||
<delete id="deleteItemSerials" parameterType="map">
|
||||
DELETE FROM CONTRACT_ITEM_SERIAL
|
||||
WHERE ITEM_OBJID = #{itemObjId}
|
||||
</update>
|
||||
</delete>
|
||||
|
||||
<!-- 고객사 담당자 정보 조회 -->
|
||||
<select id="getCustomerContactInfo" parameterType="map" resultType="map">
|
||||
@@ -5875,4 +5874,16 @@ WHERE
|
||||
ORDER BY CI.SEQ
|
||||
</select>
|
||||
|
||||
<!-- 프로젝트번호 또는 OBJID로 CONTRACT_ITEM 조회 (S/N 동기화용) -->
|
||||
<select id="getContractItemByProject" parameterType="map" resultType="map">
|
||||
SELECT CI.OBJID AS ITEM_OBJID
|
||||
FROM PROJECT_MGMT PM
|
||||
JOIN CONTRACT_ITEM CI
|
||||
ON CI.CONTRACT_OBJID = PM.CONTRACT_OBJID
|
||||
AND CI.PART_OBJID = PM.PART_OBJID
|
||||
AND CI.STATUS = 'ACTIVE'
|
||||
WHERE (PM.PROJECT_NO = #{projectNo} OR PM.OBJID::VARCHAR = #{projectNo})
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -844,19 +844,22 @@
|
||||
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: 해당 품목의 시리얼 번호 (여러 개일 경우 "S/N 외 N건" 형식)
|
||||
(SELECT
|
||||
CASE
|
||||
WHEN COUNT(*) = 0 THEN ''
|
||||
WHEN COUNT(*) = 1 THEN MIN(CIS.SERIAL_NO)
|
||||
ELSE MIN(CIS.SERIAL_NO) || ' 외 ' || (COUNT(*) - 1)::TEXT || '건'
|
||||
END
|
||||
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
|
||||
AND CI.PART_OBJID = T.PART_OBJID
|
||||
AND CI.STATUS = 'ACTIVE'
|
||||
AND CIS.SERIAL_NO IS NOT NULL) AS SERIAL_NO,
|
||||
-- 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
|
||||
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
|
||||
AND CI.PART_OBJID = T.PART_OBJID
|
||||
AND CI.STATUS = 'ACTIVE'
|
||||
AND CIS.SERIAL_NO IS NOT NULL),
|
||||
SR.serial_no
|
||||
) AS SERIAL_NO,
|
||||
COALESCE(T.QUANTITY::numeric, 0) AS ORDER_QUANTITY,
|
||||
-- 요청납기: CONTRACT_ITEM 우선, 없으면 PROJECT_MGMT, 없으면 CONTRACT_MGMT
|
||||
COALESCE(
|
||||
@@ -893,20 +896,10 @@
|
||||
COALESCE(SR.sales_vat, 0) AS SALES_VAT,
|
||||
COALESCE(SR.sales_total_amount, 0) AS SALES_TOTAL_AMOUNT,
|
||||
COALESCE(SR.sales_total_amount, 0) AS SALES_TOTAL_AMOUNT_KRW,
|
||||
-- 잔량 계산: 수주수량 - shipment_log의 split_quantity 합계
|
||||
COALESCE(T.QUANTITY::numeric, 0) - COALESCE(
|
||||
(SELECT SUM(COALESCE(split_quantity, 0))
|
||||
FROM shipment_log
|
||||
WHERE target_objid = T.PROJECT_NO),
|
||||
0
|
||||
) AS REMAINING_QUANTITY,
|
||||
-- 잔량원화총액 계산: (수주수량 - shipment_log 합계) * 판매단가
|
||||
(COALESCE(T.QUANTITY::numeric, 0) - COALESCE(
|
||||
(SELECT SUM(COALESCE(split_quantity, 0))
|
||||
FROM shipment_log
|
||||
WHERE target_objid = T.PROJECT_NO),
|
||||
0
|
||||
)) * COALESCE(SR.sales_unit_price, 0) AS REMAINING_AMOUNT_KRW,
|
||||
-- 잔량 계산: 수주수량 - sales_registration.sales_quantity
|
||||
COALESCE(T.QUANTITY::numeric, 0) - COALESCE(SR.sales_quantity, 0) AS REMAINING_QUANTITY,
|
||||
-- 잔량원화총액 계산: 잔량 * 판매단가
|
||||
(COALESCE(T.QUANTITY::numeric, 0) - COALESCE(SR.sales_quantity, 0)) * COALESCE(SR.sales_unit_price, 0) AS REMAINING_AMOUNT_KRW,
|
||||
COALESCE(SR.sales_currency, T.CONTRACT_CURRENCY) AS SALES_CURRENCY,
|
||||
CODE_NAME(COALESCE(SR.sales_currency, T.CONTRACT_CURRENCY)) AS SALES_CURRENCY_NAME,
|
||||
COALESCE(SR.sales_exchange_rate, T.CONTRACT_PRICE_CURRENCY::numeric, 0) AS SALES_EXCHANGE_RATE,
|
||||
@@ -942,13 +935,14 @@
|
||||
THEN '분할판매'
|
||||
ELSE ''
|
||||
END AS SALES_STATUS,
|
||||
SR.sale_no AS SALES_REG_NO,
|
||||
T.OBJID::VARCHAR AS SALE_NO,
|
||||
'ORIGINAL' AS RECORD_TYPE,
|
||||
'' AS SPLIT_LOG_ID,
|
||||
-- 거래명세서 존재 여부
|
||||
-- 거래명세서 존재 여부 (LinkedProjectObjids에 해당 프로젝트 OBJID 포함 여부)
|
||||
CASE WHEN EXISTS(
|
||||
SELECT 1 FROM NSWOS100_TBL
|
||||
WHERE OdOrderNo = T.PROJECT_NO
|
||||
SELECT 1 FROM NSWOS100_TBL
|
||||
WHERE T.OBJID::VARCHAR = ANY(STRING_TO_ARRAY(LinkedProjectObjids, ','))
|
||||
) THEN 'Y' ELSE 'N' END AS HAS_TRANSACTION_STATEMENT
|
||||
FROM PROJECT_MGMT AS T
|
||||
LEFT JOIN sales_registration SR ON T.PROJECT_NO = SR.project_no
|
||||
@@ -1346,7 +1340,18 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
AND T.CUSTOMER_OBJID = #{customer_objid}
|
||||
</if>
|
||||
<if test="serialNo != null and serialNo != ''">
|
||||
AND SR.serial_no LIKE '%' || #{serialNo} || '%'
|
||||
AND (
|
||||
EXISTS (
|
||||
SELECT 1 FROM CONTRACT_ITEM CI
|
||||
JOIN CONTRACT_ITEM_SERIAL CIS ON CI.OBJID = CIS.ITEM_OBJID
|
||||
WHERE CI.CONTRACT_OBJID = T.CONTRACT_OBJID
|
||||
AND CI.PART_OBJID = T.PART_OBJID
|
||||
AND CI.STATUS = 'ACTIVE'
|
||||
AND UPPER(CIS.STATUS) = 'ACTIVE'
|
||||
AND UPPER(CIS.SERIAL_NO) LIKE UPPER('%' || #{serialNo} || '%')
|
||||
)
|
||||
OR SR.serial_no LIKE '%' || #{serialNo} || '%'
|
||||
)
|
||||
</if>
|
||||
<if test="poNo != null and poNo != ''">
|
||||
AND EXISTS (SELECT 1 FROM CONTRACT_MGMT CM WHERE CM.OBJID = T.CONTRACT_OBJID AND CM.PO_NO LIKE '%' || #{poNo} || '%')
|
||||
@@ -1550,19 +1555,17 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
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: 해당 품목의 시리얼 번호 (여러 개일 경우 "S/N 외 N건" 형식)
|
||||
(SELECT
|
||||
CASE
|
||||
WHEN COUNT(*) = 0 THEN ''
|
||||
WHEN COUNT(*) = 1 THEN MIN(CIS.SERIAL_NO)
|
||||
ELSE MIN(CIS.SERIAL_NO) || ' 외 ' || (COUNT(*) - 1)::TEXT || '건'
|
||||
END
|
||||
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
|
||||
AND CI.PART_OBJID = T.PART_OBJID
|
||||
AND CI.STATUS = 'ACTIVE'
|
||||
AND CIS.SERIAL_NO IS NOT NULL) AS SERIAL_NO,
|
||||
-- S/N: CONTRACT_ITEM_SERIAL(마스터) 우선, 전체 콤마 리스트 (판매등록 폼 파싱용)
|
||||
COALESCE(
|
||||
(SELECT STRING_AGG(CIS.SERIAL_NO, ', ' ORDER BY CIS.SERIAL_NO)
|
||||
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
|
||||
AND CI.PART_OBJID = T.PART_OBJID
|
||||
AND CI.STATUS = 'ACTIVE'
|
||||
AND CIS.SERIAL_NO IS NOT NULL),
|
||||
SR.serial_no
|
||||
) AS SERIAL_NO,
|
||||
COALESCE(T.QUANTITY::numeric, 0) AS ORDER_QUANTITY,
|
||||
-- 요청납기: CONTRACT_ITEM 우선, 없으면 PROJECT_MGMT, 없으면 CONTRACT_MGMT
|
||||
COALESCE(
|
||||
@@ -1648,8 +1651,8 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
CODE_NAME(CM.CONTRACT_CURRENCY) AS SALES_CURRENCY_NAME,
|
||||
COALESCE(CM.EXCHANGE_RATE::NUMERIC, 0) AS SALES_EXCHANGE_RATE,
|
||||
|
||||
-- 수주 날짜 - VARCHAR 타입이므로 그대로 사용
|
||||
CM.ORDER_DATE AS SHIPPING_DATE,
|
||||
-- 출하일 기본값: 오늘 날짜
|
||||
TO_CHAR(CURRENT_DATE, 'YYYY-MM-DD') AS SHIPPING_DATE,
|
||||
|
||||
-- 담당자
|
||||
CM.PM_USER_ID AS MANAGER
|
||||
@@ -1662,7 +1665,6 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
CM.OBJID,
|
||||
CM.CONTRACT_CURRENCY,
|
||||
CM.EXCHANGE_RATE,
|
||||
CM.ORDER_DATE,
|
||||
CM.PM_USER_ID
|
||||
</select>
|
||||
|
||||
@@ -1696,8 +1698,8 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
CODE_NAME(CM.CONTRACT_CURRENCY) AS SALES_CURRENCY_NAME,
|
||||
COALESCE(NULLIF(CM.EXCHANGE_RATE, '')::NUMERIC, 0) AS SALES_EXCHANGE_RATE,
|
||||
|
||||
-- 수주 날짜 - VARCHAR 타입이므로 그대로 사용
|
||||
CM.ORDER_DATE AS SHIPPING_DATE,
|
||||
-- 출하일 기본값: 오늘 날짜
|
||||
TO_CHAR(CURRENT_DATE, 'YYYY-MM-DD') AS SHIPPING_DATE,
|
||||
|
||||
-- 담당자
|
||||
CM.PM_USER_ID AS MANAGER
|
||||
@@ -1711,7 +1713,6 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
CM.OBJID,
|
||||
CM.CONTRACT_CURRENCY,
|
||||
CM.EXCHANGE_RATE,
|
||||
CM.ORDER_DATE,
|
||||
CM.PM_USER_ID,
|
||||
PM.QUANTITY
|
||||
</select>
|
||||
@@ -1920,6 +1921,30 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
WHERE target_objid = #{projectNo}
|
||||
),
|
||||
shipping_order_status = '출하지시'
|
||||
<if test="managerUserId != null and managerUserId != ''">
|
||||
, manager_user_id = #{managerUserId}
|
||||
</if>
|
||||
<if test="incoterms != null and incoterms != ''">
|
||||
, incoterms = #{incoterms}
|
||||
</if>
|
||||
<if test="serialNo != null and serialNo != ''">
|
||||
, serial_no = #{serialNo}
|
||||
</if>
|
||||
<if test="shippingMethod != null and shippingMethod != ''">
|
||||
, shipping_method = #{shippingMethod}
|
||||
</if>
|
||||
<if test="shippingDate != null and shippingDate != ''">
|
||||
, shipping_date = TO_DATE(#{shippingDate}, 'YYYY-MM-DD')
|
||||
</if>
|
||||
<if test="salesUnitPrice != null and salesUnitPrice != ''">
|
||||
, sales_unit_price = #{salesUnitPrice}::numeric
|
||||
</if>
|
||||
<if test="salesCurrency != null and salesCurrency != ''">
|
||||
, sales_currency = #{salesCurrency}
|
||||
</if>
|
||||
<if test="salesExchangeRate != null and salesExchangeRate != ''">
|
||||
, sales_exchange_rate = #{salesExchangeRate}::numeric
|
||||
</if>
|
||||
WHERE sale_no = #{saleNo}
|
||||
</update>
|
||||
|
||||
@@ -1976,7 +2001,7 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
WHERE PM.PROJECT_NO = #{projectNo}
|
||||
</select>
|
||||
|
||||
<!-- 거래명세서 저장 - NSWOS100_TBL 테이블 사용 -->
|
||||
<!-- 거래명세서 저장 - NSWOS100_TBL 테이블 사용 (ON CONFLICT DO UPDATE) -->
|
||||
<insert id="saveTransactionStatement" parameterType="map">
|
||||
/* salesNcollectMgmt.saveTransactionStatement - 거래명세서 저장 */
|
||||
INSERT INTO NSWOS100_TBL (
|
||||
@@ -1995,6 +2020,7 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
,IsQty /* 납품수량 */
|
||||
,IsPrice /* 납품단가 */
|
||||
,IsAmount /* 납품금액 */
|
||||
,LinkedProjectObjids /* 연결된 프로젝트 OBJID 목록 */
|
||||
) VALUES (
|
||||
#{suVndCd} /* 업체코드 */
|
||||
,#{issueDt} /* 작성일자 */
|
||||
@@ -2011,6 +2037,7 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
,COALESCE(#{isQty}, 0)::integer /* 납품수량 */
|
||||
,COALESCE(#{isPrice}, 0)::numeric /* 납품단가 */
|
||||
,COALESCE(#{isAmount}, 0)::numeric /* 납품금액 */
|
||||
,#{linkedProjectObjids} /* 연결된 프로젝트 OBJID 목록 */
|
||||
) ON CONFLICT (SuVndCd, IssueDt, IssueNo, IsNo) DO
|
||||
UPDATE SET
|
||||
ProdCd = COALESCE(#{prodCd}, '')
|
||||
@@ -2024,6 +2051,7 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
,IsQty = COALESCE(#{isQty}, 0)::integer
|
||||
,IsPrice = COALESCE(#{isPrice}, 0)::numeric
|
||||
,IsAmount = COALESCE(#{isAmount}, 0)::numeric
|
||||
,LinkedProjectObjids = #{linkedProjectObjids}
|
||||
</insert>
|
||||
|
||||
<!-- 거래명세서 번호 생성 -->
|
||||
@@ -2051,7 +2079,7 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
|
||||
<select id="getSavedTransactionStatement" parameterType="map" resultType="map">
|
||||
/* salesNcollectMgmt.getSavedTransactionStatement - 저장된 거래명세서 조회 */
|
||||
SELECT
|
||||
SELECT
|
||||
SuVndCd,
|
||||
IssueDt,
|
||||
IssueNo,
|
||||
@@ -2066,9 +2094,10 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
|
||||
IsDt,
|
||||
IsQty,
|
||||
IsPrice,
|
||||
IsAmount
|
||||
IsAmount,
|
||||
LinkedProjectObjids
|
||||
FROM NSWOS100_TBL
|
||||
WHERE OdOrderNo = #{projectNo}
|
||||
WHERE #{projectObjid} = ANY(STRING_TO_ARRAY(LinkedProjectObjids, ','))
|
||||
ORDER BY IsNo
|
||||
</select>
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.pms.common.SqlMapConfig;
|
||||
import com.pms.common.bean.PersonBean;
|
||||
import com.pms.common.utils.CommonUtils;
|
||||
import com.pms.common.utils.Constants;
|
||||
import com.pms.common.utils.SerialNoSyncUtil;
|
||||
import com.pms.api.SalesSlipApiClient;
|
||||
|
||||
/**
|
||||
@@ -367,100 +368,70 @@ public Map<String, Object> saveSaleRegistration(HttpServletRequest request, Map<
|
||||
}
|
||||
|
||||
System.out.println("serialNo: " + paramMap.get("serialNo"));
|
||||
System.out.println("manager → managerUserId: " + paramMap.get("managerUserId"));
|
||||
System.out.println("manager: " + paramMap.get("manager"));
|
||||
|
||||
// 모든 판매를 shipment_log에 기록 (분할 출하 방식 통일)
|
||||
// 1. 해당 프로젝트의 sales_registration 레코드 확인
|
||||
Map<String, Object> checkParam = new HashMap<String, Object>();
|
||||
checkParam.put("orderNo", projectNo);
|
||||
Map<String, Object> existingSale = sqlSession.selectOne("salesNcollectMgmt.getSaleInfo", checkParam);
|
||||
|
||||
Object saleNoObj = null;
|
||||
if(existingSale != null) {
|
||||
saleNoObj = existingSale.get("SALE_NO");
|
||||
if(saleNoObj == null) saleNoObj = existingSale.get("sale_no");
|
||||
}
|
||||
|
||||
System.out.println("existingSale: " + (existingSale != null ? "있음" : "없음"));
|
||||
System.out.println("SALE_NO: " + saleNoObj);
|
||||
|
||||
// 2. sales_registration 레코드가 없으면 먼저 생성
|
||||
if(saleNoObj == null) {
|
||||
System.out.println("sales_registration 레코드 생성 (첫 판매)");
|
||||
// saleNo가 있으면 수정 모드 → sales_registration 직접 UPDATE
|
||||
if(saleNo != null && !"".equals(saleNo)) {
|
||||
System.out.println("=== 수정 모드: updateSaleRegistration ===");
|
||||
paramMap.put("shippingOrderStatus", "출하지시");
|
||||
sqlSession.update("salesNcollectMgmt.updateSaleRegistration", paramMap);
|
||||
} else {
|
||||
// 신규 등록 모드
|
||||
System.out.println("=== 신규 등록 모드 ===");
|
||||
|
||||
// sales_registration에 기본 레코드 INSERT (수량은 0으로)
|
||||
Map<String, Object> baseRecord = new HashMap<String, Object>();
|
||||
baseRecord.put("orderNo", projectNo);
|
||||
baseRecord.put("salesQuantity", 0); // 기본 레코드는 수량 0
|
||||
baseRecord.put("salesUnitPrice", paramMap.get("salesUnitPrice"));
|
||||
baseRecord.put("salesSupplyPrice", 0);
|
||||
baseRecord.put("salesVat", 0);
|
||||
baseRecord.put("salesTotalAmount", 0);
|
||||
baseRecord.put("salesCurrency", paramMap.get("salesCurrency"));
|
||||
baseRecord.put("salesExchangeRate", paramMap.get("salesExchangeRate"));
|
||||
baseRecord.put("shippingDate", paramMap.get("shippingDate"));
|
||||
baseRecord.put("shippingMethod", paramMap.get("shippingMethod"));
|
||||
baseRecord.put("managerUserId", paramMap.get("managerUserId")); // 위에서 manager → managerUserId 매핑됨
|
||||
baseRecord.put("incoterms", paramMap.get("incoterms"));
|
||||
baseRecord.put("serialNo", paramMap.get("serialNo"));
|
||||
System.out.println("insertSaleRegistration - serialNo: " + paramMap.get("serialNo"));
|
||||
baseRecord.put("shippingOrderStatus", "출하지시"); // 자동으로 출하지시 상태 설정
|
||||
baseRecord.put("cretEmpNo", paramMap.get("cretEmpNo"));
|
||||
// 1. 해당 프로젝트의 sales_registration 레코드 확인
|
||||
Map<String, Object> checkParam = new HashMap<String, Object>();
|
||||
checkParam.put("orderNo", projectNo);
|
||||
Map<String, Object> existingSale = sqlSession.selectOne("salesNcollectMgmt.getSaleInfo", checkParam);
|
||||
|
||||
sqlSession.insert("salesNcollectMgmt.insertSaleRegistration", baseRecord);
|
||||
|
||||
// 생성된 sale_no 조회
|
||||
existingSale = sqlSession.selectOne("salesNcollectMgmt.getSaleInfo", checkParam);
|
||||
saleNoObj = existingSale.get("SALE_NO");
|
||||
if(saleNoObj == null) saleNoObj = existingSale.get("sale_no");
|
||||
|
||||
System.out.println("생성된 SALE_NO: " + saleNoObj);
|
||||
}
|
||||
|
||||
// 3. shipment_log에 판매 기록 INSERT
|
||||
System.out.println("shipment_log에 판매 기록 INSERT");
|
||||
|
||||
Object orderQtyObj = existingSale.get("ORDER_QUANTITY");
|
||||
if(orderQtyObj == null) orderQtyObj = existingSale.get("order_quantity");
|
||||
|
||||
System.out.println("ORDER_QUANTITY: " + orderQtyObj);
|
||||
|
||||
if(orderQtyObj == null || saleNoObj == null) {
|
||||
System.out.println("=== existingSale 전체 내용 ===");
|
||||
for(Object key : existingSale.keySet()) {
|
||||
System.out.println(key + ": " + existingSale.get(key));
|
||||
Object saleNoObj = null;
|
||||
if(existingSale != null) {
|
||||
saleNoObj = existingSale.get("SALE_NO");
|
||||
if(saleNoObj == null) saleNoObj = existingSale.get("sale_no");
|
||||
}
|
||||
|
||||
System.out.println("existingSale: " + (existingSale != null ? "있음" : "없음"));
|
||||
System.out.println("SALE_NO: " + saleNoObj);
|
||||
|
||||
// 2. sales_registration 레코드가 없으면 생성
|
||||
if(saleNoObj == null) {
|
||||
System.out.println("sales_registration 레코드 생성 (첫 판매)");
|
||||
|
||||
Map<String, Object> baseRecord = new HashMap<String, Object>();
|
||||
baseRecord.put("orderNo", projectNo);
|
||||
baseRecord.put("salesQuantity", paramMap.get("salesQuantity"));
|
||||
baseRecord.put("salesUnitPrice", paramMap.get("salesUnitPrice"));
|
||||
baseRecord.put("salesSupplyPrice", paramMap.get("salesSupplyPrice"));
|
||||
baseRecord.put("salesVat", paramMap.get("salesVat"));
|
||||
baseRecord.put("salesTotalAmount", paramMap.get("salesTotalAmount"));
|
||||
baseRecord.put("salesCurrency", paramMap.get("salesCurrency"));
|
||||
baseRecord.put("salesExchangeRate", paramMap.get("salesExchangeRate"));
|
||||
baseRecord.put("shippingDate", paramMap.get("shippingDate"));
|
||||
baseRecord.put("shippingMethod", paramMap.get("shippingMethod"));
|
||||
baseRecord.put("managerUserId", paramMap.get("manager"));
|
||||
baseRecord.put("incoterms", paramMap.get("incoterms"));
|
||||
baseRecord.put("serialNo", paramMap.get("serialNo"));
|
||||
baseRecord.put("shippingOrderStatus", "출하지시");
|
||||
baseRecord.put("cretEmpNo", paramMap.get("cretEmpNo"));
|
||||
|
||||
sqlSession.insert("salesNcollectMgmt.insertSaleRegistration", baseRecord);
|
||||
System.out.println("sales_registration INSERT 완료");
|
||||
} else {
|
||||
// 이미 레코드가 있으면 UPDATE
|
||||
System.out.println("기존 레코드 존재 → updateSaleRegistration");
|
||||
paramMap.put("shippingOrderStatus", "출하지시");
|
||||
sqlSession.update("salesNcollectMgmt.updateSaleRegistration", paramMap);
|
||||
}
|
||||
throw new RuntimeException("ORDER_QUANTITY 또는 SALE_NO가 null입니다");
|
||||
}
|
||||
|
||||
paramMap.put("targetObjid", projectNo);
|
||||
paramMap.put("originalQuantity", orderQtyObj);
|
||||
// S/N → CONTRACT_ITEM_SERIAL 동기화
|
||||
String serialNo = CommonUtils.nullToEmpty((String) paramMap.get("serialNo"));
|
||||
String writer = CommonUtils.nullToEmpty((String) paramMap.get("cretEmpNo"));
|
||||
|
||||
// 잔량 계산
|
||||
int orderQuantity = Integer.parseInt(String.valueOf(orderQtyObj).split("\\.")[0]);
|
||||
int salesQuantity = Integer.parseInt(String.valueOf(paramMap.get("salesQuantity")));
|
||||
int remainingQuantity = orderQuantity - salesQuantity;
|
||||
|
||||
System.out.println("orderQuantity: " + orderQuantity);
|
||||
System.out.println("salesQuantity: " + salesQuantity);
|
||||
System.out.println("remainingQuantity: " + remainingQuantity);
|
||||
|
||||
paramMap.put("remainingQuantity", remainingQuantity);
|
||||
paramMap.put("parentSaleNo", saleNoObj);
|
||||
|
||||
System.out.println("shipment_log INSERT 직전 파라미터:");
|
||||
System.out.println(" targetObjid: " + paramMap.get("targetObjid"));
|
||||
System.out.println(" parentSaleNo: " + paramMap.get("parentSaleNo"));
|
||||
System.out.println(" cretEmpNo: " + paramMap.get("cretEmpNo"));
|
||||
|
||||
sqlSession.insert("salesNcollectMgmt.insertShipmentLog", paramMap);
|
||||
|
||||
// 4. sales_registration의 sales_quantity를 shipment_log 합계로 업데이트
|
||||
System.out.println("sales_registration 업데이트 - shipment_log 합계 반영");
|
||||
Map<String, Object> updateParam = new HashMap<String, Object>();
|
||||
updateParam.put("projectNo", projectNo);
|
||||
updateParam.put("saleNo", saleNoObj);
|
||||
sqlSession.update("salesNcollectMgmt.updateSalesQuantityFromShipmentLog", updateParam);
|
||||
if(projectNo != null && !projectNo.isEmpty()) {
|
||||
SerialNoSyncUtil.syncSerialToContractItemSerial(
|
||||
sqlSession, projectNo, serialNo, writer);
|
||||
}
|
||||
|
||||
sqlSession.commit();
|
||||
resultMap.put("result", true);
|
||||
@@ -1514,52 +1485,64 @@ public Map<String, Object> saveSaleRegistration(HttpServletRequest request, Map<
|
||||
System.out.println("=== 거래명세서 저장 시작 ===");
|
||||
System.out.println("paramMap: " + paramMap);
|
||||
|
||||
// 업체코드 (고객 정보에서 추출 필요 - 임시로 '0001' 사용)
|
||||
String suVndCd = "0001";
|
||||
|
||||
// 작성일자 (오늘 날짜)
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
|
||||
String issueDt = sdf.format(new Date());
|
||||
|
||||
// 납품일자 포맷 변환 (한글 날짜 또는 YYYY-MM-DD → YYYYMMDD)
|
||||
|
||||
// 납품일자 포맷 변환
|
||||
String deliveryDate = "";
|
||||
String defaultIssueDt = sdf.format(new Date());
|
||||
if(paramMap.get("deliveryDate") != null && !paramMap.get("deliveryDate").equals("")) {
|
||||
String deliveryDateStr = String.valueOf(paramMap.get("deliveryDate"));
|
||||
|
||||
// 한글 날짜 형식인 경우 (예: "목요일, 11월 13, 2025")
|
||||
// 오늘 날짜로 대체
|
||||
if(deliveryDateStr.contains("월") || deliveryDateStr.contains("일")) {
|
||||
deliveryDate = issueDt; // 작성일자와 동일하게 설정
|
||||
System.out.println("납품일자 변환 (한글): " + deliveryDateStr + " → " + deliveryDate + " (오늘 날짜 사용)");
|
||||
}
|
||||
// YYYY-MM-DD 형식인 경우
|
||||
else if(deliveryDateStr.contains("-")) {
|
||||
deliveryDate = deliveryDateStr.replaceAll("-", ""); // "2025-11-13" → "20251113"
|
||||
System.out.println("납품일자 변환 (하이픈): " + deliveryDateStr + " → " + deliveryDate);
|
||||
}
|
||||
// 이미 YYYYMMDD 형식인 경우
|
||||
else if(deliveryDateStr.length() == 8) {
|
||||
deliveryDate = defaultIssueDt;
|
||||
} else if(deliveryDateStr.contains("-")) {
|
||||
deliveryDate = deliveryDateStr.replaceAll("-", "");
|
||||
} else if(deliveryDateStr.length() == 8) {
|
||||
deliveryDate = deliveryDateStr;
|
||||
System.out.println("납품일자 변환 (8자리): " + deliveryDateStr + " → " + deliveryDate);
|
||||
}
|
||||
// 그 외의 경우 오늘 날짜 사용
|
||||
else {
|
||||
deliveryDate = issueDt;
|
||||
System.out.println("납품일자 변환 (기타): " + deliveryDateStr + " → " + deliveryDate + " (오늘 날짜 사용)");
|
||||
} else {
|
||||
deliveryDate = defaultIssueDt;
|
||||
}
|
||||
}
|
||||
|
||||
// 거래명세서 번호 생성
|
||||
Map<String, Object> noParam = new HashMap<String, Object>();
|
||||
noParam.put("suVndCd", suVndCd);
|
||||
noParam.put("issueDt", issueDt);
|
||||
Integer issueNo = sqlSession.selectOne("salesNcollectMgmt.getNextTransactionStatementNo", noParam);
|
||||
|
||||
System.out.println("업체코드: " + suVndCd);
|
||||
System.out.println("작성일자: " + issueDt);
|
||||
System.out.println("거래명세서번호: " + issueNo);
|
||||
|
||||
// 품목 정보 저장
|
||||
|
||||
// 연결된 프로젝트 OBJID 목록 (콤마 구분)
|
||||
String linkedProjectObjids = paramMap.get("projectObjids") != null
|
||||
? String.valueOf(paramMap.get("projectObjids")) : "";
|
||||
|
||||
// 첫 번째 프로젝트 OBJID로 기존 거래명세서 확인
|
||||
String firstObjid = linkedProjectObjids.split(",")[0].trim();
|
||||
Map<String, Object> checkParam = new HashMap<String, Object>();
|
||||
checkParam.put("projectObjid", firstObjid);
|
||||
List<Map<String, Object>> existingData = sqlSession.selectList("salesNcollectMgmt.getSavedTransactionStatement", checkParam);
|
||||
|
||||
String issueDt;
|
||||
Integer issueNo;
|
||||
|
||||
if(existingData != null && !existingData.isEmpty()) {
|
||||
Map<String, Object> first = existingData.get(0);
|
||||
issueDt = String.valueOf(first.get("issuedt"));
|
||||
issueNo = Integer.parseInt(String.valueOf(first.get("issueno")));
|
||||
// 기존 거래명세서 업데이트 시 DB에 저장된 LinkedProjectObjids 유지
|
||||
String existingLinked = String.valueOf(first.get("linkedprojectobjids"));
|
||||
if(existingLinked != null && !existingLinked.isEmpty() && !"null".equals(existingLinked)) {
|
||||
linkedProjectObjids = existingLinked;
|
||||
}
|
||||
System.out.println("기존 거래명세서 업데이트: IssueDt=" + issueDt + ", IssueNo=" + issueNo + ", LinkedObjids=" + linkedProjectObjids);
|
||||
} else {
|
||||
issueDt = defaultIssueDt;
|
||||
Map<String, Object> noParam = new HashMap<String, Object>();
|
||||
noParam.put("suVndCd", suVndCd);
|
||||
noParam.put("issueDt", issueDt);
|
||||
issueNo = sqlSession.selectOne("salesNcollectMgmt.getNextTransactionStatementNo", noParam);
|
||||
System.out.println("신규 거래명세서 생성: IssueDt=" + issueDt + ", IssueNo=" + issueNo);
|
||||
}
|
||||
|
||||
// OdOrderNo용 첫 번째 프로젝트번호 (기존 호환)
|
||||
String firstProjectNo = String.valueOf(paramMap.get("projectNos")).split(",")[0].trim();
|
||||
if(firstProjectNo.length() > 50) {
|
||||
firstProjectNo = firstProjectNo.substring(0, 50);
|
||||
}
|
||||
|
||||
// 거래명세서 1건만 저장 (모든 품목 포함)
|
||||
List<Map<String, Object>> items = (List<Map<String, Object>>) paramMap.get("items");
|
||||
if(items != null && items.size() > 0) {
|
||||
int seqNo = 1;
|
||||
@@ -1569,76 +1552,53 @@ public Map<String, Object> saveSaleRegistration(HttpServletRequest request, Map<
|
||||
insertParam.put("issueDt", issueDt);
|
||||
insertParam.put("issueNo", issueNo);
|
||||
insertParam.put("isNo", seqNo);
|
||||
|
||||
// 품목 정보
|
||||
insertParam.put("prodCd", ""); // 기종코드
|
||||
|
||||
// 발주번호 (프로젝트번호) - VARCHAR(15) 제한
|
||||
String projectNos = String.valueOf(paramMap.get("projectNos"));
|
||||
if(projectNos.length() > 15) {
|
||||
projectNos = projectNos.substring(0, 15); // 15자로 자르기
|
||||
|
||||
String productName = item.get("productName") != null ? String.valueOf(item.get("productName")) : "";
|
||||
if(productName.length() > 50) {
|
||||
productName = productName.substring(0, 50);
|
||||
}
|
||||
insertParam.put("odOrderNo", projectNos);
|
||||
|
||||
// 품번 - VARCHAR(15) 제한
|
||||
insertParam.put("prodCd", productName);
|
||||
insertParam.put("odOrderNo", firstProjectNo);
|
||||
insertParam.put("linkedProjectObjids", linkedProjectObjids);
|
||||
|
||||
String spec = String.valueOf(item.get("spec"));
|
||||
if(spec != null && spec.length() > 15) {
|
||||
spec = spec.substring(0, 15); // 15자로 자르기
|
||||
if(spec != null && spec.length() > 50) {
|
||||
spec = spec.substring(0, 50);
|
||||
}
|
||||
insertParam.put("imItemId", spec);
|
||||
|
||||
insertParam.put("rmDueDt", ""); // 납기일자
|
||||
|
||||
// 수량 정보
|
||||
insertParam.put("rmDueDt", "");
|
||||
|
||||
String quantityStr = String.valueOf(item.get("quantity"));
|
||||
quantityStr = quantityStr.replaceAll(",", "").replaceAll("[^0-9]", "");
|
||||
int quantity = 0;
|
||||
try {
|
||||
quantity = Integer.parseInt(quantityStr);
|
||||
} catch(Exception e) {
|
||||
quantity = 0;
|
||||
}
|
||||
insertParam.put("rmOrderQty", quantity); // 발주수량
|
||||
insertParam.put("rmRcptQty", 0); // 입고처리수량
|
||||
insertParam.put("rmRemQty", 0); // 잔량
|
||||
insertParam.put("isDt", deliveryDate); // 납기일자 (포맷 변환된 값)
|
||||
insertParam.put("isQty", quantity); // 납품수량
|
||||
|
||||
// 금액 정보
|
||||
try { quantity = Integer.parseInt(quantityStr); } catch(Exception e) { quantity = 0; }
|
||||
insertParam.put("rmOrderQty", quantity);
|
||||
insertParam.put("rmRcptQty", 0);
|
||||
insertParam.put("rmRemQty", 0);
|
||||
insertParam.put("isDt", deliveryDate);
|
||||
insertParam.put("isQty", quantity);
|
||||
|
||||
String unitPriceStr = String.valueOf(item.get("unitPrice"));
|
||||
unitPriceStr = unitPriceStr.replaceAll(",", "").replaceAll("[^0-9.]", "");
|
||||
double unitPrice = 0;
|
||||
try {
|
||||
unitPrice = Double.parseDouble(unitPriceStr);
|
||||
} catch(Exception e) {
|
||||
unitPrice = 0;
|
||||
}
|
||||
|
||||
try { unitPrice = Double.parseDouble(unitPriceStr); } catch(Exception e) { unitPrice = 0; }
|
||||
|
||||
String supplyPriceStr = String.valueOf(item.get("supplyPrice"));
|
||||
supplyPriceStr = supplyPriceStr.replaceAll(",", "").replaceAll("[^0-9.]", "");
|
||||
double supplyPrice = 0;
|
||||
try {
|
||||
supplyPrice = Double.parseDouble(supplyPriceStr);
|
||||
} catch(Exception e) {
|
||||
supplyPrice = 0;
|
||||
}
|
||||
|
||||
insertParam.put("isPrice", unitPrice); // 납품단가
|
||||
insertParam.put("isAmount", supplyPrice); // 납품금액
|
||||
|
||||
try { supplyPrice = Double.parseDouble(supplyPriceStr); } catch(Exception e) { supplyPrice = 0; }
|
||||
|
||||
insertParam.put("isPrice", unitPrice);
|
||||
insertParam.put("isAmount", supplyPrice);
|
||||
|
||||
System.out.println("품목 " + seqNo + " 저장: " + item.get("productName"));
|
||||
System.out.println(" - 품번: " + item.get("spec"));
|
||||
System.out.println(" - 수량: " + quantity);
|
||||
System.out.println(" - 단가: " + unitPrice);
|
||||
System.out.println(" - 금액: " + supplyPrice);
|
||||
|
||||
sqlSession.insert("salesNcollectMgmt.saveTransactionStatement", insertParam);
|
||||
seqNo++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sqlSession.commit();
|
||||
|
||||
|
||||
resultMap.put("success", true);
|
||||
resultMap.put("message", "거래명세서가 저장되었습니다.");
|
||||
resultMap.put("issueNo", issueNo);
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.pms.common.SqlMapConfig;
|
||||
import com.pms.common.bean.PersonBean;
|
||||
import com.pms.common.utils.CommonUtils;
|
||||
import com.pms.common.utils.Constants;
|
||||
import com.pms.common.utils.SerialNoSyncUtil;
|
||||
|
||||
@Service
|
||||
public class ProductionPlanningService {
|
||||
@@ -1897,20 +1898,28 @@ public class ProductionPlanningService {
|
||||
SqlSession sqlSession = null;
|
||||
|
||||
try {
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession();
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
|
||||
|
||||
String objid = CommonUtils.nullToEmpty((String)paramMap.get("OBJID"));
|
||||
String actionType = CommonUtils.nullToEmpty((String)paramMap.get("actionType"));
|
||||
|
||||
if("regist".equals(actionType) || "".equals(objid)) {
|
||||
// 신규 등록
|
||||
paramMap.put("OBJID", CommonUtils.createObjId());
|
||||
sqlSession.insert("productionplanning.insertProdPlan", paramMap);
|
||||
} else {
|
||||
// 수정
|
||||
sqlSession.update("productionplanning.updateProdPlan", paramMap);
|
||||
}
|
||||
|
||||
// S/N → CONTRACT_ITEM_SERIAL 동기화 (프로젝트 연결 시)
|
||||
String projectNo = CommonUtils.nullToEmpty((String)paramMap.get("PROJECT_NO"));
|
||||
String serialNo = CommonUtils.nullToEmpty((String)paramMap.get("SERIAL_NO"));
|
||||
String writer = CommonUtils.nullToEmpty((String)paramMap.get("userId"));
|
||||
|
||||
if(!projectNo.isEmpty()) {
|
||||
SerialNoSyncUtil.syncSerialToContractItemSerial(
|
||||
sqlSession, projectNo, serialNo, writer);
|
||||
}
|
||||
|
||||
sqlSession.commit();
|
||||
result = true;
|
||||
} catch(Exception e) {
|
||||
|
||||
Reference in New Issue
Block a user