V20260210 #189

Merged
hjjeong merged 3 commits from V20260210 into main 2026-03-27 08:33:18 +00:00
11 changed files with 222 additions and 133 deletions

View File

@@ -41,11 +41,16 @@
section.business_popup_min_width {
padding: 0 !important;
margin: 0 auto !important;
width: calc(100% - 16px) !important;
max-width: none !important;
width: calc(100% - 8px) !important;
border: none !important;
box-shadow: none !important;
}
#EntirePopupFormWrap {
width: 100% !important;
margin: 5px 0 0 0 !important;
padding: 0 5px 10px 5px !important;
box-sizing: border-box;
}
/* ===== 품목 그리드 컬럼 리사이즈 ===== */
@@ -483,52 +488,52 @@
// S/N
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<input type="text" name="item_serial_no[]" class="item-serial-no" placeholder="클릭하여 S/N 추가" readonly style="width:95%; padding:5px; cursor:pointer; background-color:#f8f9fa;" onclick="fn_openItemSnPopup(\'' + itemId + '\')" />';
html += '<input type="text" name="item_serial_no[]" class="item-serial-no" placeholder="클릭하여 S/N 추가" readonly style="width:100%; padding:5px; cursor:pointer; background-color:#f8f9fa;" onclick="fn_openItemSnPopup(\'' + itemId + '\')" />';
html += '<input type="hidden" name="item_serial_no_list[]" id="' + itemId + '_sn_list" value="" />';
html += '</td>';
// 요청납기
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<input type="text" name="item_due_date[]" class="item-due-date date_icon" style="width:90%; padding:5px;" />';
html += '<input type="text" name="item_due_date[]" class="item-due-date date_icon" style="width:100%; padding:5px;" />';
html += '</td>';
// 고객요청사항
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<textarea name="item_customer_request[]" class="item-customer-request" style="width:95%; padding:5px; min-height:34px; resize:vertical; font-family:inherit; font-size:inherit;" rows="1"></textarea>';
html += '<textarea name="item_customer_request[]" class="item-customer-request" style="width:100%; padding:5px; min-height:34px; resize:vertical; font-family:inherit; font-size:inherit;" rows="1"></textarea>';
html += '</td>';
// 반납사유
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<select name="item_return_reason[]" class="item-return-reason select2" style="width:95%;"></select>';
html += '<select name="item_return_reason[]" class="item-return-reason select2" style="width:100%;"></select>';
html += '</td>';
// 수주수량 (Machine이고 프로젝트가 있으면 readonly)
html += '<td style="padding:5px; border:1px solid #ddd;">';
if(isMachine && hasProject) {
html += '<input type="text" name="item_order_quantity[]" class="item-order-quantity" style="width:90%; padding:5px; text-align:right; background:#f5f5f5;" required numberOnly readonly title="Machine 제품은 프로젝트 생성 후 수량 변경이 불가능합니다." />';
html += '<input type="text" name="item_order_quantity[]" class="item-order-quantity" style="width:100%; padding:5px; text-align:right; background:#f5f5f5;" required numberOnly readonly title="Machine 제품은 프로젝트 생성 후 수량 변경이 불가능합니다." />';
} else {
html += '<input type="text" name="item_order_quantity[]" class="item-order-quantity" style="width:90%; padding:5px; text-align:right;" required numberOnly />';
html += '<input type="text" name="item_order_quantity[]" class="item-order-quantity" style="width:100%; padding:5px; text-align:right;" required numberOnly />';
}
html += '</td>';
// 수주단가
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<input type="text" name="item_order_unit_price[]" class="item-order-unit-price" style="width:90%; padding:5px; text-align:right;" numberOnly />';
html += '<input type="text" name="item_order_unit_price[]" class="item-order-unit-price" style="width:100%; padding:5px; text-align:right;" numberOnly />';
html += '</td>';
// 수주공급가액 (자동계산 + 수정가능)
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<input type="text" name="item_order_supply_price[]" class="item-order-supply-price" style="width:90%; padding:5px; text-align:right;" numberOnly />';
html += '<input type="text" name="item_order_supply_price[]" class="item-order-supply-price" style="width:100%; padding:5px; text-align:right;" numberOnly />';
html += '</td>';
// 수주부가세 (자동계산 + 수정가능)
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<input type="text" name="item_order_vat[]" class="item-order-vat" style="width:90%; padding:5px; text-align:right;" numberOnly />';
html += '<input type="text" name="item_order_vat[]" class="item-order-vat" style="width:100%; padding:5px; text-align:right;" numberOnly />';
html += '</td>';
// 수주총액 (자동계산 + 수정가능)
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<input type="text" name="item_order_total_amount[]" class="item-order-total-amount" style="width:90%; padding:5px; text-align:right;" numberOnly />';
html += '<input type="text" name="item_order_total_amount[]" class="item-order-total-amount" style="width:100%; padding:5px; text-align:right;" numberOnly />';
html += '</td>';
// 삭제 버튼
@@ -718,46 +723,39 @@
var returnReason = "<%= CommonUtils.checkNull(item.get("RETURN_REASON")) %>";
var savedProduct = "<%= CommonUtils.checkNull(item.get("PRODUCT")) %>";
// 제품구분 드롭다운
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<select name="item_product[]" id="PRODUCT_' + itemId + '" class="item-product select2" style="width:100%;" required>';
html += '<option value="">선택</option>';
html += '</select>';
html += '</td>';
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<input type="text" name="item_serial_no[]" class="item-serial-no" placeholder="클릭하여 S/N 추가" readonly style="width:95%; padding:5px; cursor:pointer; background-color:#f8f9fa;" onclick="fn_openItemSnPopup(\'' + itemId + '\')" value="' + serialNos + '" />';
html += '<input type="text" name="item_serial_no[]" class="item-serial-no" placeholder="클릭하여 S/N 추가" readonly style="width:100%; padding:5px; cursor:pointer; background-color:#f8f9fa;" onclick="fn_openItemSnPopup(\'' + itemId + '\')" value="' + serialNos + '" />';
html += '<input type="hidden" name="item_serial_no_list[]" id="' + itemId + '_sn_list" value="" />';
html += '</td>';
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<input type="text" name="item_due_date[]" class="item-due-date date_icon" style="width:90%; padding:5px;" value="' + dueDate + '" />';
html += '<input type="text" name="item_due_date[]" class="item-due-date date_icon" style="width:100%; padding:5px;" value="' + dueDate + '" />';
html += '</td>';
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<textarea name="item_customer_request[]" class="item-customer-request" style="width:95%; padding:5px; min-height:34px; resize:vertical; font-family:inherit; font-size:inherit;" rows="1"></textarea>';
html += '<textarea name="item_customer_request[]" class="item-customer-request" style="width:100%; padding:5px; min-height:34px; resize:vertical; font-family:inherit; font-size:inherit;" rows="1"></textarea>';
html += '</td>';
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<select name="item_return_reason[]" class="item-return-reason select2" style="width:95%;"></select>';
html += '<select name="item_return_reason[]" class="item-return-reason select2" style="width:100%;"></select>';
html += '</td>';
// 수주 정보 (Machine이고 프로젝트가 있으면 수량 readonly)
html += '<td style="padding:5px; border:1px solid #ddd;">';
if(isMachine && hasProject) {
html += '<input type="text" name="item_order_quantity[]" class="item-order-quantity" style="width:90%; padding:5px; text-align:right; background:#f5f5f5;" required numberOnly readonly title="Machine 제품은 프로젝트 생성 후 수량 변경이 불가능합니다." value="' + (orderQuantity ? formatInteger(orderQuantity) : '') + '" />';
html += '<input type="text" name="item_order_quantity[]" class="item-order-quantity" style="width:100%; padding:5px; text-align:right; background:#f5f5f5;" required numberOnly readonly title="Machine 제품은 프로젝트 생성 후 수량 변경이 불가능합니다." value="' + (orderQuantity ? formatInteger(orderQuantity) : '') + '" />';
} else {
html += '<input type="text" name="item_order_quantity[]" class="item-order-quantity" style="width:90%; padding:5px; text-align:right;" required numberOnly value="' + (orderQuantity ? formatInteger(orderQuantity) : '') + '" />';
html += '<input type="text" name="item_order_quantity[]" class="item-order-quantity" style="width:100%; padding:5px; text-align:right;" required numberOnly value="' + (orderQuantity ? formatInteger(orderQuantity) : '') + '" />';
}
html += '</td>';
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<input type="text" name="item_order_unit_price[]" class="item-order-unit-price" style="width:90%; padding:5px; text-align:right;" numberOnly value="' + (orderUnitPrice ? addComma(orderUnitPrice) : '') + '" />';
html += '<input type="text" name="item_order_unit_price[]" class="item-order-unit-price" style="width:100%; padding:5px; text-align:right;" numberOnly value="' + (orderUnitPrice ? addComma(orderUnitPrice) : '') + '" />';
html += '</td>';
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<input type="text" name="item_order_supply_price[]" class="item-order-supply-price" style="width:90%; padding:5px; text-align:right;" numberOnly value="' + (orderSupplyPrice ? addComma(orderSupplyPrice) : '') + '" />';
html += '<input type="text" name="item_order_supply_price[]" class="item-order-supply-price" style="width:100%; padding:5px; text-align:right;" numberOnly value="' + (orderSupplyPrice ? addComma(orderSupplyPrice) : '') + '" />';
html += '</td>';
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<input type="text" name="item_order_vat[]" class="item-order-vat" style="width:90%; padding:5px; text-align:right;" numberOnly value="' + (orderVat ? addComma(orderVat) : '') + '" />';
html += '<input type="text" name="item_order_vat[]" class="item-order-vat" style="width:100%; padding:5px; text-align:right;" numberOnly value="' + (orderVat ? addComma(orderVat) : '') + '" />';
html += '</td>';
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<input type="text" name="item_order_total_amount[]" class="item-order-total-amount" style="width:90%; padding:5px; text-align:right;" numberOnly value="' + (orderTotalAmount ? addComma(orderTotalAmount) : '') + '" />';
html += '<input type="text" name="item_order_total_amount[]" class="item-order-total-amount" style="width:100%; padding:5px; text-align:right;" numberOnly value="' + (orderTotalAmount ? addComma(orderTotalAmount) : '') + '" />';
html += '</td>';
html += '<td style="text-align:center; padding:5px; border:1px solid #ddd;">';
@@ -1676,13 +1674,13 @@
<table class="pmsPopuptable" id="itemListTable">
<colgroup>
<col width="3%" /> <!-- 번호 -->
<col width="8%" /> <!-- 제품구분 -->
<col width="6%" /> <!-- 제품구분 -->
<col width="7%" /> <!-- 품번 -->
<col width="7%" /> <!-- 품명 -->
<col width="10%" /> <!-- 품명 -->
<col width="9%" /> <!-- S/N -->
<col width="7%" /> <!-- 요청납기 -->
<col width="11%" /> <!-- 고객요청사항 -->
<col width="7%" /> <!-- 반납사유 -->
<col width="6%" /> <!-- 반납사유 -->
<col width="6%" /> <!-- 수주수량 -->
<col width="7%" /> <!-- 수주단가 -->
<col width="7%" /> <!-- 수주공급가액 -->

