중간커밋

This commit is contained in:
leeheejin
2025-11-26 11:12:42 +09:00
parent cd4f5afe87
commit 47cfa6bbf9
11 changed files with 1254 additions and 468 deletions

View File

@@ -663,6 +663,15 @@ VALUES
SRM.PROJECT_NO,
PM.PROJECT_NO AS PROJECT_NUMBER,
PM.PROJECT_NAME,
COALESCE(
PM.OBJID,
(SELECT OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1)
) AS PROJECT_MGMT_OBJID,
-- M-BOM 조회용 BOM_REPORT_OBJID 추가
COALESCE(
PM.BOM_REPORT_OBJID,
(SELECT BOM_REPORT_OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1)
) AS BOM_REPORT_OBJID,
PM.SETUP,
SM.SUPPLY_NAME AS CUSTOMER_NAME,
SM.OBJID::VARCHAR AS CUSTOMER_OBJID, -- 고객사 OBJID (드롭다운 선택용)
@@ -705,7 +714,7 @@ VALUES
FROM
SALES_REQUEST_MASTER SRM
LEFT JOIN PROJECT_MGMT PM ON SRM.PROJECT_NO = PM.OBJID::VARCHAR
LEFT JOIN PROJECT_MGMT PM ON (SRM.PROJECT_NO = PM.OBJID::VARCHAR OR SRM.PROJECT_NO = PM.PROJECT_NO)
LEFT JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID::VARCHAR
LEFT JOIN SUPPLY_MNG SM ON CM.CUSTOMER_OBJID::VARCHAR = SM.OBJID::VARCHAR
LEFT JOIN PURCHASE_ORDER_MASTER POM ON SRM.OBJID = POM.SALES_REQUEST_OBJID
@@ -1242,31 +1251,51 @@ VALUES
AND PM.OBJID = #{PROJECT_NO}
</select>
<!-- 전체 품목 조회 (M-BOM이 없을 때 사용) -->
<select id="getAllPartMngList" parameterType="map" resultType="map">
SELECT
PM.OBJID,
PM.PART_NO,
PM.PART_NAME,
PM.SPEC,
PM.MAKER,
PM.MATERIAL,
PM.UNIT,
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = PM.UNIT) AS UNIT_TITLE
FROM PART_MNG PM
WHERE 1=1
AND PM.IS_LAST = '1'
ORDER BY PM.PART_NO
LIMIT 500
</select>
<select id="SalesBomPartListByProjectUnit" parameterType="map" resultType="map">
<!-- M-BOM 데이터 조회: PROJECT_MGMT.BOM_REPORT_OBJID -> BOM_PART_QTY -> PART_MNG -->
<!-- M-BOM 데이터 조회: getMbomList와 동일한 조인 방식 사용 (BPQ.PART_NO = PM.PART_NO) -->
SELECT
BPQ.BOM_REPORT_OBJID
,BPQ.PART_NO AS PART_OBJID
,PM.PART_NAME
,PM.PART_NO
,PM.SPEC
,PM.MAKER
,PM.REMARK
,PM.UNIT
,COALESCE(PM.PART_NO, BPQ.PART_NO, '') AS PART_NO
,COALESCE(PM.PART_NAME, '') AS PART_NAME
,COALESCE(PM.PART_NAME, '') AS PART_FULL_NAME
,COALESCE(PM.SPEC, '') AS SPEC
,BPQ.QTY AS ORDER_QTY
,COALESCE(PM.MAKER, '') AS MAKER
,'' AS REMARK
,'' AS UNIT
,NULL AS SUPPLY_OBJID
,NULL AS WRITER
FROM
PROJECT_MGMT AS PJT
INNER JOIN BOM_PART_QTY AS BPQ
ON PJT.BOM_REPORT_OBJID = BPQ.BOM_REPORT_OBJID::VARCHAR
LEFT JOIN PART_MNG AS PM
ON COALESCE(NULLIF(BPQ.LAST_PART_OBJID, ''), BPQ.PART_NO) = PM.OBJID::VARCHAR
INNER JOIN BOM_PART_QTY AS BPQ
ON PJT.BOM_REPORT_OBJID::VARCHAR = BPQ.BOM_REPORT_OBJID::VARCHAR
LEFT JOIN PART_MGMT AS PM
ON BPQ.PART_NO = PM.PART_NO
WHERE 1=1
AND PJT.OBJID = #{PROJECT_OBJID}
AND PJT.OBJID::VARCHAR = #{PROJECT_OBJID}
AND COALESCE(BPQ.STATUS, '') NOT IN ('deleting', 'deleted')
AND PJT.BOM_REPORT_OBJID IS NOT NULL
AND PJT.BOM_REPORT_OBJID != ''
ORDER BY BPQ.SEQ, PM.PART_NO
ORDER BY BPQ.SEQ
</select>
<update id="mergeReceiptSalesRequestInfo" parameterType="map">
@@ -2775,18 +2804,19 @@ UPDATE SET
</update>
<!-- 구매리스트 관련 쿼리 -->
<!-- M-BOM에서 가져온 PART_OBJID는 BPQ.PART_NO 값이므로 PART_MGMT.PART_NO와 조인 -->
<select id="getSalesRequestPartList" parameterType="string" resultType="map">
SELECT
SRP.OBJID,
SRP.PART_OBJID,
PM.PART_NO,
PM.PART_NAME,
COALESCE(PM.PART_NO, '') AS PART_NO,
COALESCE(PM.PART_NAME, '') AS PART_NAME,
SRP.QTY,
SRP.PARTNER_OBJID,
SRP.PARTNER_PRICE
FROM
SALES_REQUEST_PART SRP
LEFT JOIN PART_MNG PM ON SRP.PART_OBJID = PM.OBJID::VARCHAR
LEFT JOIN PART_MGMT PM ON SRP.PART_OBJID = PM.PART_NO
WHERE
SRP.SALES_REQUEST_MASTER_OBJID = #{SALES_REQUEST_MASTER_OBJID}
ORDER BY SRP.REGDATE
@@ -2895,5 +2925,119 @@ UPDATE SET
UNIT_PRICE = #{UNIT_PRICE},
TOTAL_PRICE = #{TOTAL_PRICE}
</update>
<!-- 구매리스트 상세 조회 (기존 저장된 데이터) -->
<select id="getPurchaseListDetail" parameterType="map" resultType="map">
<!-- SALES_REQUEST_PART에서 저장된 데이터 조회, PART_MNG에서 품목정보 가져옴 -->
SELECT
SRP.OBJID,
SRP.SALES_REQUEST_MASTER_OBJID,
SRP.PART_OBJID,
COALESCE(PMG.PART_NO, '') AS PART_NO,
COALESCE(PMG.PART_NAME, '') AS PART_NAME,
SRP.QTY,
0 AS ITEM_QTY,
-- 파일 개수 (PART_MNG.OBJID 기준으로 조회)
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = PMG.OBJID AND DOC_TYPE IN ('3D_CAD') AND UPPER(STATUS) = 'ACTIVE'), 0) AS CU01_CNT,
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = PMG.OBJID AND DOC_TYPE IN ('2D_DRAWING_CAD') AND UPPER(STATUS) = 'ACTIVE'), 0) AS CU02_CNT,
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = PMG.OBJID AND DOC_TYPE IN ('2D_PDF_CAD') AND UPPER(STATUS) = 'ACTIVE'), 0) AS CU03_CNT,
COALESCE(PMG.MATERIAL, '') AS MATERIAL,
COALESCE(PMG.HEAT_TREATMENT_HARDNESS, '') AS HEAT_TREATMENT_HARDNESS,
COALESCE(PMG.HEAT_TREATMENT_METHOD, '') AS HEAT_TREATMENT_METHOD,
COALESCE(PMG.SURFACE_TREATMENT, '') AS SURFACE_TREATMENT,
COALESCE(PMG.MAKER, '') AS VENDOR,
COALESCE(PMG.PART_TYPE, '') AS PART_TYPE_TITLE,
'' AS SUPPLY_TYPE,
'' AS RAW_MATERIAL,
'' AS SIZE,
'' AS RAW_MATERIAL_NO,
0 AS REQUIRED_QTY,
0 AS ORDER_QTY,
0 AS ITEM_QTY2,
0 AS PRODUCTION_QTY,
'' AS PROCESSING_VENDOR,
NULL AS PROCESSING_DEADLINE,
NULL AS GRINDING_DEADLINE,
'Y' AS USE_YN,
0 AS NET_QTY,
0 AS PO_QTY,
SRP.PARTNER_OBJID AS VENDOR_PM,
COALESCE(NULLIF(SRP.PARTNER_PRICE, '')::numeric, 0) AS UNIT_PRICE,
COALESCE(
COALESCE(NULLIF(SRP.PARTNER_PRICE, '')::numeric, 0) * COALESCE(SRP.QTY::numeric, 0),
0
) AS TOTAL_PRICE,
NULL AS PROPOSAL_DATE
FROM
SALES_REQUEST_PART SRP
LEFT JOIN PART_MNG PMG ON SRP.PART_OBJID = PMG.OBJID::VARCHAR AND PMG.IS_LAST = '1'
WHERE
SRP.SALES_REQUEST_MASTER_OBJID = #{SALES_REQUEST_MASTER_OBJID}
ORDER BY
SRP.REGDATE
</select>
<!-- M-BOM에서 구매리스트 데이터 가져오기 (BOM_PART_QTY 기본 데이터만) -->
<select id="getMBomForPurchaseList" parameterType="map" resultType="map">
<!-- MBOM_DETAIL + PART_MNG 조인하여 조회 -->
SELECT
ROW_NUMBER() OVER (ORDER BY MD.SEQ) AS ROW_NUM,
MD.OBJID::VARCHAR AS OBJID,
MH.OBJID::VARCHAR AS BOM_REPORT_OBJID,
MD.PARENT_OBJID::VARCHAR AS PARENT_OBJID,
MD.CHILD_OBJID::VARCHAR AS CHILD_OBJID,
'' AS PARENT_PART_NO,
MD.PART_OBJID::VARCHAR AS PART_OBJID,
PM.OBJID::VARCHAR AS PM_OBJID,
COALESCE(MD.PART_NO, PM.PART_NO, '') AS PART_NO,
COALESCE(MD.PART_NAME, PM.PART_NAME, '') AS PART_NAME,
COALESCE(MD.QTY, 0) AS QTY,
COALESCE(MD.QTY, 0) AS ITEM_QTY,
0 AS QTY_TEMP,
MD.SEQ,
COALESCE(MD.STATUS, '') AS STATUS,
'' AS LAST_PART_OBJID,
-- 파일 개수 (ATTACH_FILE_INFO에서 서브쿼리로 가져옴)
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('3D_CAD')), 0) AS CU01_CNT,
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_DRAWING_CAD')), 0) AS CU02_CNT,
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_PDF_CAD')), 0) AS CU03_CNT,
-- E-BOM 컬럼들 (PART_MNG에서 가져옴) - 디버그용으로 원본값도 출력
PM.HEAT_TREATMENT_HARDNESS AS PM_HEAT_RAW,
PM.HEAT_TREATMENT_METHOD AS PM_METHOD_RAW,
PM.SURFACE_TREATMENT AS PM_SURFACE_RAW,
COALESCE(PM.MATERIAL, MD.RAW_MATERIAL, '') AS MATERIAL,
COALESCE(PM.HEAT_TREATMENT_HARDNESS, '') AS HEAT_TREATMENT_HARDNESS,
COALESCE(PM.HEAT_TREATMENT_METHOD, '') AS HEAT_TREATMENT_METHOD,
COALESCE(PM.SURFACE_TREATMENT, '') AS SURFACE_TREATMENT,
COALESCE(PM.MAKER, MD.VENDOR, '') AS VENDOR,
COALESCE((SELECT CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = PM.PART_TYPE), '') AS PART_TYPE_TITLE,
-- 생산관리 컬럼들 (MBOM_DETAIL에서 가져옴)
COALESCE(MD.SUPPLY_TYPE, '') AS SUPPLY_TYPE,
COALESCE(MD.RAW_MATERIAL, '') AS RAW_MATERIAL,
COALESCE(MD.RAW_MATERIAL_SIZE, '') AS SIZE,
COALESCE(MD.RAW_MATERIAL_PART_NO, '') AS RAW_MATERIAL_NO,
COALESCE(MD.REQUIRED_QTY, 0) AS REQUIRED_QTY,
COALESCE(MD.ORDER_QTY, 0) AS ORDER_QTY,
COALESCE(MD.PRODUCTION_QTY, 0) AS PRODUCTION_QTY,
COALESCE(MD.PROCESSING_VENDOR, '') AS PROCESSING_VENDOR,
MD.PROCESSING_DEADLINE,
MD.GRINDING_DEADLINE,
-- 구매 컬럼들 (편집 가능)
'Y' AS USE_YN,
0 AS NET_QTY,
0 AS PO_QTY,
COALESCE(MD.VENDOR, '') AS VENDOR_PM,
COALESCE(MD.UNIT_PRICE, 0) AS UNIT_PRICE,
COALESCE(MD.TOTAL_PRICE, 0) AS TOTAL_PRICE,
NULL AS PROPOSAL_DATE
FROM
MBOM_HEADER MH
INNER JOIN MBOM_DETAIL MD ON MH.OBJID = MD.MBOM_HEADER_OBJID
LEFT JOIN PART_MNG PM ON PM.OBJID::VARCHAR = MD.PART_OBJID::VARCHAR
WHERE
MH.PROJECT_OBJID = #{PROJECT_MGMT_OBJID}
ORDER BY
MD.SEQ
</select>
</mapper>

