개발관리_설계변경리스트

This commit is contained in:
2026-01-07 14:49:27 +09:00
parent 2d836456c6
commit 799ea4faf7
4 changed files with 654 additions and 0 deletions

View File

@@ -0,0 +1,294 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="com.pms.common.utils.*"%>
<%@ page import="java.util.*" %>
<%@include file= "/init.jsp" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><%=Constants.SYSTEM_NAME%> - M-BOM 변경 이력 상세</title>
<style>
body, html {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
}
.history-container {
padding: 20px;
}
h2 {
text-align: center;
color: #333;
margin-bottom: 20px;
}
.history-header {
background-color: #333;
color: white;
padding: 10px 15px;
margin-bottom: 20px;
border-radius: 4px;
}
.history-header span {
margin-right: 20px;
}
table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #4CAF50;
color: white;
font-weight: bold;
}
.section-title {
background-color: #5bc0de;
color: white;
font-weight: bold;
text-align: center;
}
.change-add {
background-color: #e7f4e7;
}
.change-delete {
background-color: #ffe7e7;
}
.change-modify {
background-color: #fff4e6;
}
.before-value {
color: #999;
text-decoration: line-through;
}
.after-value {
color: #d9534f;
font-weight: bold;
}
.btn-close {
display: block;
width: 100px;
margin: 20px auto;
padding: 10px 20px;
background-color: #6c757d;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.btn-close:hover {
background-color: #5a6268;
}
</style>
</head>
<body>
<div class="history-container">
<h2>M-BOM 변경 이력 상세</h2>
<div class="history-header">
<span><strong>변경유형:</strong> ${historyInfo.CHANGE_TYPE}</span>
<span><strong>변경일:</strong> ${historyInfo.CHANGE_DATE}</span>
<span><strong>작성자:</strong> ${historyInfo.CHANGE_USER_NAME}</span>
<span><strong>프로젝트:</strong> ${historyInfo.PROJECT_NO}</span>
</div>
<div id="historyContent">
<!-- JavaScript로 동적 생성 -->
</div>
<button class="btn-close" onclick="window.close();">닫기</button>
</div>
<script>
// 가공업체 목록 (OBJID -> 업체명 변환용)
var vendorMap = {};
// 가공업체 목록 로드
function loadVendorList() {
$.ajax({
url: '/common/getClientMngList.do',
method: 'POST',
async: false,
dataType: 'json',
success: function(data) {
if(data && data.length > 0) {
data.forEach(function(item) {
vendorMap[item.CODE_ID] = item.NAME;
});
}
}
});
}
// OBJID를 업체명으로 변환
function getVendorName(objid) {
if(!objid) return '';
return vendorMap[objid] || objid;
}
// 필드명 한글 변환
function getFieldNameKorean(field) {
var fieldMap = {
"QTY": "수량",
"SUPPLY_TYPE": "자급/사급",
"RAW_MATERIAL": "소재",
"RAW_MATERIAL_SIZE": "사이즈",
"RAW_MATERIAL_PART_NO": "소재품번",
"PROCESSING_VENDOR": "가공업체",
"PROCESSING_DEADLINE": "가공납기",
"GRINDING_DEADLINE": "연삭납기",
"REQUIRED_QTY": "소재소요량",
"ORDER_QTY": "소재발주수량",
"PRODUCTION_QTY": "제작수량",
"REMARK": "비고"
};
return fieldMap[field] || field;
}
$(function(){
// 가공업체 목록 로드
loadVendorList();
// 이력 데이터 파싱 및 표시
var changeType = '${historyInfo.CHANGE_TYPE}';
var beforeDataStr = '${historyInfo.BEFORE_DATA_ESCAPED}';
var afterDataStr = '${historyInfo.AFTER_DATA_ESCAPED}';
try {
var beforeData = beforeDataStr ? JSON.parse(beforeDataStr) : null;
var afterData = afterDataStr ? JSON.parse(afterDataStr) : null;
var html = "";
if(changeType === "CREATE") {
// 생성 이력
html = generateCreateHistoryTable(afterData);
} else if(changeType === "UPDATE") {
// 수정 이력
html = generateUpdateHistoryTable(beforeData, afterData);
}
$("#historyContent").html(html);
} catch(e) {
console.error("JSON 파싱 오류:", e);
$("#historyContent").html("<p style='color: red;'>데이터 파싱 오류가 발생했습니다.</p>");
}
});
// 생성 이력 테이블 생성
function generateCreateHistoryTable(afterData) {
var html = "<table>";
html += "<tr class='section-title'><td colspan='4'>생성된 M-BOM 정보</td></tr>";
html += "<tr><th>항목</th><th>값</th><th>항목</th><th>값</th></tr>";
// 헤더 정보
html += "<tr>";
html += "<td>M-BOM 품번</td><td>" + (afterData.mbomNo || afterData.MBOM_NO || "") + "</td>";
html += "<td>품번</td><td>" + (afterData.partNo || afterData.PART_NO || "") + "</td>";
html += "</tr>";
html += "<tr>";
html += "<td>품명</td><td>" + (afterData.partName || afterData.PART_NAME || "") + "</td>";
html += "<td>기준 BOM 유형</td><td>" + (afterData.sourceBomType || afterData.SOURCE_BOM_TYPE || "") + "</td>";
html += "</tr>";
// BOM 상세 항목
var mbomData = afterData.mbomData || [];
if(mbomData.length > 0) {
html += "<tr class='section-title'><td colspan='4'>생성된 BOM 항목 (" + mbomData.length + "개)</td></tr>";
html += "<tr class='change-add'><th>품번</th><th>품명</th><th>수량</th><th>레벨</th></tr>";
for(var i = 0; i < mbomData.length; i++) {
var item = mbomData[i];
html += "<tr class='change-add'>";
html += "<td>" + (item.partNo || "") + "</td>";
html += "<td>" + (item.partName || "") + "</td>";
html += "<td>" + (item.qty || "") + "</td>";
html += "<td>" + (item.level || "") + "</td>";
html += "</tr>";
}
}
html += "</table>";
return html;
}
// 수정 이력 테이블 생성
function generateUpdateHistoryTable(beforeData, afterData) {
var html = "";
// beforeData는 변경된 항목 배열
var changedItems = beforeData;
if(!Array.isArray(changedItems) || changedItems.length === 0) {
return "<p>변경 사항이 없습니다.</p>";
}
html += "<table>";
html += "<tr class='section-title'><td colspan='4'>변경된 항목 (" + changedItems.length + "개)</td></tr>";
html += "<tr><th>변경유형</th><th>품번</th><th>품명</th><th>변경 내용</th></tr>";
for(var i = 0; i < changedItems.length; i++) {
var item = changedItems[i];
var changeType = item.changeType;
if(changeType === "ADD") {
// 추가된 항목
var afterDataItem = item.afterData || {};
html += "<tr class='change-add'>";
html += "<td>추가</td>";
html += "<td>" + (afterDataItem.partNo || "") + "</td>";
html += "<td>" + (afterDataItem.partName || "") + "</td>";
html += "<td>새 항목 추가</td>";
html += "</tr>";
} else if(changeType === "DELETE") {
// 삭제된 항목
var beforeDataItem = item.beforeData || {};
html += "<tr class='change-delete'>";
html += "<td>삭제</td>";
html += "<td>" + (beforeDataItem.PART_NO || "") + "</td>";
html += "<td>" + (beforeDataItem.PART_NAME || "") + "</td>";
html += "<td>항목 삭제</td>";
html += "</tr>";
} else if(changeType === "MODIFY") {
// 수정된 항목
html += "<tr class='change-modify'>";
html += "<td>수정</td>";
html += "<td>" + (item.partNo || "") + "</td>";
html += "<td>" + (item.partName || "") + "</td>";
html += "<td>";
var fieldChanges = item.fieldChanges || [];
for(var j = 0; j < fieldChanges.length; j++) {
var fc = fieldChanges[j];
var fieldNameKr = getFieldNameKorean(fc.field);
// 가공업체 필드는 OBJID를 업체명으로 변환
var beforeVal = fc.before;
var afterVal = fc.after;
if(fc.field === 'PROCESSING_VENDOR' || fc.field === 'processingVendor') {
beforeVal = beforeVal ? getVendorName(beforeVal) : null;
afterVal = afterVal ? getVendorName(afterVal) : null;
}
html += "<strong>" + fieldNameKr + ":</strong> ";
html += "<span class='before-value'>" + (beforeVal || "(없음)") + "</span> → ";
html += "<span class='after-value'>" + (afterVal || "(없음)") + "</span>";
if(j < fieldChanges.length - 1) html += "<br>";
}
html += "</td>";
html += "</tr>";
}
}
html += "</table>";
return html;
}
</script>
</body>
</html>