View File

@@ -696,13 +696,13 @@
html += '<input type="text" name="item_quantity[]" class="item-quantity" style="width:90%; padding:5px;" value="' + quantity + '" required numberOnly />';
html += '</td>';
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<input type="text" name="item_due_date[]" class="item-due-date date_icon" style="width:90%; padding:5px;" value="' + dueDate + '" />';
html += '<input type="text" name="item_due_date[]" class="item-due-date date_icon" style="width:100%; padding:5px;" value="' + dueDate + '" />';
html += '</td>';
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<select name="item_return_reason[]" class="item-return-reason select2" style="width:95%;"></select>';
html += '</td>';
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<textarea name="item_customer_request[]" class="item-customer-request" style="width:95%; padding:5px; min-height:34px; resize:vertical; font-family:inherit; font-size:inherit;" rows="1"></textarea>';
html += '<textarea name="item_customer_request[]" class="item-customer-request" style="width:100%; padding:5px; min-height:34px; resize:vertical; font-family:inherit; font-size:inherit;" rows="1"></textarea>';
html += '</td>';
html += '<td style="text-align:center; padding:5px; border:1px solid #ddd;">';
html += '<button type="button" onclick="fn_deleteItemRow(\'' + itemId + '\')" class="plm_btns" style="padding:5px 10px; font-size:12px;">삭제</button>';
@@ -1499,13 +1499,13 @@
html += '<input type="text" name="item_quantity[]" class="item-quantity" style="width:90%; padding:5px;" required numberOnly />';
html += '</td>';
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<input type="text" name="item_due_date[]" class="item-due-date date_icon" style="width:90%; padding:5px;" />';
html += '<input type="text" name="item_due_date[]" class="item-due-date date_icon" style="width:100%; padding:5px;" />';
html += '</td>';
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<select name="item_return_reason[]" class="item-return-reason select2" style="width:95%;"></select>';
html += '</td>';
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<textarea name="item_customer_request[]" class="item-customer-request" style="width:95%; padding:5px; min-height:34px; resize:vertical; font-family:inherit; font-size:inherit;" rows="1"></textarea>';
html += '<textarea name="item_customer_request[]" class="item-customer-request" style="width:100%; padding:5px; min-height:34px; resize:vertical; font-family:inherit; font-size:inherit;" rows="1"></textarea>';
html += '</td>';
html += '<td style="text-align:center; padding:5px; border:1px solid #ddd;">';
html += '<button type="button" onclick="fn_deleteItemRow(\'' + itemId + '\')" class="plm_btns" style="padding:5px 10px; font-size:12px;">삭제</button>';
@@ -2244,15 +2244,15 @@
<div style="max-height:300px; overflow-y:auto;">
<table class="pmsPopuptable" id="itemListTable">
<colgroup>
<col width="4%" /> <!-- 번호 -->
<col width="10%" /> <!-- 제품구분 -->
<col width="3%" /> <!-- 번호 -->
<col width="7%" /> <!-- 제품구분 -->
<col width="11%" /> <!-- 품번 -->
<col width="11%" /> <!-- 품명 -->
<col width="13%" /> <!-- S/N -->
<col width="7%" /> <!-- 수량 -->
<col width="17%" /> <!-- 품명 -->
<col width="11%" /> <!-- S/N -->
<col width="6%" /> <!-- 수량 -->
<col width="9%" /> <!-- 요청납기 -->
<col width="13%" /> <!-- 반납사유 -->
<col width="17%" /> <!-- 고객요청사항 -->
<col width="8%" /> <!-- 반납사유 -->
<col width="18%" /> <!-- 고객요청사항 -->
<col width="5%" /> <!-- 삭제 -->
</colgroup>
<thead>