View File

@@ -152,14 +152,14 @@ $(document).ready(function(){
,{name:"CLIENT_TYPE",index:"CLIENT_TYPE", width: 100, align:"center", hidden: false, sortable:false, editable:true
,edittype:"select"
,formatter:"select"
,editoptions:{
,editoptions:{
value: client_type
,dataInit : function(e){
e.style.width = "92%";
e.style.fontSize = 13;
}
}
}
,dataInit : function(e){
e.style.width = "92%";
e.style.fontSize = 13;
}
}
}
,{name:"BUS_REG_NO",index:"BUS_REG_NO", width: 150, align:"center", hidden: false, sortable:false, editable:true
,editoptions:{dataInit : function(e){e.style.fontSize = 13;}}
}
@@ -513,23 +513,23 @@ function fn_count(){
var clientCd = gridData[i].CLIENT_CD;
if(clientCd && clientCd.trim() !== ""){
// AJAX로 중복 체크
$.ajax({
$.ajax({
url:"/admin/checkDuplicateClientMngList.do",
type:"POST",
type:"POST",
data:{"CLIENT_CD": clientCd},
dataType:"json",
async: false,
success:function(data){
dataType:"json",
async: false,
success:function(data){
if(data.result == "true"){
dupCnt++; // 중복
} else {
nowCnt++; // 신규
}
},
error: function(jqxhr, status, error){
},
error: function(jqxhr, status, error){
nowCnt++; // 에러 시 신규로 간주
}
});
}
});
}
}

View File

@@ -20,7 +20,7 @@ function saveClient(){
alert(result.MESSAGE || result.message);
if(result.RESULTFLAG == "true" || result.resultFlag == "true"){
if(opener && opener.fn_search){
opener.fn_search();
opener.fn_search();
}
self.close();
}

View File

@@ -21,20 +21,20 @@ function saveWarehouse(){
form.modify_dt.value = convertToDBFormat(modifyDt);
}
$.ajax({
$.ajax({
type: "POST",
url: "/admin/saveWarehouseListInfo.do",
data: $(form).serialize(),
dataType: "json",
success: function(result){
success: function(result){
alert(result.message);
if(result.resultFlag == "true"){
opener.fn_search();
self.close();
}
}
});
}
}
}
});
}
}
function convertToDBFormat(dateStr) {
@@ -70,10 +70,10 @@ function convertToDBFormat(dateStr) {
</script>
</head>
<body>
<section id="commonSection" class="admin_option_min">
<div class="admin_title">
<section id="commonSection" class="admin_option_min">
<div class="admin_title">
<h2>창고 등록/수정</h2>
</div>
</div>
<div id="businessPopupFormWrap">
<form name="warehouseForm" id="warehouseForm">
<input type="hidden" name="objid" value="${info.OBJID}">
@@ -87,94 +87,94 @@ function convertToDBFormat(dateStr) {
<tr>
<td class="input_title"><label for=""></label>위치명<label></td>
<td><input type="text" name="location_name" value="${info.LOCATION_NAME}" required></td>
</tr>
</tr>
<tr>
<td class="input_title"><label for=""></label>위치설명<label></td>
<td><input type="text" name="location_description" value="${info.LOCATION_DESCRIPTION}"></td>
</tr>
</tr>
<tr>
<td class="input_title"><label for=""></label>가출고코드<label></td>
<td><input type="text" name="out_code" value="${info.OUT_CODE}"></td>
</tr>
</tr>
<tr>
<td class="input_title"><label for=""></label>가출고거래처명<label></td>
<td><input type="text" name="out_co_name" value="${info.OUT_CO_NAME}"></td>
</tr>
</tr>
<tr>
<td class="input_title"><label for=""></label>적합여부<label></td>
<td>
<td>
<select name="fit_status">
<option value="">선택</option>
<option value="">선택</option>
<option value="Y" ${info.FIT_STATUS eq 'Y' ? 'selected' : ''}>적합</option>
<option value="N" ${info.FIT_STATUS eq 'N' ? 'selected' : ''}>부적합</option>
</select>
</td>
</tr>
</select>
</td>
</tr>
<tr>
<td class="input_title"><label for=""></label>가용재고여부<label></td>
<td>
<td>
<select name="available_status">
<option value="">선택</option>
<option value="">선택</option>
<option value="Y" ${info.AVAILABLE_STATUS eq 'Y' ? 'selected' : ''}>여</option>
<option value="N" ${info.AVAILABLE_STATUS eq 'N' ? 'selected' : ''}>부</option>
</select>
</td>
</tr>
</select>
</td>
</tr>
<tr>
<td class="input_title"><label for=""></label>사용여부<label></td>
<td>
<select name="use_status">
<option value="Y" ${empty info.USE_STATUS or info.USE_STATUS eq 'Y' ? 'selected' : ''}>사용</option>
<option value="N" ${info.USE_STATUS eq 'N' ? 'selected' : ''}>미사용</option>
</select>
</td>
</tr>
</select>
</td>
</tr>
<tr>
<td class="input_title"><label for=""></label>BASELOC_CD<label></td>
<td><input type="text" name="base_loc_cd" value="${info.BASE_LOC_CD}"></td>
</tr>
</tr>
<tr>
<td class="input_title"><label for=""></label>CO_CD<label></td>
<td><input type="text" name="co_cd" value="${info.CO_CD}"></td>
</tr>
</tr>
<tr>
<td class="input_title"><label for=""></label>LOC_NMK<label></td>
<td><input type="text" name="loc_nmk" value="${info.LOC_NMK}"></td>
</tr>
</tr>
<tr>
<td class="input_title"><label for=""></label>INSERT_ID<label></td>
<td><input type="text" name="insert_id" value="${info.INSERT_ID}"></td>
</tr>
</tr>
<tr>
<td class="input_title"><label for=""></label>INSERT_IP<label></td>
<td><input type="text" name="insert_ip" value="${info.INSERT_IP}"></td>
</tr>
</tr>
<tr>
<td class="input_title"><label for=""></label>INSERT_DT<label></td>
<td><input type="text" name="insert_dt" value="${info.INSERT_DT}" placeholder="YYYY-MM-DD HH:MM:SS"></td>
</tr>
</tr>
<tr>
<td class="input_title"><label for=""></label>MODIFY_ID<label></td>
<td><input type="text" name="modify_id" value="${info.MODIFY_ID}"></td>
</tr>
</tr>
<tr>
<td class="input_title"><label for=""></label>MODIFY_IP<label></td>
<td><input type="text" name="modify_ip" value="${info.MODIFY_IP}"></td>
</tr>
</tr>
<tr>
<td class="input_title"><label for=""></label>MODIFY_DT<label></td>
<td><input type="text" name="modify_dt" value="${info.MODIFY_DT}" placeholder="YYYY-MM-DD HH:MM:SS"></td>
</tr>
</tr>
<tr>
<td class="input_title"><label for=""></label>ATTR_NMK<label></td>
<td><input type="text" name="attr_nmk" value="${info.ATTR_NMK}"></td>
</tr>
</table>
</tr>
</table>
</form>
</div>
<div id="adminPopupBtnWrap">
</div>
<div id="adminPopupBtnWrap">
<button type="button" class="btns" onclick="saveWarehouse()">저장</button>
</div>
</section>
</div>
</section>
</body>
</html>

View File

@@ -1,240 +1,644 @@
<%@ 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.*" %>
<%@ 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"%>
<c:set var="now" value="<%=new java.util.Date() %>"/>
<c:set var="sysYear"><fmt:formatDate value="${now}" pattern="yyyy" /></c:set>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<c:set var="resolvedProjectId"
value="${not empty param.PROJECT_MGMT_OBJID and param.PROJECT_MGMT_OBJID ne 'null'
? param.PROJECT_MGMT_OBJID
: (not empty resultMap.PROJECT_MGMT_OBJID
? resultMap.PROJECT_MGMT_OBJID
: (not empty resultMap.PROJECT_NO ? resultMap.PROJECT_NO : ''))}" />
<c:set var="resolvedBomReportObjid"
value="${not empty param.BOM_REPORT_OBJID and param.BOM_REPORT_OBJID ne 'null'
? param.BOM_REPORT_OBJID
: (not empty resultMap.BOM_REPORT_OBJID ? resultMap.BOM_REPORT_OBJID : '')}" />
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><%=Constants.SYSTEM_NAME%></title>
<script type="text/javascript" src="/js/tabulator/tabulator_custom.js"></script>
<style>
body, html {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
}
.container {
display: flex;
flex-direction: column;
height: 100%;
}
.header {
padding: 15px 20px;
background: #f5f5f5;
border-bottom: 2px solid #ddd;
}
.header h3 {
margin: 0 0 10px 0;
color: #333;
}
.info-table {
width: 100%;
border-collapse: collapse;
}
.info-table td {
padding: 5px 10px;
}
.info-table label {
font-weight: bold;
margin-right: 10px;
}
.content {
flex: 1;
padding: 20px;
overflow: auto;
}
.footer {
padding: 15px 20px;
background: #f5f5f5;
border-top: 1px solid #ddd;
text-align: center;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<input type="button" value="저장" class="plm_btns" onclick="fn_save();" style="margin-right: 5px;">
<input type="button" value="닫기" class="plm_btns" onclick="window.close();">
</div>
<div class="content">
<div id="purchaseListTable"></div>
</div>
<div class="footer">
</div>
</div>
<script>
var _tabulGrid;
var salesRequestMasterObjid = "${param.SALES_REQUEST_MASTER_OBJID}";
var projectMgmtObjid = "${resolvedProjectId}";
var bomReportObjid = "${resolvedBomReportObjid}";
// 디버그: resultMap 내용 확인
console.log("=== JSP resultMap 디버그 ===");
console.log("resultMap.PROJECT_MGMT_OBJID:", "${resultMap.PROJECT_MGMT_OBJID}");
console.log("resultMap.BOM_REPORT_OBJID:", "${resultMap.BOM_REPORT_OBJID}");
console.log("resultMap.PROJECT_NO:", "${resultMap.PROJECT_NO}");
console.log("resolvedProjectId:", projectMgmtObjid);
console.log("resolvedBomReportObjid:", bomReportObjid);
function logDebug(){
if(window.console && typeof window.console.log === "function"){
console.log.apply(console, arguments);
}
}
function logError(){
if(window.console && typeof window.console.error === "function"){
console.error.apply(console, arguments);
}
}
$(document).ready(function(){
$('.select2').select2();
// 행추가 버튼
$("#btnAddRow").click(function(){
fn_AddRow();
});
// 행삭제 버튼
$("#btnDeleteRow").click(function(){
fn_DeleteRow();
});
// 저장 버튼
$("#btnSave").click(function(){
fn_save();
});
// 닫기 버튼
$("#btnClose").click(function(){
window.close();
});
// 초기 데이터 로드
fn_loadPurchaseList();
fn_initGrid();
logDebug("purchaseListFormPopUp :: grid initialized");
fn_loadInitialData();
});
// 구매리스트 데이터 로드
function fn_loadPurchaseList() {
var salesRequestMasterObjid = "${param.SALES_REQUEST_MASTER_OBJID}";
function fn_loadInitialData(){
logDebug("purchaseListFormPopUp :: fn_loadInitialData start",
"projectMgmtObjid=", projectMgmtObjid,
"salesRequestMasterObjid=", salesRequestMasterObjid);
var hasProject = projectMgmtObjid && projectMgmtObjid !== "" && projectMgmtObjid !== "null";
var hasMaster = salesRequestMasterObjid && salesRequestMasterObjid !== "" && salesRequestMasterObjid !== "null";
if(!salesRequestMasterObjid || salesRequestMasterObjid == "") {
return;
if(hasProject){
logDebug("purchaseListFormPopUp :: loading MBOM first");
fn_loadFromMBom(function(){
if(hasMaster){
logDebug("purchaseListFormPopUp :: merging saved purchase data after MBOM");
fn_loadPurchaseList(true);
}
});
} else if(hasMaster){
logDebug("purchaseListFormPopUp :: only saved purchase data available");
fn_loadPurchaseList(false);
} else {
logDebug("purchaseListFormPopUp :: no project or master id provided");
}
$.ajax({
url: "/salesMng/getPurchaseListData.do",
type: "POST",
data: {
SALES_REQUEST_MASTER_OBJID: salesRequestMasterObjid
}
// Tabulator 그리드 초기화
function fn_initGrid() {
var columns = [
// 1. 체크박스
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 40,
title: '<input type="checkbox" id="checkAll">',
field: 'CHK',
formatter: function(cell) {
return '<input type="checkbox" class="rowCheck">';
},
headerSort: false
},
dataType: "json",
success: function(response) {
if(response.partList && response.partList.length > 0) {
$("#partListArea").empty();
$.each(response.partList, function(i, part) {
fn_AddRow(part);
});
// 2. No
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 50,
title: 'No',
field: 'ROW_NUM',
formatter: "rownum"
},
// 3. 품번
{
headerHozAlign: 'center',
hozAlign: 'left',
widthGrow: 2,
title: '품번',
field: 'PART_NO'
},
// 4. 품명
{
headerHozAlign: 'center',
hozAlign: 'left',
widthGrow: 3,
title: '품명',
field: 'PART_NAME'
},
// 5. 수량
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 60,
title: '수량',
field: 'QTY'
},
// 6. 항목 수량
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 80,
title: '항목 수량',
field: 'ITEM_QTY'
},
// 7. 3D
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 60,
title: '3D',
field: 'CU01_CNT',
formatter: function(cell) {
var value = cell.getValue();
return value && value > 0 ? '<span class="file_icon"></span>' : '<span class="file_empty_icon"></span>';
}
},
error: function(xhr, status, error) {
console.error("데이터 로드 오류:", error);
// 8. 2D
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 60,
title: '2D',
field: 'CU02_CNT',
formatter: function(cell) {
var value = cell.getValue();
return value && value > 0 ? '<span class="file_icon"></span>' : '<span class="file_empty_icon"></span>';
}
},
// 9. PDF
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 60,
title: 'PDF',
field: 'CU03_CNT',
formatter: function(cell) {
var value = cell.getValue();
return value && value > 0 ? '<span class="file_icon"></span>' : '<span class="file_empty_icon"></span>';
}
},
// 10. 재료
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 100,
title: '재료',
field: 'MATERIAL'
},
// 11. 열처리경도
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 120,
title: '열처리경도',
field: 'HEAT_TREATMENT_HARDNESS'
},
// 12. 열처리방법
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 120,
title: '열처리방법',
field: 'HEAT_TREATMENT_METHOD'
},
// 13. 표면처리
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 100,
title: '표면처리',
field: 'SURFACE_TREATMENT'
},
// 14. 공급업체
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 150,
title: '공급업체',
field: 'VENDOR'
},
// 15. 범주 이름
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 100,
title: '범주 이름',
field: 'PART_TYPE_TITLE'
},
// 16. 지급/사급
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 100,
title: '지급/사급',
field: 'SUPPLY_TYPE'
},
// 17. 소재
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 100,
title: '소재',
field: 'RAW_MATERIAL'
},
// 18. 사이즈
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 100,
title: '사이즈',
field: 'SIZE'
},
// 19. 소재품번
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 120,
title: '소재품번',
field: 'RAW_MATERIAL_NO'
},
// 20. 소재소요량
{
headerHozAlign: 'center',
hozAlign: 'right',
width: 100,
title: '소재소요량',
field: 'REQUIRED_QTY',
formatter: function(cell) {
var value = cell.getValue();
return value ? Number(value).toLocaleString() : '0';
}
},
// 21. 소재발주수량
{
headerHozAlign: 'center',
hozAlign: 'right',
width: 120,
title: '소재발주수량',
field: 'ORDER_QTY',
formatter: function(cell) {
var value = cell.getValue();
return value ? Number(value).toLocaleString() : '0';
}
},
// 22. 항목수량
{
headerHozAlign: 'center',
hozAlign: 'right',
width: 80,
title: '항목수량',
field: 'ITEM_QTY'
},
// 23. 제작수량
{
headerHozAlign: 'center',
hozAlign: 'right',
width: 100,
title: '제작수량',
field: 'PRODUCTION_QTY',
formatter: function(cell) {
var value = cell.getValue();
return value ? Number(value).toLocaleString() : '0';
}
},
// 24. 가공업체
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 150,
title: '가공업체',
field: 'PROCESSING_VENDOR'
},
// 25. 가공납기
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 100,
title: '가공납기',
field: 'PROCESSING_DEADLINE'
},
// 26. 연삭납기
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 100,
title: '연삭납기',
field: 'GRINDING_DEADLINE'
},
// 27. 사용여부
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 80,
title: '사용여부',
field: 'USE_YN',
editor: 'list',
editorParams: {
values: ['Y', 'N']
}
},
// 28. 정미수량 (편집 가능)
{
headerHozAlign: 'center',
hozAlign: 'right',
width: 100,
title: '정미수량',
field: 'NET_QTY',
editor: 'number',
formatter: function(cell) {
var value = cell.getValue();
return value ? Number(value).toLocaleString() : '0';
}
},
// 29. 발주수량
{
headerHozAlign: 'center',
hozAlign: 'right',
width: 100,
title: '발주수량',
field: 'PO_QTY',
editor: 'number',
formatter: function(cell) {
var value = cell.getValue();
return value ? Number(value).toLocaleString() : '0';
}
},
// 30. 공급업체2
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 150,
title: '공급업체2',
field: 'VENDOR_PM',
editor: 'input',
editable: true
},
// 31. 단가
{
headerHozAlign: 'center',
hozAlign: 'right',
width: 100,
title: '단가',
field: 'UNIT_PRICE',
editor: 'number',
editable: true,
formatter: function(cell) {
var value = cell.getValue();
return value ? Number(value).toLocaleString() : '0';
}
},
// 32. 총단가
{
headerHozAlign: 'center',
hozAlign: 'right',
width: 100,
title: '총단가',
field: 'TOTAL_PRICE',
formatter: function(cell) {
var data = cell.getRow().getData();
var qty = parseFloat(data.PO_QTY) || 0;
var unitPrice = parseFloat(data.UNIT_PRICE) || 0;
var totalPrice = qty * unitPrice;
return totalPrice > 0 ? totalPrice.toLocaleString() : '0';
}
},
// 33. 품의서작성일
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 100,
title: '품의서작성일',
field: 'PROPOSAL_DATE'
}
];
_tabulGrid = new Tabulator("#purchaseListTable", {
layout: "fitData",
height: "calc(100vh - 200px)",
columns: columns,
data: [],
placeholder: "데이터가 없습니다."
});
// 전체 체크박스 이벤트
$(document).on('click', '#checkAll', function() {
$('.rowCheck').prop('checked', $(this).prop('checked'));
});
// 셀 편집 이벤트
_tabulGrid.on("cellEdited", function(cell) {
var field = cell.getField();
var row = cell.getRow();
var data = row.getData();
// 발주수량 또는 단가 변경 시 총단가 자동 계산
if(field === 'PO_QTY' || field === 'UNIT_PRICE') {
row.reformat();
}
});
}
// 행추가
function fn_AddRow(data) {
var rowNum = $("#partListArea tr").length + 1;
var objid = data ? data.OBJID : "";
var partNo = data ? data.PART_NO : "";
var partName = data ? data.PART_NAME : "";
var qty = data ? data.QTY : "";
var html = "";
html += "<tr id='row_" + rowNum + "'>";
html += " <td><input type='checkbox' name='rowCheck' class='rowCheck'></td>";
html += " <td>" + rowNum + "</td>";
html += " <td><input type='text' name='PART_NO' value='" + partNo + "' style='width:100%;' readonly></td>";
html += " <td><input type='text' name='PART_NAME' value='" + partName + "' style='width:100%;' readonly></td>";
html += " <td><input type='text' name='QTY' value='" + qty + "' style='width:100%;' readonly></td>";
html += " <td><input type='text' name='ITEM_QTY' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='FILE_3D' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='FILE_2D' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='FILE_PDF' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='MATERIAL' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='HEAT_TREATMENT_HARDNESS' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='HEAT_TREATMENT_METHOD' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='SURFACE_TREATMENT' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='SUPPLIER' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='CATEGORY_NAME' value='' style='width:100%;'></td>";
html += " <td><select name='SUPPLY_TYPE' style='width:100%;'><option value=''>선택</option><option value='지급'>지급</option><option value='사급'>사급</option></select></td>";
html += " <td><input type='text' name='RAW_MATERIAL' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='SIZE' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='RAW_MATERIAL_PART_NO' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='RAW_MATERIAL_REQUIRED_QTY' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='RAW_MATERIAL_ORDER_QTY' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='ITEM_QTY2' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='PRODUCTION_QTY' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='PROCESSING_COMPANY' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='PROCESSING_DELIVERY_DATE' value='' style='width:100%;' class='date_icon'></td>";
html += " <td><input type='text' name='GRINDING_DELIVERY_DATE' value='' style='width:100%;' class='date_icon'></td>";
html += " <td><select name='USE_YN' style='width:100%;'><option value='Y' selected>Y</option><option value='N'>N</option></select></td>";
html += " <td><input type='text' name='NET_QTY' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='ORDER_QTY' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='SUPPLIER2' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='UNIT_PRICE' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='TOTAL_PRICE' value='' style='width:100%;' readonly></td>";
html += " <td><input type='text' name='PROPOSAL_DATE' value='' style='width:100%;' readonly></td>";
html += " <input type='hidden' name='OBJID' value='" + objid + "'>";
html += "</tr>";
$("#partListArea").append(html);
// 날짜 선택기 초기화
_fnc_datepick();
// 단가 * 수량 = 총단가 자동 계산
$("#row_" + rowNum + " input[name='UNIT_PRICE'], #row_" + rowNum + " input[name='ORDER_QTY']").on("keyup", function() {
var row = $(this).closest("tr");
var unitPrice = parseFloat(row.find("input[name='UNIT_PRICE']").val()) || 0;
var orderQty = parseFloat(row.find("input[name='ORDER_QTY']").val()) || 0;
var totalPrice = unitPrice * orderQty;
row.find("input[name='TOTAL_PRICE']").val(totalPrice);
// 기존 구매리스트 조회
function fn_loadPurchaseList(mergeMode) {
logDebug("purchaseListFormPopUp :: fn_loadPurchaseList", "mergeMode=", mergeMode, "masterId=", salesRequestMasterObjid);
$.ajax({
url: "/salesMng/getPurchaseListDetail.do",
method: 'post',
data: {
SALES_REQUEST_MASTER_OBJID: salesRequestMasterObjid
},
dataType: 'json',
success: function(data) {
logDebug("purchaseListFormPopUp :: purchase list loaded", data);
if(data && data.list) {
if(mergeMode){
fn_mergeSavedData(data.list);
}else{
_tabulGrid.setData(data.list);
}
}
},
error: function(jqxhr, status, error){
logError("구매리스트 조회 오류:", error);
Swal.fire({
title: '오류',
text: '구매리스트 조회 중 오류가 발생했습니다.',
icon: 'error'
});
}
});
}
// 행삭제
function fn_DeleteRow() {
var checkedRows = $("input[name='rowCheck']:checked");
if(checkedRows.length == 0) {
Swal.fire({
title: '알림',
text: '삭제할 행을 선택해주세요.',
icon: 'info'
});
return;
}
checkedRows.each(function() {
$(this).closest("tr").remove();
// M-BOM에서 구매리스트 생성
function fn_loadFromMBom(callback) {
console.log("=== fn_loadFromMBom 호출 ===");
console.log("PROJECT_MGMT_OBJID:", projectMgmtObjid);
console.log("BOM_REPORT_OBJID:", bomReportObjid);
$.ajax({
url: "/salesMng/getMBomForPurchaseList.do",
method: 'post',
data: {
PROJECT_MGMT_OBJID: projectMgmtObjid,
bomReportObjId: bomReportObjid
},
dataType: 'json',
success: function(data) {
console.log("=== M-BOM AJAX 응답 ===");
console.log("전체 응답:", JSON.stringify(data));
console.log("data.list:", data ? data.list : "data가 null");
console.log("list 길이:", (data && data.list) ? data.list.length : 0);
if(data && data.list && data.list.length > 0) {
console.log("첫번째 항목 전체 키:", Object.keys(data.list[0]));
console.log("첫번째 항목 PM_HEAT_RAW:", data.list[0].PM_HEAT_RAW);
console.log("첫번째 항목 PM_METHOD_RAW:", data.list[0].PM_METHOD_RAW);
console.log("첫번째 항목 PM_SURFACE_RAW:", data.list[0].PM_SURFACE_RAW);
console.log("첫번째 항목 HEAT_TREATMENT_HARDNESS:", data.list[0].HEAT_TREATMENT_HARDNESS);
}
var list = (data && data.list) ? data.list : [];
if(list.length > 0) {
console.log("M-BOM 데이터 " + list.length + "건 로드됨");
_tabulGrid.setData(list);
} else {
console.log("M-BOM 데이터 없음!");
// 알림 제거 - 머지 모드에서는 알림 안 띄움
}
if(typeof callback === "function"){
callback(list);
}
},
error: function(jqxhr, status, error){
console.error("=== M-BOM AJAX 오류 ===");
console.error("status:", status);
console.error("error:", error);
console.error("responseText:", jqxhr.responseText);
Swal.fire({
title: '오류',
text: 'M-BOM 조회 중 오류가 발생했습니다.',
icon: 'error'
});
if(typeof callback === "function"){
callback([]);
}
}
});
}
function fn_mergeSavedData(savedList){
logDebug("purchaseListFormPopUp :: merging saved data", savedList);
if(!savedList || savedList.length === 0) return;
var rowMap = {};
_tabulGrid.getRows().forEach(function(row){
var rowData = row.getData();
if(rowData && rowData.PART_OBJID){
rowMap[rowData.PART_OBJID] = row;
}
});
// 행 번호 재정렬
$("#partListArea tr").each(function(i) {
$(this).find("td:eq(1)").text(i + 1);
savedList.forEach(function(item){
var key = item.PART_OBJID;
var targetRow = rowMap[key];
if(targetRow){
targetRow.update(item);
}else{
_tabulGrid.addData([item], true);
}
});
}
// 저장
function fn_save() {
var salesRequestMasterObjid = "${param.SALES_REQUEST_MASTER_OBJID}";
var gridData = _tabulGrid.getData();
if(!salesRequestMasterObjid || salesRequestMasterObjid == "") {
Swal.fire({
title: '오류',
text: '구매요청서 정보가 없습니다.',
icon: 'error'
});
return;
}
// 테이블 데이터 수집
var partList = [];
$("#partListArea tr").each(function() {
var row = $(this);
var partData = {
OBJID: row.find("input[name='OBJID']").val(),
PART_NO: row.find("input[name='PART_NO']").val(),
PART_NAME: row.find("input[name='PART_NAME']").val(),
QTY: row.find("input[name='QTY']").val(),
ITEM_QTY: row.find("input[name='ITEM_QTY']").val(),
FILE_3D: row.find("input[name='FILE_3D']").val(),
FILE_2D: row.find("input[name='FILE_2D']").val(),
FILE_PDF: row.find("input[name='FILE_PDF']").val(),
MATERIAL: row.find("input[name='MATERIAL']").val(),
HEAT_TREATMENT_HARDNESS: row.find("input[name='HEAT_TREATMENT_HARDNESS']").val(),
HEAT_TREATMENT_METHOD: row.find("input[name='HEAT_TREATMENT_METHOD']").val(),
SURFACE_TREATMENT: row.find("input[name='SURFACE_TREATMENT']").val(),
SUPPLIER: row.find("input[name='SUPPLIER']").val(),
CATEGORY_NAME: row.find("input[name='CATEGORY_NAME']").val(),
SUPPLY_TYPE: row.find("select[name='SUPPLY_TYPE']").val(),
RAW_MATERIAL: row.find("input[name='RAW_MATERIAL']").val(),
SIZE: row.find("input[name='SIZE']").val(),
RAW_MATERIAL_PART_NO: row.find("input[name='RAW_MATERIAL_PART_NO']").val(),
RAW_MATERIAL_REQUIRED_QTY: row.find("input[name='RAW_MATERIAL_REQUIRED_QTY']").val(),
RAW_MATERIAL_ORDER_QTY: row.find("input[name='RAW_MATERIAL_ORDER_QTY']").val(),
ITEM_QTY2: row.find("input[name='ITEM_QTY2']").val(),
PRODUCTION_QTY: row.find("input[name='PRODUCTION_QTY']").val(),
PROCESSING_COMPANY: row.find("input[name='PROCESSING_COMPANY']").val(),
PROCESSING_DELIVERY_DATE: row.find("input[name='PROCESSING_DELIVERY_DATE']").val(),
GRINDING_DELIVERY_DATE: row.find("input[name='GRINDING_DELIVERY_DATE']").val(),
USE_YN: row.find("select[name='USE_YN']").val(),
NET_QTY: row.find("input[name='NET_QTY']").val(),
ORDER_QTY: row.find("input[name='ORDER_QTY']").val(),
SUPPLIER2: row.find("input[name='SUPPLIER2']").val(),
UNIT_PRICE: row.find("input[name='UNIT_PRICE']").val(),
TOTAL_PRICE: row.find("input[name='TOTAL_PRICE']").val()
};
partList.push(partData);
});
if(partList.length == 0) {
if(!gridData || gridData.length === 0) {
Swal.fire({
title: '알림',
text: '저장할 데이터가 없습니다.',
icon: 'info'
icon: 'warning'
});
return;
}
// 품의서작성일 자동 설정 (현재 날짜)
var today = new Date();
var proposalDate = today.getFullYear() + '-' +
String(today.getMonth() + 1).padStart(2, '0') + '-' +
String(today.getDate()).padStart(2, '0');
gridData.forEach(function(item) {
if(!item.PROPOSAL_DATE) {
item.PROPOSAL_DATE = proposalDate;
}
});
Swal.fire({
title: '저장',
text: '구매리스트를 저장하시겠습니까?',
title: '확인',
text: '저장하시겠습니까?',
icon: 'question',
showCancelButton: true,
confirmButtonText: '저장',
confirmButtonText: '확인',
cancelButtonText: '취소'
}).then((result) => {
if (result.isConfirmed) {
$.ajax({
url: "/salesMng/savePurchaseList.do",
type: "POST",
method: 'post',
data: {
SALES_REQUEST_MASTER_OBJID: salesRequestMasterObjid,
partList: JSON.stringify(partList)
PROJECT_MGMT_OBJID: projectMgmtObjid,
purchaseListData: JSON.stringify(gridData)
},
dataType: "json",
success: function(response) {
if(response.result == "success") {
dataType: 'json',
success: function(data) {
if(data && (data.resultFlag === 'S' || data.RESULTFLAG === 'S')) {
Swal.fire({
title: '완료',
title: '성공',
text: '저장되었습니다.',
icon: 'success'
}).then(() => {
@@ -245,13 +649,13 @@ function fn_save() {
});
} else {
Swal.fire({
title: '오류',
text: response.message || '저장 중 오류가 발생했습니다.',
title: '실패',
text: data.message || data.MESSAGE || '저장에 실패했습니다.',
icon: 'error'
});
}
},
error: function(xhr, status, error) {
error: function(jqxhr, status, error){
console.error("저장 오류:", error);
Swal.fire({
title: '오류',
@@ -263,145 +667,6 @@ function fn_save() {
}
});
}
// 날짜 선택기 초기화
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
});
}
}
</script>
<style>
.purchase_list_table {
width: 100%;
border-collapse: collapse;
font-size: 12px;
}
.purchase_list_table th {
background-color: #f5f5f5;
border: 1px solid #ddd;
padding: 8px;
text-align: center;
font-weight: bold;
}
.purchase_list_table td {
border: 1px solid #ddd;
padding: 4px;
text-align: center;
}
.purchase_list_table input[type="text"],
.purchase_list_table select {
border: 1px solid #ccc;
padding: 2px;
}
</style>
</head>
<body>
<form name="form1" id="form1" method="post">
<input type="hidden" name="SALES_REQUEST_MASTER_OBJID" value="${param.SALES_REQUEST_MASTER_OBJID}">
<section>
<div class="plm_menu_name" style="display:flex;">
<h2 style="width:100%;height:60px;text-align:center;margin-top:15px;">
<span style="font-size:24px;">구매리스트 작성</span>
</h2>
</div>
<div class="btn_wrap">
<div class="plm_btn_wrap" style="padding:0 8 0 8; text-align: right;">
<input type="button" value="행추가" class="plm_btns" id="btnAddRow">
<input type="button" value="행삭제" class="plm_btns" id="btnDeleteRow">
<input type="button" value="저장" class="plm_btns" id="btnSave">
<input type="button" value="닫기" class="plm_btns" id="btnClose">
</div>
</div>
<div style="overflow-x:auto; overflow-y:auto; max-height:600px;">
<table class="purchase_list_table">
<colgroup>
<col width="30px">
<col width="40px">
<col width="120px">
<col width="150px">
<col width="80px">
<col width="80px">
<col width="80px">
<col width="80px">
<col width="80px">
<col width="100px">
<col width="100px">
<col width="100px">
<col width="100px">
<col width="120px">
<col width="100px">
<col width="80px">
<col width="100px">
<col width="100px">
<col width="120px">
<col width="100px">
<col width="100px">
<col width="80px">
<col width="80px">
<col width="120px">
<col width="100px">
<col width="100px">
<col width="80px">
<col width="80px">
<col width="80px">
<col width="120px">
<col width="80px">
<col width="80px">
<col width="100px">
</colgroup>
<thead>
<tr>
<th><input type="checkbox" id="allCheck"></th>
<th>NO</th>
<th>품번</th>
<th>품명</th>
<th>수량</th>
<th>항목수량</th>
<th>3D</th>
<th>2D</th>
<th>PDF</th>
<th>재료</th>
<th>열처리경도</th>
<th>열처리방법</th>
<th>표면처리</th>
<th>공급업체</th>
<th>범주이름</th>
<th>지급/사급</th>
<th>소재</th>
<th>사이즈</th>
<th>소재품번</th>
<th>소재소요량</th>
<th>소재발주수량</th>
<th>항목수량</th>
<th>제작수량</th>
<th>가공업체</th>
<th>가공납기</th>
<th>연삭납기</th>
<th>사용여부</th>
<th>정미수량</th>
<th>발주수량</th>
<th>공급업체</th>
<th>단가</th>
<th>총단가</th>
<th>품의서작성일</th>
</tr>
</thead>
<tbody id="partListArea">
<!-- 동적으로 행 추가 -->
</tbody>
</table>
</div>
</section>
</form>
</body>
</body>
</html>

View File

@@ -178,6 +178,8 @@ $("#REQUEST_CD,#PROJECT_NO,#CUSTOMER_NAME,#PRODUCT_NAME,#MECHANICAL_TYPE,#PROJEC
}
}
// ★★★ M-BOM 품목 자동 로드 ★★★
fn_loadMbomParts($(this).val());
}
});
@@ -296,14 +298,35 @@ function fn_getSalesRequestTargetPartList(masterObjId,bomObjId){
});
$("#partListArea").append(appendText);
// 프로젝트번호가 설정되어 있는지 확인하고, 없으면 품번 드롭다운을 채울 수 없음
var projectNo = $("#PROJECT_NO").val();
if(!projectNo || projectNo == "") {
console.warn("프로젝트번호가 선택되지 않아 품번 목록을 불러올 수 없습니다.");
}
$.each(resultData, function(i){
var rowObjId = fnc_checkNull(resultData[i].OBJID);
var PART_OBJID = fnc_checkNull(resultData[i].PART_OBJID);
var PART_NO = fnc_checkNull(resultData[i].PART_NO);
var PART_NAME = fnc_checkNull(resultData[i].PART_NAME);
// 공급업체 제거로 주석처리
// var PARTNER_OBJID = fnc_checkNull(resultData[i].PARTNER_OBJID);
// fnc_getAdminSupCdListAppend("", "PARTNER_OBJID_"+rowObjId, PARTNER_OBJID);
// $("#PARTNER_OBJID_"+rowObjId).val(PARTNER_OBJID);
fn_addBomPart("PART_OBJID_"+rowObjId, PART_OBJID, "PART_NAME_"+rowObjId,"");
// M-BOM에 없는 품번이면 수동으로 추가
if(PART_OBJID != "" && PART_NO != "") {
var selectBox = $("#PART_OBJID_"+rowObjId);
// 이미 옵션이 있는지 확인
if(selectBox.find("option[value='"+PART_OBJID+"']").length == 0) {
selectBox.append("<option value='"+PART_OBJID+"'>"+PART_NO+"</option>");
}
selectBox.val(PART_OBJID);
$("#PART_NAME_"+rowObjId).val(PART_NAME);
}
});
$(".select2").select2();
},
@@ -469,44 +492,122 @@ function fn_Supply_save(){
}
}
// ★★★ 프로젝트 선택 시 M-BOM 품목 자동 로드 ★★★
function fn_loadMbomParts(projectObjId){
if(fnc_checkNull(projectObjId) == "") return;
console.log("M-BOM 품목 로드 시작, PROJECT_OBJID:", projectObjId);
// M-BOM 품목 조회
var paramData = {"sqlId":"salesMng.SalesBomPartListByProjectUnit", "PROJECT_OBJID":projectObjId};
var resultList = fnc_getJsonAllDataListBySqlId(paramData);
console.log("M-BOM 품목 조회 결과:", resultList);
if(resultList && resultList.length > 0){
// 기존 품목 초기화
$("#partListArea").empty();
// M-BOM 품목을 행으로 추가
$.each(resultList, function(i, item){
var rowObjId = fnc_createObjId();
var PART_OBJID = fnc_checkNull(item.PART_OBJID);
var PART_NO = fnc_checkNull(item.PART_NO);
var PART_NAME = fnc_checkNull(item.PART_FULL_NAME) || fnc_checkNull(item.PART_NAME);
var QTY = fnc_checkNull(item.ORDER_QTY) || 1;
var appendText = "";
appendText += "<tr class='dataTr' id='"+rowObjId+"'>";
appendText += " <input type='hidden' name='OBJID' value='"+rowObjId+"' class='TARGET_OBJID'>";
appendText += " <td class='align_c'>";
appendText += " <input type='checkbox' name='chkOBJID"+rowObjId+"' value='"+rowObjId+"' class='chkBox'>";
appendText += " </td>";
appendText += " <td class='align_l'>";
appendText += " <select name='PART_OBJID_"+rowObjId+"' id='PART_OBJID_"+rowObjId+"' reqTitle='품번' type='select' class='select2' style='width: 100%;'>";
appendText += " <option value='"+PART_OBJID+"'>"+PART_NO+"</option>";
appendText += " </select>";
appendText += " </td>";
appendText += " <td class='align_l'>";
appendText += " <input type='text' name='PART_NAME_"+rowObjId+"' id='PART_NAME_"+rowObjId+"' value='"+PART_NAME+"' readonly style='width: 100%;'>";
appendText += " </td>";
appendText += " <td class='align_c'>";
appendText += " <input type='number' name='QTY_"+rowObjId+"' value='"+QTY+"' reqTitle='수량' required style='text-align: center;'>";
appendText += " </td>";
appendText += "</tr>";
$("#partListArea").append(appendText);
// 품번 드롭다운에 M-BOM 전체 품목 옵션 추가
fn_addBomPart("PART_OBJID_"+rowObjId, PART_OBJID, "PART_NAME_"+rowObjId, "");
});
$(".select2").select2();
console.log("M-BOM 품목 " + resultList.length + "건 로드 완료");
} else {
console.log("M-BOM 품목이 없습니다.");
}
}
//계약제품, 업체명으로 BOM에 등록된 부품정보를 자동 추가
function fn_addBomPart(selectboxId,selectedVal,sql_id,sql_supply){
$("#BOM_REPORT_OBJID").val("");
//var type = $("#TYPE").val(); //발주부품
var project_objid = $("#PROJECT_NO").val(); //프로젝트명
var unit_code = $("#UNIT_NAME").val(); //유닛명
//var partner_objid = $("#PARTNER_OBJID").val(); //공급업체
//console.log('type:'+type + ' contract_mgmt_objid:'+contract_mgmt_objid + ' unit_code:'+unit_code + ' partner_objid:'+partner_objid);
$("#"+selectboxId).empty();
$("#"+selectboxId).append("<option value=''>선택</option>");
//프로젝트번호만 있으면 품번 조회 가능 (유닛명은 선택사항)
var resultList = [];
// 1. 프로젝트가 선택되어 있으면 M-BOM 품목 먼저 조회
if(fnc_checkNull(project_objid)!=""){
$("#"+selectboxId).empty();
$("#"+selectboxId).append("<option value=''>선택</option>");
//구매BOM 조회해서 부품정보를 가져온다
var paramData = {"sqlId":"salesMng.SalesBomPartListByProjectUnit", "PROJECT_OBJID":project_objid};
// 유닛명이 있으면 추가
if(fnc_checkNull(unit_code)!=""){
paramData.UNIT_CODE = unit_code;
}
var resultList = fnc_getJsonAllDataListBySqlId(paramData);
resultList = fnc_getJsonAllDataListBySqlId(paramData);
console.log("M-BOM 품목 조회 결과:", resultList.length, "건");
}
// 2. M-BOM 품목이 없으면 전체 PART_MNG에서 조회
if(resultList.length == 0){
console.log("M-BOM 품목이 없어 전체 품목에서 조회합니다.");
var allPartData = {"sqlId":"salesMng.getAllPartMngList"};
resultList = fnc_getJsonAllDataListBySqlId(allPartData);
console.log("전체 품목 조회 결과:", resultList.length, "건");
// 전체 품목 조회 결과 처리
if(0 < resultList.length){
for (var i = 0; i < resultList.length; i++) {
var commonCodeId = resultList[i].PART_OBJID;
var commonCodeId = resultList[i].OBJID;
var commonCodeName = resultList[i].PART_NO;
var partName = resultList[i].PART_NAME;
var supplyObjid = resultList[i].SUPPLY_OBJID;
$("#"+selectboxId).append("<option value='"+commonCodeId+"' data-part_name='"+partName+"' data-supplyObjid='"+supplyObjid+"'>"+commonCodeName+"</option>");
$("#"+selectboxId).append("<option value='"+commonCodeId+"' data-part_name='"+partName+"'>"+commonCodeName+"</option>");
}
$("#"+selectboxId).val(selectedVal);
$("#"+selectboxId).change(function(){
$("#"+sql_id).val($(this).find("option:selected").attr("data-part_name"));
$("#"+sql_supply).val($(this).find("option:selected").attr("data-supplyObjid"));
});
}
} else {
// M-BOM 품목 처리
for (var i = 0; i < resultList.length; i++) {
var commonCodeId = resultList[i].PART_OBJID;
var commonCodeName = resultList[i].PART_NO;
var partName = resultList[i].PART_NAME || resultList[i].PART_FULL_NAME;
var supplyObjid = resultList[i].SUPPLY_OBJID;
$("#"+selectboxId).append("<option value='"+commonCodeId+"' data-part_name='"+partName+"' data-supplyObjid='"+supplyObjid+"'>"+commonCodeName+"</option>");
}
}
// 선택값 설정 및 change 이벤트 바인딩
if(fnc_checkNull(selectedVal) != ""){
$("#"+selectboxId).val(selectedVal);
}
$("#"+selectboxId).off("change").on("change", function(){
$("#"+sql_id).val($(this).find("option:selected").attr("data-part_name"));
if(sql_supply){
$("#"+sql_supply).val($(this).find("option:selected").attr("data-supplyObjid"));
}
});
$("#"+selectboxId).trigger("change");
}

View File

@@ -100,7 +100,7 @@ $(document).ready(function(){
//구매요청서 작성
$("#btnOrderReg").click(function(){
fn_openSalesRequestPopUp("");
fn_openSalesRequestFormPopUp("");
});
//품의서 생성 (TODO: 품의서 생성 기능 구현 필요 - 기존 발주서 작성 기능과 다름)
@@ -221,16 +221,16 @@ var columns = [
,{headerHozAlign : 'center', hozAlign : 'center', title : "유/무상", field :"PAID_TYPE_NAME" , widthGrow:0.9 }
,{headerHozAlign : 'center', hozAlign : 'left', title : "품번", field :"PART_NO" , widthGrow:1.4}
,{headerHozAlign : 'center', hozAlign : 'left' , title : "품명", field :"PART_NAME" , widthGrow:1.8 }
,{headerHozAlign : 'center', hozAlign : 'center', title : "구매요청서", field :"REQUEST_MNG_NO" , widthGrow:1.1,
formatter: function(cell, formatterParams, onRendered){
var objid = fnc_checkNull(cell.getData().OBJID);
var iconClass = (objid != '' && objid != null) ? 'file_icon' : 'file_empty_icon';
return '<a href="#" class="File ' + iconClass + '" style="width:20px; height:20px; display:inline-block;"></a>';
},
cellClick : function(e, cell) {
fn_openSalesRequestPopUp(cell.getData().OBJID);
,{headerHozAlign : 'center', hozAlign : 'center', title : "구매요청서", field :"REQUEST_MNG_NO" , widthGrow:1.1,
formatter: function(cell, formatterParams, onRendered){
var objid = fnc_checkNull(cell.getData().OBJID);
var iconClass = (objid != '' && objid != null) ? 'file_icon' : 'file_empty_icon';
return '<a href="#" class="File ' + iconClass + '" style="width:20px; height:20px; display:inline-block;"></a>';
},
cellClick : function(e, cell) {
fn_openSalesRequestFormPopUp(cell.getData().OBJID);
}
}
}
,{headerHozAlign : 'center', hozAlign : 'center', title : "요청인", field :"REQUEST_USER_NAME" , widthGrow:1.1 }
,{headerHozAlign : 'center', hozAlign : 'center', title : "입고요청일", field :"DELIVERY_REQUEST_DATE" , widthGrow:1.1 }
,{headerHozAlign : 'center', hozAlign : 'center', title : "작성일", field :"REGDATE_TITLE" , widthGrow:1.1 }
@@ -281,17 +281,16 @@ function fn_salesRequestTargetBOMListPopUp(){
window.open(url,"salesRequestTargetBOMListPopUp","width=1300,height=550");
}
//구매의뢰 요청 팝업
//구매의뢰 요청 팝업 (요청번호 클릭 시 - 구매리스트 화면)
function fn_openSalesRequestPopUp(objId){
var url = "";
if("" == objId){
url = "/salesMng/salesRequestFormPopUp.do?SALES_REQUEST_MASTER_OBJID="+objId;
}else{
//url = "/salesMng/salesRequestDetailPopUp.do?SALES_REQUEST_MASTER_OBJID="+objId;
url = "/salesMng/salesRequestFormPopUp.do?SALES_REQUEST_MASTER_OBJID="+objId;
}
window.open(url,"salesRequestPopUp","width=1100,height=630");
var url = "/salesMng/purchaseListFormPopUp.do?SALES_REQUEST_MASTER_OBJID="+objId;
window.open(url,"purchaseListPopUp","width=1400,height=800,scrollbars=yes,resizable=yes");
}
//구매요청서 작성 팝업 (구매요청서 파일 아이콘 클릭 시)
function fn_openSalesRequestFormPopUp(objId){
var url = "/salesMng/salesRequestFormPopUp.do?SALES_REQUEST_MASTER_OBJID="+objId;
window.open(url,"salesRequestFormPopUp","width=1100,height=630");
}
function fn_releaseSalesRequest(){

View File

@@ -0,0 +1,17 @@
-- SALES_REQUEST_PART 테이블에 구매리스트 필수 컬럼만 추가
-- 기존: OBJID, PART_OBJID, SALES_REQUEST_MASTER_OBJID, QTY, PARTNER_OBJID, PARTNER_PRICE, WRITER, REGDATE 등
ALTER TABLE SALES_REQUEST_PART
ADD COLUMN IF NOT EXISTS PART_NO VARCHAR(100), -- 품번 (직접 입력용)
ADD COLUMN IF NOT EXISTS PART_NAME VARCHAR(200), -- 품명 (직접 입력용)
ADD COLUMN IF NOT EXISTS UNIT_PRICE VARCHAR(50), -- 단가
ADD COLUMN IF NOT EXISTS TOTAL_PRICE VARCHAR(50), -- 총단가
ADD COLUMN IF NOT EXISTS PROPOSAL_DATE DATE; -- 품의서작성일
-- 컬럼 설명
COMMENT ON COLUMN SALES_REQUEST_PART.PART_NO IS '품번';
COMMENT ON COLUMN SALES_REQUEST_PART.PART_NAME IS '품명';
COMMENT ON COLUMN SALES_REQUEST_PART.UNIT_PRICE IS '단가';
COMMENT ON COLUMN SALES_REQUEST_PART.TOTAL_PRICE IS '총단가';
COMMENT ON COLUMN SALES_REQUEST_PART.PROPOSAL_DATE IS '품의서작성일';

View File

@@ -663,6 +663,15 @@ VALUES
SRM.PROJECT_NO,
PM.PROJECT_NO AS PROJECT_NUMBER,
PM.PROJECT_NAME,
COALESCE(
PM.OBJID,
(SELECT OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1)
) AS PROJECT_MGMT_OBJID,
-- M-BOM 조회용 BOM_REPORT_OBJID 추가
COALESCE(
PM.BOM_REPORT_OBJID,
(SELECT BOM_REPORT_OBJID FROM PROJECT_MGMT WHERE PROJECT_NO = SRM.PROJECT_NO LIMIT 1)
) AS BOM_REPORT_OBJID,
PM.SETUP,
SM.SUPPLY_NAME AS CUSTOMER_NAME,
SM.OBJID::VARCHAR AS CUSTOMER_OBJID, -- 고객사 OBJID (드롭다운 선택용)
@@ -705,7 +714,7 @@ VALUES
FROM
SALES_REQUEST_MASTER SRM
LEFT JOIN PROJECT_MGMT PM ON SRM.PROJECT_NO = PM.OBJID::VARCHAR
LEFT JOIN PROJECT_MGMT PM ON (SRM.PROJECT_NO = PM.OBJID::VARCHAR OR SRM.PROJECT_NO = PM.PROJECT_NO)
LEFT JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID::VARCHAR
LEFT JOIN SUPPLY_MNG SM ON CM.CUSTOMER_OBJID::VARCHAR = SM.OBJID::VARCHAR
LEFT JOIN PURCHASE_ORDER_MASTER POM ON SRM.OBJID = POM.SALES_REQUEST_OBJID
@@ -1242,31 +1251,51 @@ VALUES
AND PM.OBJID = #{PROJECT_NO}
</select>
<!-- 전체 품목 조회 (M-BOM이 없을 때 사용) -->
<select id="getAllPartMngList" parameterType="map" resultType="map">
SELECT
PM.OBJID,
PM.PART_NO,
PM.PART_NAME,
PM.SPEC,
PM.MAKER,
PM.MATERIAL,
PM.UNIT,
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = PM.UNIT) AS UNIT_TITLE
FROM PART_MNG PM
WHERE 1=1
AND PM.IS_LAST = '1'
ORDER BY PM.PART_NO
LIMIT 500
</select>
<select id="SalesBomPartListByProjectUnit" parameterType="map" resultType="map">
<!-- M-BOM 데이터 조회: PROJECT_MGMT.BOM_REPORT_OBJID -> BOM_PART_QTY -> PART_MNG -->
<!-- M-BOM 데이터 조회: getMbomList와 동일한 조인 방식 사용 (BPQ.PART_NO = PM.PART_NO) -->
SELECT
BPQ.BOM_REPORT_OBJID
,BPQ.PART_NO AS PART_OBJID
,PM.PART_NAME
,PM.PART_NO
,PM.SPEC
,PM.MAKER
,PM.REMARK
,PM.UNIT
,COALESCE(PM.PART_NO, BPQ.PART_NO, '') AS PART_NO
,COALESCE(PM.PART_NAME, '') AS PART_NAME
,COALESCE(PM.PART_NAME, '') AS PART_FULL_NAME
,COALESCE(PM.SPEC, '') AS SPEC
,BPQ.QTY AS ORDER_QTY
,COALESCE(PM.MAKER, '') AS MAKER
,'' AS REMARK
,'' AS UNIT
,NULL AS SUPPLY_OBJID
,NULL AS WRITER
FROM
PROJECT_MGMT AS PJT
INNER JOIN BOM_PART_QTY AS BPQ
ON PJT.BOM_REPORT_OBJID = BPQ.BOM_REPORT_OBJID::VARCHAR
LEFT JOIN PART_MNG AS PM
ON COALESCE(NULLIF(BPQ.LAST_PART_OBJID, ''), BPQ.PART_NO) = PM.OBJID::VARCHAR
INNER JOIN BOM_PART_QTY AS BPQ
ON PJT.BOM_REPORT_OBJID::VARCHAR = BPQ.BOM_REPORT_OBJID::VARCHAR
LEFT JOIN PART_MGMT AS PM
ON BPQ.PART_NO = PM.PART_NO
WHERE 1=1
AND PJT.OBJID = #{PROJECT_OBJID}
AND PJT.OBJID::VARCHAR = #{PROJECT_OBJID}
AND COALESCE(BPQ.STATUS, '') NOT IN ('deleting', 'deleted')
AND PJT.BOM_REPORT_OBJID IS NOT NULL
AND PJT.BOM_REPORT_OBJID != ''
ORDER BY BPQ.SEQ, PM.PART_NO
ORDER BY BPQ.SEQ
</select>
<update id="mergeReceiptSalesRequestInfo" parameterType="map">
@@ -2775,18 +2804,19 @@ UPDATE SET
</update>
<!-- 구매리스트 관련 쿼리 -->
<!-- M-BOM에서 가져온 PART_OBJID는 BPQ.PART_NO 값이므로 PART_MGMT.PART_NO와 조인 -->
<select id="getSalesRequestPartList" parameterType="string" resultType="map">
SELECT
SRP.OBJID,
SRP.PART_OBJID,
PM.PART_NO,
PM.PART_NAME,
COALESCE(PM.PART_NO, '') AS PART_NO,
COALESCE(PM.PART_NAME, '') AS PART_NAME,
SRP.QTY,
SRP.PARTNER_OBJID,
SRP.PARTNER_PRICE
FROM
SALES_REQUEST_PART SRP
LEFT JOIN PART_MNG PM ON SRP.PART_OBJID = PM.OBJID::VARCHAR
LEFT JOIN PART_MGMT PM ON SRP.PART_OBJID = PM.PART_NO
WHERE
SRP.SALES_REQUEST_MASTER_OBJID = #{SALES_REQUEST_MASTER_OBJID}
ORDER BY SRP.REGDATE
@@ -2895,5 +2925,119 @@ UPDATE SET
UNIT_PRICE = #{UNIT_PRICE},
TOTAL_PRICE = #{TOTAL_PRICE}
</update>
<!-- 구매리스트 상세 조회 (기존 저장된 데이터) -->
<select id="getPurchaseListDetail" parameterType="map" resultType="map">
<!-- SALES_REQUEST_PART에서 저장된 데이터 조회, PART_MNG에서 품목정보 가져옴 -->
SELECT
SRP.OBJID,
SRP.SALES_REQUEST_MASTER_OBJID,
SRP.PART_OBJID,
COALESCE(PMG.PART_NO, '') AS PART_NO,
COALESCE(PMG.PART_NAME, '') AS PART_NAME,
SRP.QTY,
0 AS ITEM_QTY,
-- 파일 개수 (PART_MNG.OBJID 기준으로 조회)
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = PMG.OBJID AND DOC_TYPE IN ('3D_CAD') AND UPPER(STATUS) = 'ACTIVE'), 0) AS CU01_CNT,
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = PMG.OBJID AND DOC_TYPE IN ('2D_DRAWING_CAD') AND UPPER(STATUS) = 'ACTIVE'), 0) AS CU02_CNT,
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO WHERE TARGET_OBJID = PMG.OBJID AND DOC_TYPE IN ('2D_PDF_CAD') AND UPPER(STATUS) = 'ACTIVE'), 0) AS CU03_CNT,
COALESCE(PMG.MATERIAL, '') AS MATERIAL,
COALESCE(PMG.HEAT_TREATMENT_HARDNESS, '') AS HEAT_TREATMENT_HARDNESS,
COALESCE(PMG.HEAT_TREATMENT_METHOD, '') AS HEAT_TREATMENT_METHOD,
COALESCE(PMG.SURFACE_TREATMENT, '') AS SURFACE_TREATMENT,
COALESCE(PMG.MAKER, '') AS VENDOR,
COALESCE(PMG.PART_TYPE, '') AS PART_TYPE_TITLE,
'' AS SUPPLY_TYPE,
'' AS RAW_MATERIAL,
'' AS SIZE,
'' AS RAW_MATERIAL_NO,
0 AS REQUIRED_QTY,
0 AS ORDER_QTY,
0 AS ITEM_QTY2,
0 AS PRODUCTION_QTY,
'' AS PROCESSING_VENDOR,
NULL AS PROCESSING_DEADLINE,
NULL AS GRINDING_DEADLINE,
'Y' AS USE_YN,
0 AS NET_QTY,
0 AS PO_QTY,
SRP.PARTNER_OBJID AS VENDOR_PM,
COALESCE(NULLIF(SRP.PARTNER_PRICE, '')::numeric, 0) AS UNIT_PRICE,
COALESCE(
COALESCE(NULLIF(SRP.PARTNER_PRICE, '')::numeric, 0) * COALESCE(SRP.QTY::numeric, 0),
0
) AS TOTAL_PRICE,
NULL AS PROPOSAL_DATE
FROM
SALES_REQUEST_PART SRP
LEFT JOIN PART_MNG PMG ON SRP.PART_OBJID = PMG.OBJID::VARCHAR AND PMG.IS_LAST = '1'
WHERE
SRP.SALES_REQUEST_MASTER_OBJID = #{SALES_REQUEST_MASTER_OBJID}
ORDER BY
SRP.REGDATE
</select>
<!-- M-BOM에서 구매리스트 데이터 가져오기 (BOM_PART_QTY 기본 데이터만) -->
<select id="getMBomForPurchaseList" parameterType="map" resultType="map">
<!-- MBOM_DETAIL + PART_MNG 조인하여 조회 -->
SELECT
ROW_NUMBER() OVER (ORDER BY MD.SEQ) AS ROW_NUM,
MD.OBJID::VARCHAR AS OBJID,
MH.OBJID::VARCHAR AS BOM_REPORT_OBJID,
MD.PARENT_OBJID::VARCHAR AS PARENT_OBJID,
MD.CHILD_OBJID::VARCHAR AS CHILD_OBJID,
'' AS PARENT_PART_NO,
MD.PART_OBJID::VARCHAR AS PART_OBJID,
PM.OBJID::VARCHAR AS PM_OBJID,
COALESCE(MD.PART_NO, PM.PART_NO, '') AS PART_NO,
COALESCE(MD.PART_NAME, PM.PART_NAME, '') AS PART_NAME,
COALESCE(MD.QTY, 0) AS QTY,
COALESCE(MD.QTY, 0) AS ITEM_QTY,
0 AS QTY_TEMP,
MD.SEQ,
COALESCE(MD.STATUS, '') AS STATUS,
'' AS LAST_PART_OBJID,
-- 파일 개수 (ATTACH_FILE_INFO에서 서브쿼리로 가져옴)
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('3D_CAD')), 0) AS CU01_CNT,
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_DRAWING_CAD')), 0) AS CU02_CNT,
COALESCE((SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE PM.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_PDF_CAD')), 0) AS CU03_CNT,
-- E-BOM 컬럼들 (PART_MNG에서 가져옴) - 디버그용으로 원본값도 출력
PM.HEAT_TREATMENT_HARDNESS AS PM_HEAT_RAW,
PM.HEAT_TREATMENT_METHOD AS PM_METHOD_RAW,
PM.SURFACE_TREATMENT AS PM_SURFACE_RAW,
COALESCE(PM.MATERIAL, MD.RAW_MATERIAL, '') AS MATERIAL,
COALESCE(PM.HEAT_TREATMENT_HARDNESS, '') AS HEAT_TREATMENT_HARDNESS,
COALESCE(PM.HEAT_TREATMENT_METHOD, '') AS HEAT_TREATMENT_METHOD,
COALESCE(PM.SURFACE_TREATMENT, '') AS SURFACE_TREATMENT,
COALESCE(PM.MAKER, MD.VENDOR, '') AS VENDOR,
COALESCE((SELECT CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = PM.PART_TYPE), '') AS PART_TYPE_TITLE,
-- 생산관리 컬럼들 (MBOM_DETAIL에서 가져옴)
COALESCE(MD.SUPPLY_TYPE, '') AS SUPPLY_TYPE,
COALESCE(MD.RAW_MATERIAL, '') AS RAW_MATERIAL,
COALESCE(MD.RAW_MATERIAL_SIZE, '') AS SIZE,
COALESCE(MD.RAW_MATERIAL_PART_NO, '') AS RAW_MATERIAL_NO,
COALESCE(MD.REQUIRED_QTY, 0) AS REQUIRED_QTY,
COALESCE(MD.ORDER_QTY, 0) AS ORDER_QTY,
COALESCE(MD.PRODUCTION_QTY, 0) AS PRODUCTION_QTY,
COALESCE(MD.PROCESSING_VENDOR, '') AS PROCESSING_VENDOR,
MD.PROCESSING_DEADLINE,
MD.GRINDING_DEADLINE,
-- 구매 컬럼들 (편집 가능)
'Y' AS USE_YN,
0 AS NET_QTY,
0 AS PO_QTY,
COALESCE(MD.VENDOR, '') AS VENDOR_PM,
COALESCE(MD.UNIT_PRICE, 0) AS UNIT_PRICE,
COALESCE(MD.TOTAL_PRICE, 0) AS TOTAL_PRICE,
NULL AS PROPOSAL_DATE
FROM
MBOM_HEADER MH
INNER JOIN MBOM_DETAIL MD ON MH.OBJID = MD.MBOM_HEADER_OBJID
LEFT JOIN PART_MNG PM ON PM.OBJID::VARCHAR = MD.PART_OBJID::VARCHAR
WHERE
MH.PROJECT_OBJID = #{PROJECT_MGMT_OBJID}
ORDER BY
MD.SEQ
</select>
</mapper>

View File

@@ -1095,23 +1095,90 @@ public class SalesMngController {
*/
@RequestMapping("/salesMng/purchaseListFormPopUp.do")
public String purchaseListFormPopUp(HttpServletRequest request, @RequestParam Map paramMap){
Map resultMap = new HashMap();
try{
String salesRequestMasterObjId = CommonUtils.checkNull(paramMap.get("SALES_REQUEST_MASTER_OBJID"));
String projectMgmtObjId = CommonUtils.checkNull(paramMap.get("PROJECT_MGMT_OBJID"));
if(!"".equals(salesRequestMasterObjId)){
// 기존 구매리스트 조회
resultMap = salesMngService.getSalesRequestMasterInfo(request, paramMap);
}else if(!"".equals(projectMgmtObjId)){
// M-BOM에서 새로 생성
resultMap.put("OBJID", CommonUtils.createObjId());
resultMap.put("STATUS", "create");
}else{
resultMap.put("OBJID", CommonUtils.createObjId());
resultMap.put("STATUS", "create");
}
}catch(Exception e){
e.printStackTrace();
}
request.setAttribute("resultMap", resultMap);
return "/salesMng/purchaseListFormPopUp";
}
/**
* 구매리스트 데이터 조회
* 구매리스트 상세 조회 (기존 구매리스트)
* @param request
* @param paramMap
* @return
*/
@ResponseBody
@RequestMapping("/salesMng/getPurchaseListData.do")
public Map getPurchaseListData(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
@RequestMapping("/salesMng/getPurchaseListDetail.do")
public Map getPurchaseListDetail(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
Map resultMap = new HashMap();
try{
resultMap = salesMngService.getPurchaseListData(request, paramMap);
List<Map> list = salesMngService.getPurchaseListDetail(request, paramMap);
resultMap.put("list", list);
}catch(Exception e){
e.printStackTrace();
resultMap.put("list", new ArrayList());
}
return resultMap;
}
/**
* M-BOM에서 구매리스트 생성
* @param request
* @param paramMap
* @return
*/
@ResponseBody
@RequestMapping("/salesMng/getMBomForPurchaseList.do")
public Map getMBomForPurchaseList(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
Map resultMap = new HashMap();
try{
System.out.println("========== getMBomForPurchaseList 호출 ==========");
System.out.println("paramMap: " + paramMap);
System.out.println("PROJECT_MGMT_OBJID: " + paramMap.get("PROJECT_MGMT_OBJID"));
System.out.println("bomReportObjId: " + paramMap.get("bomReportObjId"));
List<Map> list = salesMngService.getMBomForPurchaseList(request, paramMap);
// 키를 대문자로 변환
List<Map<String, Object>> upperList = new ArrayList<Map<String, Object>>();
if(list != null) {
for(Map item : list) {
Map<String, Object> upperItem = new HashMap<String, Object>();
for(Object key : item.keySet()) {
upperItem.put(key.toString().toUpperCase(), item.get(key));
}
upperList.add(upperItem);
}
}
System.out.println("결과 리스트 크기: " + upperList.size());
if(!upperList.isEmpty()) {
System.out.println("첫번째 항목: " + upperList.get(0));
}
resultMap.put("list", upperList);
}catch(Exception e){
System.out.println("getMBomForPurchaseList 오류 발생!");
e.printStackTrace();
resultMap.put("list", new ArrayList());
}
return resultMap;
}

View File

@@ -1785,4 +1785,53 @@ public class SalesMngService {
return resultMap;
}
/**
* 구매리스트 상세 조회 (기존 저장된 데이터)
* @param request
* @param paramMap
* @return
* @throws Exception
*/
public List<Map> getPurchaseListDetail(HttpServletRequest request, Map<String, Object> paramMap) throws Exception {
SqlSession sqlSession = null;
List<Map> resultList = new ArrayList<Map>();
try {
sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
resultList = sqlSession.selectList("salesMng.getPurchaseListDetail", paramMap);
} catch(Exception e) {
e.printStackTrace();
throw e;
} finally {
if(sqlSession != null) sqlSession.close();
}
return resultList;
}
/**
* M-BOM에서 구매리스트 데이터 가져오기
* @param request
* @param paramMap
* @return
* @throws Exception
*/
public List<Map> getMBomForPurchaseList(HttpServletRequest request, Map<String, Object> paramMap) throws Exception {
SqlSession sqlSession = null;
List<Map> resultList = new ArrayList<Map>();
try {
sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
// M-BOM 데이터 조회 (레벨 구조 없이 평평하게)
resultList = sqlSession.selectList("salesMng.getMBomForPurchaseList", paramMap);
} catch(Exception e) {
e.printStackTrace();
throw e;
} finally {
if(sqlSession != null) sqlSession.close();
}
return resultList;
}
}