View File

@@ -0,0 +1,207 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ page import="com.pms.common.utils.*"%>
<%@ page import="java.util.*" %>
<%@include file= "/init.jsp" %>
<c:set var="now" value="<%=new java.util.Date() %>"/>
<c:set var="sysYear"><fmt:formatDate value="${now}" pattern="yyyy" /></c:set>
<%
// DB에서 메뉴명 조회 (공통 유틸 사용)
String menuObjId = request.getParameter("menuObjId");
String menuName = CommonUtils.getMenuName(menuObjId, "생산관리_M-BOM 변경이력");
%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><%=Constants.SYSTEM_NAME%></title>
<style>
body, html {
overflow-x: hidden;
width: 100%;
margin: 0;
padding: 0;
}
</style>
<script type="text/javascript" src="/js/tabulator/tabulator_custom.js"></script>
</head>
<body>
<script type="text/javascript">
// Tabulator 그리드 전역 변수
var _tabulGrid;
$(document).ready(function(){
_fnc_datepick(); // 날짜 선택기 초기화
$('.select2').select2(); // select2 초기화
// Enter 키로 검색
$("input").keyup(function(e) {
if (e.keyCode == 13) {
fn_search();
}
});
// 조회 버튼
$("#btnSearch").click(function(){
fn_search();
});
// 초기 조회
fn_search();
});
// 날짜 선택기 초기화 함수
function _fnc_datepick(){
var $dateinput = $("input.date_icon");
for(var i=0; i<$dateinput.length; i++){
$dateinput.eq(i).attr("size","10");
$dateinput.eq(i).datepicker({
changeMonth:true,
changeYear:true
});
}
}
// 그리드 컬럼 정의 - M-BOM 변경 이력 목록 (MBOM_HISTORY 기준)
var columns = [
{title:'OBJID', field:'OBJID', visible: false},
{title:'PROJECT_OBJID', field:'PROJECT_OBJID', visible: false},
{title:'MBOM_HEADER_OBJID', field:'MBOM_HEADER_OBJID', visible: false},
{title:'HISTORY_OBJID', field:'HISTORY_OBJID', visible: false},
// 프로젝트번호
{headerHozAlign: 'center', hozAlign: 'left', title: '프로젝트번호', field: 'PROJECT_NO', width: 120,
formatter: fnc_createGridAnchorTag,
cellClick: function(e, cell) {
fn_openSaleRegPopup(cell.getData().PROJECT_NO, "detail");
}
},
// 주문유형
{headerHozAlign: 'center', hozAlign: 'center', title: '주문유형', field: 'CATEGORY_NAME', width: 80},
// 제품구분
{headerHozAlign: 'center', hozAlign: 'center', title: '제품구분', field: 'PRODUCT_NAME', width: 80},
// 국내/해외
{headerHozAlign: 'center', hozAlign: 'center', title: '국내/해외', field: 'AREA_NAME', width: 90},
// 접수일
{headerHozAlign: 'center', hozAlign: 'center', title: '접수일', field: 'RECEIPT_DATE', width: 100},
// 고객사
{headerHozAlign: 'center', hozAlign: 'left', title: '고객사', field: 'CUSTOMER_NAME', width: 120},
// 유/무상
{headerHozAlign: 'center', hozAlign: 'center', title: '유/무상', field: 'PAID_TYPE_NAME', width: 80},
// 품번
{headerHozAlign: 'center', hozAlign: 'left', title: '품번', field: 'PART_NO', width: 150},
// 품명
{headerHozAlign: 'center', hozAlign: 'left', title: '품명', field: 'PART_NAME', width: 180},
// 수주수량
{headerHozAlign: 'center', hozAlign: 'right', title: '수주수량', field: 'QUANTITY', width: 80},
// 요청납기
{headerHozAlign: 'center', hozAlign: 'center', title: '요청납기', field: 'REQ_DEL_DATE', width: 90},
// 고객사요청사항
{headerHozAlign: 'center', hozAlign: 'left', title: '고객사요청사항', field: 'CUSTOMER_REQUEST'},
// 변경일
{headerHozAlign: 'center', hozAlign: 'center', title: '변경일', field: 'CHANGE_DATE', width: 140},
// 작성자
{headerHozAlign: 'center', hozAlign: 'center', title: '작성자', field: 'CHANGE_USER_NAME', width: 80},
// 이력보기
{headerHozAlign: 'center', hozAlign: 'center', title: '이력보기', field: 'CHANGE_TYPE', width: 80,
formatter: fnc_subInfoValueFormatter,
cellClick: function(e, cell) {
var rowData = cell.getData();
var historyObjId = fnc_checkNull(rowData.HISTORY_OBJID);
if(historyObjId) {
fn_openMbomHistoryDetailPopup(historyObjId);
}
}
}
];
// 검색 함수
function fn_search(){
_tabulGrid = fnc_tabul_search(_tabul_layout_fitColumns, _tabulGrid, "/productionplanning/mBomHistoryGridList.do", columns, false);
}
// 프로젝트 상세 팝업
function fn_openSaleRegPopup(orderNo, saleNo){
var popup_width = 1000;
var popup_height = 550;
var url = "/salesMgmt/salesRegForm.do?orderNo=" + encodeURIComponent(orderNo) + "&saleNo=" + (saleNo ? encodeURIComponent(saleNo) : "");
fn_centerPopup(popup_width, popup_height, url);
}
// M-BOM 이력 상세 팝업 (개별 히스토리 건)
function fn_openMbomHistoryDetailPopup(historyObjId) {
var popup_width = 1400;
var popup_height = 800;
var url = "/productionplanning/mBomHistoryDetailPopup.do?historyObjId=" + historyObjId;
fn_centerPopup(popup_width, popup_height, url, 'mbomHistoryDetailPopup');
}
</script>
<form name="form1" id="form1" method="post">
<input type="hidden" name="actionType" id="actionType">
<div class="content-box">
<div class="content-box-s">
<div class="plm_menu_name_gdnsi">
<h2>
<span><%=menuName%></span>
</h2>
<div class="btnArea">
<input type="button" class="plm_btns" value="조회" id="btnSearch">
</div>
</div>
<!-- 검색 영역 -->
<div id="plmSearchZon">
<table>
<tr>
<td><label for="search_category_cd">주문유형</label></td>
<td>
<select name="search_category_cd" id="search_category_cd" style="" class="select2" autocomplete="off">
<option value="">선택</option>
${code_map.category_cd}
</select>
</td>
<td><label for="search_product_cd">제품구분</label></td>
<td>
<select name="search_product_cd" id="search_product_cd" style="" class="select2" autocomplete="off">
<option value="">선택</option>
${code_map.product_cd}
</select>
</td>
<td><label for="search_area_cd">국내/해외</label></td>
<td>
<select name="search_area_cd" id="search_area_cd" style="" class="select2" autocomplete="off">
<option value="">선택</option>
<option value="0001220">국내</option>
<option value="0001221">해외</option>
</select>
</td>
<td><label for="search_customer_objid">고객사</label></td>
<td>
<select name="search_customer_objid" id="search_customer_objid" style="width:253px" class="select2" autocomplete="off">
<option value="">선택</option>
${code_map.customer_cd}
</select>
</td>
<td><label>변경일</label></td>
<td>
<input type="text" name="search_change_date_from" id="search_change_date_from" autocomplete="off" value="" class="date_icon" style="width:100px;">~
<input type="text" name="search_change_date_to" id="search_change_date_to" autocomplete="off" value="" class="date_icon" style="width:100px;">
</td>
</tr>
</table>
</div>
<!-- 그리드 영역 -->
<%@include file= "/WEB-INF/view/common/common_gridArea.jsp" %>
</div>
</div>
</form>
</body>
</html>

