영업관리_견적관리 결재상신 아마란스 연동(추가 테스트 필요) #149
@@ -151,33 +151,37 @@ $(document).ready(function(){
|
||||
document.form1.submit();
|
||||
});
|
||||
|
||||
//결재상신
|
||||
// 결재상신 (Amaranth10 전자결재 SSO 방식)
|
||||
$("#btnApproval").click(function(){
|
||||
var selectedData = _tabulGrid.getSelectedData();
|
||||
if(selectedData.length<1){
|
||||
if(selectedData.length < 1){
|
||||
Swal.fire("결재상신할 행을 선택해주십시오.");
|
||||
return false;
|
||||
}else if(selectedData.length>1){
|
||||
} else if(selectedData.length > 1){
|
||||
Swal.fire("한번에 한개의 결재만 가능합니다.");
|
||||
return false;
|
||||
}else{
|
||||
|
||||
var targetStatus = fnc_checkNull(selectedData[0].APPR_STATUS);
|
||||
var status = fnc_checkNull(selectedData[0].STATUS);
|
||||
} else {
|
||||
var amaranthStatus = fnc_checkNull(selectedData[0].AMARANTH_STATUS);
|
||||
var estObjId = fnc_checkNull(selectedData[0].EST_OBJID);
|
||||
var contractObjId = fnc_checkNull(selectedData[0].OBJID);
|
||||
var customerObjId = fnc_checkNull(selectedData[0].CUSTOMER_OBJID);
|
||||
|
||||
// 견적서 작성 여부 확인
|
||||
|
||||
if(estObjId == ""){
|
||||
Swal.fire("견적서를 먼저 작성해주세요.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(targetStatus == "결재완료" || targetStatus == "결재중" || targetStatus == "결재불필요" || status == "cancel"){
|
||||
Swal.fire("작성중/결재반려인 상태만 결재상신 가능합니다.");
|
||||
|
||||
if(amaranthStatus == "inProcess"){
|
||||
Swal.fire("결재 진행중인 건은 상신할 수 없습니다.");
|
||||
return false;
|
||||
}else{
|
||||
} else if(amaranthStatus == "complete"){
|
||||
Swal.fire("결재 완료된 건은 상신할 수 없습니다.");
|
||||
return false;
|
||||
} else if(amaranthStatus == "notRequired"){
|
||||
Swal.fire("결재불필요로 처리된 건입니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 결재 필요 여부 체크 (재오더/신규수주/가격인하)
|
||||
$.ajax({
|
||||
url: "/contractMgmt/checkApprovalRequired.do",
|
||||
@@ -191,9 +195,8 @@ $(document).ready(function(){
|
||||
if(response.result == "success") {
|
||||
var approvalRequired = response.approvalRequired;
|
||||
var reason = response.reason;
|
||||
|
||||
|
||||
if(approvalRequired == "N") {
|
||||
// 재오더 + 가격동일/인상 → 결재불필요
|
||||
Swal.fire({
|
||||
title: '결재 불필요',
|
||||
html: '재오더(가격동일/인상)로 결재가 필요하지 않습니다.<br>결재불필요로 처리하시겠습니까?<br><br><small>* 결재불필요 처리 후 메일발송이 가능합니다.</small>',
|
||||
@@ -205,13 +208,10 @@ $(document).ready(function(){
|
||||
cancelButtonText: '취소'
|
||||
}).then((result) => {
|
||||
if(result.isConfirmed) {
|
||||
// 결재불필요 처리
|
||||
$.ajax({
|
||||
url: "/contractMgmt/setApprovalNotRequired.do",
|
||||
type: "POST",
|
||||
data: {
|
||||
estObjId: estObjId
|
||||
},
|
||||
data: { estObjId: estObjId },
|
||||
dataType: "json",
|
||||
success: function(res) {
|
||||
if(res.result == "success") {
|
||||
@@ -223,7 +223,7 @@ $(document).ready(function(){
|
||||
confirmButtonText: "메일발송",
|
||||
cancelButtonText: "나중에"
|
||||
}).then((mailResult) => {
|
||||
fn_search(); // 목록 새로고침
|
||||
fn_search();
|
||||
if(mailResult.isConfirmed) {
|
||||
fn_openMailFormPopup(contractObjId);
|
||||
}
|
||||
@@ -239,14 +239,10 @@ $(document).ready(function(){
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 신규수주 또는 가격인하 → 결재필요
|
||||
var reasonText = "";
|
||||
if(reason == "신규수주") {
|
||||
reasonText = "신규수주입니다.";
|
||||
} else if(reason == "가격인하") {
|
||||
reasonText = "가격인하 건입니다.";
|
||||
}
|
||||
|
||||
if(reason == "신규수주") reasonText = "신규수주입니다.";
|
||||
else if(reason == "가격인하") reasonText = "가격인하 건입니다.";
|
||||
|
||||
Swal.fire({
|
||||
title: '결재상신',
|
||||
html: (reasonText ? reasonText + '<br>' : '') + '결재상신 하시겠습니까?<br><br><small>* 결재완료 후 메일발송이 가능합니다.</small>',
|
||||
@@ -258,24 +254,18 @@ $(document).ready(function(){
|
||||
cancelButtonText: '취소'
|
||||
}).then((result) => {
|
||||
if(result.isConfirmed) {
|
||||
var objId = estObjId;
|
||||
var title = encodeURIComponent(fnc_checkNull(selectedData[0].CONTRACT_NO));
|
||||
var approvalUrl = "/approval/registApproval.do?targetType=CONTRACT_ESTIMATE&targetObjId="+objId+"&approvalTitle="+title;
|
||||
window.open(approvalUrl, "registApproval", "width=700,height=700");
|
||||
fn_openAmaranthApproval(estObjId, fnc_checkNull(selectedData[0].CONTRACT_NO));
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// API 오류 시 기존 방식으로 진행
|
||||
fn_showApprovalConfirmSimple(estObjId, selectedData[0].CONTRACT_NO);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
// AJAX 오류 시 기존 방식으로 진행
|
||||
fn_showApprovalConfirmSimple(estObjId, selectedData[0].CONTRACT_NO);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -427,15 +417,19 @@ var columns = [
|
||||
fn_showEstimateList(objid);
|
||||
}
|
||||
},
|
||||
// 12. 결재상태
|
||||
{headerHozAlign : 'center', hozAlign : 'center', minWidth: 50, widthGrow: 0.7, title : '결재상태', field : 'APPR_STATUS',
|
||||
formatter:fnc_createGridAnchorTag,
|
||||
cellClick:function(e, cell){
|
||||
var APPROVAL_OBJID = fnc_checkNull(cell.getData().APPROVAL_OBJID);
|
||||
var ROUTE_OBJID = fnc_checkNull(cell.getData().ROUTE_OBJID);
|
||||
approval_form(APPROVAL_OBJID,ROUTE_OBJID);
|
||||
}
|
||||
},
|
||||
// 12. 아마란스 결재상태 (hidden)
|
||||
{title:'AMARANTH_STATUS', field:'AMARANTH_STATUS', visible: false},
|
||||
// 13. 결재상태 (아마란스 전자결재)
|
||||
{headerHozAlign : 'center', hozAlign : 'center', minWidth: 50, widthGrow: 0.7, title : '결재상태', field : 'APPR_STATUS',
|
||||
formatter:function(cell){
|
||||
var val = fnc_checkNull(cell.getValue());
|
||||
if(val == '결재중') return "<span style='color:#e67e22; font-weight:bold;'>" + val + "</span>";
|
||||
if(val == '결재완료') return "<span style='color:#27ae60; font-weight:bold;'>" + val + "</span>";
|
||||
if(val == '반려') return "<span style='color:#e74c3c; font-weight:bold;'>" + val + "</span>";
|
||||
if(val == '결재불필요') return "<span style='color:#3498db; font-weight:bold;'>" + val + "</span>";
|
||||
return val;
|
||||
}
|
||||
},
|
||||
// 13. 메일발송
|
||||
{headerHozAlign : 'center', hozAlign : 'center', minWidth: 50, widthGrow: 0.7, title : '메일발송', field : 'MAIL_SEND_STATUS',
|
||||
formatter: function(cell, formatterParams, onRendered){
|
||||
@@ -634,12 +628,6 @@ function fn_delete(){
|
||||
}
|
||||
}
|
||||
|
||||
function approval_form(APPROVAL_OBJID,ROUTE_OBJID){
|
||||
|
||||
url = "/approval/approvalDetail.do?approvalObjId="+APPROVAL_OBJID+"&routeObjId="+ROUTE_OBJID;
|
||||
|
||||
fn_centerPopup(650,400,url,'approvalDetailPopup')
|
||||
}
|
||||
|
||||
function fn_FileRegist(objId, docType, docTypeName){
|
||||
var popup_width = 800;
|
||||
@@ -825,7 +813,7 @@ function fn_showSerialNoPopup(serialNoString){
|
||||
});
|
||||
}
|
||||
|
||||
// 결재상신 확인 다이얼로그 (단순 버전)
|
||||
// 결재상신 확인 다이얼로그 (단순 버전 - 아마란스 전자결재)
|
||||
function fn_showApprovalConfirmSimple(estObjId, contractNo) {
|
||||
Swal.fire({
|
||||
title: '결재상신',
|
||||
@@ -838,9 +826,39 @@ function fn_showApprovalConfirmSimple(estObjId, contractNo) {
|
||||
cancelButtonText: '취소'
|
||||
}).then((result) => {
|
||||
if(result.isConfirmed) {
|
||||
var title = encodeURIComponent(fnc_checkNull(contractNo));
|
||||
var approvalUrl = "/approval/registApproval.do?targetType=CONTRACT_ESTIMATE&targetObjId="+estObjId+"&approvalTitle="+title;
|
||||
window.open(approvalUrl, "registApproval", "width=700,height=700");
|
||||
fn_openAmaranthApproval(estObjId, contractNo);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Amaranth10 전자결재 SSO 팝업 열기
|
||||
function fn_openAmaranthApproval(estObjId, contractNo) {
|
||||
var title = "견적서 결재" + (contractNo ? " - " + contractNo : "");
|
||||
|
||||
$.ajax({
|
||||
url: "/approval/getAmaranthSsoUrl.do",
|
||||
type: "POST",
|
||||
data: {
|
||||
"targetType": "CONTRACT_ESTIMATE",
|
||||
"targetObjId": estObjId,
|
||||
"approvalTitle": title,
|
||||
"outProcessCode": "${AMARANTH_OUT_PROCESS_CODE}",
|
||||
"formId": "",
|
||||
"compSeq": "1000",
|
||||
"deptSeq": ""
|
||||
},
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
if(data.resultCode == 0 && data.resultData && data.resultData.fullUrl) {
|
||||
var fullUrl = data.resultData.fullUrl;
|
||||
window.open(fullUrl, "amaranthApproval", "width=1200,height=900,scrollbars=yes,resizable=yes");
|
||||
} else {
|
||||
Swal.fire("결재 연동 오류: " + (data.resultMsg || "알 수 없는 오류"));
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error("Amaranth SSO URL 요청 오류:", error);
|
||||
Swal.fire("결재 시스템 연동 중 오류가 발생했습니다.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -603,7 +603,7 @@
|
||||
SELECT
|
||||
CONTRACT_OBJID
|
||||
FROM ESTIMATE_TEMPLATE
|
||||
WHERE OBJID = #{estObjId}::NUMERIC
|
||||
WHERE OBJID::VARCHAR = #{estObjId}
|
||||
</select>
|
||||
|
||||
<!-- =====================================================
|
||||
@@ -671,6 +671,23 @@
|
||||
WHERE APPRO_KEY = #{approKey}
|
||||
</update>
|
||||
|
||||
<!-- 결재불필요 처리: AMARANTH_APPROVAL에 notRequired 상태로 등록 -->
|
||||
<insert id="insertAmaranthApprovalNotRequired" parameterType="map">
|
||||
INSERT INTO AMARANTH_APPROVAL (
|
||||
APPRO_KEY, TARGET_TYPE, TARGET_OBJID, APPROVAL_TITLE, WRITER, STATUS, REGDATE
|
||||
) VALUES (
|
||||
#{approKey}, #{targetType}, #{targetObjId}, '결재불필요', #{writer}, 'notRequired', NOW()
|
||||
)
|
||||
</insert>
|
||||
|
||||
<!-- 결재불필요 처리: 기존 AMARANTH_APPROVAL 레코드 상태 변경 -->
|
||||
<update id="updateAmaranthApprovalNotRequired" parameterType="map">
|
||||
UPDATE AMARANTH_APPROVAL SET
|
||||
STATUS = 'notRequired',
|
||||
UPDATE_DATE = NOW()
|
||||
WHERE TARGET_OBJID = #{targetObjId} AND TARGET_TYPE = #{targetType}
|
||||
</update>
|
||||
|
||||
<!-- 품의서(SALES_REQUEST_MASTER) 결재 상태 변경 -->
|
||||
<update id="changeProposalApprovalStatus" parameterType="map">
|
||||
UPDATE SALES_REQUEST_MASTER SET
|
||||
@@ -678,4 +695,57 @@
|
||||
WHERE OBJID::VARCHAR = #{targetObjId}::VARCHAR
|
||||
</update>
|
||||
|
||||
<!-- 견적서 정보 조회 (결재 본문용) -->
|
||||
<select id="getEstimateInfoForApproval" parameterType="map" resultType="map">
|
||||
SELECT
|
||||
ET.OBJID,
|
||||
ET.CONTRACT_OBJID,
|
||||
ET.ESTIMATE_NO,
|
||||
ET.TEMPLATE_TYPE,
|
||||
ET.EXECUTOR,
|
||||
ET.RECIPIENT,
|
||||
ET.CONTACT_PERSON,
|
||||
ET.MODEL_NAME,
|
||||
ET.TOTAL_AMOUNT,
|
||||
ET.TOTAL_AMOUNT_KRW,
|
||||
ET.MANAGER_NAME,
|
||||
ET.MANAGER_CONTACT,
|
||||
ET.PART_NAME,
|
||||
ET.WRITER,
|
||||
ET.NOTE1,
|
||||
ET.NOTE2,
|
||||
ET.NOTE3,
|
||||
ET.NOTE4,
|
||||
ET.NOTE_REMARKS,
|
||||
ET.VALIDITY_PERIOD,
|
||||
TO_CHAR(ET.REGDATE, 'YYYY-MM-DD') AS REGDATE,
|
||||
CM.CONTRACT_NO,
|
||||
(SELECT CLIENT_NM FROM CLIENT_MNG AS C WHERE 'C_' || C.OBJID::VARCHAR = CM.CUSTOMER_OBJID) AS CUSTOMER_NAME,
|
||||
CM.AREA_CD,
|
||||
CODE_NAME(CM.CONTRACT_CURRENCY) AS CURRENCY_NAME,
|
||||
CM.EXCHANGE_RATE,
|
||||
(SELECT DEPT_NAME || ' ' || USER_NAME FROM USER_INFO WHERE USER_ID = ET.WRITER) AS WRITER_NAME
|
||||
FROM ESTIMATE_TEMPLATE ET
|
||||
LEFT JOIN CONTRACT_MGMT CM ON ET.CONTRACT_OBJID = CM.OBJID
|
||||
WHERE ET.OBJID::VARCHAR = #{targetObjId}
|
||||
</select>
|
||||
|
||||
<!-- 견적서 품목 리스트 조회 (결재 본문용) -->
|
||||
<select id="getEstimateItemsForApproval" parameterType="map" resultType="map">
|
||||
SELECT
|
||||
SEQ,
|
||||
CATEGORY,
|
||||
DESCRIPTION,
|
||||
SPECIFICATION,
|
||||
QUANTITY,
|
||||
UNIT,
|
||||
UNIT_PRICE,
|
||||
AMOUNT,
|
||||
NOTE,
|
||||
REMARK
|
||||
FROM ESTIMATE_TEMPLATE_ITEM
|
||||
WHERE TEMPLATE_OBJID::VARCHAR = #{targetObjId}
|
||||
ORDER BY SEQ
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -1659,7 +1659,7 @@ public class ContractMgmtController {
|
||||
|
||||
request.setAttribute("code_map",code_map);
|
||||
request.setAttribute("actionType",actionType);
|
||||
//request.setAttribute("LIST", list);
|
||||
request.setAttribute("AMARANTH_OUT_PROCESS_CODE", com.pms.common.utils.Constants.AMARANTH_OUT_PROCESS_CODE);
|
||||
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
|
||||
@@ -423,7 +423,7 @@
|
||||
<sql id="contractBase">
|
||||
(
|
||||
SELECT
|
||||
OBJID
|
||||
T.OBJID
|
||||
,CATEGORY_CD
|
||||
,CODE_NAME(CATEGORY_CD) AS CATEGORY_NAME
|
||||
,CUSTOMER_OBJID
|
||||
@@ -494,9 +494,9 @@
|
||||
,CONTRACT_PRICE_CURRENCY
|
||||
,CONTRACT_CURRENCY
|
||||
,CODE_NAME(CONTRACT_CURRENCY) AS CONTRACT_CURRENCY_NAME
|
||||
,REGDATE
|
||||
,TO_CHAR(REGDATE,'YYYY-MM-DD') AS REG_DATE
|
||||
,WRITER
|
||||
,T.REGDATE
|
||||
,TO_CHAR(T.REGDATE,'YYYY-MM-DD') AS REG_DATE
|
||||
,T.WRITER
|
||||
,(SELECT USER_NAME FROM USER_INFO AS O WHERE O.USER_ID = T.WRITER ) AS WRITER_NAME
|
||||
,(SELECT COUNT(1) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = T.OBJID AND DOC_TYPE IN ('FTC_ORDER', 'ORDER') AND UPPER(STATUS) = 'ACTIVE') AS CU01_CNT
|
||||
<!-- ,(SELECT COUNT(1) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = T.OBJID AND DOC_TYPE='contractMgmt01' AND UPPER(STATUS) = 'ACTIVE') AS CU01_CNT
|
||||
@@ -555,10 +555,18 @@
|
||||
ORDER BY LOG_TIME DESC
|
||||
LIMIT 1
|
||||
) AS MAIL_SEND_DATE
|
||||
,A.APPR_STATUS
|
||||
,A.APPROVAL_OBJID
|
||||
,A.ROUTE_OBJID
|
||||
,(SELECT objid FROM ESTIMATE_TEMPLATE WHERE CONTRACT_OBJID = T.OBJID order by regdate desc limit 1) AS EST_OBJID
|
||||
,CASE
|
||||
WHEN AMR.STATUS = 'complete' THEN '결재완료'
|
||||
WHEN AMR.STATUS = 'inProcess' THEN '결재중'
|
||||
WHEN AMR.STATUS = 'reject' THEN '반려'
|
||||
WHEN AMR.STATUS = 'create' THEN '작성중'
|
||||
WHEN AMR.STATUS = 'notRequired' THEN '결재불필요'
|
||||
ELSE ''
|
||||
END AS APPR_STATUS
|
||||
,COALESCE(AMR.STATUS, '') AS AMARANTH_STATUS
|
||||
,A.APPROVAL_OBJID
|
||||
,A.ROUTE_OBJID
|
||||
,(SELECT objid FROM ESTIMATE_TEMPLATE WHERE CONTRACT_OBJID = T.OBJID order by regdate desc limit 1) AS EST_OBJID
|
||||
-- 최근 차수 견적서 합계 정보
|
||||
,(SELECT TOTAL_AMOUNT FROM ESTIMATE_TEMPLATE WHERE CONTRACT_OBJID = T.OBJID ORDER BY REGDATE DESC LIMIT 1) AS EST_TOTAL_AMOUNT
|
||||
,(SELECT TOTAL_AMOUNT_KRW FROM ESTIMATE_TEMPLATE WHERE CONTRACT_OBJID = T.OBJID ORDER BY REGDATE DESC LIMIT 1) AS EST_TOTAL_AMOUNT_KRW
|
||||
@@ -731,10 +739,13 @@
|
||||
WHERE
|
||||
A.OBJID = B.APPROVAL_OBJID
|
||||
AND TARGET_TYPE IN ('CONTRACT_ESTIMATE')
|
||||
) A
|
||||
ON (SELECT objid FROM ESTIMATE_TEMPLATE WHERE CONTRACT_OBJID = T.OBJID order by regdate desc limit 1)::numeric = A.TARGET_OBJID
|
||||
)
|
||||
</sql>
|
||||
) A
|
||||
ON (SELECT objid FROM ESTIMATE_TEMPLATE WHERE CONTRACT_OBJID = T.OBJID order by regdate desc limit 1)::numeric = A.TARGET_OBJID
|
||||
LEFT OUTER JOIN AMARANTH_APPROVAL AMR
|
||||
ON (SELECT objid FROM ESTIMATE_TEMPLATE WHERE CONTRACT_OBJID = T.OBJID order by regdate desc limit 1)::VARCHAR = AMR.TARGET_OBJID
|
||||
AND AMR.TARGET_TYPE = 'CONTRACT_ESTIMATE'
|
||||
)
|
||||
</sql>
|
||||
|
||||
<!-- //계약관리 리스트 -->
|
||||
<select id="contractList" parameterType="map" resultType="map">
|
||||
@@ -5659,15 +5670,15 @@ WHERE
|
||||
WITH current_items AS (
|
||||
SELECT
|
||||
ETI.PART_OBJID,
|
||||
COALESCE(PM.PART_NO, ETI.PART_NO) AS PART_NO,
|
||||
CAST(COALESCE(NULLIF(ETI.SUPPLY_UNIT_PRICE, ''), '0') AS NUMERIC) AS CURRENT_PRICE
|
||||
PM.PART_NO,
|
||||
CAST(COALESCE(NULLIF(ETI.UNIT_PRICE, ''), '0') AS NUMERIC) AS CURRENT_PRICE
|
||||
FROM ESTIMATE_TEMPLATE ET
|
||||
INNER JOIN ESTIMATE_TEMPLATE_ITEM ETI ON ET.OBJID = ETI.TEMPLATE_OBJID
|
||||
LEFT JOIN PART_MNG PM ON ETI.PART_OBJID = PM.OBJID
|
||||
WHERE ET.CONTRACT_OBJID = #{contractObjId}::NUMERIC
|
||||
WHERE ET.CONTRACT_OBJID::VARCHAR = #{contractObjId}
|
||||
AND ET.OBJID = (
|
||||
SELECT OBJID FROM ESTIMATE_TEMPLATE
|
||||
WHERE CONTRACT_OBJID = #{contractObjId}::NUMERIC
|
||||
WHERE CONTRACT_OBJID::VARCHAR = #{contractObjId}
|
||||
ORDER BY REGDATE DESC LIMIT 1
|
||||
)
|
||||
),
|
||||
@@ -5675,16 +5686,16 @@ WHERE
|
||||
SELECT
|
||||
CI.PART_OBJID,
|
||||
COALESCE(PM.PART_NO, CI.PART_NO) AS PART_NO,
|
||||
MAX(CAST(COALESCE(NULLIF(ETI.SUPPLY_UNIT_PRICE, ''), '0') AS NUMERIC)) AS PREV_MAX_PRICE
|
||||
MAX(CAST(COALESCE(NULLIF(ETI.UNIT_PRICE, ''), '0') AS NUMERIC)) AS PREV_MAX_PRICE
|
||||
FROM CONTRACT_MGMT CM
|
||||
INNER JOIN CONTRACT_ITEM CI ON CM.OBJID = CI.CONTRACT_OBJID AND CI.STATUS = 'ACTIVE'
|
||||
LEFT JOIN PART_MNG PM ON CI.PART_OBJID = PM.OBJID
|
||||
LEFT JOIN ESTIMATE_TEMPLATE ET ON ET.CONTRACT_OBJID = CM.OBJID
|
||||
LEFT JOIN ESTIMATE_TEMPLATE_ITEM ETI ON ET.OBJID = ETI.TEMPLATE_OBJID
|
||||
AND (ETI.PART_OBJID = CI.PART_OBJID OR ETI.PART_NO = CI.PART_NO)
|
||||
AND ETI.PART_OBJID = CI.PART_OBJID
|
||||
WHERE CM.CUSTOMER_OBJID = #{customerObjId}
|
||||
AND CM.OBJID != #{contractObjId}::NUMERIC
|
||||
AND CM.STATUS != 'cancel'
|
||||
AND CM.OBJID::VARCHAR != #{contractObjId}
|
||||
AND CM.STATUS_CD != 'cancel'
|
||||
AND CM.CONTRACT_RESULT = '0000964'
|
||||
GROUP BY CI.PART_OBJID, COALESCE(PM.PART_NO, CI.PART_NO)
|
||||
)
|
||||
|
||||
@@ -3766,43 +3766,35 @@ private String encodeImageToBase64(String imagePath) {
|
||||
|
||||
/**
|
||||
* 결재불필요 처리 (재오더 + 가격동일/인상인 경우)
|
||||
* APPROVAL 테이블에 결재불필요 상태로 레코드 생성
|
||||
* AMARANTH_APPROVAL 테이블에 notRequired 상태로 등록/갱신
|
||||
* @param paramMap - estObjId, userId
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void setApprovalNotRequired(Map paramMap) throws Exception {
|
||||
SqlSession sqlSession = null;
|
||||
|
||||
|
||||
try {
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
|
||||
|
||||
|
||||
String estObjId = CommonUtils.checkNull(paramMap.get("estObjId"));
|
||||
String userId = CommonUtils.checkNull(paramMap.get("userId"));
|
||||
|
||||
// APPROVAL 테이블에 결재불필요 레코드 생성
|
||||
Map<String, Object> approvalParam = new HashMap<String, Object>();
|
||||
approvalParam.put("OBJID", CommonUtils.createObjId());
|
||||
approvalParam.put("TARGET_TYPE", "CONTRACT_ESTIMATE");
|
||||
approvalParam.put("TARGET_OBJID", estObjId);
|
||||
approvalParam.put("APPROVAL_TITLE", "결재불필요");
|
||||
approvalParam.put("WRITER", userId);
|
||||
|
||||
sqlSession.insert("contractMgmt.insertApprovalNotRequired", approvalParam);
|
||||
|
||||
// ROUTE 테이블에 결재불필요 상태 레코드 생성
|
||||
Map<String, Object> routeParam = new HashMap<String, Object>();
|
||||
routeParam.put("OBJID", CommonUtils.createObjId());
|
||||
routeParam.put("APPROVAL_OBJID", approvalParam.get("OBJID"));
|
||||
routeParam.put("TARGET_OBJID", estObjId);
|
||||
routeParam.put("TARGET_TYPE", "CONTRACT_ESTIMATE");
|
||||
routeParam.put("STATUS", "notRequired"); // 결재불필요 상태
|
||||
routeParam.put("ROUTE_SEQ", "1");
|
||||
routeParam.put("WRITER", userId);
|
||||
|
||||
sqlSession.insert("contractMgmt.insertRouteNotRequired", routeParam);
|
||||
|
||||
|
||||
Map<String, Object> queryParam = new HashMap<String, Object>();
|
||||
queryParam.put("targetObjId", estObjId);
|
||||
queryParam.put("targetType", "CONTRACT_ESTIMATE");
|
||||
|
||||
Map existing = sqlSession.selectOne("approval.selectAmaranthApprovalByTarget", queryParam);
|
||||
|
||||
if(existing != null) {
|
||||
sqlSession.update("approval.updateAmaranthApprovalNotRequired", queryParam);
|
||||
} else {
|
||||
queryParam.put("approKey", "NOT_REQ_" + estObjId + "_" + System.currentTimeMillis());
|
||||
queryParam.put("writer", userId);
|
||||
sqlSession.insert("approval.insertAmaranthApprovalNotRequired", queryParam);
|
||||
}
|
||||
|
||||
sqlSession.commit();
|
||||
|
||||
|
||||
} catch(Exception e) {
|
||||
if(sqlSession != null) sqlSession.rollback();
|
||||
throw e;
|
||||
|
||||
@@ -1837,10 +1837,14 @@ public class ApprovalService {
|
||||
// API 클라이언트 생성
|
||||
com.pms.api.AmaranthApprovalApiClient apiClient = new com.pms.api.AmaranthApprovalApiClient();
|
||||
|
||||
// 첨부파일 처리: ATTACH_FILE_INFO에서 품의서 파일 조회 → 원챔버 업로드
|
||||
// 첨부파일 처리: targetType별 분기하여 원챔버 업로드
|
||||
String fileListEncoded = null;
|
||||
try {
|
||||
fileListEncoded = uploadProposalFilesToOneChamber(apiClient, empSeq, targetObjId);
|
||||
if("CONTRACT_ESTIMATE".equals(targetType)) {
|
||||
fileListEncoded = uploadEstimateFilesToOneChamber(apiClient, empSeq, targetObjId);
|
||||
} else {
|
||||
fileListEncoded = uploadProposalFilesToOneChamber(apiClient, empSeq, targetObjId);
|
||||
}
|
||||
} catch(Exception fileEx) {
|
||||
System.err.println("[첨부파일] 원챔버 업로드 중 오류 (결재는 계속 진행): " + fileEx.getMessage());
|
||||
fileEx.printStackTrace();
|
||||
@@ -2022,6 +2026,324 @@ public class ApprovalService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적서 첨부파일을 원챔버에 업로드하고 fileList (URL 인코딩) 반환
|
||||
* @return URL 인코딩된 fileList JSON 문자열 (파일 없으면 null)
|
||||
*/
|
||||
private String uploadEstimateFilesToOneChamber(
|
||||
com.pms.api.AmaranthApprovalApiClient apiClient,
|
||||
String empSeq, String targetObjId) throws Exception {
|
||||
|
||||
if(targetObjId == null || targetObjId.isEmpty()) return null;
|
||||
|
||||
SqlSession sqlSession = SqlMapConfig.getInstance().getSqlSession(true);
|
||||
try {
|
||||
Map<String, String> authResult = apiClient.getAuthToken(AMARANTH_BASE_URL, empSeq);
|
||||
if(!"true".equals(authResult.get("success"))){
|
||||
throw new Exception("파일 업로드용 인증 토큰 발급 실패: " + authResult.get("resultMsg"));
|
||||
}
|
||||
String authToken = authResult.get("authToken");
|
||||
String userHashKey = authResult.get("hashKey");
|
||||
|
||||
StringBuilder listItems = new StringBuilder();
|
||||
int uploadCount = 0;
|
||||
|
||||
// 1. 견적서 본문을 HTML 파일로 생성하여 업로드
|
||||
try {
|
||||
Map<String, Object> estParam = new HashMap<String, Object>();
|
||||
estParam.put("targetObjId", targetObjId);
|
||||
Map<String, Object> estimateInfo = sqlSession.selectOne("approval.getEstimateInfoForApproval", estParam);
|
||||
|
||||
if(estimateInfo != null){
|
||||
estimateInfo = CommonUtils.toUpperCaseMapKey(estimateInfo);
|
||||
String estimateNo = CommonUtils.checkNull(estimateInfo.get("ESTIMATE_NO"));
|
||||
|
||||
Map<String, Object> itemParam = new HashMap<String, Object>();
|
||||
itemParam.put("targetObjId", targetObjId);
|
||||
List<Map> itemList = sqlSession.selectList("approval.getEstimateItemsForApproval", itemParam);
|
||||
|
||||
String fullHtml = buildEstimateFormFileHtml(estimateInfo, itemList);
|
||||
|
||||
String tempFileName = "견적서_" + estimateNo + ".html";
|
||||
java.io.File tempFile = java.io.File.createTempFile("estimate_", ".html");
|
||||
java.io.OutputStreamWriter writer = new java.io.OutputStreamWriter(
|
||||
new java.io.FileOutputStream(tempFile), "UTF-8");
|
||||
writer.write(fullHtml);
|
||||
writer.close();
|
||||
|
||||
System.out.println("[첨부파일] 견적서 HTML 생성: " + tempFileName + " (" + tempFile.length() + " bytes)");
|
||||
|
||||
String uploadResponse = apiClient.uploadFileToOneChamber(
|
||||
AMARANTH_BASE_URL, authToken, userHashKey, empSeq, tempFile, tempFileName
|
||||
);
|
||||
|
||||
String listItem = apiClient.extractListItemFromUploadResponse(uploadResponse);
|
||||
if(listItem != null){
|
||||
listItems.append(listItem);
|
||||
uploadCount++;
|
||||
System.out.println("[첨부파일] 견적서 HTML 업로드 성공");
|
||||
}
|
||||
|
||||
tempFile.delete();
|
||||
}
|
||||
} catch(Exception htmlEx){
|
||||
System.err.println("[첨부파일] 견적서 HTML 생성/업로드 오류: " + htmlEx.getMessage());
|
||||
}
|
||||
|
||||
// 2. ATTACH_FILE_INFO에서 기존 첨부파일도 업로드
|
||||
Map<String, Object> fileParam = new HashMap<String, Object>();
|
||||
fileParam.put("targetObjId", targetObjId);
|
||||
List<Map<String, Object>> fileList = sqlSession.selectList("common.getFileList", fileParam);
|
||||
|
||||
if(fileList != null && !fileList.isEmpty()){
|
||||
System.out.println("[첨부파일] 견적서(" + targetObjId + ") 기존 첨부파일 " + fileList.size() + "건 발견");
|
||||
|
||||
for(Map<String, Object> fileInfo : fileList){
|
||||
String savedFileName = CommonUtils.checkNull(fileInfo.get("saved_file_name"));
|
||||
String realFileName = CommonUtils.checkNull(fileInfo.get("real_file_name"));
|
||||
String filePath = CommonUtils.checkNull(fileInfo.get("file_path"));
|
||||
|
||||
if(savedFileName.isEmpty()) continue;
|
||||
|
||||
String fullPath = filePath + "/" + savedFileName;
|
||||
java.io.File physicalFile = new java.io.File(fullPath);
|
||||
if(!physicalFile.exists()){
|
||||
System.err.println("[첨부파일] 파일 미존재: " + fullPath);
|
||||
continue;
|
||||
}
|
||||
|
||||
String originalName = realFileName.isEmpty() ? savedFileName : realFileName;
|
||||
|
||||
String uploadResponse = apiClient.uploadFileToOneChamber(
|
||||
AMARANTH_BASE_URL, authToken, userHashKey, empSeq, physicalFile, originalName
|
||||
);
|
||||
|
||||
String listItem = apiClient.extractListItemFromUploadResponse(uploadResponse);
|
||||
if(listItem != null){
|
||||
if(uploadCount > 0) listItems.append(",");
|
||||
listItems.append(listItem);
|
||||
uploadCount++;
|
||||
System.out.println("[첨부파일] 업로드 성공: " + originalName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(uploadCount == 0) return null;
|
||||
|
||||
String fileListJson = "[" + listItems.toString() + "]";
|
||||
String fileListEncoded = java.net.URLEncoder.encode(fileListJson, "UTF-8");
|
||||
|
||||
System.out.println("[첨부파일] 견적서 총 " + uploadCount + "건 업로드 완료");
|
||||
|
||||
return fileListEncoded;
|
||||
|
||||
} finally {
|
||||
if(sqlSession != null) sqlSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적서 데이터를 HTML 파일로 구성 (결재 첨부파일용)
|
||||
*/
|
||||
private String buildEstimateFormFileHtml(Map estimateInfo, List<Map> itemList){
|
||||
String estimateNo = CommonUtils.checkNull(estimateInfo.get("ESTIMATE_NO"));
|
||||
String contractNo = CommonUtils.checkNull(estimateInfo.get("CONTRACT_NO"));
|
||||
String customerName = CommonUtils.checkNull(estimateInfo.get("CUSTOMER_NAME"));
|
||||
String writerName = CommonUtils.checkNull(estimateInfo.get("WRITER_NAME"));
|
||||
String regdate = CommonUtils.checkNull(estimateInfo.get("REGDATE"));
|
||||
String totalAmount = CommonUtils.checkNull(estimateInfo.get("TOTAL_AMOUNT"));
|
||||
String totalAmountKrw = CommonUtils.checkNull(estimateInfo.get("TOTAL_AMOUNT_KRW"));
|
||||
String currencyName = CommonUtils.checkNull(estimateInfo.get("CURRENCY_NAME"));
|
||||
String exchangeRate = CommonUtils.checkNull(estimateInfo.get("EXCHANGE_RATE"));
|
||||
String recipient = CommonUtils.checkNull(estimateInfo.get("RECIPIENT"));
|
||||
String contactPerson = CommonUtils.checkNull(estimateInfo.get("CONTACT_PERSON"));
|
||||
String modelName = CommonUtils.checkNull(estimateInfo.get("MODEL_NAME"));
|
||||
String validityPeriod = CommonUtils.checkNull(estimateInfo.get("VALIDITY_PERIOD"));
|
||||
String noteRemarks = CommonUtils.checkNull(estimateInfo.get("NOTE_REMARKS"));
|
||||
|
||||
StringBuilder html = new StringBuilder();
|
||||
html.append("<!DOCTYPE html><html><head><meta charset='UTF-8'>");
|
||||
html.append("<title>견적서 - " + estimateNo + "</title>");
|
||||
html.append("<style>body{font-family:'맑은 고딕',sans-serif;font-size:10pt;margin:20px;}");
|
||||
html.append("table{border-collapse:collapse;width:100%;}");
|
||||
html.append("th,td{border:1px solid #333;padding:6px 8px;font-size:9pt;}");
|
||||
html.append("th{background-color:#4472C4;color:#fff;text-align:center;}");
|
||||
html.append(".header{font-size:14pt;font-weight:bold;text-align:center;margin-bottom:15px;}");
|
||||
html.append(".info-table td{border:1px solid #999;} .info-table th{background-color:#D9E2F3;color:#333;}");
|
||||
html.append("</style></head><body>");
|
||||
|
||||
html.append("<div class='header'>견 적 서</div>");
|
||||
|
||||
// 기본 정보 테이블
|
||||
html.append("<table class='info-table' style='margin-bottom:15px;'>");
|
||||
html.append("<tr><th style='width:15%'>견적번호</th><td style='width:35%'>" + estimateNo + "</td>");
|
||||
html.append("<th style='width:15%'>영업번호</th><td style='width:35%'>" + contractNo + "</td></tr>");
|
||||
html.append("<tr><th>고객사</th><td>" + customerName + "</td>");
|
||||
html.append("<th>작성일</th><td>" + regdate + "</td></tr>");
|
||||
html.append("<tr><th>수신</th><td>" + recipient + "</td>");
|
||||
html.append("<th>담당자</th><td>" + contactPerson + "</td></tr>");
|
||||
html.append("<tr><th>작성자</th><td>" + writerName + "</td>");
|
||||
html.append("<th>모델명</th><td>" + modelName + "</td></tr>");
|
||||
|
||||
if(!currencyName.isEmpty()){
|
||||
html.append("<tr><th>통화</th><td>" + currencyName + "</td>");
|
||||
html.append("<th>환율</th><td>" + exchangeRate + "</td></tr>");
|
||||
}
|
||||
|
||||
html.append("<tr><th>합계금액</th><td colspan='3'>");
|
||||
if(!totalAmountKrw.isEmpty() && !"0".equals(totalAmountKrw)){
|
||||
html.append(totalAmountKrw + " (KRW)");
|
||||
if(!totalAmount.isEmpty()) html.append(" / " + totalAmount + " (" + currencyName + ")");
|
||||
} else {
|
||||
html.append(totalAmount);
|
||||
}
|
||||
html.append("</td></tr>");
|
||||
|
||||
if(!validityPeriod.isEmpty()){
|
||||
html.append("<tr><th>유효기간</th><td colspan='3'>" + validityPeriod + "</td></tr>");
|
||||
}
|
||||
html.append("</table>");
|
||||
|
||||
// 품목 리스트
|
||||
if(itemList != null && !itemList.isEmpty()){
|
||||
html.append("<table>");
|
||||
html.append("<thead><tr>");
|
||||
html.append("<th>No</th><th>품명</th><th>규격</th><th>수량</th><th>단위</th><th>단가</th><th>금액</th><th>비고</th>");
|
||||
html.append("</tr></thead><tbody>");
|
||||
|
||||
int no = 1;
|
||||
for(Map item : itemList){
|
||||
item = CommonUtils.toUpperCaseMapKey(item);
|
||||
html.append("<tr>");
|
||||
html.append("<td style='text-align:center;'>" + no++ + "</td>");
|
||||
html.append("<td>" + CommonUtils.checkNull(item.get("DESCRIPTION")) + "</td>");
|
||||
html.append("<td>" + CommonUtils.checkNull(item.get("SPECIFICATION")) + "</td>");
|
||||
html.append("<td style='text-align:right;'>" + CommonUtils.checkNull(item.get("QUANTITY")) + "</td>");
|
||||
html.append("<td style='text-align:center;'>" + CommonUtils.checkNull(item.get("UNIT")) + "</td>");
|
||||
html.append("<td style='text-align:right;'>" + CommonUtils.checkNull(item.get("UNIT_PRICE")) + "</td>");
|
||||
html.append("<td style='text-align:right;'>" + CommonUtils.checkNull(item.get("AMOUNT")) + "</td>");
|
||||
html.append("<td>" + CommonUtils.checkNull(item.get("REMARK")) + "</td>");
|
||||
html.append("</tr>");
|
||||
}
|
||||
html.append("</tbody></table>");
|
||||
}
|
||||
|
||||
// 비고
|
||||
if(!noteRemarks.isEmpty()){
|
||||
html.append("<br/><div><strong>비고:</strong><br/>" + noteRemarks.replace("\n", "<br/>") + "</div>");
|
||||
}
|
||||
|
||||
html.append("</body></html>");
|
||||
return html.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적서 데이터를 HTML 본문으로 구성 (아마란스 결재 화면 표시용)
|
||||
*/
|
||||
private String buildEstimateContentsHtml(Map estimateInfo, List<Map> itemList){
|
||||
StringBuilder html = new StringBuilder();
|
||||
|
||||
String estimateNo = CommonUtils.checkNull(estimateInfo.get("ESTIMATE_NO"));
|
||||
String contractNo = CommonUtils.checkNull(estimateInfo.get("CONTRACT_NO"));
|
||||
String customerName = CommonUtils.checkNull(estimateInfo.get("CUSTOMER_NAME"));
|
||||
String writerName = CommonUtils.checkNull(estimateInfo.get("WRITER_NAME"));
|
||||
String regdate = CommonUtils.checkNull(estimateInfo.get("REGDATE"));
|
||||
String totalAmount = CommonUtils.checkNull(estimateInfo.get("TOTAL_AMOUNT"));
|
||||
String totalAmountKrw = CommonUtils.checkNull(estimateInfo.get("TOTAL_AMOUNT_KRW"));
|
||||
String currencyName = CommonUtils.checkNull(estimateInfo.get("CURRENCY_NAME"));
|
||||
String exchangeRate = CommonUtils.checkNull(estimateInfo.get("EXCHANGE_RATE"));
|
||||
String recipient = CommonUtils.checkNull(estimateInfo.get("RECIPIENT"));
|
||||
String contactPerson = CommonUtils.checkNull(estimateInfo.get("CONTACT_PERSON"));
|
||||
String modelName = CommonUtils.checkNull(estimateInfo.get("MODEL_NAME"));
|
||||
String validityPeriod = CommonUtils.checkNull(estimateInfo.get("VALIDITY_PERIOD"));
|
||||
String noteRemarks = CommonUtils.checkNull(estimateInfo.get("NOTE_REMARKS"));
|
||||
|
||||
html.append("<div style='font-family:맑은 고딕,sans-serif;font-size:10pt;'>");
|
||||
html.append("<h3 style='text-align:center;margin-bottom:10px;'>견 적 서</h3>");
|
||||
|
||||
html.append("<table cellspacing='0' cellpadding='4' style='border-collapse:collapse;width:100%;margin-bottom:10px;'>");
|
||||
html.append("<tr><td style='border:1px solid #333;background-color:#D9E2F3;width:15%;font-weight:bold;font-size:9pt;'>견적번호</td>");
|
||||
html.append("<td style='border:1px solid #333;width:35%;font-size:9pt;'>" + estimateNo + "</td>");
|
||||
html.append("<td style='border:1px solid #333;background-color:#D9E2F3;width:15%;font-weight:bold;font-size:9pt;'>영업번호</td>");
|
||||
html.append("<td style='border:1px solid #333;width:35%;font-size:9pt;'>" + contractNo + "</td></tr>");
|
||||
|
||||
html.append("<tr><td style='border:1px solid #333;background-color:#D9E2F3;font-weight:bold;font-size:9pt;'>고객사</td>");
|
||||
html.append("<td style='border:1px solid #333;font-size:9pt;'>" + customerName + "</td>");
|
||||
html.append("<td style='border:1px solid #333;background-color:#D9E2F3;font-weight:bold;font-size:9pt;'>작성일</td>");
|
||||
html.append("<td style='border:1px solid #333;font-size:9pt;'>" + regdate + "</td></tr>");
|
||||
|
||||
html.append("<tr><td style='border:1px solid #333;background-color:#D9E2F3;font-weight:bold;font-size:9pt;'>수신</td>");
|
||||
html.append("<td style='border:1px solid #333;font-size:9pt;'>" + recipient + "</td>");
|
||||
html.append("<td style='border:1px solid #333;background-color:#D9E2F3;font-weight:bold;font-size:9pt;'>담당자</td>");
|
||||
html.append("<td style='border:1px solid #333;font-size:9pt;'>" + contactPerson + "</td></tr>");
|
||||
|
||||
html.append("<tr><td style='border:1px solid #333;background-color:#D9E2F3;font-weight:bold;font-size:9pt;'>작성자</td>");
|
||||
html.append("<td style='border:1px solid #333;font-size:9pt;'>" + writerName + "</td>");
|
||||
html.append("<td style='border:1px solid #333;background-color:#D9E2F3;font-weight:bold;font-size:9pt;'>모델명</td>");
|
||||
html.append("<td style='border:1px solid #333;font-size:9pt;'>" + modelName + "</td></tr>");
|
||||
|
||||
if(!currencyName.isEmpty()){
|
||||
html.append("<tr><td style='border:1px solid #333;background-color:#D9E2F3;font-weight:bold;font-size:9pt;'>통화</td>");
|
||||
html.append("<td style='border:1px solid #333;font-size:9pt;'>" + currencyName + "</td>");
|
||||
html.append("<td style='border:1px solid #333;background-color:#D9E2F3;font-weight:bold;font-size:9pt;'>환율</td>");
|
||||
html.append("<td style='border:1px solid #333;font-size:9pt;'>" + exchangeRate + "</td></tr>");
|
||||
}
|
||||
|
||||
html.append("<tr><td style='border:1px solid #333;background-color:#D9E2F3;font-weight:bold;font-size:9pt;'>합계금액</td>");
|
||||
html.append("<td style='border:1px solid #333;font-size:9pt;' colspan='3'>");
|
||||
if(!totalAmountKrw.isEmpty() && !"0".equals(totalAmountKrw)){
|
||||
html.append(totalAmountKrw + " (KRW)");
|
||||
if(!totalAmount.isEmpty()) html.append(" / " + totalAmount + " (" + currencyName + ")");
|
||||
} else {
|
||||
html.append(totalAmount);
|
||||
}
|
||||
html.append("</td></tr>");
|
||||
|
||||
if(!validityPeriod.isEmpty()){
|
||||
html.append("<tr><td style='border:1px solid #333;background-color:#D9E2F3;font-weight:bold;font-size:9pt;'>유효기간</td>");
|
||||
html.append("<td style='border:1px solid #333;font-size:9pt;' colspan='3'>" + validityPeriod + "</td></tr>");
|
||||
}
|
||||
html.append("</table>");
|
||||
|
||||
// 품목 리스트
|
||||
if(itemList != null && !itemList.isEmpty()){
|
||||
html.append("<table cellspacing='0' cellpadding='4' style='border-collapse:collapse;width:100%;'>");
|
||||
html.append("<thead><tr>");
|
||||
html.append("<th style='border:1px solid #333;background-color:#4472C4;color:#fff;text-align:center;font-size:9pt;'>No</th>");
|
||||
html.append("<th style='border:1px solid #333;background-color:#4472C4;color:#fff;text-align:center;font-size:9pt;'>품명</th>");
|
||||
html.append("<th style='border:1px solid #333;background-color:#4472C4;color:#fff;text-align:center;font-size:9pt;'>규격</th>");
|
||||
html.append("<th style='border:1px solid #333;background-color:#4472C4;color:#fff;text-align:center;font-size:9pt;'>수량</th>");
|
||||
html.append("<th style='border:1px solid #333;background-color:#4472C4;color:#fff;text-align:center;font-size:9pt;'>단위</th>");
|
||||
html.append("<th style='border:1px solid #333;background-color:#4472C4;color:#fff;text-align:center;font-size:9pt;'>단가</th>");
|
||||
html.append("<th style='border:1px solid #333;background-color:#4472C4;color:#fff;text-align:center;font-size:9pt;'>금액</th>");
|
||||
html.append("<th style='border:1px solid #333;background-color:#4472C4;color:#fff;text-align:center;font-size:9pt;'>비고</th>");
|
||||
html.append("</tr></thead><tbody>");
|
||||
|
||||
int no = 1;
|
||||
for(Map item : itemList){
|
||||
item = CommonUtils.toUpperCaseMapKey(item);
|
||||
html.append("<tr>");
|
||||
html.append("<td style='border:1px solid #333;text-align:center;font-size:9pt;'>" + no++ + "</td>");
|
||||
html.append("<td style='border:1px solid #333;font-size:9pt;'>" + CommonUtils.checkNull(item.get("DESCRIPTION")) + "</td>");
|
||||
html.append("<td style='border:1px solid #333;font-size:9pt;'>" + CommonUtils.checkNull(item.get("SPECIFICATION")) + "</td>");
|
||||
html.append("<td style='border:1px solid #333;text-align:right;font-size:9pt;'>" + CommonUtils.checkNull(item.get("QUANTITY")) + "</td>");
|
||||
html.append("<td style='border:1px solid #333;text-align:center;font-size:9pt;'>" + CommonUtils.checkNull(item.get("UNIT")) + "</td>");
|
||||
html.append("<td style='border:1px solid #333;text-align:right;font-size:9pt;'>" + CommonUtils.checkNull(item.get("UNIT_PRICE")) + "</td>");
|
||||
html.append("<td style='border:1px solid #333;text-align:right;font-size:9pt;'>" + CommonUtils.checkNull(item.get("AMOUNT")) + "</td>");
|
||||
html.append("<td style='border:1px solid #333;font-size:9pt;'>" + CommonUtils.checkNull(item.get("REMARK")) + "</td>");
|
||||
html.append("</tr>");
|
||||
}
|
||||
html.append("</tbody></table>");
|
||||
}
|
||||
|
||||
if(!noteRemarks.isEmpty()){
|
||||
html.append("<br/><div><strong>비고:</strong><br/>" + noteRemarks.replace("\n", "<br/>") + "</div>");
|
||||
}
|
||||
|
||||
html.append("</div>");
|
||||
return html.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Amaranth10 전자결재 콜백 처리
|
||||
* 결재 이벤트(상신/진행/종결/반려/삭제 등) 발생 시 Amaranth10에서 호출
|
||||
@@ -2091,6 +2413,9 @@ public class ApprovalService {
|
||||
} else if("SALES_REQUEST".equals(targetType)){
|
||||
sqlSession.update("approval.salesRequestApprovalStatus", statusParam);
|
||||
System.out.println("구매요청 상태 변경 - targetObjId: " + targetObjId + " → " + proposalStatus);
|
||||
} else if("CONTRACT_ESTIMATE".equals(targetType)){
|
||||
// 견적서: AMARANTH_APPROVAL 테이블만으로 상태 관리 (품의서와 동일 패턴)
|
||||
System.out.println("견적서 결재 상태 변경 - targetObjId: " + targetObjId + " → " + internalStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2195,6 +2520,22 @@ public class ApprovalService {
|
||||
title = "품의서 결재 - " + proposalNo;
|
||||
}
|
||||
}
|
||||
} else if("CONTRACT_ESTIMATE".equals(targetType) && !targetObjId.isEmpty()){
|
||||
Map<String, Object> estParam = new HashMap();
|
||||
estParam.put("targetObjId", targetObjId);
|
||||
Map<String, Object> estimateInfo = sqlSession.selectOne("approval.getEstimateInfoForApproval", estParam);
|
||||
|
||||
if(estimateInfo != null){
|
||||
estimateInfo = CommonUtils.toUpperCaseMapKey(estimateInfo);
|
||||
|
||||
List<Map> itemList = sqlSession.selectList("approval.getEstimateItemsForApproval", estParam);
|
||||
contentsHtml = buildEstimateContentsHtml(estimateInfo, itemList);
|
||||
|
||||
String estimateNo = CommonUtils.checkNull(estimateInfo.get("ESTIMATE_NO"));
|
||||
if(!estimateNo.isEmpty()){
|
||||
title = "견적서 결재 - " + estimateNo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user