생산관리 생산계획 완성, 실적관리는 틀만..

This commit is contained in:
2025-12-19 15:19:40 +09:00
parent 708393ad7a
commit bbc4474d55
7 changed files with 676 additions and 137 deletions

View File

@@ -1788,4 +1788,60 @@ public class ProductionPlanningController extends BaseService {
return resultMap;
}
/**
* 생산실적 등록/수정 팝업
*/
@RequestMapping("/productionplanning/prodResultFormPopup.do")
public String prodResultFormPopup(HttpServletRequest request, @RequestParam Map<String, Object> paramMap) {
return "/productionplanning/prodResultFormPopup";
}
/**
* 생산실적 목록 조회
*/
@ResponseBody
@RequestMapping("/productionplanning/getProdResultList.do")
public Map getProdResultList(HttpServletRequest request, @RequestParam Map<String, Object> paramMap) {
Map<String, Object> resultMap = new HashMap<String, Object>();
try {
List list = productionPlanningService.getProdResultList(paramMap);
resultMap.put("result", "success");
resultMap.put("list", list);
} catch(Exception e) {
e.printStackTrace();
resultMap.put("result", "fail");
resultMap.put("msg", "조회 실패");
}
return resultMap;
}
/**
* 생산실적 저장 (JSON)
*/
@ResponseBody
@RequestMapping(value="/productionplanning/saveProdResultList.do", produces="application/json;charset=UTF-8")
public Map saveProdResultList(HttpServletRequest request, @RequestBody Map<String, Object> paramMap) {
Map<String, Object> resultMap = new HashMap<String, Object>();
try {
HttpSession session = request.getSession();
PersonBean person = (PersonBean) session.getAttribute(Constants.PERSON_BEAN);
paramMap.put("userId", person.getUserId());
paramMap.put("userName", person.getUserName());
boolean success = productionPlanningService.saveProdResultList(paramMap);
if(success) {
resultMap.put("result", "success");
resultMap.put("msg", "저장되었습니다.");
} else {
resultMap.put("result", "fail");
resultMap.put("msg", "저장에 실패했습니다.");
}
} catch(Exception e) {
e.printStackTrace();
resultMap.put("result", "fail");
resultMap.put("msg", "저장 중 오류가 발생했습니다.");
}
return resultMap;
}
}

View File