View File

@@ -2107,4 +2107,68 @@ public class ProductionPlanningController extends BaseService {
return resultMap;
}
/**
* M-BOM 변경이력 목록 페이지
*/
@RequestMapping("/productionplanning/mBomHistoryList.do")
public String mBomHistoryList(HttpServletRequest request, @RequestParam Map paramMap){
Map code_map = new HashMap();
try {
// 주문유형 (0000167)
code_map.put("category_cd", commonService.bizMakeOptionList("0000167", (String)paramMap.get("search_category_cd"), "common.getCodeselect"));
// 제품구분 (0000001)
code_map.put("product_cd", commonService.bizMakeOptionList("0000001", (String)paramMap.get("search_product_cd"), "common.getCodeselect"));
// 고객사 (SUPPLY_MNG + CLIENT_MNG)
code_map.put("customer_cd", commonService.bizMakeOptionList("", (String)paramMap.get("search_customer_objid"), "common.getAllSupplySelect"));
request.setAttribute("code_map", code_map);
} catch(Exception e) {
e.printStackTrace();
}
return "/productionplanning/mBomHistoryList";
}
/**
* M-BOM 변경이력 그리드 목록 조회 (MBOM_HISTORY 기준)
*/
@ResponseBody
@RequestMapping("/productionplanning/mBomHistoryGridList.do")
public Map mBomHistoryGridList(HttpServletRequest request, @RequestParam Map paramMap){
commonService.selectListPagingNew("productionplanning.getMbomHistoryGridList", request, paramMap);
return paramMap;
}
/**
* M-BOM 변경이력 상세 팝업
*/
@RequestMapping("/productionplanning/mBomHistoryDetailPopup.do")
public String mBomHistoryDetailPopup(HttpServletRequest request, @RequestParam Map paramMap){
try {
String historyObjId = CommonUtils.nullToEmpty((String)paramMap.get("historyObjId"));
if(!"".equals(historyObjId)) {
// 이력 상세 정보 조회
Map<String, Object> historyInfo = commonService.selectOne("productionplanning.getMbomHistoryDetail", request, paramMap);
if(historyInfo != null) {
// JSON 데이터 이스케이프 처리 (JSP에서 JavaScript로 전달 시 오류 방지)
String beforeData = CommonUtils.nullToEmpty((String)historyInfo.get("BEFORE_DATA"));
String afterData = CommonUtils.nullToEmpty((String)historyInfo.get("AFTER_DATA"));
// 줄바꿈, 작은따옴표 등 이스케이프
beforeData = beforeData.replace("\\", "\\\\").replace("'", "\\'").replace("\n", "\\n").replace("\r", "");
afterData = afterData.replace("\\", "\\\\").replace("'", "\\'").replace("\n", "\\n").replace("\r", "");
historyInfo.put("BEFORE_DATA_ESCAPED", beforeData);
historyInfo.put("AFTER_DATA_ESCAPED", afterData);
request.setAttribute("historyInfo", historyInfo);
}
}
} catch(Exception e) {
e.printStackTrace();
}
return "/productionplanning/mBomHistoryDetailPopup";
}
}

