Files
wace_plm/WebContent/WEB-INF/view/contractMgmt/estimateTemplate2.jsp
hjjeong 141ef2c580 feat: 주문서관리 수주등록 기능 구현 및 Admin 버튼 UI 개선
- 주문서관리 목록 페이지 추가 (orderMgmtList.jsp)
- 수주등록 팝업 기능 구현 (orderRegistFormPopup.jsp)
  * 영업정보 선택 후 수주 정보 입력
  * 환종/환율 자동 로드 및 금액 자동 계산
  * 단가×수량 → 공급가액, 부가세, 총액 자동 계산
- Controller: orderRegistFormPopup, saveOrderInfo 메서드 추가
- Service: getContractInfo, getOrderInfo, saveOrderInfo 메서드 추가
- Mapper: 수주 정보 조회/저장 쿼리 추가 (updateOrderInfo)
- CONTRACT_MGMT 테이블의 수주 관련 컬럼 활용
- Header Admin 버튼 UI 개선 (인라인 표시)
2025-10-17 10:00:18 +09:00

724 lines
20 KiB
Plaintext

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="com.pms.common.utils.*"%>
<%@ page import="java.util.*" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@include file= "/init.jsp" %>
<%
PersonBean person = (PersonBean)session.getAttribute(Constants.PERSON_BEAN);
String userId = CommonUtils.checkNull(person.getUserId());
String objId = CommonUtils.checkNull(request.getParameter("objId"));
%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><%=Constants.SYSTEM_NAME%> - 장비 견적서</title>
<style type="text/css">
@media print {
@page {
size: A4;
margin: 10mm;
}
body {
margin: 0;
padding: 0;
}
.no-print {
display: none !important;
}
}
body {
font-family: "Malgun Gothic", "맑은 고딕", Arial, sans-serif;
font-size: 10pt;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
.estimate-container {
width: 210mm;
min-height: 297mm;
background: white;
margin: 0 auto;
padding: 15mm;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
box-sizing: border-box;
}
.header-section {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 20px;
}
.logo-section {
flex: 0 0 150px;
}
.logo-img {
width: 120px;
height: auto;
}
.title-section {
flex: 1;
text-align: center;
}
.title {
font-size: 24pt;
font-weight: bold;
letter-spacing: 15px;
margin-bottom: 20px;
}
.company-info {
flex: 0 0 200px;
text-align: right;
font-size: 9pt;
line-height: 1.5;
}
.company-name {
font-weight: bold;
font-size: 10pt;
margin-bottom: 5px;
}
.basic-info {
display: flex;
gap: 10px;
margin-bottom: 20px;
font-size: 10pt;
}
.basic-info-left {
flex: 0 0 40%;
}
.basic-info-right {
flex: 1;
}
.info-row {
display: flex;
margin-bottom: 5px;
}
.info-label {
width: 80px;
font-weight: bold;
}
.info-value {
flex: 1;
}
.model-header {
background-color: #90EE90;
padding: 8px;
text-align: center;
font-weight: bold;
border: 1px solid #000;
margin-bottom: 0;
}
.items-table {
width: 100%;
border-collapse: collapse;
margin-bottom: 0;
}
.items-table th,
.items-table td {
border: 1px solid #000;
padding: 8px;
font-size: 9pt;
}
.items-table th {
background-color: #E8E8E8;
font-weight: bold;
text-align: center;
}
.items-table .col-no { width: 5%; text-align: center; }
.items-table .col-desc { width: 25%; }
.items-table .col-spec { width: 30%; }
.items-table .col-qty { width: 7%; text-align: center; }
.items-table .col-price { width: 12%; text-align: right; }
.items-table .col-amount { width: 12%; text-align: right; }
.items-table .col-remark { width: 9%; text-align: center; }
.category-row {
background-color: #f0f0f0;
font-weight: bold;
}
.subtotal-row {
background-color: #FFFF00;
font-weight: bold;
}
.subtotal-row td {
text-align: center;
}
.detail-row {
height: 60px;
}
.notes-section {
margin-top: 20px;
padding: 15px;
border: 1px solid #ddd;
font-size: 9pt;
line-height: 1.8;
}
.notes-section ul {
margin: 5px 0;
padding-left: 20px;
}
.notes-section li {
margin-bottom: 5px;
}
.footer-section {
display: flex;
justify-content: space-between;
margin-top: 20px;
font-size: 8pt;
color: #666;
}
.company-footer {
text-align: right;
font-weight: bold;
font-size: 11pt;
}
input[type="text"],
textarea {
border: none;
outline: none;
background: transparent;
width: 100%;
font-family: inherit;
font-size: inherit;
}
.editable {
background-color: #fffef0;
}
.highlight {
background-color: #FFFF00 !important;
}
.vat-badge {
background-color: #FFFF00;
padding: 3px 8px;
font-weight: bold;
display: inline-block;
}
.btn-area {
text-align: center;
margin-top: 20px;
padding: 10px;
}
.plm_btns {
padding: 10px 30px;
margin: 0 5px;
font-size: 14px;
cursor: pointer;
}
@media print {
.editable {
background-color: transparent;
}
textarea {
border: none !important;
overflow: hidden;
resize: none;
}
input[type="text"] {
border: none !important;
}
}
</style>
<script type="text/javascript">
$(function(){
// 인쇄 버튼
$("#btnPrint").click(function(){
window.print();
});
// 저장 버튼
$("#btnSave").click(function(){
if(confirm("장비 견적서를 저장하시겠습니까?")) {
fn_save();
}
});
// 닫기 버튼
$("#btnClose").click(function(){
self.close();
});
// 금액 자동 계산
$(".item-qty, .item-price").on("change keyup", function(){
fn_calculateAmount($(this).closest("tr"));
fn_calculateSubtotal($(this).closest("tbody"));
});
// 콤마 자동 추가
$(".item-price, .item-amount, .subtotal-amount").on("blur", function(){
var val = $(this).val().replace(/,/g, "");
if(!isNaN(val) && val !== "") {
$(this).val(addComma(val));
}
});
// 데이터 로드
if("<%=objId%>" !== "" && "<%=objId%>" !== "-1") {
fn_loadData();
}
});
// 금액 계산
function fn_calculateAmount(row) {
if(row.hasClass("category-row") || row.hasClass("subtotal-row")) {
return;
}
var qty = row.find(".item-qty").val() || "1";
var price = row.find(".item-price").val().replace(/,/g, "") || "0";
var amount = parseInt(qty) * parseInt(price);
if(!isNaN(amount)) {
row.find(".item-amount").val(addComma(amount));
}
}
// 소계 계산
function fn_calculateSubtotal(tbody) {
var total = 0;
tbody.find("tr:not(.category-row):not(.subtotal-row)").each(function() {
var amount = $(this).find(".item-amount").val();
if(amount) {
var numAmount = parseInt(amount.replace(/,/g, "").replace(/-/g, ""));
if(!isNaN(numAmount)) {
total += numAmount;
}
}
});
tbody.find(".subtotal-amount").val(addComma(total));
}
// 콤마 추가
function addComma(num) {
var regexp = /\B(?=(\d{3})+(?!\d))/g;
return num.toString().replace(regexp, ',');
}
// 데이터 로드
function fn_loadData() {
$.ajax({
url: "/contractMgmt/getEstimateDetail.do",
type: "POST",
data: {
objId: "<%=objId%>",
template_type: "2"
},
dataType: "json",
success: function(data) {
if(data && data.estimate) {
// 기본 정보 바인딩
$("#executor_date").val(data.estimate.EXECUTOR_DATE || "");
$("#recipient").val(data.estimate.RECIPIENT || "");
$("#model_name").val(data.estimate.MODEL_NAME || "");
$("#model_code").val(data.estimate.MODEL_CODE || "RUV-RA500S");
// 비고 내용 - 기존 데이터가 있을 때만 덮어쓰기
if(data.estimate.NOTES_CONTENT && data.estimate.NOTES_CONTENT !== "") {
$("#notes_content").val(data.estimate.NOTES_CONTENT);
}
// 견적 유효기간 - 기존 데이터가 있을 때만 덮어쓰기
if(data.estimate.VALIDITY_PERIOD && data.estimate.VALIDITY_PERIOD !== "") {
$("#validity_period").val(data.estimate.VALIDITY_PERIOD);
}
// 품목 데이터 로드 (카테고리별로 구분된 경우)
if(data.items && data.items.length > 0) {
// 데이터 바인딩 로직
}
}
},
error: function() {
Swal.fire("데이터를 불러오는데 실패했습니다.");
}
});
}
// 저장
function fn_save() {
var categories = [];
// 각 카테고리별 데이터 수집
$(".category-section").each(function() {
var section = $(this);
var categoryName = section.data("category");
var items = [];
section.find("tr.detail-row").each(function() {
var row = $(this);
items.push({
description: row.find(".item-desc").val(),
specification: row.find(".item-spec").val(),
quantity: row.find(".item-qty").val(),
unit_price: row.find(".item-price").val().replace(/,/g, ""),
amount: row.find(".item-amount").val().replace(/,/g, ""),
remark: row.find(".item-remark").val()
});
});
var subtotal = section.find(".subtotal-amount").val().replace(/,/g, "");
categories.push({
category: categoryName,
items: items,
subtotal: subtotal
});
});
var formData = {
objId: "<%=objId%>",
template_type: "2",
executor_date: $("#executor_date").val(),
recipient: $("#recipient").val(),
model_name: $("#model_name").val(),
model_code: $("#model_code").val(),
notes_content: $("#notes_content").val(),
validity_period: $("#validity_period").val(),
categories: JSON.stringify(categories)
};
$.ajax({
url: "/contractMgmt/saveEstimate.do",
type: "POST",
data: formData,
dataType: "json",
success: function(data) {
if(data.result === "success") {
Swal.fire({
title: "저장되었습니다.",
icon: "success"
}).then(function() {
if(opener && opener.fn_search) {
opener.fn_search();
}
self.close();
});
} else {
Swal.fire("저장에 실패했습니다.");
}
},
error: function() {
Swal.fire("저장 중 오류가 발생했습니다.");
}
});
}
</script>
</head>
<body>
<div class="estimate-container">
<!-- 헤더 섹션 -->
<div class="header-section">
<div class="logo-section">
<img src="<%=request.getContextPath()%>/images/logo.png" alt="RPS Logo" style="max-width: 150px; height: auto;">
</div>
<div class="title-section">
<div class="title">견 적 서</div>
</div>
<div style="flex: 0 0 200px; text-align: right; font-size: 9pt; line-height: 1.5;">
<!-- 빈 공간 (기존 회사정보 위치) -->
</div>
</div>
<!-- 기본 정보 (좌우 배치) -->
<div style="display: flex; justify-content: space-between; margin-top: 20px; margin-bottom: 20px; padding: 0 10px;">
<div style="text-align: left; font-size: 10pt; line-height: 2;">
<div><strong>시행일자 :</strong> <input type="text" id="executor_date" value="" style="width: 200px; border: none; border-bottom: 1px solid #999; background: #fffef0; padding: 2px 5px;"></div>
<div><strong>수 신 처 :</strong> <input type="text" id="recipient" value="" style="width: 200px; border: none; border-bottom: 1px solid #999; background: #fffef0; padding: 2px 5px;"></div>
<div><strong>품  명 :</strong> <input type="text" id="model_name" value="RUV-RA500S" style="width: 200px; border: none; border-bottom: 1px solid #999; background: #fffef0; padding: 2px 5px;"></div>
</div>
<div style="text-align: right;">
<!-- 회사정보 -->
<div style="display: inline-block; min-width: 300px;">
<div style="font-weight: bold; font-size: 11pt; margin-bottom: 5px;">RPS CO., LTD</div>
<div style="font-size: 9pt; line-height: 1.5;">대전광역시 유성구 국제과학로 10로 8</div>
<div style="font-size: 9pt; line-height: 1.5;">TEL: (042)602-3300, FAX: (042)672-3399</div>
</div>
</div>
</div>
<!-- 설비 Model 헤더 -->
<div class="model-header">
설비 Model : <span class="editable" style="display: inline-block; min-width: 200px;">
<input type="text" id="model_code" value="RUV-RA500S" style="text-align: center; font-weight: bold;">
</span>
</div>
<!-- 품목 테이블 헤더 -->
<table class="items-table">
<thead>
<tr>
<th class="col-no">NO</th>
<th class="col-desc">DESCRIPTION</th>
<th class="col-spec">SPECIFICATION</th>
<th class="col-qty">Q'TY</th>
<th>UNIT PRICE</th>
<th>AMOUNT</th>
<th class="col-remark">REMARK</th>
</tr>
</thead>
</table>
<!-- 1. 초음파 CNC Machine -->
<table class="items-table category-section" data-category="cnc_machine">
<tbody>
<tr class="category-row">
<td class="col-no" rowspan="2">1</td>
<td colspan="6">초음파 CNC Machine</td>
</tr>
<tr class="detail-row">
<td class="editable"><input type="text" class="item-desc" value=""></td>
<td class="editable">
<div><input type="text" value="Hole 가공" style="margin-bottom: 5px;"></div>
<div class="highlight"><input type="text" class="item-spec" value="최종 견적가"></div>
</td>
<td class="editable"><input type="text" class="item-qty" value="1"></td>
<td class="editable"><input type="text" class="item-price" value=""></td>
<td class="editable"><input type="text" class="item-amount" value="" readonly></td>
<td class="editable">
<div class="vat-badge">VAT 별도</div>
</td>
</tr>
</tbody>
</table>
<!-- 1. 기구 -->
<table class="items-table category-section" data-category="scan_odom">
<tbody>
<tr class="category-row">
<td class="col-no" rowspan="2">1</td>
<td colspan="6">기구</td>
</tr>
<tr class="detail-row">
<td class="editable"><input type="text" class="item-desc" value=""></td>
<td class="editable"><input type="text" class="item-spec" value=""></td>
<td class="editable"><input type="text" class="item-qty" value=""></td>
<td class="editable"><input type="text" class="item-price" value=""></td>
<td class="editable"><input type="text" class="item-amount" value="" readonly></td>
<td class="editable"><input type="text" class="item-remark" value=""></td>
</tr>
</tbody>
</table>
<!-- 2. 초음파 스핀들 모듈 -->
<table class="items-table category-section" data-category="scan_odom">
<tbody>
<tr class="category-row">
<td class="col-no" rowspan="2">2</td>
<td colspan="6">초음파 스핀들 모듈</td>
</tr>
<tr class="detail-row">
<td class="editable"><input type="text" class="item-desc" value=""></td>
<td class="editable"><input type="text" class="item-spec" value=""></td>
<td class="editable"><input type="text" class="item-qty" value=""></td>
<td class="editable"><input type="text" class="item-price" value=""></td>
<td class="editable"><input type="text" class="item-amount" value="" readonly></td>
<td class="editable"><input type="text" class="item-remark" value=""></td>
</tr>
</tbody>
</table>
<!-- 3. 전장 -->
<table class="items-table category-section" data-category="electric">
<tbody>
<tr class="category-row">
<td class="col-no" rowspan="2">3</td>
<td colspan="6">전장</td>
</tr>
<tr class="detail-row">
<td class="editable"><input type="text" class="item-desc" value=""></td>
<td class="editable"><input type="text" class="item-spec" value=""></td>
<td class="editable"><input type="text" class="item-qty" value=""></td>
<td class="editable"><input type="text" class="item-price" value=""></td>
<td class="editable"><input type="text" class="item-amount" value="" readonly></td>
<td class="editable"><input type="text" class="item-remark" value=""></td>
</tr>
</tbody>
</table>
<!-- 4. UTILITY -->
<table class="items-table category-section" data-category="utility">
<tbody>
<tr class="category-row">
<td class="col-no" rowspan="2">4</td>
<td colspan="6">UTILITY</td>
</tr>
<tr class="detail-row">
<td class="editable"><input type="text" class="item-desc" value=""></td>
<td class="editable"><input type="text" class="item-spec" value=""></td>
<td class="editable"><input type="text" class="item-qty" value=""></td>
<td class="editable"><input type="text" class="item-price" value=""></td>
<td class="editable"><input type="text" class="item-amount" value="" readonly></td>
<td class="editable"><input type="text" class="item-remark" value=""></td>
</tr>
</tbody>
</table>
<!-- 5. 자동화 -->
<table class="items-table category-section" data-category="automation">
<tbody>
<tr class="subtotal-row">
<td colspan="5">Subtotal</td>
<td class="editable"><input type="text" class="subtotal-amount" value="-" readonly></td>
<td></td>
</tr>
<tr class="category-row">
<td class="col-no" rowspan="2">5</td>
<td colspan="6">자동화</td>
</tr>
<tr class="detail-row">
<td class="editable"><input type="text" class="item-desc" value=""></td>
<td class="editable"><input type="text" class="item-spec" value=""></td>
<td class="editable"><input type="text" class="item-qty" value=""></td>
<td class="editable"><input type="text" class="item-price" value=""></td>
<td class="editable"><input type="text" class="item-amount" value="" readonly></td>
<td class="editable"><input type="text" class="item-remark" value=""></td>
</tr>
<tr class="subtotal-row">
<td colspan="5">Subtotal</td>
<td class="editable"><input type="text" class="subtotal-amount" value="-" readonly></td>
<td></td>
</tr>
</tbody>
</table>
<!-- 6. Option -->
<table class="items-table category-section" data-category="option">
<tbody>
<tr class="category-row">
<td class="col-no" rowspan="2">6</td>
<td colspan="6">Option</td>
</tr>
<tr class="detail-row">
<td class="editable"><input type="text" class="item-desc" value=""></td>
<td class="editable"><input type="text" class="item-spec" value=""></td>
<td class="editable"><input type="text" class="item-qty" value=""></td>
<td class="editable"><input type="text" class="item-price" value=""></td>
<td class="editable"><input type="text" class="item-amount" value="" readonly></td>
<td class="editable"><input type="text" class="item-remark" value=""></td>
</tr>
<tr class="subtotal-row">
<td colspan="5">Subtotal</td>
<td class="editable"><input type="text" class="subtotal-amount" value="-" readonly></td>
<td></td>
</tr>
</tbody>
</table>
<!-- 7. Set up -->
<table class="items-table category-section" data-category="setup">
<tbody>
<tr class="category-row">
<td class="col-no" rowspan="2">7</td>
<td colspan="6">Set up</td>
</tr>
<tr class="detail-row">
<td class="editable"><input type="text" class="item-desc" value=""></td>
<td class="editable"><input type="text" class="item-spec" value=""></td>
<td class="editable"><input type="text" class="item-qty" value=""></td>
<td class="editable"><input type="text" class="item-price" value=""></td>
<td class="editable"><input type="text" class="item-amount" value="" readonly></td>
<td class="editable"><input type="text" class="item-remark" value=""></td>
</tr>
<tr class="subtotal-row">
<td colspan="5">Subtotal</td>
<td class="editable"><input type="text" class="subtotal-amount" value="-" readonly></td>
<td></td>
</tr>
</tbody>
</table>
<!-- 8. 포장 /물류 -->
<table class="items-table category-section" data-category="packing">
<tbody>
<tr class="category-row">
<td class="col-no" rowspan="2">8</td>
<td colspan="6">포장 /물류</td>
</tr>
<tr class="detail-row">
<td class="editable"><input type="text" class="item-desc" value=""></td>
<td class="editable"><input type="text" class="item-spec" value=""></td>
<td class="editable"><input type="text" class="item-qty" value=""></td>
<td class="editable"><input type="text" class="item-price" value=""></td>
<td class="editable"><input type="text" class="item-amount" value="" readonly></td>
<td class="editable"><input type="text" class="item-remark" value=""></td>
</tr>
<tr class="subtotal-row">
<td colspan="5">Subtotal</td>
<td class="editable"><input type="text" class="subtotal-amount" value="-" readonly></td>
<td></td>
</tr>
</tbody>
</table>
<!-- 비고 섹션 -->
<div class="notes-section editable">
<textarea id="notes_content" style="width: 100%; min-height: 180px; border: 1px solid #ddd; padding: 10px; font-family: inherit; font-size: 9pt; line-height: 1.8; resize: vertical;">■ 최종 견적가는 부가세 별도입니다.
■ 장비 납기 : 발주 후 0개월
■ 운송 조건 : -
■ 결제 조건 : 계약금 : 0% / 잔금 : 0%
- 계약금 : 발주
- 잔 금 : 설치 완료 후
■ 특이사항 : 최종 장비 사양 확인 후 추가 변경 발생 시 금액 변동 가능성 있음.
■ Warrenty Period: 0년(소모성 parts 제외)
■ 주의 : RPS 동의없이 초음파 스핀들의 임의 탈거 또는 해체시 보증 할수 없음.
■ 해당 견적은 양산 0대 기준의 견적으로 후속 장비 진행 시 동일한 가격 책정 요청 드림.</textarea>
</div>
<!-- 푸터 -->
<div class="footer-section">
<div><input type="text" id="validity_period" value="* 견적유효기간: 0주 " style="width: 250px; text-align: left;"></div>
<div class="company-footer">㈜ 알 피 에 스</div>
</div>
<div style="text-align: right; font-size: 7pt; color: #999; margin-top: 5px;">
* RPS 대외비 - 본자료는 RPS의 사전허가 없이 제3자에게 제공할 수 없음을 알려드립니다.
</div>
</div>
<!-- 버튼 영역 -->
<div class="btn-area no-print">
<input type="button" value="인쇄" id="btnPrint" class="plm_btns">
<input type="button" value="저장" id="btnSave" class="plm_btns">
<input type="button" value="닫기" id="btnClose" class="plm_btns">
</div>
</body>
</html>