View File

@@ -64,6 +64,9 @@ String templateObjId = CommonUtils.checkNull(request.getParameter("templateObjId
.no-print {
display: none !important;
}
.delete-btn-cell button {
display: none !important;
}
}
body {
@@ -160,13 +163,15 @@ body {
width: 100%;
border-collapse: collapse;
margin-bottom: 30px;
table-layout: fixed;
}
.items-table th,
.items-table td {
border: 1px solid #000;
padding: 3px 5px;
padding: 8px 2px;
text-align: center;
vertical-align: middle;
font-size: 9pt;
line-height: 1.3;
}
@@ -176,14 +181,15 @@ body {
font-weight: bold;
}
.items-table .col-no { width: 6%; }
.items-table .col-desc { width: 20%; }
.items-table .col-no { width: 4%; }
.items-table .col-desc { width: 12%; }
.items-table .col-spec { width: 22%; }
.items-table .col-qty { width: 7%; }
.items-table .col-unit { width: 8%; }
.items-table .col-price { width: 11%; }
.items-table .col-amount { width: 11%; }
.items-table .col-note { width: 15%; }
.items-table .col-qty { width: 4%; }
.items-table .col-unit { width: 5%; }
.items-table .col-price { width: 14%; }
.items-table .col-amount { width: 15%; }
.items-table .col-note { width: 9%; white-space: normal; word-break: break-all; }
.items-table td { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.items-table .text-left {
text-align: left;
@@ -191,6 +197,8 @@ body {
.items-table .text-right {
text-align: right;
overflow: hidden;
word-break: break-all;
}
.notes-section {
@@ -262,6 +270,12 @@ textarea {
width: 100%;
font-family: inherit;
font-size: inherit;
box-sizing: border-box;
}
.item-price,
.item-amount {
text-align: right;
}
.item-amount {
@@ -269,9 +283,12 @@ textarea {
}
textarea {
resize: vertical;
min-height: 25px;
padding: 2px;
resize: none;
height: 1.3em;
min-height: auto;
padding: 0 2px;
white-space: nowrap;
overflow: hidden;
}
.editable {
@@ -373,7 +390,7 @@ $(function(){
$(document).on("blur", ".item-price", function(){
var val = $(this).val().replace(/,/g, "");
if(!isNaN(val) && val !== "") {
$(this).val(Number(val).toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 2}));
$(this).val(Number(val).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}));
}
fn_calculateTotal();
});
@@ -502,10 +519,16 @@ function fn_calculateTotalKRW(total) {
$("#totalAmountKRW").text("₩" + addComma(totalKRW));
}
// 금액 포맷 (소수점 2자리 + 천단위 콤마)
// 금액 포맷 (항상 소수점 2자리, 천단위 콤마)
function addComma(num) {
if(num === '' || num === null || num === undefined) return '';
return Number(num).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
// DB에 콤마가 포함된 값이 저장된 경우를 위해 콤마 제거 후 파싱
var n = Number(String(num).replace(/,/g, ''));
if(isNaN(n)) return '';
return n.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
}
// 통화 기호 반환
@@ -702,7 +725,7 @@ function fn_loadContractItems(contractObjId) {
itemsHtml += '<tr class="total-row">';
itemsHtml += '<td colspan="6" style="text-align: center; font-weight: bold; background-color: #f0f0f0;">계</td>';
itemsHtml += '<td class="text-right" style="font-weight: bold; background-color: #f0f0f0;"><span id="totalAmount">0</span></td>';
itemsHtml += '<td style="background-color: #f0f0f0; text-align: center;"><button type="button" class="btn-delete-total-row" style="padding: 2px 8px; font-size: 9pt; cursor: pointer;">삭제</button></td>';
itemsHtml += '<td class="delete-btn-cell" style="background-color: #f0f0f0; text-align: center;"><button type="button" class="btn-delete-total-row" style="padding: 2px 8px; font-size: 9pt; cursor: pointer;">삭제</button></td>';
itemsHtml += '</tr>';
// 원화환산 공급가액 행 추가 (숨김)
@@ -864,7 +887,7 @@ function fn_loadData() {
itemsHtml += '<tr class="total-row">';
itemsHtml += '<td colspan="6" style="text-align: center; font-weight: bold; background-color: #f0f0f0;">계</td>';
itemsHtml += '<td class="text-right" style="font-weight: bold; background-color: #f0f0f0;"><span id="totalAmount">0</span></td>';
itemsHtml += '<td style="background-color: #f0f0f0; text-align: center;"><button type="button" class="btn-delete-total-row" style="padding: 2px 8px; font-size: 9pt; cursor: pointer;">삭제</button></td>';
itemsHtml += '<td class="delete-btn-cell" style="background-color: #f0f0f0; text-align: center;"><button type="button" class="btn-delete-total-row" style="padding: 2px 8px; font-size: 9pt; cursor: pointer;">삭제</button></td>';
itemsHtml += '</tr>';
// 원화환산 공급가액 행 추가 (숨김)
@@ -1082,7 +1105,7 @@ function fn_loadTemplateData(templateObjId){
itemsHtml += '<tr class="total-row">';
itemsHtml += '<td colspan="6" style="text-align: center; font-weight: bold; background-color: #f0f0f0;">계</td>';
itemsHtml += '<td class="text-right" style="font-weight: bold; background-color: #f0f0f0;"><span id="totalAmount">0</span></td>';
itemsHtml += '<td style="background-color: #f0f0f0; text-align: center;"><button type="button" class="btn-delete-total-row" style="padding: 2px 8px; font-size: 9pt; cursor: pointer;">삭제</button></td>';
itemsHtml += '<td class="delete-btn-cell" style="background-color: #f0f0f0; text-align: center;"><button type="button" class="btn-delete-total-row" style="padding: 2px 8px; font-size: 9pt; cursor: pointer;">삭제</button></td>';
itemsHtml += '</tr>';
// 원화환산 공급가액 행 추가 (숨김)
@@ -1422,7 +1445,7 @@ function fn_save() {
<th class="col-spec">규 격<br>SPECIFICATION</th>
<th class="col-qty">수량<br>Q'TY</th>
<th class="col-unit">단위<br>UNIT</th>
<th class="col-price">단 가<br>UNIT<br>PRICE</th>
<th class="col-price">단 가<br>UNIT PRICE</th>
<th class="col-amount">금 액<br>AMOUNT</th>
<th class="col-note">비고</th>
</tr>
@@ -1458,7 +1481,7 @@ function fn_save() {
<tr class="total-row">
<td colspan="6" style="text-align: center; font-weight: bold; background-color: #f0f0f0;">계</td>
<td class="text-right" style="font-weight: bold; background-color: #f0f0f0;"><span id="totalAmount">0</span></td>
<td style="background-color: #f0f0f0; text-align: center;"><button type="button" class="btn-delete-total-row" style="padding: 2px 8px; font-size: 9pt; cursor: pointer;">삭제</button></td>
<td class="delete-btn-cell" style="background-color: #f0f0f0; text-align: center;"><button type="button" class="btn-delete-total-row" style="padding: 2px 8px; font-size: 9pt; cursor: pointer;">삭제</button></td>
</tr>
<!-- 원화환산 공급가액 행 (숨김) -->
<tr class="total-krw-row" style="display: none;">
@@ -1521,15 +1544,17 @@ function fn_replaceFormElementsWithText() {
$('.estimate-container').find('input[type="text"], textarea, select').each(function(idx) {
var $el = $(this);
var displayText = '';
if ($el.is('select')) {
displayText = $el.find('option:selected').text() || '';
} else {
displayText = $el.val() || '';
}
var computedStyle = window.getComputedStyle(this);
var elWidth = $el.outerWidth();
// 단가/금액 컬럼이 좁아 잘릴 수 있으므로 부모 td의 내부 너비 사용
var parentTd = $el.closest('td');
var elWidth = parentTd.length > 0 ? parentTd.innerWidth() : $el.outerWidth();
var span = $('<span class="pdf-temp-text"></span>');
span.text(displayText);
span.css({
@@ -1604,29 +1629,31 @@ function fn_generatePdf() {
}
});
// 버튼 영역 임시 숨김
// 버튼 영역 임시 숨김 (삭제 버튼 셀 전체 숨김으로 PDF에 노출 방지)
$('.btn-area').hide();
$('.btn-delete-row').hide();
$('.btn-delete-total-row').hide();
// 폼 요소를 텍스트로 변환 (html2canvas 글자 잘림 방지)
var formBackup = fn_replaceFormElementsWithText();
// PDF 생성을 위해 스타일 조정
var container = $('.estimate-container');
var originalBg = container.css('background');
var originalShadow = container.css('box-shadow');
var originalPadding = container.css('padding');
// 깔끔한 PDF를 위해 배경, 그림자, 패딩 제거
container.css({
'background': 'white',
'box-shadow': 'none',
'padding': '10mm'
});
// body 배경색도 흰색으로
var originalBodyBg = $('body').css('background-color');
$('body').css('background-color', 'white');
// 견적서 컨테이너 캡처
html2canvas(document.querySelector('.estimate-container'), {
scale: 2, // 적절한 해상도 (파일 크기 최적화)
@@ -1645,6 +1672,8 @@ function fn_generatePdf() {
fn_restoreFormElements(formBackup);
// 버튼 영역 다시 표시
$('.btn-area').show();
$('.btn-delete-row').show();
$('.btn-delete-total-row').show();
try {
// Canvas를 JPEG 이미지로 변환 (PNG보다 파일 크기 작음)
@@ -1696,6 +1725,8 @@ function fn_generatePdf() {
}).catch(function(error) {
fn_restoreFormElements(formBackup);
$('.btn-area').show();
$('.btn-delete-row').show();
$('.btn-delete-total-row').show();
Swal.close();
console.error('Canvas 캡처 오류:', error);
Swal.fire({
@@ -1709,7 +1740,7 @@ function fn_generatePdf() {
// PDF를 Base64로 생성하여 서버로 전송하는 함수
function fn_generateAndUploadPdf(callback) {
console.log('fn_generateAndUploadPdf 호출됨');
// 라이브러리 로드 확인
if(typeof html2canvas === 'undefined' || typeof jsPDF === 'undefined') {
console.error('필요한 라이브러리가 로드되지 않았습니다.');
@@ -1718,30 +1749,32 @@ function fn_generateAndUploadPdf(callback) {
}
return;
}
// 버튼 영역 임시 숨김
// 버튼 영역 임시 숨김 (삭제 버튼 셀 전체 숨김으로 PDF에 노출 방지)
$('.btn-area').hide();
$('.btn-delete-row').hide();
$('.btn-delete-total-row').hide();
// 폼 요소를 텍스트로 변환 (html2canvas 글자 잘림 방지)
var formBackup = fn_replaceFormElementsWithText();
// PDF 생성을 위해 스타일 조정
var container = $('.estimate-container');
var originalBg = container.css('background');
var originalShadow = container.css('box-shadow');
var originalPadding = container.css('padding');
// 깔끔한 PDF를 위해 배경, 그림자, 패딩 제거
container.css({
'background': 'white',
'box-shadow': 'none',
'padding': '10mm'
});
// body 배경색도 흰색으로
var originalBodyBg = $('body').css('background-color');
$('body').css('background-color', 'white');
// 견적서 컨테이너 캡처
html2canvas(document.querySelector('.estimate-container'), {
scale: 2, // 적절한 해상도 (파일 크기 최적화)
@@ -1750,7 +1783,7 @@ function fn_generateAndUploadPdf(callback) {
backgroundColor: '#ffffff'
}).then(function(canvas) {
console.log('Canvas 캡처 완료');
// 스타일 복원
container.css({
'background': originalBg,
@@ -1758,12 +1791,14 @@ function fn_generateAndUploadPdf(callback) {
'padding': originalPadding
});
$('body').css('background-color', originalBodyBg);
// 폼 요소 복원
fn_restoreFormElements(formBackup);
// 버튼 영역 다시 표시
$('.btn-area').show();
$('.btn-delete-row').show();
$('.btn-delete-total-row').show();
try {
// Canvas를 JPEG 이미지로 변환 (PNG보다 파일 크기 작음)
@@ -1809,6 +1844,8 @@ function fn_generateAndUploadPdf(callback) {
}).catch(function(error) {
fn_restoreFormElements(formBackup);
$('.btn-area').show();
$('.btn-delete-row').show();
$('.btn-delete-total-row').show();
console.error('Canvas 캡처 오류:', error);
if(callback && typeof callback === 'function') {
callback(null);

View File

@@ -29,6 +29,9 @@ boolean isApproved = "결재완료".equals(apprStatus) || "결재중".equals(app
.no-print {
display: none !important;
}
.delete-btn-cell button {
display: none !important;
}
}
body {
@@ -530,10 +533,16 @@ function fn_calculateSubtotal(tbody) {
tbody.find(".subtotal-amount").val(addComma(total));
}
// 금액 포맷 (소수점 2자리 + 천단위 콤마)
// 금액 포맷 (항상 소수점 2자리, 천단위 콤마)
function addComma(num) {
if(num === '' || num === null || num === undefined) return '';
return Number(num).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
// DB에 콤마가 포함된 값이 저장된 경우를 위해 콤마 제거 후 파싱
var n = Number(String(num).replace(/,/g, ''));
if(isNaN(n)) return '';
return n.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
}
// 카테고리 추가
@@ -558,7 +567,7 @@ function fn_addCategory() {
'<tr class="category-row">' +
'<td rowspan="2" class="category-no">' + newCategoryNo + '</td>' +
'<td colspan="4" contenteditable="true">' + newCategoryName + '</td>' +
'<td style="text-align: center;">' +
'<td class="delete-btn-cell" style="text-align: center;">' +
'<button type="button" class="btn-delete-category" onclick="fn_deleteCategory(this)" style="padding: 2px 8px; font-size: 10px; cursor: pointer; background-color: #dc3545; color: white; border: none; border-radius: 3px;">삭제</button>' +
'</td>' +
'</tr>' +
@@ -622,7 +631,7 @@ function fn_createCategoryFromData(category) {
'<tr class="category-row">' +
'<td rowspan="2" class="category-no">' + categoryNo + '</td>' +
'<td colspan="4" contenteditable="true">' + categoryName + '</td>' +
'<td style="text-align: center;">' +
'<td class="delete-btn-cell" style="text-align: center;">' +
'<button type="button" class="btn-delete-category" onclick="fn_deleteCategory(this)" style="padding: 2px 8px; font-size: 10px; cursor: pointer; background-color: #dc3545; color: white; border: none; border-radius: 3px;">삭제</button>' +
'</td>' +
'</tr>' +
@@ -1069,9 +1078,10 @@ function fn_generateAndUploadPdf(callback) {
return;
}
// 버튼 영역 임시 숨김
// 버튼 영역 임시 숨김 (삭제 버튼 셀 전체 숨김으로 PDF에 노출 방지)
$('.estimate-btn-area').hide();
$('.btn-delete-category').hide();
// textarea를 div로 변환 (줄바꿈 보존)
var textareaBackup = [];
$('textarea').each(function(index) {
@@ -1140,7 +1150,8 @@ function fn_generateAndUploadPdf(callback) {
// 버튼 영역 다시 표시
$('.estimate-btn-area').show();
$('.btn-delete-category').show();
try {
// Canvas를 JPEG 이미지로 변환 (PNG보다 파일 크기 작음)
var imgData = canvas.toDataURL('image/jpeg', 0.85); // 85% 품질
@@ -1189,6 +1200,7 @@ function fn_generateAndUploadPdf(callback) {
});
$('.estimate-btn-area').show();
$('.btn-delete-category').show();
console.error('Canvas 캡처 오류:', error);
if(callback && typeof callback === 'function') {
callback(null);
@@ -1302,7 +1314,7 @@ function fn_generateAndUploadPdf(callback) {
<tr class="category-row">
<td rowspan="2" class="category-no">1</td>
<td colspan="4" contenteditable="true">기구</td>
<td style="text-align: center;">
<td class="delete-btn-cell" style="text-align: center;">
<button type="button" class="btn-delete-category" onclick="fn_deleteCategory(this)" style="padding: 2px 8px; font-size: 10px; cursor: pointer; background-color: #dc3545; color: white; border: none; border-radius: 3px;">삭제</button>
</td>
</tr>
@@ -1366,7 +1378,7 @@ Z: SRG25 P급, C0
<tr class="category-row">
<td rowspan="2" class="category-no">2</td>
<td colspan="4" contenteditable="true">초음파 스핀들 모듈</td>
<td style="text-align: center;">
<td class="delete-btn-cell" style="text-align: center;">
<button type="button" class="btn-delete-category" onclick="fn_deleteCategory(this)" style="padding: 2px 8px; font-size: 10px; cursor: pointer; background-color: #dc3545; color: white; border: none; border-radius: 3px;">삭제</button>
</td>
</tr>
@@ -1407,7 +1419,7 @@ Z: SRG25 P급, C0
<tr class="category-row">
<td rowspan="2" class="category-no">3</td>
<td colspan="4" contenteditable="true">전장</td>
<td style="text-align: center;">
<td class="delete-btn-cell" style="text-align: center;">
<button type="button" class="btn-delete-category" onclick="fn_deleteCategory(this)" style="padding: 2px 8px; font-size: 10px; cursor: pointer; background-color: #dc3545; color: white; border: none; border-radius: 3px;">삭제</button>
</td>
</tr>
@@ -1451,7 +1463,7 @@ SIEMENS CONTROL PANEL 828D</textarea>
<tr class="category-row">
<td rowspan="2" class="category-no">4</td>
<td colspan="4" contenteditable="true">UTILITY</td>
<td style="text-align: center;">
<td class="delete-btn-cell" style="text-align: center;">
<button type="button" class="btn-delete-category" onclick="fn_deleteCategory(this)" style="padding: 2px 8px; font-size: 10px; cursor: pointer; background-color: #dc3545; color: white; border: none; border-radius: 3px;">삭제</button>
</td>
</tr>
@@ -1521,7 +1533,7 @@ LUBRICATION
<tr class="category-row">
<td rowspan="2" class="category-no">5</td>
<td colspan="4" contenteditable="true">Option</td>
<td style="text-align: center;">
<td class="delete-btn-cell" style="text-align: center;">
<button type="button" class="btn-delete-category" onclick="fn_deleteCategory(this)" style="padding: 2px 8px; font-size: 10px; cursor: pointer; background-color: #dc3545; color: white; border: none; border-radius: 3px;">삭제</button>
</td>
</tr>
@@ -1570,7 +1582,7 @@ NV4Blue(Renishaw)
<tr class="category-row">
<td rowspan="2" class="category-no">6</td>
<td colspan="4" contenteditable="true">Set up</td>
<td style="text-align: center;">
<td class="delete-btn-cell" style="text-align: center;">
<button type="button" class="btn-delete-category" onclick="fn_deleteCategory(this)" style="padding: 2px 8px; font-size: 10px; cursor: pointer; background-color: #dc3545; color: white; border: none; border-radius: 3px;">삭제</button>
</td>
</tr>
@@ -1615,7 +1627,7 @@ NV4Blue(Renishaw)
<tr class="category-row">
<td rowspan="2" class="category-no">7</td>
<td colspan="4" contenteditable="true">포장/물류</td>
<td style="text-align: center;">
<td class="delete-btn-cell" style="text-align: center;">
<button type="button" class="btn-delete-category" onclick="fn_deleteCategory(this)" style="padding: 2px 8px; font-size: 10px; cursor: pointer; background-color: #dc3545; color: white; border: none; border-radius: 3px;">삭제</button>
</td>
</tr>

View File

@@ -827,7 +827,7 @@ function fn_openOrderConfirmPopup(contractObjId, currentStatus){
fn_search();
});
} else {
Swal.fire("수주확정 저장 중 오류가 발생했습니다.");
Swal.fire("수주확정 저장 중 오류가 발생했습니다.\n" + (data.message || ""));
}
},
error: function(){

View File

@@ -169,7 +169,7 @@
// 품목이 없으면 메시지 표시
if($("#itemListBody tr.item-row").length == 0) {
$("#itemListBody").html('<tr id="noItemRow"><td colspan="9" style="text-align:center; padding:30px; color:#999;">품목 추가 버튼을 클릭하여 품목을 등록하세요.</td></tr>');
$("#itemListBody").html('<tr id="noItemRow"><td colspan="11" style="text-align:center; padding:30px; color:#999;">품목 추가 버튼을 클릭하여 품목을 등록하세요.</td></tr>');
}
}
}
@@ -254,6 +254,12 @@
var html = '<tr id="' + itemId + '" class="item-row">';
html += '<td>' + (i + 1) + '</td>';
// 제품구분 드롭다운
html += '<td style="padding:5px; border:1px solid #ddd;">';
html += '<select name="item_product[]" id="PRODUCT_' + itemId + '" class="item-product select2" style="width:100%;" required>';
html += '<option value="">선택</option>';
html += '</select>';
html += '</td>';
html += '<td><input type="text" class="item-part-no" value="' + (item.PART_NO || '') + '" readonly style="background:#f5f5f5;" /></td>';
html += '<td><input type="text" class="item-part-name" value="' + (item.PART_NAME || '') + '" readonly style="background:#f5f5f5;" /></td>';
html += '<td><input type="text" class="item-serial-no" value="' + serialNoDisplay + '" readonly style="background:#f5f5f5;" title="' + serialNo + '" /></td>';
@@ -281,6 +287,11 @@
$("#itemListBody").append(html);
// 제품구분 드롭다운 초기화 (견적요청에서 저장된 값으로 세팅)
var savedProduct = item.PRODUCT || '';
fnc_getCodeListAppend("0000001", "PRODUCT_" + itemId, savedProduct);
$("#PRODUCT_" + itemId).select2({ width: '100%' });
// 콤마 추가 (수량은 정수, 금액은 소수점 2자리)
$("#" + itemId + " .item-quantity").val(addCommaInt(removeComma($("#" + itemId + " .item-quantity").val())));
$("#" + itemId + " .item-unit-price").val(addComma($("#" + itemId + " .item-unit-price").val()));
@@ -351,6 +362,7 @@
var $row = $(this);
items.push({
contractItemObjId: $row.find(".item-contract-item-objid").val(), // CONTRACT_ITEM의 OBJID
product: $row.find(".item-product").val(), // 제품구분
partObjId: $row.find(".item-part-objid").val(),
partNo: $row.find(".item-part-no").val(),
partName: $row.find(".item-part-name").val(),
@@ -490,25 +502,27 @@
<div style="max-height:300px; overflow-y:auto;">
<table class="pmsPopuptable" id="itemListTable">
<colgroup>
<col width="4%" /> <!-- 번호 -->
<col width="10%" /> <!-- 품번 -->
<col width="13%" /> <!-- 품 -->
<col width="12%" /> <!-- S/N -->
<col width="8%" /> <!-- 수주수량 -->
<col width="11%" /> <!-- 수주단가 -->
<col width="12%" /> <!-- 수주공급가액 -->
<col width="11%" /> <!-- 수주부가세 -->
<col width="12%" /> <!-- 수주총액 -->
<col width="7%" /> <!-- 삭제 -->
<col width="3%" /> <!-- 번호 -->
<col width="9%" /> <!-- 제품구분 -->
<col width="9%" /> <!-- 품 -->
<col width="12%" /> <!-- 품명 -->
<col width="10%" /> <!-- S/N -->
<col width="7%" /> <!-- 수주수량 -->
<col width="10%" /> <!-- 수주단가 -->
<col width="11%" /> <!-- 수주공급가액 -->
<col width="10%" /> <!-- 수주부가세 -->
<col width="11%" /> <!-- 수주총액 -->
<col width="5%" /> <!-- 삭제 -->
</colgroup>
<thead>
<tr style="background:#f5f5f5;">
<th style="text-align:center; padding:8px; border:1px solid #ddd;">No</th>
<th style="text-align:center; padding:8px; border:1px solid #ddd;">제품구분 <span style="color:red;">*</span></th>
<th style="text-align:center; padding:8px; border:1px solid #ddd;">품번</th>
<th style="text-align:center; padding:8px; border:1px solid #ddd;">품명</th>
<th style="text-align:center; padding:8px; border:1px solid #ddd;">S/N</th>
<th style="text-align:center; padding:8px; border:1px solid #ddd;">수주수량 <span style="color:red;">*</span></th>
<th style="text-align:center; padding:8px; border:1px solid #ddd;">수주단가 </th>
<th style="text-align:center; padding:8px; border:1px solid #ddd;">수주단가</th>
<th style="text-align:center; padding:8px; border:1px solid #ddd;">수주공급가액</th>
<th style="text-align:center; padding:8px; border:1px solid #ddd;">수주부가세</th>
<th style="text-align:center; padding:8px; border:1px solid #ddd;">수주총액</th>
@@ -518,7 +532,7 @@
<tbody id="itemListBody">
<!-- 품목 행이 동적으로 추가됩니다 -->
<tr id="noItemRow">
<td colspan="10" style="text-align:center; padding:30px; color:#999;">
<td colspan="11" style="text-align:center; padding:30px; color:#999;">
견적요청에 등록된 품목이 자동으로 표시됩니다.
</td>
</tr>

View File

@@ -7420,7 +7420,7 @@ SELECT
,CONTRACT_OBJID
,CATEGORY_CD
,CUSTOMER_OBJID
,PRODUCT
,PRODUCT
,CUSTOMER_PROJECT_NAME
,STATUS_CD
,DUE_DATE
@@ -7479,7 +7479,7 @@ SELECT
,#{objId}
,CATEGORY_CD
,CUSTOMER_OBJID
,PRODUCT
,COALESCE(#{product}, PRODUCT)
,CUSTOMER_PROJECT_NAME
,STATUS_CD
,DUE_DATE
@@ -7529,8 +7529,8 @@ SELECT
WHEN '판매' THEN 'S'
ELSE 'T'
END || '-' ||
-- 제품구분 코드 (PRODUCT를 약어로 매핑)
CASE CODE_NAME(PRODUCT)
-- 제품구분 코드 (품목별 PRODUCT를 약어로 매핑, 없으면 마스터 PRODUCT)
CASE CODE_NAME(COALESCE(#{product}, PRODUCT))
WHEN 'Machine' THEN 'MC'
WHEN 'A/S' THEN 'AS'
WHEN 'D/S' THEN 'DS'
@@ -7539,7 +7539,7 @@ SELECT
WHEN 'A/C' THEN 'AC'
WHEN 'W/M' THEN 'WM'
WHEN '기타' THEN '기타'
ELSE REPLACE(CODE_NAME(PRODUCT), '/', '')
ELSE REPLACE(CODE_NAME(COALESCE(#{product}, PRODUCT)), '/', '')
END || '-' ||
-- 날짜 (YYMMDD)
TO_CHAR(CURRENT_DATE, 'YYMMDD') || '-' ||
@@ -7559,7 +7559,7 @@ SELECT
WHEN '판매' THEN 'S'
ELSE 'T'
END || '-' ||
CASE CODE_NAME(PRODUCT)
CASE CODE_NAME(COALESCE(#{product}, PRODUCT))
WHEN 'Machine' THEN 'MC'
WHEN 'A/S' THEN 'AS'
WHEN 'D/S' THEN 'DS'
@@ -7568,7 +7568,7 @@ SELECT
WHEN 'A/C' THEN 'AC'
WHEN 'W/M' THEN 'WM'
WHEN '기타' THEN '기타'
ELSE REPLACE(CODE_NAME(PRODUCT), '/', '')
ELSE REPLACE(CODE_NAME(COALESCE(#{product}, PRODUCT)), '/', '')
END || '-' ||
TO_CHAR(CURRENT_DATE, 'YYMMDD') || '-%'
),
@@ -7766,11 +7766,21 @@ SELECT
MANUFACTURE_PLANT = #{manufacture_plant},
</if>
<if test="quantity != null and quantity != ''">
QUANTITY = #{quantity}
QUANTITY = #{quantity},
</if>
<if test="product != null and product != ''">
PRODUCT = #{product}
</if>
</set>
WHERE CONTRACT_OBJID = #{objId}
AND PART_OBJID = #{part_objid}
<choose>
<when test="contract_item_objid != null and contract_item_objid != ''">
AND CONTRACT_ITEM_OBJID = #{contract_item_objid}
</when>
<otherwise>
AND PART_OBJID = #{part_objid}
</otherwise>
</choose>
</update>
<delete id="deleteProjectMngInfo" parameterType="map">

View File

@@ -302,8 +302,15 @@ public class SalesNcollectMgmtController {
contractParam.put("objId", contractObjId);
Map<String, Object> contractInfo = commonService.selectOne("contractMgmt.getContractInfo", request, contractParam);
// PROJECT_MGMT에서 품번/품명/S/N/요청납기/고객요청사항/반납사유 조회
// PROJECT_MGMT에서 품번/품명/S/N/요청납기/고객요청사항/반납사유/제품구분 조회
if(projectInfo != null) {
// 제품구분 (프로젝트에 저장된 품목별 제품구분 우선)
Object projProduct = projectInfo.get("product") != null ? projectInfo.get("product") : projectInfo.get("PRODUCT");
Object projProductName = projectInfo.get("product_name") != null ? projectInfo.get("product_name") : projectInfo.get("PRODUCT_NAME");
if(projProduct != null && !"".equals(projProduct.toString())) {
contractInfo.put("PRODUCT", projProduct);
contractInfo.put("PRODUCT_NAME", projProductName);
}
// 품번
if(contractInfo.get("PART_NO") == null || "".equals(contractInfo.get("PART_NO"))) {
contractInfo.put("PART_NO", projectInfo.get("part_no") != null ? projectInfo.get("part_no") : projectInfo.get("PART_NO"));

View File

@@ -5288,6 +5288,9 @@ WHERE
ORDER_SUPPLY_PRICE = #{orderSupplyPrice},
ORDER_VAT = #{orderVat},
ORDER_TOTAL_AMOUNT = #{orderTotalAmount}
<if test="product != null and product != ''">
,PRODUCT = #{product}
</if>
WHERE OBJID = #{contractItemObjId}
</update>

View File

@@ -1787,8 +1787,10 @@ ORDER BY T.REGDATE DESC, T.PROJECT_NO DESC
<!-- 프로젝트 기본 정보 조회 (CONTRACT_OBJID 포함) -->
<select id="getProjectInfo" parameterType="map" resultType="map">
/* salesNcollectMgmt.getProjectInfo - PROJECT_MGMT의 상세 정보 조회 (최신 1개) */
SELECT
SELECT
PM.CONTRACT_OBJID,
PM.PRODUCT,
CODE_NAME(PM.PRODUCT) AS PRODUCT_NAME,
PM.PART_NO,
PM.PART_NAME,
-- 요청납기 (CONTRACT_ITEM의 DUE_DATE 우선, 없으면 PROJECT_MGMT.DUE_DATE)

View File

@@ -2893,6 +2893,7 @@ private String encodeImageToBase64(String imagePath) {
String orderTotalAmount = item.get("orderTotalAmount") != null ? item.get("orderTotalAmount").toString().replace(",", "") : "0";
itemMap.put("contractItemObjId", item.get("contractItemObjId") != null ? item.get("contractItemObjId").toString() : "");
itemMap.put("product", item.get("product") != null ? item.get("product").toString() : "");
itemMap.put("orderQuantity", item.get("orderQuantity") != null ? item.get("orderQuantity").toString() : "");
itemMap.put("orderUnitPrice", item.get("orderUnitPrice") != null ? item.get("orderUnitPrice").toString() : "");
itemMap.put("orderSupplyPrice", orderSupplyPrice);
@@ -2928,18 +2929,16 @@ private String encodeImageToBase64(String imagePath) {
// 프로젝트가 이미 존재하는 경우에는 수량/납기 등 업데이트 반영
resultList = sqlSession.selectOne("contractMgmt.getProjectListBycontractObjid", paramMap);
if(resultList != null) {
// 제품구분 확인
Map<String, Object> contractInfo = (Map<String, Object>) sqlSession.selectOne("contractMgmt.getContractBasicInfo", paramMap);
contractInfo = CommonUtils.toUpperCaseMapKey(contractInfo);
String product_cd = contractInfo != null ? CommonUtils.checkNull(contractInfo.get("PRODUCT")) : "";
boolean isMachine = "0000928".equals(product_cd);
paramMap.put("contractObjId", contract_objid);
List contractItemsRaw2 = sqlSession.selectList("contractMgmt.getContractItems", paramMap);
List<Map<String, Object>> contractItems = CommonUtils.toUpperCaseMapKey(contractItemsRaw2);
if(contractItems != null && !contractItems.isEmpty()) {
for(Map item : contractItems) {
// 품목별 제품구분 판단
String itemProductCd = CommonUtils.checkNull(item.get("PRODUCT"));
boolean isMachine = "0000928".equals(itemProductCd);
Object quantityObj = item.get("ORDER_QUANTITY") != null ? item.get("ORDER_QUANTITY") : item.get("QUANTITY");
int itemQuantity = 1;
try {
@@ -2949,6 +2948,7 @@ private String encodeImageToBase64(String imagePath) {
}
Map<String, Object> updateParam = new HashMap<String, Object>();
updateParam.putAll(paramMap);
updateParam.put("contract_item_objid", String.valueOf(item.get("OBJID")));
updateParam.put("part_objid", item.get("PART_OBJID"));
if(isMachine) {
updateParam.remove("quantity");
@@ -2956,6 +2956,7 @@ private String encodeImageToBase64(String imagePath) {
updateParam.put("quantity", String.valueOf(itemQuantity));
}
updateParam.put("due_date", item.get("DUE_DATE"));
updateParam.put("product", itemProductCd);
sqlSession.update("project.ModifyProjectByContract", updateParam);
}
} else {
@@ -3005,13 +3006,7 @@ private String encodeImageToBase64(String imagePath) {
Map<String, Object> contractInfo = (Map<String, Object>) sqlSession.selectOne("contractMgmt.getContractBasicInfo", paramMap);
contractInfo = CommonUtils.toUpperCaseMapKey(contractInfo);
String product_cd = contractInfo != null ? CommonUtils.checkNull(contractInfo.get("PRODUCT")) : "";
String category_cd = contractInfo != null ? CommonUtils.checkNull(contractInfo.get("CATEGORY_CD")) : "";
boolean isMachine = "0000928".equals(product_cd);
if(isMachine) {
System.out.println("[수주확정] 제품구분: Machine(0000928) - 품목별 수량만큼 프로젝트 생성");
}
// 품목별로 프로젝트 생성 또는 업데이트
paramMap.put("contractObjId", objId);
@@ -3019,9 +3014,13 @@ private String encodeImageToBase64(String imagePath) {
List<Map<String, Object>> contractItems = CommonUtils.toUpperCaseMapKey(contractItemsRaw);
if(contractItems != null && !contractItems.isEmpty()) {
System.out.println("[수주확정] 품목 개수: " + contractItems.size() + "개 - 프로젝트 " + (hasProject ? "업데이트" : "생성") + " 시작" + (isMachine ? " (Machine - 수량별 생성)" : ""));
System.out.println("[수주확정] 품목 개수: " + contractItems.size() + "개 - 프로젝트 " + (hasProject ? "업데이트" : "생성") + " 시작");
for(Map item : contractItems) {
// 품목별 제품구분 판단
String itemProductCd = CommonUtils.checkNull(item.get("PRODUCT"));
boolean isMachine = "0000928".equals(itemProductCd);
// 수량 가져오기 (소수점 형태 "2.00"도 처리)
Object quantityObj = item.get("ORDER_QUANTITY") != null ? item.get("ORDER_QUANTITY") : item.get("QUANTITY");
int itemQuantity = 1;
@@ -3034,6 +3033,10 @@ private String encodeImageToBase64(String imagePath) {
// Machine인 경우 수량만큼 반복, 아니면 1번만 실행
int loopCount = (isMachine && !hasProject) ? itemQuantity : 1;
if(isMachine) {
System.out.println("[수주확정] 제품구분: Machine(0000928) - 품번: " + item.get("PART_NO") + ", 수량 " + itemQuantity + "만큼 프로젝트 생성");
}
for(int q = 0; q < loopCount; q++) {
if(!hasProject) {
// 프로젝트가 없으면 모든 품목에 대해 생성
@@ -3047,6 +3050,8 @@ private String encodeImageToBase64(String imagePath) {
projectParam.put("part_objid", item.get("PART_OBJID"));
projectParam.put("part_no", item.get("PART_NO"));
projectParam.put("part_name", item.get("PART_NAME"));
// 품목별 제품구분 전달 (PROJECT_NO 생성 및 PRODUCT 컬럼에 사용)
projectParam.put("product", itemProductCd);
// Machine인 경우 각 프로젝트의 수량은 1, 아니면 원래 수량
projectParam.put("quantity", isMachine ? "1" : String.valueOf(itemQuantity));
projectParam.put("due_date", item.get("DUE_DATE"));
@@ -3070,6 +3075,7 @@ private String encodeImageToBase64(String imagePath) {
// 프로젝트가 있으면 모든 품목 업데이트 (수량, 금액 등만)
Map<String, Object> updateParam = new HashMap<String, Object>();
updateParam.putAll(paramMap);
updateParam.put("contract_item_objid", String.valueOf(item.get("OBJID")));
updateParam.put("part_objid", item.get("PART_OBJID"));
// Machine인 경우 수량은 변경하지 않음 (프로젝트별 1로 유지)
if(isMachine) {