거래로그조회 처리결과(성공/실패/오류) 추가
eapim-admin CI / build (push) Waiting to run

This commit is contained in:
eastargh
2026-09-17 15:06:55 +09:00
parent 9de6020a5b
commit 96c1135b98
5 changed files with 147 additions and 17 deletions
@@ -260,6 +260,59 @@
} }
// 처리결과: ERRYN='Y'면 에러, 업무(BIZ) 오류코드(ERRCODE_BIZ)면 오류, 나머지는 성공
// 단, SEQ(LOGPRCSSSERNO) 100/200은 아직 처리 완료 전 단계라 에러/오류가 아니면(=성공이면) 표시하지 않는다
function computePrcsResult(errYn, eaiErrCd, logPrcssSerno) {
var isBizErr = eaiErrCd != null && bizErrCodeSet.has(String(eaiErrCd).trim());
// ERRYN은 EAIERRCTNT(에러내용)만 보고 Y/N을 매기므로 업무(BIZ) 오류도 Y가 된다.
// isBizErr을 먼저 봐야 업무오류가 "에러"로 잘못 표시되지 않는다.
if (isBizErr) {
return "오류";
} else if (errYn == "Y") {
return "실패";
} else if (logPrcssSerno == "100" || logPrcssSerno == "200") {
return "";
} else {
return "성공";
}
}
// 같은 거래(EAISVCSERNO)의 400(응답)이 에러/오류면 300(요청)의 "성공" 표시를 지운다.
// jqGrid의 getCell/setCell은 formatter 결과가 아니라 원본 데이터를 읽고 쓰는데, PRCS_RESULT_TMP는
// 서버 데이터에 없는 가상 컬럼이라 그 방식으로는 행 간 보정이 반영되지 않는다(직접 확인됨).
// 그래서 grid가 원본 JSON을 받는 시점(beforeProcessing)에 각 행에 PRCS_RESULT_TMP 값을 미리 계산해
// 박아두고, formatter는 그 값을 그대로 꺼내 쓰기만 한다.
function applyPrcsResult(rows) {
var byEaiSvcSerno = {};
rows.forEach(function (row) {
var key = row.EAISVCSERNO;
(byEaiSvcSerno[key] = byEaiSvcSerno[key] || []).push(row);
});
rows.forEach(function (row) {
var result = computePrcsResult(row.ERRYN, row.EAIERRCD, row.LOGPRCSSSERNO);
if (row.LOGPRCSSSERNO == "300" && result == "성공") {
var siblings = byEaiSvcSerno[row.EAISVCSERNO] || [];
var has400Error = siblings.some(function (sib) {
if (sib.LOGPRCSSSERNO != "400") return false;
var sibResult = computePrcsResult(sib.ERRYN, sib.EAIERRCD, "400");
return sibResult == "실패" || sibResult == "오류";
});
if (has400Error) {
result = "";
}
}
row.PRCS_RESULT_TMP = result;
});
}
function prcsResultFormatter(cellvalue, options, rowObject) {
return rowObject.PRCS_RESULT_TMP || "";
}
$(document).ready(function () { $(document).ready(function () {
console.log(roleString); console.log(roleString);
@@ -306,7 +359,8 @@
'<%=localeMessage.getString("tracking.telgmrecvtrancd")%>', '<%=localeMessage.getString("tracking.telgmrecvtrancd")%>',
'<%= localeMessage.getString("eaiMessage.eaiSvcName")%>', '<%= localeMessage.getString("eaiMessage.eaiSvcName")%>',
'<%= localeMessage.getString("eaiMessage.eaiSvcDesc")%>', '<%= localeMessage.getString("eaiMessage.eaiSvcDesc")%>',
'<%=localeMessage.getString("tracking.eaibzwkdstcd")%>', '업무명',
'처리결과',
'<%=localeMessage.getString("tracking.extBizName")%>', '<%=localeMessage.getString("tracking.extBizName")%>',
'<%=localeMessage.getString("tracking.ifDisKeyVal")%>', '<%=localeMessage.getString("tracking.ifDisKeyVal")%>',
'APP 명', 'APP 명',
@@ -330,14 +384,15 @@
{name: 'ERRYN', hidden: true}, {name: 'ERRYN', hidden: true},
{name: 'TRACKASISKEY1CTNT', hidden: true}, {name: 'TRACKASISKEY1CTNT', hidden: true},
{name: 'TRACKASISKEY2CTNT', hidden: true}, {name: 'TRACKASISKEY2CTNT', hidden: true},
{name: 'EAISVCSERNO_TMP', align: 'left', width: '220', formatter: trimFormatter}, {name: 'EAISVCSERNO_TMP', align: 'left', width: '120', formatter: trimFormatter},
{name: 'KEYMGTMSGCTNT', align: 'left', width: '300'}, {name: 'KEYMGTMSGCTNT', align: 'left', width: '300'},
{name: 'LOGPRCSSSERNO_TMP', align: 'center', width: '40'}, {name: 'LOGPRCSSSERNO_TMP', align: 'center', width: '40'},
{name: 'TELGMRECVTRANCD', align: 'left', width: '135', hidden: true}, {name: 'TELGMRECVTRANCD', align: 'left', width: '135', hidden: true},
{name: 'EAISVCNAME', align: 'left', width: '160'}, {name: 'EAISVCNAME', align: 'left', width: '160'},
{name: 'EAISVCDESC', align: 'left', width: '280'}, {name: 'EAISVCDESC', align: 'left', width: '280'},
{name: 'EAIBZWKDSTCD_TMP', align: 'center', width: '50'}, {name: 'EAIBZWKDSTCD_TMP', align: 'center', width: '50'},
{name: 'PRCS_RESULT_TMP', align: 'center', width: '60', formatter: prcsResultFormatter},
{name: 'EXTBIZCD', align: 'center', width: '50', hidden: isApiGw}, {name: 'EXTBIZCD', align: 'center', width: '50', hidden: isApiGw},
{name: 'REFKEY', align: 'left', width: '280', hidden: isApiGw}, {name: 'REFKEY', align: 'left', width: '280', hidden: isApiGw},
{name: 'CLIENTNAME', align: 'left', width: '120', hidden: !isApiGw}, {name: 'CLIENTNAME', align: 'left', width: '120', hidden: !isApiGw},
@@ -356,6 +411,9 @@
jsonReader: { jsonReader: {
repeatitems: false repeatitems: false
}, },
beforeProcessing: function (data) {
applyPrcsResult(data.rows || []);
},
rowNum: 10000, rowNum: 10000,
height: '520', height: '520',
viewrecords: true, viewrecords: true,
@@ -394,21 +452,18 @@
var uniqueCount = calculateUniqueLogCount("#grid"); var uniqueCount = calculateUniqueLogCount("#grid");
updateLogCountDisplay(uniqueCount, displayedLogs, totalLogs); updateLogCountDisplay(uniqueCount, displayedLogs, totalLogs);
//에러 행 색상 표시 //에러 행 색상 표시 (업무(BIZ) 오류는 배경색을 칠하지 않는다)
var rows = $(this).getDataIDs(); var rows = $(this).getDataIDs();
for (var i = 0; i < rows.length; i++) { for (var i = 0; i < rows.length; i++) {
var errYn = $("#grid").getCell(rows[i], 'ERRYN'); var errYn = $("#grid").getCell(rows[i], 'ERRYN');
var eaiErrCd = $("#grid").getCell(rows[i], 'EAIERRCD'); var eaiErrCd = $("#grid").getCell(rows[i], 'EAIERRCD');
var isBizErr = eaiErrCd != null && bizErrCodeSet.has(String(eaiErrCd).trim()); var isBizErr = eaiErrCd != null && bizErrCodeSet.has(String(eaiErrCd).trim());
if (isBizErr) { if (errYn == "Y" && !isBizErr) {
// 업무(BIZ) 오류코드(ERRCODE_BIZ) - 하늘색 배경
$("#" + rows[i]).find("td").css("background-color", "#BEEDFF");
} else if (errYn == "Y") {
$("#" + rows[i]).find("td").css("background-color", "#FFCC99"); $("#" + rows[i]).find("td").css("background-color", "#FFCC99");
} }
} }
$("#grid").tuiTableRowSpan("7"); $("#grid").tuiTableRowSpan("7");
//1000건이상 alert //1000건이상 alert
@@ -627,8 +682,9 @@
<th ><%=localeMessage.getString("tracking.logtype")%></th> <th ><%=localeMessage.getString("tracking.logtype")%></th>
<td> <td>
<c:set var="deepLinkErrorYn" value="${not empty searchErrorYn ? searchErrorYn : param.searchErrorYn}" /> <c:set var="deepLinkErrorYn" value="${not empty searchErrorYn ? searchErrorYn : param.searchErrorYn}" />
<input type="radio" name="searchErrorYn" value="N" ${deepLinkErrorYn eq 'Y' ? '' : 'checked="checked"'} id="sub2_2_1_1"><label for="sub2_2_1_1"><%= localeMessage.getString("tracking.allLog") %></label> <input type="radio" name="searchErrorYn" value="N" ${deepLinkErrorYn eq 'Y' or deepLinkErrorYn eq 'B' ? '' : 'checked="checked"'} id="sub2_2_1_1"><label for="sub2_2_1_1"><%= localeMessage.getString("tracking.allLog") %></label>
<input type="radio" name="searchErrorYn" value="Y" ${deepLinkErrorYn eq 'Y' ? 'checked="checked"' : ''} id="sub2_2_1_2"><label for="sub2_2_1_2"><%= localeMessage.getString("tracking.errLog") %></label> <input type="radio" name="searchErrorYn" value="Y" ${deepLinkErrorYn eq 'Y' ? 'checked="checked"' : ''} id="sub2_2_1_2"><label for="sub2_2_1_2"><%= localeMessage.getString("tracking.errLog") %></label>
<input type="radio" name="searchErrorYn" value="B" ${deepLinkErrorYn eq 'B' ? 'checked="checked"' : ''} id="sub2_2_1_3"><label for="sub2_2_1_3"><%= localeMessage.getString("tracking.bizErrLog") %></label>
</td> </td>
<!-- 로그조회키 --> <!-- 로그조회키 -->
@@ -194,7 +194,11 @@ public class EAILogRepositoryImpl implements EAILogRepository {
// query.where(qeaiLog.eaierrcd.trim().isNotEmpty()); // query.where(qeaiLog.eaierrcd.trim().isNotEmpty());
// } // }
if (StringUtils.equalsIgnoreCase(eaiLogSearch.getSearchErrorYn(), "Y")) { // Y: 에러로그(시스템 에러, ERRCODE_BIZ 제외) / B: 오류로그(업무오류, ERRCODE_BIZ만)
boolean searchErrLog = StringUtils.equalsIgnoreCase(eaiLogSearch.getSearchErrorYn(), "Y");
boolean searchBizErrLog = StringUtils.equalsIgnoreCase(eaiLogSearch.getSearchErrorYn(), "B");
if (searchErrLog || searchBizErrLog) {
// 에러 로그가 있는 eaisevrinstncname을 찾는 서브쿼리 // 에러 로그가 있는 eaisevrinstncname을 찾는 서브쿼리
// entityPathBase를 사용하여 동적 테이블에 대한 서브쿼리 생성 // entityPathBase를 사용하여 동적 테이블에 대한 서브쿼리 생성
JPAQuery<String> errorInstancesSubQuery = new JPAQueryFactory(em) JPAQuery<String> errorInstancesSubQuery = new JPAQueryFactory(em)
@@ -206,12 +210,17 @@ public class EAILogRepositoryImpl implements EAILogRepository {
qeaiLog.eaierrcd.trim().isNotEmpty() qeaiLog.eaierrcd.trim().isNotEmpty()
); );
// ERRCODE_BIZ(업무 오류) 코드는 시스템 에러가 아니므로 "에러로그" 검색 대상에서 제외
List<String> bizErrCodes = codeService.findByIdCodegroup(ERRCODE_BIZ_GROUP).stream() List<String> bizErrCodes = codeService.findByIdCodegroup(ERRCODE_BIZ_GROUP).stream()
.map(code -> code.getId().getCode()) .map(code -> code.getId().getCode())
.collect(Collectors.toList()); .collect(Collectors.toList());
if (!bizErrCodes.isEmpty()) { if (searchBizErrLog) {
// 오류로그: 업무오류(ERRCODE_BIZ) 코드만
errorInstancesSubQuery.where(bizErrCodes.isEmpty()
? qeaiLog.eaierrcd.isNull().and(qeaiLog.eaierrcd.isNotNull()) // 등록된 업무오류 코드가 없으면 결과 없음
: qeaiLog.eaierrcd.in(bizErrCodes));
} else if (!bizErrCodes.isEmpty()) {
// 에러로그: ERRCODE_BIZ(업무 오류) 코드는 시스템 에러가 아니므로 제외
errorInstancesSubQuery.where(qeaiLog.eaierrcd.notIn(bizErrCodes)); errorInstancesSubQuery.where(qeaiLog.eaierrcd.notIn(bizErrCodes));
} }
@@ -7,6 +7,7 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -399,8 +400,13 @@ public class DbTrackingService extends BaseService {
public List<Map<String, Object>> selectListToExcel( public List<Map<String, Object>> selectListToExcel(
EAILogSearch eaiLogSearch) { EAILogSearch eaiLogSearch) {
Page<EAILogUI> page = this.selectList(Pageable.unpaged(), eaiLogSearch); Page<EAILogUI> page = this.selectList(Pageable.unpaged(), eaiLogSearch);
List<EAILogUI> uiList = page.getContent();
List<String> prcsResults = computePrcsResults(uiList);
return page.getContent().stream().map(ui -> { List<Map<String, Object>> result = new ArrayList<>();
for (int i = 0; i < uiList.size(); i++) {
EAILogUI ui = uiList.get(i);
Map<String, Object> map = new HashMap<>(); Map<String, Object> map = new HashMap<>();
map.put("EAISVCSERNO_TMP", ui.getEaisvcserno()); map.put("EAISVCSERNO_TMP", ui.getEaisvcserno());
@@ -409,14 +415,71 @@ public class DbTrackingService extends BaseService {
map.put("EAISVCNAME", ui.getEaisvcname()); map.put("EAISVCNAME", ui.getEaisvcname());
map.put("EAISVCDESC", ui.getEaisvcdesc()); map.put("EAISVCDESC", ui.getEaisvcdesc());
map.put("EAIBZWKDSTCD_TMP", ui.getEaibzwkdstcd()); map.put("EAIBZWKDSTCD_TMP", ui.getEaibzwkdstcd());
map.put("PRCS_RESULT_TMP", prcsResults.get(i));
map.put("EXTBIZCD", ui.getExtbizcd()); map.put("EXTBIZCD", ui.getExtbizcd());
map.put("REFKEY", ui.getRefkey()); map.put("REFKEY", ui.getRefkey());
map.put("MSGDPSTYMS_TMP", ui.getMsgdpstyms()); map.put("MSGDPSTYMS_TMP", ui.getMsgdpstyms());
map.put("MSGPRCSSYMS", ui.getMsgprcssyms()); map.put("MSGPRCSSYMS", ui.getMsgprcssyms());
return map; result.add(map);
}).collect(Collectors.toList()); }
return result;
}
/**
* 처리결과(그리드의 PRCS_RESULT_TMP 컬럼과 동일한 판정) - trackingMan.jsp의
* computePrcsResult/applyPrcsResult 와 동일한 규칙을 서버에서 재현한다(엑셀 다운로드는
* 그리드가 아니라 이 서비스가 새로 조회한 결과를 쓰므로 그리드의 계산 결과를 재사용할 수 없다).
*
* <p>EAIERRCD가 업무(BIZ) 오류코드(ERRCODE_BIZ)면 "오류", ERRYN='Y'(에러내용 있음)면 "실패",
* SEQ(LOGPRCSSSERNO) 100/200은 아직 처리 완료 전 단계라 위 두 경우가 아니면 빈 값, 나머지는 "성공".
* 단, 같은 거래(EAISVCSERNO)의 400(응답)이 실패/오류면 300(요청)의 "성공"은 표시하지 않는다.</p>
*/
private List<String> computePrcsResults(List<EAILogUI> uiList) {
Set<String> bizErrCodes = comboService.getFromCode("ERRCODE_BIZ").stream()
.map(ComboVo::getCode)
.collect(Collectors.toSet());
Map<String, Boolean> has400ErrorBySvcSerno = new HashMap<>();
for (EAILogUI ui : uiList) {
if ("400".equals(ui.getLogprcssserno()) && isErrorResult(computeSinglePrcsResult(ui, bizErrCodes))) {
has400ErrorBySvcSerno.put(ui.getEaisvcserno(), true);
}
}
List<String> results = new ArrayList<>(uiList.size());
for (EAILogUI ui : uiList) {
String result = computeSinglePrcsResult(ui, bizErrCodes);
if ("300".equals(ui.getLogprcssserno()) && "성공".equals(result)
&& Boolean.TRUE.equals(has400ErrorBySvcSerno.get(ui.getEaisvcserno()))) {
result = "";
}
results.add(result);
}
return results;
}
private boolean isErrorResult(String result) {
return "실패".equals(result) || "오류".equals(result);
}
private String computeSinglePrcsResult(EAILogUI ui, Set<String> bizErrCodes) {
String eaiErrCd = ui.getEaierrcd();
boolean isBizErr = eaiErrCd != null && bizErrCodes.contains(eaiErrCd.trim());
String logPrcssSerno = ui.getLogprcssserno();
if (isBizErr) {
return "오류";
} else if (StringUtils.isNotBlank(ui.getEaierrctnt())) {
return "실패";
} else if ("100".equals(logPrcssSerno) || "200".equals(logPrcssSerno)) {
return "";
} else {
return "성공";
}
} }
public Map<String, List<ComboVo>> selectCombo() { public Map<String, List<ComboVo>> selectCombo() {
@@ -2110,6 +2110,7 @@ tracking.eaisvcname = IF Service Code
tracking.eaisvcserno = EAI Service No tracking.eaisvcserno = EAI Service No
tracking.eaisvcserno_tmp = Service Serial No. tracking.eaisvcserno_tmp = Service Serial No.
tracking.errLog = Error Log tracking.errLog = Error Log
tracking.bizErrLog = Biz Error Log
tracking.erryn = Error Yn tracking.erryn = Error Yn
tracking.extBizCd = External Biz.Code tracking.extBizCd = External Biz.Code
tracking.extBizName = Ext.Biz.Name tracking.extBizName = Ext.Biz.Name
@@ -2208,7 +2208,8 @@ tracking.eaisvcname = API \uBA85
tracking.eaisvcserno = EAI\uC11C\uBE44\uC2A4 \uBC88\uD638 tracking.eaisvcserno = EAI\uC11C\uBE44\uC2A4 \uBC88\uD638
tracking.eaisvcserno_tmp = \uAC70\uB798\uACE0\uC720\uBC88\uD638 tracking.eaisvcserno_tmp = \uAC70\uB798\uACE0\uC720\uBC88\uD638
tracking.errLog = \uC5D0\uB7EC\uB85C\uADF8 tracking.errLog = \uC5D0\uB7EC\uB85C\uADF8
tracking.erryn = \uC5D0\uB7EC\uC5EC\uBD80 tracking.bizErrLog = \uC624\uB958\uB85C\uADF8
tracking.erryn = \uC5D0\uB7EC\uC5EC\uBD80
tracking.extBizCd = \uB300\uC678\uC5C5\uBB34\uAD6C\uBD84 tracking.extBizCd = \uB300\uC678\uC5C5\uBB34\uAD6C\uBD84
tracking.extBizName = \uB300\uC678\uC5C5\uBB34\uBA85 tracking.extBizName = \uB300\uC678\uC5C5\uBB34\uBA85
tracking.ifDisKeyVal = \uC5C5\uBB34 \uC11C\uBE44\uC2A4\uD0A4 tracking.ifDisKeyVal = \uC5C5\uBB34 \uC11C\uBE44\uC2A4\uD0A4