@@ -4406,134 +4406,161 @@
<!-- 생산계획&실적관리 그리드 목록 조회 -->
<select id="prodPlanResultMgmtGridList" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT
PM.OBJID,
PM.PROJECT_NO,
CM.PRODUCT,
COALESCE(
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.PRODUCT LIMIT 1),
''
) AS PRODUCT_NAME,
CM.CATEGORY_CD AS CATEGORY_CODE,
COALESCE(
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.CATEGORY_CD LIMIT 1),
CM.CATEGORY_CD
) AS CATEGORY_CODE_NAME,
-- 생산유형 (TODO: 실제 컬럼명 확인 필요)
'' AS PRODUCTION_TYPE,
'' AS PRODUCTION_TYPE_NAME,
CM.CUSTOMER_OBJID,
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(CI.DUE_DATE, PM.DUE_DATE, CM.REQ_DEL_DATE) AS REQ_DEL_DATE,
-- 고객사요청사항
COALESCE(CI.CUSTOMER_REQUEST, '') AS CUSTOMER_REQUEST,
-- 품번/품명
COALESCE(CI.PART_NO, PM.PART_NO, '') AS PART_NO,
COALESCE(CI.PART_NAME, PM.PART_NAME, '') AS PART_NAME,
-- S/N
(SELECT
CASE
WHEN COUNT(*) = 0 THEN ''
WHEN COUNT(*) = 1 THEN MIN(CIS.SERIAL_NO)
ELSE MIN(CIS.SERIAL_NO) || ' 외 ' || (COUNT(*) - 1)::TEXT || '건'
END
FROM CONTRACT_ITEM_SERIAL CIS
WHERE CIS.ITEM_OBJID = CI.OBJID
AND UPPER(CIS.STATUS) = 'ACTIVE'
AND CIS.SERIAL_NO IS NOT NULL) AS SERIAL_NO,
-- 수주수량
COALESCE(PM.QUANTITY::numeric, CI.ORDER_QUANTITY::numeric, 0) AS QUANTITY,
-- 추가생산수량 (TODO: 실제 테이블/컬럼 확인 필요)
0 AS EXTRA_PROD_QTY,
-- 총생산수량 (수주수량 + 추가생산수량)
COALESCE(PM.QUANTITY::numeric, CI.ORDER_QUANTITY::numeric, 0) AS TOTAL_PROD_QTY,
-- 완조립 수량 (TODO: 실제 테이블/컬럼 확인 필요)
0 AS ASSEMBLY_QTY,
-- 검사 수량 (TODO: 실제 테이블/컬럼 확인 필요)
0 AS INSPECTION_QTY,
-- 출하대기 수량 (TODO: 실제 테이블/컬럼 확인 필요)
0 AS SHIP_WAIT_QTY,
-- 장비조립WBS (TODO: 실제 테이블/컬럼 확인 필요)
'' AS EQUIPMENT_WBS,
-- 생산계획 OBJID (있으면 수정, 없으면 신규)
NULL AS PROD_PLAN_OBJID
FROM
PROJECT_MGMT PM
LEFT JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
LEFT OUTER JOIN CONTRACT_ITEM CI ON PM.CONTRACT_OBJID = CI.CONTRACT_OBJID
AND PM.PART_OBJID = CI.PART_OBJID
AND CI.STATUS = 'ACTIVE'
SELECT * FROM (
-- 1. 프로젝트 기반 데이터 (기존)
SELECT
PM.OBJID,
PM.PROJECT_NO,
CM.PRODUCT,
COALESCE(
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.PRODUCT LIMIT 1),
''
) AS PRODUCT_NAME,
CM.CATEGORY_CD AS CATEGORY_CODE,
COALESCE(
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.CATEGORY_CD LIMIT 1),
CM.CATEGORY_CD
) AS CATEGORY_CODE_NAME,
COALESCE(PP.PRODUCTION_TYPE, '') AS PRODUCTION_TYPE,
COALESCE(
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = PP.PRODUCTION_TYPE LIMIT 1),
''
) AS PRODUCTION_TYPE_NAME,
CM.CUSTOMER_OBJID,
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(CI.DUE_DATE, PM.DUE_DATE, CM.REQ_DEL_DATE) AS REQ_DEL_DATE,
COALESCE(CI.CUSTOMER_REQUEST, '') AS CUSTOMER_REQUEST,
COALESCE(CI.PART_NO, PM.PART_NO, '') AS PART_NO,
COALESCE(CI.PART_NAME, PM.PART_NAME, '') AS PART_NAME,
(SELECT
CASE
WHEN COUNT(*) = 0 THEN ''
WHEN COUNT(*) = 1 THEN MIN(CIS.SERIAL_NO)
ELSE MIN(CIS.SERIAL_NO) || ' 외 ' || (COUNT(*) - 1)::TEXT || '건'
END
FROM CONTRACT_ITEM_SERIAL CIS
WHERE CIS.ITEM_OBJID = CI.OBJID
AND UPPER(CIS.STATUS) = 'ACTIVE'
AND CIS.SERIAL_NO IS NOT NULL) AS SERIAL_NO,
COALESCE(NULLIF(PM.QUANTITY, '')::numeric, NULLIF(CI.ORDER_QUANTITY, '')::numeric, 0) AS QUANTITY,
COALESCE(NULLIF(PP.EXTRA_PROD_QTY, '')::numeric, 0) AS EXTRA_PROD_QTY,
COALESCE(NULLIF(PM.QUANTITY, '')::numeric, NULLIF(CI.ORDER_QUANTITY, '')::numeric, 0) + COALESCE(NULLIF(PP.EXTRA_PROD_QTY, '')::numeric, 0) AS TOTAL_PROD_QTY,
0 AS ASSEMBLY_QTY,
0 AS INSPECTION_QTY,
0 AS SHIP_WAIT_QTY,
'' AS EQUIPMENT_WBS,
PP.OBJID AS PROD_PLAN_OBJID,
PM.REGDATE AS SORT_DATE
FROM
PROJECT_MGMT PM
LEFT JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
LEFT OUTER JOIN CONTRACT_ITEM CI ON PM.CONTRACT_OBJID = CI.CONTRACT_OBJID
AND PM.PART_OBJID = CI.PART_OBJID
AND CI.STATUS = 'ACTIVE'
LEFT OUTER JOIN PRODUCTION_PLAN PP ON PP.PROJECT_OBJID = PM.OBJID
AND PP.STATUS = 'active'
WHERE PM.PROJECT_NO IS NOT NULL AND PM.PROJECT_NO != ''
UNION ALL
-- 2. 프로젝트 없이 등록한 생산계획
SELECT
PP.OBJID AS OBJID,
'' AS PROJECT_NO,
PP.PRODUCT_CODE AS PRODUCT,
COALESCE(
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = PP.PRODUCT_CODE LIMIT 1),
''
) AS PRODUCT_NAME,
PP.CATEGORY_CODE AS CATEGORY_CODE,
COALESCE(
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = PP.CATEGORY_CODE LIMIT 1),
''
) AS CATEGORY_CODE_NAME,
COALESCE(PP.PRODUCTION_TYPE, '') AS PRODUCTION_TYPE,
COALESCE(
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = PP.PRODUCTION_TYPE LIMIT 1),
''
) AS PRODUCTION_TYPE_NAME,
PP.CUSTOMER_OBJID,
COALESCE(
(SELECT CLIENT_NM FROM CLIENT_MNG WHERE OBJID::VARCHAR = PP.CUSTOMER_OBJID LIMIT 1),
''
) AS CUSTOMER_NAME,
PP.REQ_DEL_DATE,
COALESCE(PP.CUSTOMER_REQUEST, '') AS CUSTOMER_REQUEST,
COALESCE(PP.PART_NO, '') AS PART_NO,
COALESCE(PP.PART_NAME, '') AS PART_NAME,
COALESCE(PP.SERIAL_NO, '') AS SERIAL_NO,
COALESCE(NULLIF(PP.ORDER_QTY, '')::numeric, 0) AS QUANTITY,
COALESCE(NULLIF(PP.EXTRA_PROD_QTY, '')::numeric, 0) AS EXTRA_PROD_QTY,
COALESCE(NULLIF(PP.TOTAL_PROD_QTY, '')::numeric, 0) AS TOTAL_PROD_QTY,
0 AS ASSEMBLY_QTY,
0 AS INSPECTION_QTY,
0 AS SHIP_WAIT_QTY,
'' AS EQUIPMENT_WBS,
PP.OBJID AS PROD_PLAN_OBJID,
PP.REGDATE AS SORT_DATE
FROM PRODUCTION_PLAN PP
WHERE PP.STATUS = 'active'
AND (PP.PROJECT_OBJID IS NULL OR PP.PROJECT_OBJID = '')
) T
WHERE 1=1
AND PM.PROJECT_NO IS NOT NULL
AND PM.PROJECT_NO != ''
<!-- 프로젝트번호 검색 (multiple select) -->
<if test="search_project_nos != null and search_project_nos != ''">
AND PM.OBJID::VARCHAR IN
AND T.OBJID::VARCHAR IN
<foreach item="projNo" collection="search_project_nos.split(',')" open="(" separator="," close=")">
#{projNo}
</foreach>
</if>
<!-- 제품구분 검색 -->
<if test="search_product_code != null and search_product_code != ''">
AND CM.PRODUCT = #{search_product_code}
AND T.PRODUCT = #{search_product_code}
</if>
<!-- 주문유형 검색 -->
<if test="search_category_code != null and search_category_code != ''">
AND CM.CATEGORY_CD = #{search_category_code}
AND T.CATEGORY_CODE = #{search_category_code}
</if>
<!-- 생산유형 검색 -->
<if test="search_production_type != null and search_production_type != ''">
AND 1=1 <!-- TODO: 생산유형 컬럼 확인 후 조건 추가 -->
AND T.PRODUCTION_TYPE = #{search_production_type}
</if>
<!-- 고객사 검색 (C_ 접두사 처리) -->
<!-- 고객사 검색 -->
<if test="search_customer_objid != null and search_customer_objid != ''">
AND (
CM.CUSTOMER_OBJID = #{search_customer_objid}
OR CM.CUSTOMER_OBJID = REPLACE(#{search_customer_objid}, 'C_', '')
OR REPLACE(CM.CUSTOMER_OBJID, 'C_', '') = REPLACE(#{search_customer_objid}, 'C_', '')
T.CUSTOMER_OBJID = #{search_customer_objid}
OR T.CUSTOMER_OBJID = REPLACE(#{search_customer_objid}, 'C_', '')
OR REPLACE(T.CUSTOMER_OBJID, 'C_', '') = REPLACE(#{search_customer_objid}, 'C_', '')
)
</if>
<!-- 요청납기 검색 -->
<if test="search_req_del_date_from != null and search_req_del_date_from != ''">
AND COALESCE(CI.DUE_DATE, PM.DUE_DATE, CM.REQ_DEL_DATE) >= #{search_req_del_date_from}
AND T.REQ_DEL_DATE >= #{search_req_del_date_from}
</if>
<if test="search_req_del_date_to != null and search_req_del_date_to != ''">
AND COALESCE(CI.DUE_DATE, PM.DUE_DATE, CM.REQ_DEL_DATE) &lt;= #{search_req_del_date_to}
AND T.REQ_DEL_DATE &lt;= #{search_req_del_date_to}
</if>
<!-- 품번 검색 -->
<if test="search_part_no != null and search_part_no != ''">
AND (
UPPER(PM.PART_NO) LIKE '%' || UPPER(#{search_part_no}) || '%'
OR UPPER(CI.PART_NO) LIKE '%' || UPPER(#{search_part_no}) || '%'
)
AND UPPER(T.PART_NO) LIKE '%' || UPPER(#{search_part_no}) || '%'
</if>
<!-- 품명 검색 -->
<if test="search_part_name != null and search_part_name != ''">
AND (
UPPER(PM.PART_NAME) LIKE '%' || UPPER(#{search_part_name}) || '%'
OR UPPER(CI.PART_NAME) LIKE '%' || UPPER(#{search_part_name}) || '%'
)
AND UPPER(T.PART_NAME) LIKE '%' || UPPER(#{search_part_name}) || '%'
</if>
<!-- S/N 검색 -->
<if test="search_serial_no != null and search_serial_no != ''">
AND EXISTS (
SELECT 1 FROM CONTRACT_ITEM_SERIAL CIS
WHERE CIS.ITEM_OBJID = CI.OBJID
AND UPPER(CIS.STATUS) = 'ACTIVE'
AND UPPER(CIS.SERIAL_NO) LIKE '%' || UPPER(#{search_serial_no}) || '%'
)
AND UPPER(T.SERIAL_NO) LIKE '%' || UPPER(#{search_serial_no}) || '%'
</if>
ORDER BY PM.REGDATE DESC, PM.PROJECT_NO DESC
ORDER BY T.SORT_DATE DESC, T.PROJECT_NO DESC
</select>
<!-- 프로젝트 정보 조회 (생산계획 폼용) -->
@@ -4650,4 +4677,71 @@
WHERE OBJID = #{OBJID}
</update>
<!-- 생산실적 목록 조회 -->
<select id="getProdResultList" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT
OBJID,
PROJECT_OBJID,
RESULT_TYPE,
TO_CHAR(RESULT_DATE::DATE, 'YYYY-MM-DD') AS RESULT_DATE,
RESULT_QTY,
SERIAL_NO,
WORKER_ID,
WORKER_NAME,
REMARK,
STATUS
FROM PRODUCTION_RESULT
WHERE PROJECT_OBJID = #{projectObjid}
AND STATUS = 'active'
<if test="resultType != null and resultType != ''">
AND RESULT_TYPE = #{resultType}
</if>
ORDER BY RESULT_DATE DESC, REGDATE DESC
</select>
<!-- 생산실적 등록 -->
<insert id="insertProdResult" parameterType="map">
INSERT INTO PRODUCTION_RESULT (
OBJID,
PROJECT_OBJID,
RESULT_TYPE,
RESULT_DATE,
RESULT_QTY,
SERIAL_NO,
WORKER_ID,
WORKER_NAME,
REMARK,
STATUS,
REGDATE,
WRITER
) VALUES (
#{OBJID},
#{PROJECT_OBJID},
#{RESULT_TYPE},
#{RESULT_DATE},
#{RESULT_QTY},
#{SERIAL_NO},
#{userId},
#{WORKER_NAME},
#{REMARK},
'active',
NOW(),
#{userId}
)
</insert>
<!-- 생산실적 수정 -->
<update id="updateProdResult" parameterType="map">
UPDATE PRODUCTION_RESULT SET
RESULT_TYPE = #{RESULT_TYPE},
RESULT_DATE = #{RESULT_DATE},
RESULT_QTY = #{RESULT_QTY},
SERIAL_NO = #{SERIAL_NO},
WORKER_NAME = #{WORKER_NAME},
REMARK = #{REMARK},
MODDATE = NOW(),
MODIFIER = #{userId}
WHERE OBJID = #{OBJID}
</update>
</mapper>

View File

@@ -1758,4 +1758,73 @@ public class ProductionPlanningService {
return result;
}
/**
* 생산실적 목록 조회
*/
public List getProdResultList(Map<String, Object> paramMap) {
List resultList = new ArrayList();
SqlSession sqlSession = null;
try {
sqlSession = SqlMapConfig.getInstance().getSqlSession();
resultList = sqlSession.selectList("productionplanning.getProdResultList", paramMap);
} catch(Exception e) {
e.printStackTrace();
} finally {
if(sqlSession != null) {
sqlSession.close();
}
}
return resultList;
}
/**
* 생산실적 저장 (리스트)
*/
@SuppressWarnings("unchecked")
public boolean saveProdResultList(Map<String, Object> paramMap) {
boolean result = false;
SqlSession sqlSession = null;
try {
sqlSession = SqlMapConfig.getInstance().getSqlSession();
String projectObjid = CommonUtils.nullToEmpty((String)paramMap.get("projectObjid"));
String userId = CommonUtils.nullToEmpty((String)paramMap.get("userId"));
List<Map<String, Object>> resultList = (List<Map<String, Object>>)paramMap.get("resultList");
if(resultList != null && resultList.size() > 0) {
for(Map<String, Object> row : resultList) {
row.put("PROJECT_OBJID", projectObjid);
row.put("userId", userId);
String objid = CommonUtils.nullToEmpty((String)row.get("OBJID"));
if("".equals(objid)) {
// 신규 등록
row.put("OBJID", CommonUtils.createObjId());
sqlSession.insert("productionplanning.insertProdResult", row);
} else {
// 수정
sqlSession.update("productionplanning.updateProdResult", row);
}
}
}
sqlSession.commit();
result = true;
} catch(Exception e) {
e.printStackTrace();
if(sqlSession != null) {
sqlSession.rollback();
}
} finally {
if(sqlSession != null) {
sqlSession.close();
}
}
return result;
}
}