View File

@@ -4933,4 +4933,93 @@
WHERE PROJECT_OBJID = #{projectObjid}
</delete>
<!-- M-BOM 변경이력 목록 조회 (MBOM_HISTORY 기준) -->
<select id="getMbomHistoryGridList" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT
MH.OBJID AS HISTORY_OBJID,
MH.MBOM_HEADER_OBJID,
MH.CHANGE_TYPE,
--TO_CHAR(MH.CHANGE_DATE, 'YYYY-MM-DD HH24:MI:SS') AS CHANGE_DATE,
TO_CHAR(MH.CHANGE_DATE, 'YYYY-MM-DD') AS CHANGE_DATE,
MH.CHANGE_USER,
COALESCE(
(SELECT USER_NAME FROM USER_INFO WHERE USER_ID = MH.CHANGE_USER LIMIT 1),
MH.CHANGE_USER
) AS CHANGE_USER_NAME,
PM.OBJID AS PROJECT_OBJID,
PM.PROJECT_NO,
PM.PART_NO,
PM.PART_NAME,
COALESCE(PM.QUANTITY::numeric, 0) AS QUANTITY,
COALESCE(PM.DUE_DATE, CM.REQ_DEL_DATE) AS REQ_DEL_DATE,
CM.OBJID AS CONTRACT_OBJID,
COALESCE((SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.CATEGORY_CD LIMIT 1), '') AS CATEGORY_NAME,
COALESCE((SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.PRODUCT LIMIT 1), '') AS PRODUCT_NAME,
COALESCE((SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.AREA_CD LIMIT 1), '') AS AREA_NAME,
TO_CHAR(PM.REGDATE, 'YYYY-MM-DD') AS RECEIPT_DATE,
COALESCE(
CASE WHEN CM.CUSTOMER_OBJID LIKE 'C_%' THEN (SELECT CLIENT_NM FROM CLIENT_MNG AS C WHERE 'C_' || C.OBJID::VARCHAR = CM.CUSTOMER_OBJID LIMIT 1) ELSE (SELECT SUPPLY_NAME FROM SUPPLY_MNG WHERE OBJID::VARCHAR = CM.CUSTOMER_OBJID::VARCHAR LIMIT 1) END,
''
) AS CUSTOMER_NAME,
COALESCE(
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.PAID_TYPE LIMIT 1),
CASE
WHEN CM.PAID_TYPE = 'paid' THEN '유상'
WHEN CM.PAID_TYPE = 'free' THEN '무상'
ELSE ''
END
) AS PAID_TYPE_NAME,
COALESCE(CI.CUSTOMER_REQUEST, '') AS CUSTOMER_REQUEST
FROM MBOM_HISTORY MH
INNER JOIN MBOM_HEADER MHD ON MH.MBOM_HEADER_OBJID = MHD.OBJID
INNER JOIN PROJECT_MGMT PM ON MHD.PROJECT_OBJID = PM.OBJID::VARCHAR
LEFT OUTER JOIN CONTRACT_ITEM CI ON PM.CONTRACT_OBJID = CI.CONTRACT_OBJID
LEFT JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
WHERE 1=1
<if test="search_category_cd != null and search_category_cd != ''">
AND CM.CATEGORY_CD = #{search_category_cd}
</if>
<if test="search_product_cd != null and search_product_cd != ''">
AND CM.PRODUCT = #{search_product_cd}
</if>
<if test="search_area_cd != null and search_area_cd != ''">
AND CM.AREA_CD = #{search_area_cd}
</if>
<if test="search_customer_objid != null and search_customer_objid != ''">
AND CM.CUSTOMER_OBJID = #{search_customer_objid}
</if>
<if test="search_change_date_from != null and search_change_date_from != ''">
AND MH.CHANGE_DATE >= TO_DATE(#{search_change_date_from}, 'YYYY-MM-DD')
</if>
<if test="search_change_date_to != null and search_change_date_to != ''">
AND MH.CHANGE_DATE &lt;= TO_DATE(#{search_change_date_to}, 'YYYY-MM-DD') + INTERVAL '1 day'
</if>
ORDER BY MH.CHANGE_DATE DESC
</select>
<!-- M-BOM 변경이력 상세 조회 (개별 히스토리 건) -->
<select id="getMbomHistoryDetail" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT
MH.OBJID AS HISTORY_OBJID,
MH.MBOM_HEADER_OBJID,
MH.CHANGE_TYPE,
MH.CHANGE_DESCRIPTION,
MH.BEFORE_DATA::TEXT AS BEFORE_DATA,
MH.AFTER_DATA::TEXT AS AFTER_DATA,
TO_CHAR(MH.CHANGE_DATE, 'YYYY-MM-DD HH24:MI:SS') AS CHANGE_DATE,
MH.CHANGE_USER,
COALESCE(
(SELECT USER_NAME FROM USER_INFO WHERE USER_ID = MH.CHANGE_USER LIMIT 1),
MH.CHANGE_USER
) AS CHANGE_USER_NAME,
-- PROJECT 정보
PM.PROJECT_NO,
PM.PART_NO,
PM.PART_NAME
FROM MBOM_HISTORY MH
INNER JOIN MBOM_HEADER MHD ON MH.MBOM_HEADER_OBJID = MHD.OBJID
INNER JOIN PROJECT_MGMT PM ON MHD.PROJECT_OBJID = PM.OBJID::VARCHAR
WHERE MH.OBJID::VARCHAR = #{historyObjId}
</select>
</mapper>