Compare commits
22 Commits
V202512180
...
V202512290
| Author | SHA1 | Date | |
|---|---|---|---|
| 5836f8d571 | |||
| 4bbd0c1e4e | |||
| 5df50b7247 | |||
| 5959604464 | |||
| b53b20945b | |||
|
|
001f38d0f3 | ||
| ba09a208cf | |||
|
|
451b16f051 | ||
|
|
122ba638a6 | ||
|
|
9c27c71dbb | ||
| 4ed18d9f11 | |||
| 29671cb26a | |||
|
|
138e178005 | ||
|
|
969a136179 | ||
| eea2f67983 | |||
| d20382e717 | |||
| 5b0850f919 | |||
|
|
1fa303cc0f | ||
| bfc9d768c8 | |||
| 2ee76a8f20 | |||
|
|
ac8551c821 | ||
|
|
6dd802feda |
@@ -3958,12 +3958,22 @@
|
||||
ORDER BY REGDATE DESC, MBOM_NO
|
||||
</select>
|
||||
|
||||
<!-- M-BOM 목록 (bizMakeOptionList용) -->
|
||||
<!-- M-BOM 목록 (bizMakeOptionList용) - (E-BOM) 텍스트 제거 -->
|
||||
<select id="getMbomListForSelect2" parameterType="map" resultType="map">
|
||||
SELECT
|
||||
OBJID AS CODE,
|
||||
COALESCE(MBOM_NO, '') ||
|
||||
CASE WHEN SOURCE_BOM_TYPE IS NOT NULL AND SOURCE_BOM_TYPE != '' THEN ' (' || SOURCE_BOM_TYPE || ')' ELSE '' END AS NAME
|
||||
COALESCE(MBOM_NO, '') AS NAME
|
||||
FROM MBOM_HEADER
|
||||
WHERE STATUS = 'Y'
|
||||
ORDER BY REGDATE DESC, MBOM_NO
|
||||
</select>
|
||||
|
||||
<!-- M-BOM 목록 (품명 포함, 원자재소요량/반제품소요량용) -->
|
||||
<select id="getMbomListWithPartName" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
SELECT
|
||||
OBJID,
|
||||
MBOM_NO,
|
||||
COALESCE(PART_NAME, '') AS PART_NAME
|
||||
FROM MBOM_HEADER
|
||||
WHERE STATUS = 'Y'
|
||||
ORDER BY REGDATE DESC, MBOM_NO
|
||||
@@ -4500,9 +4510,9 @@
|
||||
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,
|
||||
COALESCE((SELECT SUM(RESULT_QTY) FROM PRODUCTION_RESULT PR WHERE PR.PROJECT_OBJID = PM.OBJID::VARCHAR AND PR.RESULT_TYPE = 'ASSEMBLY' AND PR.STATUS = 'active'), 0) AS ASSEMBLY_QTY,
|
||||
COALESCE((SELECT SUM(RESULT_QTY) FROM PRODUCTION_RESULT PR WHERE PR.PROJECT_OBJID = PM.OBJID::VARCHAR AND PR.RESULT_TYPE = 'INSPECTION' AND PR.STATUS = 'active'), 0) AS INSPECTION_QTY,
|
||||
COALESCE((SELECT SUM(RESULT_QTY) FROM PRODUCTION_RESULT PR WHERE PR.PROJECT_OBJID = PM.OBJID::VARCHAR AND PR.RESULT_TYPE = 'SHIP_WAIT' AND PR.STATUS = 'active'), 0) AS SHIP_WAIT_QTY,
|
||||
'' AS EQUIPMENT_WBS,
|
||||
PP.OBJID AS PROD_PLAN_OBJID,
|
||||
PM.REGDATE AS SORT_DATE
|
||||
@@ -4550,9 +4560,9 @@
|
||||
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,
|
||||
COALESCE((SELECT SUM(RESULT_QTY) FROM PRODUCTION_RESULT PR WHERE PR.PROJECT_OBJID = PP.OBJID::VARCHAR AND PR.RESULT_TYPE = 'ASSEMBLY' AND PR.STATUS = 'active'), 0) AS ASSEMBLY_QTY,
|
||||
COALESCE((SELECT SUM(RESULT_QTY) FROM PRODUCTION_RESULT PR WHERE PR.PROJECT_OBJID = PP.OBJID::VARCHAR AND PR.RESULT_TYPE = 'INSPECTION' AND PR.STATUS = 'active'), 0) AS INSPECTION_QTY,
|
||||
COALESCE((SELECT SUM(RESULT_QTY) FROM PRODUCTION_RESULT PR WHERE PR.PROJECT_OBJID = PP.OBJID::VARCHAR AND PR.RESULT_TYPE = 'SHIP_WAIT' AND PR.STATUS = 'active'), 0) AS SHIP_WAIT_QTY,
|
||||
'' AS EQUIPMENT_WBS,
|
||||
PP.OBJID AS PROD_PLAN_OBJID,
|
||||
PP.REGDATE AS SORT_DATE
|
||||
@@ -4610,31 +4620,54 @@
|
||||
ORDER BY T.SORT_DATE DESC, T.PROJECT_NO DESC
|
||||
</select>
|
||||
|
||||
<!-- 프로젝트 정보 조회 (생산계획 폼용) -->
|
||||
<!-- 프로젝트 정보 조회 (생산계획 폼용) - PROJECT_MGMT 또는 PRODUCTION_PLAN에서 조회 -->
|
||||
<select id="getProdPlanProjectInfo" parameterType="map" resultType="map">
|
||||
SELECT
|
||||
PM.OBJID,
|
||||
PM.PROJECT_NO,
|
||||
COALESCE(CI.PART_NO, PM.PART_NO) AS PART_NO,
|
||||
COALESCE(CI.PART_NAME, PM.PART_NAME) AS PART_NAME,
|
||||
COALESCE(CM.PRODUCT, PM.PRODUCT) AS PRODUCT_CODE,
|
||||
COALESCE(CM.CATEGORY_CD, '') AS CATEGORY_CODE,
|
||||
COALESCE(CM.CUSTOMER_OBJID, PM.CUSTOMER_OBJID) AS CUSTOMER_OBJID,
|
||||
COALESCE(CI.DUE_DATE, PM.DUE_DATE, CM.REQ_DEL_DATE) AS REQ_DEL_DATE,
|
||||
PM.QUANTITY AS ORDER_QTY,
|
||||
CM.CUSTOMER_REQUEST,
|
||||
(
|
||||
SELECT STRING_AGG(CIS.SERIAL_NO, ', ' ORDER BY CIS.SERIAL_NO)
|
||||
FROM CONTRACT_ITEM_SERIAL CIS
|
||||
WHERE CIS.ITEM_OBJID = CI.OBJID
|
||||
AND UPPER(CIS.STATUS) = 'ACTIVE'
|
||||
) AS SERIAL_NO
|
||||
FROM PROJECT_MGMT PM
|
||||
LEFT JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
|
||||
LEFT JOIN CONTRACT_ITEM CI ON CI.CONTRACT_OBJID = PM.CONTRACT_OBJID
|
||||
AND CI.PART_OBJID = PM.PART_OBJID
|
||||
AND CI.STATUS = 'ACTIVE'
|
||||
WHERE PM.OBJID = #{projectObjid}
|
||||
SELECT * FROM (
|
||||
-- 1. PROJECT_MGMT 기반 조회
|
||||
SELECT
|
||||
PM.OBJID::VARCHAR AS OBJID,
|
||||
COALESCE(PM.PROJECT_NO, '') AS PROJECT_NO,
|
||||
COALESCE(CI.PART_NO, PM.PART_NO, '') AS PART_NO,
|
||||
COALESCE(CI.PART_NAME, PM.PART_NAME, '') AS PART_NAME,
|
||||
COALESCE(CM.PRODUCT, PM.PRODUCT, '') AS PRODUCT_CODE,
|
||||
COALESCE(CM.CATEGORY_CD, '') AS CATEGORY_CODE,
|
||||
COALESCE(CM.CUSTOMER_OBJID, PM.CUSTOMER_OBJID, '')::VARCHAR AS CUSTOMER_OBJID,
|
||||
COALESCE(CI.DUE_DATE, PM.DUE_DATE, CM.REQ_DEL_DATE, '') AS REQ_DEL_DATE,
|
||||
COALESCE(NULLIF(PM.QUANTITY, '')::numeric, 0) AS ORDER_QTY,
|
||||
COALESCE((SELECT NULLIF(PP.EXTRA_PROD_QTY, '')::numeric FROM PRODUCTION_PLAN PP WHERE PP.PROJECT_OBJID = PM.OBJID AND UPPER(PP.STATUS) = 'ACTIVE' LIMIT 1), 0) AS EXTRA_PROD_QTY,
|
||||
COALESCE(CM.CUSTOMER_REQUEST, '') AS CUSTOMER_REQUEST,
|
||||
COALESCE((
|
||||
SELECT STRING_AGG(CIS.SERIAL_NO, ', ' ORDER BY CIS.SERIAL_NO)
|
||||
FROM CONTRACT_ITEM_SERIAL CIS
|
||||
WHERE CIS.ITEM_OBJID = CI.OBJID
|
||||
AND UPPER(CIS.STATUS) = 'ACTIVE'
|
||||
), '') AS SERIAL_NO
|
||||
FROM PROJECT_MGMT PM
|
||||
LEFT JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
|
||||
LEFT JOIN CONTRACT_ITEM CI ON CI.CONTRACT_OBJID = PM.CONTRACT_OBJID
|
||||
AND CI.PART_OBJID = PM.PART_OBJID
|
||||
AND CI.STATUS = 'ACTIVE'
|
||||
WHERE PM.OBJID::VARCHAR = #{projectObjid}
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- 2. PRODUCTION_PLAN 기반 조회 (OBJID로 직접 조회)
|
||||
SELECT
|
||||
PP.OBJID::VARCHAR AS OBJID,
|
||||
'' AS PROJECT_NO,
|
||||
COALESCE(PP.PART_NO, '') AS PART_NO,
|
||||
COALESCE(PP.PART_NAME, '') AS PART_NAME,
|
||||
COALESCE(PP.PRODUCT_CODE, '') AS PRODUCT_CODE,
|
||||
COALESCE(PP.CATEGORY_CODE, '') AS CATEGORY_CODE,
|
||||
COALESCE(PP.CUSTOMER_OBJID, '')::VARCHAR AS CUSTOMER_OBJID,
|
||||
COALESCE(PP.REQ_DEL_DATE, '') AS REQ_DEL_DATE,
|
||||
COALESCE(NULLIF(PP.ORDER_QTY, '')::numeric, 0) AS ORDER_QTY,
|
||||
COALESCE(NULLIF(PP.EXTRA_PROD_QTY, '')::numeric, 0) AS EXTRA_PROD_QTY,
|
||||
COALESCE(PP.CUSTOMER_REQUEST, '') AS CUSTOMER_REQUEST,
|
||||
COALESCE(PP.SERIAL_NO, '') AS SERIAL_NO
|
||||
FROM PRODUCTION_PLAN PP
|
||||
WHERE PP.OBJID::VARCHAR = #{projectObjid}
|
||||
) T
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
@@ -4754,6 +4787,7 @@
|
||||
RESULT_TYPE,
|
||||
RESULT_DATE,
|
||||
RESULT_QTY,
|
||||
ROW_SEQ,
|
||||
SERIAL_NO,
|
||||
WORKER_ID,
|
||||
WORKER_NAME,
|
||||
@@ -4767,6 +4801,7 @@
|
||||
#{RESULT_TYPE},
|
||||
#{RESULT_DATE},
|
||||
#{RESULT_QTY},
|
||||
#{ROW_SEQ},
|
||||
#{SERIAL_NO},
|
||||
#{userId},
|
||||
#{WORKER_NAME},
|
||||
@@ -4860,4 +4895,40 @@
|
||||
ORDER BY MD.RAW_MATERIAL_PART_NO
|
||||
</select>
|
||||
|
||||
<!-- 생산실적 날짜별 조회 (피봇) -->
|
||||
<select id="getProdResultListByDate" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
SELECT
|
||||
ROW_SEQ,
|
||||
RESULT_DATE,
|
||||
COALESCE(SUM(CASE WHEN RESULT_TYPE = 'ASSEMBLY' THEN RESULT_QTY ELSE 0 END), 0) AS ASSEMBLY_QTY,
|
||||
COALESCE(SUM(CASE WHEN RESULT_TYPE = 'INSPECTION' THEN RESULT_QTY ELSE 0 END), 0) AS INSPECTION_QTY,
|
||||
COALESCE(SUM(CASE WHEN RESULT_TYPE = 'SHIP_WAIT' THEN RESULT_QTY ELSE 0 END), 0) AS SHIP_WAIT_QTY,
|
||||
MAX(REMARK) AS REMARK
|
||||
FROM PRODUCTION_RESULT
|
||||
WHERE PROJECT_OBJID = #{projectObjid}
|
||||
AND STATUS = 'active'
|
||||
GROUP BY ROW_SEQ, RESULT_DATE
|
||||
ORDER BY ROW_SEQ ASC
|
||||
</select>
|
||||
|
||||
<!-- 생산실적 행별 삭제 -->
|
||||
<delete id="deleteProdResultByRowSeq" parameterType="map">
|
||||
DELETE FROM PRODUCTION_RESULT
|
||||
WHERE PROJECT_OBJID = #{projectObjid}
|
||||
AND ROW_SEQ = #{rowSeq}
|
||||
</delete>
|
||||
|
||||
<!-- 생산실적 날짜별 삭제 (기존 데이터 삭제 후 재입력용) -->
|
||||
<delete id="deleteProdResultByDate" parameterType="map">
|
||||
DELETE FROM PRODUCTION_RESULT
|
||||
WHERE PROJECT_OBJID = #{projectObjid}
|
||||
AND RESULT_DATE = #{resultDate}
|
||||
</delete>
|
||||
|
||||
<!-- 생산실적 프로젝트 전체 삭제 -->
|
||||
<delete id="deleteProdResultByProject" parameterType="map">
|
||||
DELETE FROM PRODUCTION_RESULT
|
||||
WHERE PROJECT_OBJID = #{projectObjid}
|
||||
</delete>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -4293,17 +4293,20 @@ SELECT POM.OBJID
|
||||
,POM.TOTAL_PRICE
|
||||
,POM.DISCOUNT_PRICE
|
||||
,POM.TOTAL_SUPPLY_UNIT_PRICE
|
||||
,POM.TOTAL_SUPPLY_PRICE
|
||||
-- ,POM.TOTAL_SUPPLY_PRICE
|
||||
,S1.TOTAL_SUPPLY_PRICE
|
||||
,POM.NEGO_RATE
|
||||
,POM.MULTI_MASTER_YN
|
||||
,POM.MULTI_YN
|
||||
,CASE WHEN POM.MULTI_MASTER_YN = 'Y' THEN '' ELSE POM.MULTI_YN END MULTI_YN_MAKED
|
||||
,COALESCE(POM.FORM_TYPE, '') AS FORM_TYPE
|
||||
<!-- ,S1.TOTAL_PO_QTY -->
|
||||
,(SELECT SUM(ORDER_QTY::NUMERIC) FROM PURCHASE_ORDER_PART AS O WHERE POM.OBJID::VARCHAR = O.PURCHASE_ORDER_MASTER_OBJID) AS TOTAL_PO_QTY
|
||||
<!--,(SELECT SUM(REAL_ORDER_QTY::NUMERIC) FROM PURCHASE_ORDER_PART AS O WHERE POM.OBJID::VARCHAR = O.PURCHASE_ORDER_MASTER_OBJID) AS TOTAL_PO_QTY -->
|
||||
,S1.CUR_DELIVERY_DATE
|
||||
,S1.TOTAL_DELIVERY_QTY
|
||||
,S1.TOTAL_DELIVERY_PRICE
|
||||
,S1.TOTAL_NOT_DELIVERY_PRICE
|
||||
<!-- ,(S1.TOTAL_PO_QTY - S1.TOTAL_DELIVERY_QTY - S1.TOTAL_DEFECT_QTY) AS NON_DELIVERY_QTY -->
|
||||
,((SELECT SUM(ORDER_QTY::NUMERIC) FROM PURCHASE_ORDER_PART AS O WHERE POM.OBJID::VARCHAR = O.PURCHASE_ORDER_MASTER_OBJID) - (S1.TOTAL_DELIVERY_QTY <!-- - S1.TOTAL_DEFECT_QTY --> )) AS NON_DELIVERY_QTY
|
||||
<!-- ,S1.TOTAL_DEFECT_QTY -->
|
||||
@@ -4355,19 +4358,23 @@ SELECT POM.OBJID
|
||||
LEFT OUTER JOIN(
|
||||
SELECT POP.PURCHASE_ORDER_MASTER_OBJID
|
||||
,SUM(POP.ORDER_QTY::NUMERIC) AS TOTAL_PO_QTY
|
||||
,MAX(DH.RECEIPT_DATE) AS CUR_DELIVERY_DATE
|
||||
,SUM(DH.RECEIPT_QTY::NUMERIC) AS TOTAL_DELIVERY_QTY
|
||||
,SUM(pop.partner_price::NUMERIC * DH.RECEIPT_QTY::NUMERIC) AS TOTAL_DELIVERY_PRICE
|
||||
|
||||
<!-- ,SUM(DH.ERROR_QTY::NUMERIC) AS TOTAL_DEFECT_QTY -->
|
||||
<!-- ,MAX(DH.DELIVERY_DATE) AS CUR_DELIVERY_DATE
|
||||
,SUM(DH.DELIVERY_QTY::NUMERIC) AS TOTAL_DELIVERY_QTY
|
||||
,SUM(DH.DEFECT_QTY::NUMERIC) AS TOTAL_DEFECT_QTY -->
|
||||
,MAX(AP_AGG.MAX_RECEIPT_DATE) AS CUR_DELIVERY_DATE
|
||||
,SUM(COALESCE(AP_AGG.SUM_RECEIPT_QTY, 0)) AS TOTAL_DELIVERY_QTY
|
||||
-- 발주금액 = 단가 × 발주수량
|
||||
,SUM(COALESCE(POP.PARTNER_PRICE::NUMERIC, 0) * COALESCE(POP.ORDER_QTY::NUMERIC, 0)) AS TOTAL_SUPPLY_PRICE
|
||||
-- 입고금액 = 단가 × 입고수량
|
||||
,SUM(COALESCE(POP.PARTNER_PRICE::NUMERIC, 0) * COALESCE(AP_AGG.SUM_RECEIPT_QTY, 0)) AS TOTAL_DELIVERY_PRICE
|
||||
-- 미입고금액 = 단가 × (발주수량 - 입고수량)
|
||||
,SUM(COALESCE(POP.PARTNER_PRICE::NUMERIC, 0) * (COALESCE(POP.ORDER_QTY::NUMERIC, 0) - COALESCE(AP_AGG.SUM_RECEIPT_QTY, 0))) AS TOTAL_NOT_DELIVERY_PRICE
|
||||
FROM PURCHASE_ORDER_PART POP
|
||||
LEFT OUTER JOIN ARRIVAL_PLAN DH
|
||||
ON POP.OBJID = DH.ORDER_PART_OBJID
|
||||
<!-- LEFT OUTER JOIN DELIVERY_HISTORY DH -->
|
||||
<!-- ON POP.PART_OBJID = DH.PART_OBJID -->
|
||||
LEFT OUTER JOIN (
|
||||
-- ARRIVAL_PLAN을 ORDER_PART_OBJID별로 먼저 집계
|
||||
SELECT ORDER_PART_OBJID
|
||||
,SUM(RECEIPT_QTY::NUMERIC) AS SUM_RECEIPT_QTY
|
||||
,MAX(RECEIPT_DATE) AS MAX_RECEIPT_DATE
|
||||
FROM ARRIVAL_PLAN
|
||||
GROUP BY ORDER_PART_OBJID
|
||||
) AP_AGG ON POP.OBJID = AP_AGG.ORDER_PART_OBJID
|
||||
GROUP BY POP.PURCHASE_ORDER_MASTER_OBJID
|
||||
) AS S1 ON POM.OBJID::VARCHAR = S1.PURCHASE_ORDER_MASTER_OBJID
|
||||
LEFT OUTER JOIN PROJECT_MGMT AS CM
|
||||
|
||||
@@ -1358,30 +1358,32 @@
|
||||
DELETE FROM PROCESS_INSPECTION_DETAIL WHERE MASTER_OBJID = #{MASTER_OBJID}
|
||||
</delete>
|
||||
|
||||
<!-- 공정검사 목록 조회 (엑셀용) - 상세 정보 포함 -->
|
||||
<!-- 공정검사 목록 조회 (엑셀용) - 상세 정보 포함 (디테일 기준) -->
|
||||
<select id="getProcessInspectionListForExcel" parameterType="map" resultType="map">
|
||||
SELECT
|
||||
/* 공정검사 마스터 정보 */
|
||||
PIM.INSPECTION_DATE
|
||||
, (SELECT U.USER_NAME FROM USER_INFO U WHERE U.USER_ID = PIM.INSPECTOR_ID) AS INSPECTOR_NAME
|
||||
, PIM.REMARK AS MASTER_REMARK
|
||||
/* 검사일, 검사자는 디테일에서 가져옴 */
|
||||
COALESCE(PID.INSPECTION_DATE, '') AS INSPECTION_DATE
|
||||
, COALESCE((SELECT U.USER_NAME FROM USER_INFO U WHERE U.USER_ID = PID.INSPECTOR_ID), '') AS INSPECTOR_NAME
|
||||
, COALESCE((SELECT CODE_NAME(PM.PRODUCT) FROM PROJECT_MGMT PM WHERE PM.OBJID = PID.PROJECT_OBJID), '') AS PRODUCT_TYPE
|
||||
/* 공정검사 디테일 정보 */
|
||||
, (SELECT CC.CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = PID.PROCESS_CD) AS PROCESS_NAME
|
||||
, (SELECT PM.PROJECT_NO FROM PROJECT_MGMT PM WHERE PM.OBJID = PID.PROJECT_OBJID) AS PROJECT_NO
|
||||
, PID.PART_NO
|
||||
, PID.PART_NAME
|
||||
, PID.INSPECTION_QTY
|
||||
, PID.DEFECT_QTY
|
||||
, COALESCE((SELECT CC.CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = PID.PROCESS_CD), '') AS PROCESS_NAME
|
||||
, COALESCE((SELECT PM.PROJECT_NO FROM PROJECT_MGMT PM WHERE PM.OBJID = PID.PROJECT_OBJID), '') AS PROJECT_NO
|
||||
, COALESCE(PID.PART_NO, '') AS PART_NO
|
||||
, COALESCE(PID.PART_NAME, '') AS PART_NAME
|
||||
, COALESCE(PID.INSPECTION_QTY, 0) AS INSPECTION_QTY
|
||||
, COALESCE(PID.DEFECT_QTY, 0) AS DEFECT_QTY
|
||||
, CASE WHEN COALESCE(PID.INSPECTION_QTY, 0) > 0
|
||||
THEN ROUND((COALESCE(PID.DEFECT_QTY, 0)::NUMERIC / PID.INSPECTION_QTY::NUMERIC) * 100, 2)
|
||||
ELSE NULL END AS DEFECT_RATE
|
||||
, PID.WORK_ENV_STATUS
|
||||
, PID.MEASURING_DEVICE
|
||||
, (SELECT DEPT_NAME FROM DEPT_INFO WHERE DEPT_CODE = PID.DEPT_CD) AS DEPT_NAME
|
||||
, (SELECT U2.USER_NAME FROM USER_INFO U2 WHERE U2.USER_ID = PID.USER_ID) AS USER_NAME
|
||||
, PID.REMARK AS DETAIL_REMARK
|
||||
, PID.ACTION_STATUS
|
||||
, PID.INSPECTION_RESULT
|
||||
ELSE 0 END AS DEFECT_RATE
|
||||
, COALESCE(PID.WORK_ENV_STATUS, '') AS WORK_ENV_STATUS
|
||||
, COALESCE(PID.MEASURING_DEVICE, '') AS MEASURING_DEVICE
|
||||
, COALESCE((SELECT DI.DEPT_NAME FROM DEPT_INFO DI WHERE DI.DEPT_CODE = PID.DEPT_CD), '') AS DEPT_NAME
|
||||
, COALESCE((SELECT U2.USER_NAME FROM USER_INFO U2 WHERE U2.USER_ID = PID.USER_ID), '') AS USER_NAME
|
||||
, COALESCE(PID.REMARK, '') AS DETAIL_REMARK
|
||||
, COALESCE(PID.ACTION_STATUS, '') AS ACTION_STATUS
|
||||
, COALESCE(NULLIF(PID.INSPECTION_RESULT, ''),
|
||||
(SELECT CASE WHEN COUNT(CASE WHEN PID2.INSPECTION_RESULT = 'NG' THEN 1 END) > 0 THEN 'NG' ELSE 'OK' END
|
||||
FROM PROCESS_INSPECTION_DETAIL PID2 WHERE PID2.MASTER_OBJID = PIM.OBJID), '') AS INSPECTION_RESULT
|
||||
FROM PROCESS_INSPECTION_MASTER PIM
|
||||
INNER JOIN PROCESS_INSPECTION_DETAIL PID ON PID.MASTER_OBJID = PIM.OBJID
|
||||
WHERE 1=1
|
||||
@@ -1396,15 +1398,15 @@
|
||||
</if>
|
||||
<if test="search_inspector != null and search_inspector != ''">
|
||||
AND (
|
||||
UPPER(PIM.INSPECTOR_ID) LIKE UPPER('%' || #{search_inspector} || '%')
|
||||
OR UPPER((SELECT USER_NAME FROM USER_INFO WHERE USER_ID = PIM.INSPECTOR_ID)) LIKE UPPER('%' || #{search_inspector} || '%')
|
||||
UPPER(PID.INSPECTOR_ID) LIKE UPPER('%' || #{search_inspector} || '%')
|
||||
OR UPPER((SELECT USER_NAME FROM USER_INFO WHERE USER_ID = PID.INSPECTOR_ID)) LIKE UPPER('%' || #{search_inspector} || '%')
|
||||
)
|
||||
</if>
|
||||
<if test="search_inspection_date_from != null and search_inspection_date_from != ''">
|
||||
AND PIM.INSPECTION_DATE <![CDATA[>=]]> #{search_inspection_date_from}
|
||||
AND PID.INSPECTION_DATE <![CDATA[>=]]> #{search_inspection_date_from}
|
||||
</if>
|
||||
<if test="search_inspection_date_to != null and search_inspection_date_to != ''">
|
||||
AND PIM.INSPECTION_DATE <![CDATA[<=]]> #{search_inspection_date_to}
|
||||
AND PID.INSPECTION_DATE <![CDATA[<=]]> #{search_inspection_date_to}
|
||||
</if>
|
||||
<if test="search_inspection_result != null and search_inspection_result != ''">
|
||||
AND PID.INSPECTION_RESULT = #{search_inspection_result}
|
||||
@@ -1540,96 +1542,62 @@
|
||||
ORDER BY MIN(T.INSPECTION_DATE) DESC, T.INSPECTION_GROUP_ID
|
||||
</select>
|
||||
|
||||
<!-- 반제품검사 엑셀 다운로드용 데이터 조회 (그룹화 후 쉼표로 나열) -->
|
||||
<!-- 반제품검사 엑셀 다운로드용 데이터 조회 (전체 풀어서 개별 행으로) -->
|
||||
<select id="getSemiProductInspectionListForExcel" parameterType="map" resultType="map">
|
||||
SELECT T.INSPECTION_GROUP_ID
|
||||
, MIN(T.OBJID) AS OBJID
|
||||
<!-- 품명(모델명): 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.MODEL_NAME, ''), ', ' ORDER BY NULLIF(T.MODEL_NAME, '')) AS MODEL_NAME
|
||||
<!-- 제품구분: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.PRODUCT_TYPE, ''), ', ' ORDER BY NULLIF(T.PRODUCT_TYPE, '')) AS PRODUCT_TYPE
|
||||
<!-- 작업지시번호: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.WORK_ORDER_NO, ''), ', ' ORDER BY NULLIF(T.WORK_ORDER_NO, '')) AS WORK_ORDER_NO
|
||||
<!-- 부품품번: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.PART_NO, ''), ', ' ORDER BY NULLIF(T.PART_NO, '')) AS PART_NO
|
||||
<!-- 부품명: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.PART_NAME, ''), ', ' ORDER BY NULLIF(T.PART_NAME, '')) AS PART_NAME
|
||||
<!-- 수량 집계 -->
|
||||
, SUM(T.RECEIPT_QTY) AS RECEIPT_QTY
|
||||
, SUM(T.GOOD_QTY) AS GOOD_QTY
|
||||
, SUM(T.DEFECT_QTY) AS DEFECT_QTY
|
||||
SELECT SPI.OBJID
|
||||
, COALESCE(TO_CHAR(SPI.INSPECTION_DATE, 'YYYY-MM-DD'), TO_CHAR(SPI.REG_DATE, 'YYYY-MM-DD')) AS INSPECTION_DATE
|
||||
, COALESCE((SELECT USER_NAME FROM USER_INFO WHERE USER_ID = SPI.INSPECTOR),
|
||||
(SELECT USER_NAME FROM USER_INFO WHERE USER_ID = SPI.WRITER), '') AS WRITER_NAME
|
||||
, COALESCE(SPI.MODEL_NAME, '') AS MODEL_NAME
|
||||
, COALESCE(SPI.PRODUCT_TYPE, '') AS PRODUCT_TYPE
|
||||
, COALESCE(SPI.WORK_ORDER_NO, '') AS WORK_ORDER_NO
|
||||
, COALESCE(SPI.PART_NO, '') AS PART_NO
|
||||
, COALESCE(SPI.PART_NAME, '') AS PART_NAME
|
||||
, COALESCE(SPI.RECEIPT_QTY, 0) AS RECEIPT_QTY
|
||||
, COALESCE(SPI.GOOD_QTY, 0) AS GOOD_QTY
|
||||
, COALESCE(SPI.DEFECT_QTY, 0) AS DEFECT_QTY
|
||||
, CASE
|
||||
WHEN SUM(T.RECEIPT_QTY) > 0
|
||||
THEN ROUND(SUM(T.DEFECT_QTY) * 100.0 / SUM(T.RECEIPT_QTY), 2)
|
||||
WHEN COALESCE(SPI.RECEIPT_QTY, 0) > 0
|
||||
THEN ROUND(COALESCE(SPI.DEFECT_QTY, 0) * 100.0 / SPI.RECEIPT_QTY, 2)
|
||||
ELSE 0
|
||||
END AS DEFECT_RATE
|
||||
, SUM(CASE WHEN T.DISPOSITION_TYPE = '수정' THEN T.DEFECT_QTY ELSE 0 END) AS REGENERATION_QTY
|
||||
, SUM(T.GOOD_QTY) + SUM(CASE WHEN T.DISPOSITION_TYPE = '수정' THEN T.DEFECT_QTY ELSE 0 END) AS FINAL_GOOD_QTY
|
||||
<!-- 검사일: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT T.INSPECTION_DATE_STR, ', ' ORDER BY T.INSPECTION_DATE_STR) AS INSPECTION_DATE
|
||||
<!-- 검사자: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.WRITER_NAME, ''), ', ' ORDER BY NULLIF(T.WRITER_NAME, '')) AS WRITER_NAME
|
||||
<!-- 불량유형: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.DEFECT_TYPE, ''), ', ' ORDER BY NULLIF(T.DEFECT_TYPE, '')) AS DEFECT_TYPE
|
||||
<!-- 불량원인: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.DEFECT_CAUSE, ''), ', ' ORDER BY NULLIF(T.DEFECT_CAUSE, '')) AS DEFECT_CAUSE
|
||||
<!-- 귀책부서: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.RESPONSIBLE_DEPT, ''), ', ' ORDER BY NULLIF(T.RESPONSIBLE_DEPT, '')) AS RESPONSIBLE_DEPT
|
||||
<!-- 처리현황: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.PROCESS_STATUS, ''), ', ' ORDER BY NULLIF(T.PROCESS_STATUS, '')) AS PROCESS_STATUS
|
||||
<!-- 처리결과: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.DISPOSITION_TYPE, ''), ', ' ORDER BY NULLIF(T.DISPOSITION_TYPE, '')) AS DISPOSITION_TYPE
|
||||
<!-- 비고: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.REMARK, ''), ', ' ORDER BY NULLIF(T.REMARK, '')) AS REMARK
|
||||
FROM (
|
||||
SELECT SPI.OBJID
|
||||
, COALESCE(SPI.INSPECTION_GROUP_ID, SPI.OBJID::VARCHAR) AS INSPECTION_GROUP_ID
|
||||
, COALESCE(SPI.MODEL_NAME, '') AS MODEL_NAME
|
||||
, COALESCE(SPI.PRODUCT_TYPE, '') AS PRODUCT_TYPE
|
||||
, COALESCE(SPI.WORK_ORDER_NO, '') AS WORK_ORDER_NO
|
||||
, COALESCE(SPI.PART_NO, '') AS PART_NO
|
||||
, COALESCE(SPI.PART_NAME, '') AS PART_NAME
|
||||
, COALESCE(SPI.RECEIPT_QTY, 0) AS RECEIPT_QTY
|
||||
, COALESCE(SPI.GOOD_QTY, 0) AS GOOD_QTY
|
||||
, COALESCE(SPI.DEFECT_QTY, 0) AS DEFECT_QTY
|
||||
, COALESCE(TO_CHAR(SPI.INSPECTION_DATE, 'YYYY-MM-DD'), TO_CHAR(SPI.REG_DATE, 'YYYY-MM-DD')) AS INSPECTION_DATE_STR
|
||||
, COALESCE((SELECT USER_NAME FROM USER_INFO WHERE USER_ID = SPI.INSPECTOR),
|
||||
(SELECT USER_NAME FROM USER_INFO WHERE USER_ID = SPI.WRITER), '') AS WRITER_NAME
|
||||
, COALESCE(SPI.DEFECT_TYPE, '') AS DEFECT_TYPE
|
||||
, COALESCE(SPI.DEFECT_CAUSE, '') AS DEFECT_CAUSE
|
||||
, COALESCE(SPI.RESPONSIBLE_DEPT, '') AS RESPONSIBLE_DEPT
|
||||
, COALESCE(SPI.PROCESS_STATUS, '') AS PROCESS_STATUS
|
||||
, COALESCE(SPI.DISPOSITION_TYPE, '') AS DISPOSITION_TYPE
|
||||
, COALESCE(SPI.REMARK, '') AS REMARK
|
||||
FROM PMS_QUALITY_SEMI_PRODUCT_INSPECTION SPI
|
||||
WHERE 1=1
|
||||
<!-- 품명(모델명) 검색 -->
|
||||
<if test="search_model_name != null and search_model_name != ''">
|
||||
AND UPPER(SPI.MODEL_NAME) LIKE UPPER('%' || #{search_model_name} || '%')
|
||||
</if>
|
||||
<!-- 작업지시번호 검색 -->
|
||||
<if test="search_work_order_no != null and search_work_order_no != ''">
|
||||
AND UPPER(SPI.WORK_ORDER_NO) LIKE UPPER('%' || #{search_work_order_no} || '%')
|
||||
</if>
|
||||
<!-- 부품품번 검색 -->
|
||||
<if test="search_part_no != null and search_part_no != ''">
|
||||
AND UPPER(SPI.PART_NO) LIKE UPPER('%' || #{search_part_no} || '%')
|
||||
</if>
|
||||
<!-- 부품명 검색 -->
|
||||
<if test="search_part_name != null and search_part_name != ''">
|
||||
AND UPPER(SPI.PART_NAME) LIKE UPPER('%' || #{search_part_name} || '%')
|
||||
</if>
|
||||
<!-- 검사일 검색 -->
|
||||
<if test="search_inspection_date != null and search_inspection_date != ''">
|
||||
AND TO_CHAR(SPI.REG_DATE, 'YYYY-MM-DD') = #{search_inspection_date}
|
||||
</if>
|
||||
<!-- 검사자 검색 -->
|
||||
<if test="search_writer != null and search_writer != ''">
|
||||
AND SPI.WRITER = #{search_writer}
|
||||
</if>
|
||||
) T
|
||||
GROUP BY T.INSPECTION_GROUP_ID
|
||||
ORDER BY MIN(T.INSPECTION_DATE_STR) DESC, T.INSPECTION_GROUP_ID
|
||||
, CASE WHEN SPI.DISPOSITION_TYPE = '수정' THEN COALESCE(SPI.DEFECT_QTY, 0) ELSE 0 END AS REGENERATION_QTY
|
||||
, COALESCE(SPI.GOOD_QTY, 0) + CASE WHEN SPI.DISPOSITION_TYPE = '수정' THEN COALESCE(SPI.DEFECT_QTY, 0) ELSE 0 END AS FINAL_GOOD_QTY
|
||||
, COALESCE(SPI.DEFECT_TYPE, '') AS DEFECT_TYPE
|
||||
, COALESCE(SPI.DEFECT_CAUSE, '') AS DEFECT_CAUSE
|
||||
, COALESCE(SPI.RESPONSIBLE_DEPT, '') AS RESPONSIBLE_DEPT
|
||||
, COALESCE(SPI.PROCESS_STATUS, '') AS PROCESS_STATUS
|
||||
, COALESCE(SPI.DISPOSITION_TYPE, '') AS DISPOSITION_TYPE
|
||||
, COALESCE(SPI.REMARK, '') AS REMARK
|
||||
, COALESCE(SPI.DATA_TYPE, '') AS DATA_TYPE
|
||||
, COALESCE(SPI.INSPECTION_GROUP_ID::VARCHAR, '') AS INSPECTION_GROUP_ID
|
||||
FROM PMS_QUALITY_SEMI_PRODUCT_INSPECTION SPI
|
||||
WHERE 1=1
|
||||
<!-- 품명(모델명) 검색 -->
|
||||
<if test="search_model_name != null and search_model_name != ''">
|
||||
AND UPPER(SPI.MODEL_NAME) LIKE UPPER('%' || #{search_model_name} || '%')
|
||||
</if>
|
||||
<!-- 작업지시번호 검색 -->
|
||||
<if test="search_work_order_no != null and search_work_order_no != ''">
|
||||
AND UPPER(SPI.WORK_ORDER_NO) LIKE UPPER('%' || #{search_work_order_no} || '%')
|
||||
</if>
|
||||
<!-- 부품품번 검색 -->
|
||||
<if test="search_part_no != null and search_part_no != ''">
|
||||
AND UPPER(SPI.PART_NO) LIKE UPPER('%' || #{search_part_no} || '%')
|
||||
</if>
|
||||
<!-- 부품명 검색 -->
|
||||
<if test="search_part_name != null and search_part_name != ''">
|
||||
AND UPPER(SPI.PART_NAME) LIKE UPPER('%' || #{search_part_name} || '%')
|
||||
</if>
|
||||
<!-- 검사일 검색 -->
|
||||
<if test="search_inspection_date != null and search_inspection_date != ''">
|
||||
AND TO_CHAR(SPI.REG_DATE, 'YYYY-MM-DD') = #{search_inspection_date}
|
||||
</if>
|
||||
<!-- 검사자 검색 -->
|
||||
<if test="search_writer != null and search_writer != ''">
|
||||
AND SPI.WRITER = #{search_writer}
|
||||
</if>
|
||||
ORDER BY SPI.INSPECTION_DATE DESC, SPI.REG_DATE DESC
|
||||
</select>
|
||||
|
||||
<!-- 반제품검사 품명(모델명) 드롭박스 목록 (CODE, NAME 형태) -->
|
||||
|
||||
@@ -41,6 +41,12 @@
|
||||
.select2-container .select2-selection--multiple .select2-selection__rendered {
|
||||
overflow: auto !important;
|
||||
}
|
||||
body, html {
|
||||
overflow-x: hidden;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
@@ -48,6 +54,9 @@
|
||||
$('.select2').select2();
|
||||
fnc_datepick();
|
||||
|
||||
// 품번/품명 Select2 AJAX 초기화
|
||||
initPartSelect2Ajax("#part_no", "#part_name", "#search_part_objid");
|
||||
|
||||
//엔터키로 조회
|
||||
$("input").keyup(function(e){
|
||||
if(e.keyCode == 13){
|
||||
@@ -101,8 +110,8 @@
|
||||
{title:"자재목록", headerHozAlign:'center',
|
||||
//frozen:false,
|
||||
columns:[
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '100', title : '프로젝트번호', field : 'PROJECT_NO' },
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '200', title : '유닛명', field : 'UNIT_NAME' },
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '130', title : '프로젝트번호', field : 'PROJECT_NO' },
|
||||
//{headerHozAlign : 'center', hozAlign : 'left', width : '200', title : '유닛명', field : 'UNIT_NAME' },
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '180', title : '품번', field : 'PART_NO' },
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '180', title : '품명', field : 'PART_NAME' },
|
||||
{headerHozAlign : 'center', hozAlign : 'left', width : '180', title : '재질', field : 'MATERIAL' },
|
||||
@@ -369,10 +378,19 @@ function fn_move(){
|
||||
</td>
|
||||
|
||||
<td><label for="">품번</label></td>
|
||||
<td><input type="text" name="part_no" id="part_no" autocomplete="off" value="${param.part_no}" style="width:150px;"/></td>
|
||||
<td>
|
||||
<select name="part_no" id="part_no" class="select2-part" style="width:150px;">
|
||||
<option value="">품번 선택</option>
|
||||
</select>
|
||||
<input type="hidden" name="search_part_objid" id="search_part_objid" value="">
|
||||
</td>
|
||||
|
||||
<td><label for="">품명</label></td>
|
||||
<td><input type="text" name="part_name" id="part_name" autocomplete="off" value="${param.part_name}" style="width:170px;"/></td>
|
||||
<td>
|
||||
<select name="part_name" id="part_name" class="select2-part" style="width:170px;">
|
||||
<option value="">품명 선택</option>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
<td><label for="">PART 구분</label></td>
|
||||
<td><select name="part_type" id="part_type" class="select2" autocomplete="off" style="width:110px;"><option value="">선택</option>${code_map.part_type}</select></td>
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
$('.select2').select2();
|
||||
fnc_datepick();
|
||||
|
||||
// 품번/품명 Select2 AJAX 초기화
|
||||
initPartSelect2Ajax("#part_no", "#part_name", "#search_part_objid");
|
||||
|
||||
//엔터키로 조회
|
||||
$("input").keyup(function(e){
|
||||
if(e.keyCode == 13){
|
||||
@@ -379,10 +382,19 @@
|
||||
</td> --%>
|
||||
|
||||
<td><label for="">품번</label></td>
|
||||
<td><input type="text" name="part_no" id="part_no" autocomplete="off" value="${param.part_no}" style="width:150px;"/></td>
|
||||
<td>
|
||||
<select name="part_no" id="part_no" class="select2-part" style="width:150px;">
|
||||
<option value="">품번 선택</option>
|
||||
</select>
|
||||
<input type="hidden" name="search_part_objid" id="search_part_objid" value="">
|
||||
</td>
|
||||
|
||||
<td><label for="">품명</label></td>
|
||||
<td><input type="text" name="part_name" id="part_name" autocomplete="off" value="${param.part_name}" style="width:150px;"/></td>
|
||||
<td>
|
||||
<select name="part_name" id="part_name" class="select2-part" style="width:150px;">
|
||||
<option value="">품명 선택</option>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
<td class=""><label>불출의뢰일</label></td>
|
||||
<td>
|
||||
|
||||
@@ -433,30 +433,41 @@ var gridFn = {
|
||||
url: "/partMng/parsingExcelFile.do"
|
||||
,datatype : "json"
|
||||
,postData:{"targetObjId":"${objid}","docType":"PART_EXCEL_IMPORT","OBJID":"${CONTRACT_OBJID}"}
|
||||
,loadComplete : function(data) {
|
||||
// CSV 파일에서만 LEVEL 값을 PARENT_PART_NO 컬럼에 표시
|
||||
if(data && data.rows) {
|
||||
for(var i = 0; i < data.rows.length; i++) {
|
||||
var row = data.rows[i];
|
||||
// CSV 파일이고 LEVEL 값이 있는 경우
|
||||
if(row.IS_CSV === 'Y' && row.LEVEL && row.LEVEL !== '') {
|
||||
// LEVEL 값을 PARENT_PART_NO 컬럼에 표시 (화면용)
|
||||
grid.jqGrid('setCell', row.id, 'PARENT_PART_NO', row.LEVEL);
|
||||
}
|
||||
,loadComplete : function(data) {
|
||||
gridFn.footerSummary();
|
||||
}
|
||||
}
|
||||
gridFn.footerSummary();
|
||||
}
|
||||
,gridComplete : function() {
|
||||
//gridFn.opennEdit(); //수정가능
|
||||
var valid = true;
|
||||
gridFn.closeEdit();
|
||||
//var tempGrid = $('#expenseDetailGrid');
|
||||
|
||||
// 1번 레벨(PARENT_PART_NO가 비어있는 행)의 품번/품명을 헤더에 자동 설정
|
||||
var isFirstLevelSet = false;
|
||||
|
||||
$.each(grid.getRowData(), function(i, d){
|
||||
console.log(d);
|
||||
console.log("Row data:", d);
|
||||
|
||||
// NOTE 검증
|
||||
if(!fnc_isEmpty(d["NOTE"])){
|
||||
valid = false;
|
||||
}
|
||||
|
||||
// PARENT_PART_NO가 비어있으면 1번 레벨 (최상위)
|
||||
var parentPartNo = d["PARENT_PART_NO"] || '';
|
||||
if(!isFirstLevelSet && parentPartNo === '') {
|
||||
var partNo = d["PART_NO"] || '';
|
||||
var partName = d["PART_NAME"] || '';
|
||||
|
||||
console.log("Level 1 found - PART_NO:", partNo, ", PART_NAME:", partName);
|
||||
|
||||
// 새로 CSV 업로드 시 항상 덮어쓰기
|
||||
if(partNo !== '') {
|
||||
$('#bom_part_no').val(partNo);
|
||||
}
|
||||
if(partName !== '') {
|
||||
$('#bom_part_name').val(partName);
|
||||
}
|
||||
isFirstLevelSet = true;
|
||||
}
|
||||
});
|
||||
gridFn.opennEdit();
|
||||
|
||||
@@ -967,11 +978,11 @@ function fn_save(){
|
||||
</td>
|
||||
<td style="font-size:12px;" class="align_c"><label for="bom_part_no">품번</label></td>
|
||||
<td>
|
||||
<input type="text" name="bom_part_no" id="bom_part_no" required reqTitle="품번" value="<%= bomPartNo %>" style="width: 100%;"/>
|
||||
<input type="text" name="bom_part_no" id="bom_part_no" required reqTitle="품번" value="<%= bomPartNo %>" style="width: 100%;" readonly/>
|
||||
</td>
|
||||
<td style="font-size:12px;" class="align_c"><label for="bom_part_name">품명</label></td>
|
||||
<td>
|
||||
<input type="text" name="bom_part_name" id="bom_part_name" required reqTitle="품명" value="<%= bomPartName %>" style="width: 200px;"/>
|
||||
<input type="text" name="bom_part_name" id="bom_part_name" required reqTitle="품명" value="<%= bomPartName %>" style="width: 200px;" readonly/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -20,6 +20,9 @@ $(document).ready(function(){
|
||||
$('.select2').select2();
|
||||
fnc_datepick();
|
||||
|
||||
// 품번/품명 Select2 AJAX 초기화
|
||||
initPartSelect2Ajax("#part_no", "#part_name", "#search_part_objid");
|
||||
|
||||
//fnc_getCodeListAppend("CUST_CD","CUSTOMER_CD","${param.CUSTOMER_CD}");
|
||||
//$("#Year").val("${sysYear}");
|
||||
|
||||
@@ -149,10 +152,19 @@ function fn_partMngHisDetail(objId){
|
||||
<td><select name="unit_code" id="unit_code" style="width:250px" class="select2" autocomplete="off"></select></td>
|
||||
|
||||
<td><label for="">품번</label></td>
|
||||
<td><input type="text" name="part_no" id="part_no" autocomplete="off" value="${param.part_no }" /></td>
|
||||
<td>
|
||||
<select name="part_no" id="part_no" class="select2-part" style="width:150px;">
|
||||
<option value="">품번 선택</option>
|
||||
</select>
|
||||
<input type="hidden" name="search_part_objid" id="search_part_objid" value="">
|
||||
</td>
|
||||
|
||||
<td><label for="">품명</label></td>
|
||||
<td><input type="text" name="part_name" id="part_name" autocomplete="off" value="${param.part_name}" /></td>
|
||||
<td>
|
||||
<select name="part_name" id="part_name" class="select2-part" style="width:150px;">
|
||||
<option value="">품명 선택</option>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
<td><label for="">EO사유</label></td>
|
||||
<td><select name="change_option" id="change_option" class="select2" autocomplete="off"><option value="">선택</option>${code_map.change_option}</select></td>
|
||||
|
||||
@@ -101,6 +101,9 @@ String connector = person.getUserId();
|
||||
}
|
||||
|
||||
$('.select2').select2();
|
||||
|
||||
// 품번/품명 Select2 AJAX 초기화
|
||||
initPartSelect2Ajax("#SEARCH_PART_NO", "#SEARCH_PART_NAME", "#SEARCH_PART_OBJID");
|
||||
|
||||
//첨부팝업
|
||||
$(".File").click(function(){
|
||||
@@ -513,14 +516,19 @@ String connector = person.getUserId();
|
||||
<!-- <td> -->
|
||||
<!-- <select name="upg_no" id="upg_no" class="select2" style="width:250px;" autocomplete="off"></select> -->
|
||||
<!-- </td> -->
|
||||
<td><label for="">품번</label></td>
|
||||
<td>
|
||||
<input type="text" name="SEARCH_PART_NO" id="SEARCH_PART_NO" style="width:150px;" autocomplete="off" value="${param.SEARCH_PART_NO}">
|
||||
</td>
|
||||
<td><label for="">품명</label></td>
|
||||
<td>
|
||||
<input type="text" name="SEARCH_PART_NAME" id="SEARCH_PART_NAME" style="width:150px;" autocomplete="off" value="${param.SEARCH_PART_NAME}">
|
||||
</td>
|
||||
<td><label for="">품번</label></td>
|
||||
<td>
|
||||
<select name="SEARCH_PART_NO" id="SEARCH_PART_NO" class="select2-part" style="width:150px;">
|
||||
<option value="">품번 선택</option>
|
||||
</select>
|
||||
<input type="hidden" name="SEARCH_PART_OBJID" id="SEARCH_PART_OBJID" value="">
|
||||
</td>
|
||||
<td><label for="">품명</label></td>
|
||||
<td>
|
||||
<select name="SEARCH_PART_NAME" id="SEARCH_PART_NAME" class="select2-part" style="width:150px;">
|
||||
<option value="">품명 선택</option>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
<td><label for="">Revision</label></td>
|
||||
<td>
|
||||
|
||||
@@ -91,6 +91,9 @@ ui-jqgrid tr.jqgrow td {
|
||||
|
||||
$('.select2').select2();
|
||||
|
||||
// 품번/품명 Select2 AJAX 초기화
|
||||
initPartSelect2Ajax("#SEARCH_PART_NO", "#SEARCH_PART_NAME", "#SEARCH_PART_OBJID");
|
||||
|
||||
fn_search();
|
||||
|
||||
|
||||
@@ -610,14 +613,19 @@ ui-jqgrid tr.jqgrow td {
|
||||
</c:forEach>
|
||||
</select>
|
||||
</td> -->
|
||||
<td><label for="">품번</label></td>
|
||||
<td>
|
||||
<input type="text" name="SEARCH_PART_NO" id="SEARCH_PART_NO" style="width:194px;" autocomplete="off" value="${param.SEARCH_PART_NO}">
|
||||
</td>
|
||||
<td><label for="">품명</label></td>
|
||||
<td>
|
||||
<input type="text" name="SEARCH_PART_NAME" id="SEARCH_PART_NAME" style="width:150px;" autocomplete="off" value="${param.SEARCH_PART_NAME}">
|
||||
</td>
|
||||
<td><label for="">품번</label></td>
|
||||
<td>
|
||||
<select name="SEARCH_PART_NO" id="SEARCH_PART_NO" class="select2-part" style="width:194px;">
|
||||
<option value="">품번 선택</option>
|
||||
</select>
|
||||
<input type="hidden" name="SEARCH_PART_OBJID" id="SEARCH_PART_OBJID" value="">
|
||||
</td>
|
||||
<td><label for="">품명</label></td>
|
||||
<td>
|
||||
<select name="SEARCH_PART_NAME" id="SEARCH_PART_NAME" class="select2-part" style="width:150px;">
|
||||
<option value="">품명 선택</option>
|
||||
</select>
|
||||
</td>
|
||||
<!-- <td><label for="">등록자</label></td>
|
||||
<td>
|
||||
<select name="WRITER" id="WRITER" required reqTitle="작성자" type="select" class="select2" autocomplete="off">
|
||||
|
||||
@@ -176,6 +176,9 @@ $(document).ready(function(){
|
||||
|
||||
$('.select2').select2();
|
||||
|
||||
// 품번/품명 Select2 AJAX 초기화
|
||||
initPartSelect2Ajax("#SEARCH_PART_NO", "#SEARCH_PART_NAME", "#SEARCH_PART_OBJID");
|
||||
|
||||
fn_search();
|
||||
});
|
||||
|
||||
@@ -731,12 +734,17 @@ function saveexcelpop() {
|
||||
|
||||
<td class="label"><label for="">품번</label></td>
|
||||
<td>
|
||||
<input type="text" name="SEARCH_PART_NO" id="SEARCH_PART_NO" style="width:250px;">
|
||||
<select name="SEARCH_PART_NO" id="SEARCH_PART_NO" class="select2-part" style="width:250px;">
|
||||
<option value="">품번 선택</option>
|
||||
</select>
|
||||
<input type="hidden" name="SEARCH_PART_OBJID" id="SEARCH_PART_OBJID" value="">
|
||||
</td>
|
||||
|
||||
<td class="label"><label for="">품명</label></td>
|
||||
<td>
|
||||
<input type="text" name="SEARCH_PART_NAME" id="SEARCH_PART_NAME" style="width:250px;">
|
||||
<select name="SEARCH_PART_NAME" id="SEARCH_PART_NAME" class="select2-part" style="width:250px;">
|
||||
<option value="">품명 선택</option>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
@@ -949,8 +949,7 @@ function compareItemFields(before, after) {
|
||||
<td>
|
||||
<input type="text" name="search_part_name" id="search_part_name" style="width: 300px;" value="" readonly>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
<td><label for="search_mbom_part_no">M-BOM 품번</label></td>
|
||||
<td>
|
||||
<input type="text" name="search_mbom_part_no" id="search_mbom_part_no" style="width: 300px;" value="" readonly>
|
||||
|
||||
@@ -41,6 +41,9 @@ $(document).ready(function(){
|
||||
_fnc_datepick(); // 날짜 선택기 초기화
|
||||
$('.select2').select2(); // select2 초기화
|
||||
|
||||
// 품번/품명 Select2 AJAX 초기화
|
||||
initPartSelect2Ajax("#search_part_no", "#search_part_name", "#search_part_objid");
|
||||
|
||||
// Enter 키로 검색
|
||||
$("input").keyup(function(e) {
|
||||
if (e.keyCode == 13) {
|
||||
@@ -660,86 +663,84 @@ function fn_openPurchaseListPopup() {
|
||||
|
||||
<!-- 검색 영역 -->
|
||||
<div id="plmSearchZon">
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 10px 15px; align-items: center;">
|
||||
<!-- 주문유형 -->
|
||||
<div style="display: flex; align-items: center; gap: 5px;">
|
||||
<label for="search_category_cd">주문유형</label>
|
||||
<select name="search_category_cd" id="search_category_cd" style="width:120px" class="select2">
|
||||
<option value="">선택</option>
|
||||
${code_map.category_cd}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 제품구분 -->
|
||||
<div style="display: flex; align-items: center; gap: 5px;">
|
||||
<label for="search_product_cd">제품구분</label>
|
||||
<select name="search_product_cd" id="search_product_cd" style="width:120px" class="select2">
|
||||
<option value="">선택</option>
|
||||
${code_map.product_cd}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 국내/해외 -->
|
||||
<div style="display: flex; align-items: center; gap: 5px;">
|
||||
<label for="search_area_cd">국내/해외</label>
|
||||
<select name="search_area_cd" id="search_area_cd" style="width:100px" class="select2">
|
||||
<option value="">선택</option>
|
||||
<option value="국내">국내</option>
|
||||
<option value="해외">해외</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 고객사 -->
|
||||
<div style="display: flex; align-items: center; gap: 5px;">
|
||||
<label for="search_customer_objid">고객사</label>
|
||||
<select name="search_customer_objid" id="search_customer_objid" style="width:150px" class="select2">
|
||||
<option value="">선택</option>
|
||||
${code_map.customer_cd}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 유/무상 -->
|
||||
<div style="display: flex; align-items: center; gap: 5px;">
|
||||
<label for="search_paid_type">유/무상</label>
|
||||
<select name="search_paid_type" id="search_paid_type" style="width:80px" class="select2">
|
||||
<option value="">선택</option>
|
||||
<option value="paid">유상</option>
|
||||
<option value="free">무상</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- S/N -->
|
||||
<div style="display: flex; align-items: center; gap: 5px;">
|
||||
<label for="search_serial_no">S/N</label>
|
||||
<input type="text" name="search_serial_no" id="search_serial_no" value="" style="width:100px;">
|
||||
</div>
|
||||
|
||||
<!-- 품번 -->
|
||||
<div style="display: flex; align-items: center; gap: 5px;">
|
||||
<label for="search_part_no">품번</label>
|
||||
<input type="text" name="search_part_no" id="search_part_no" value="" style="width:150px;">
|
||||
</div>
|
||||
|
||||
<!-- 품명 -->
|
||||
<div style="display: flex; align-items: center; gap: 5px;">
|
||||
<label for="search_part_name">품명</label>
|
||||
<input type="text" name="search_part_name" id="search_part_name" value="" style="width:150px;">
|
||||
</div>
|
||||
|
||||
<!-- 접수일 -->
|
||||
<div style="display: flex; align-items: center; gap: 5px;">
|
||||
<label>접수일</label>
|
||||
<input type="text" name="search_receipt_date_from" id="search_receipt_date_from" autocomplete="off" value="" class="date_icon" style="width:90px;"> ~
|
||||
<input type="text" name="search_receipt_date_to" id="search_receipt_date_to" autocomplete="off" value="" class="date_icon" style="width:90px;">
|
||||
</div>
|
||||
|
||||
<!-- 요청납기 -->
|
||||
<div style="display: flex; align-items: center; gap: 5px;">
|
||||
<label>요청납기</label>
|
||||
<input type="text" name="search_req_del_date_from" id="search_req_del_date_from" autocomplete="off" value="" class="date_icon" style="width:90px;"> ~
|
||||
<input type="text" name="search_req_del_date_to" id="search_req_del_date_to" autocomplete="off" value="" class="date_icon" style="width:90px;">
|
||||
</div>
|
||||
</div>
|
||||
<table>
|
||||
<tr>
|
||||
<td><label for="search_category_cd">주문유형</label></td>
|
||||
<td>
|
||||
<select name="search_category_cd" id="search_category_cd" style="width:210px" 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="width:210px" 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="width:213px" class="select2" autocomplete="off">
|
||||
<option value="">선택</option>
|
||||
<option value="국내">국내</option>
|
||||
<option value="해외">해외</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 for="search_paid_type">유/무상</label></td>
|
||||
<td>
|
||||
<select name="search_paid_type" id="search_paid_type" style="" class="select2" autocomplete="off">
|
||||
<option value="">선택</option>
|
||||
<option value="paid">유상</option>
|
||||
<option value="free">무상</option>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
<td><label for="search_serial_no">S/N</label></td>
|
||||
<td>
|
||||
<input type="text" name="search_serial_no" id="search_serial_no" value="" style="">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="search_part_no">품번</label></td>
|
||||
<td>
|
||||
<select name="search_part_no" id="search_part_no" class="select2-part" style="width:150px;">
|
||||
<option value="">품번 선택</option>
|
||||
</select>
|
||||
<input type="hidden" name="search_part_objid" id="search_part_objid" value="">
|
||||
</td>
|
||||
|
||||
<td><label for="search_part_name">품명</label></td>
|
||||
<td>
|
||||
<select name="search_part_name" id="search_part_name" class="select2-part" style="width:150px;">
|
||||
<option value="">품명 선택</option>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
<td><label>접수일</label></td>
|
||||
<td>
|
||||
<input type="text" name="search_receipt_date_from" id="search_receipt_date_from" autocomplete="off" value="" class="date_icon" style="width:100px;">~
|
||||
<input type="text" name="search_receipt_date_to" id="search_receipt_date_to" autocomplete="off" value="" class="date_icon" style="width:100px;">
|
||||
</td>
|
||||
|
||||
<td><label>요청납기</label></td>
|
||||
<td>
|
||||
<input type="text" name="search_req_del_date_from" id="search_req_del_date_from" autocomplete="off" value="" class="date_icon" style="width:120px;">~
|
||||
<input type="text" name="search_req_del_date_to" id="search_req_del_date_to" autocomplete="off" value="" class="date_icon" style="width:120px;">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 그리드 영역 -->
|
||||
|
||||
@@ -28,18 +28,68 @@
|
||||
.readonly-field {
|
||||
background-color: #eee !important;
|
||||
}
|
||||
|
||||
/* S/N 입력 필드 placeholder 색상 */
|
||||
#SERIAL_NO::placeholder {
|
||||
color: #999 !important;
|
||||
opacity: 1;
|
||||
}
|
||||
#SERIAL_NO::-webkit-input-placeholder {
|
||||
color: #999 !important;
|
||||
}
|
||||
#SERIAL_NO::-moz-placeholder {
|
||||
color: #999 !important;
|
||||
opacity: 1;
|
||||
}
|
||||
#SERIAL_NO:-ms-input-placeholder {
|
||||
color: #999 !important;
|
||||
}
|
||||
#SERIAL_NO {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<script>
|
||||
// S/N 관리 변수
|
||||
var snList = [];
|
||||
var snCounter = 1;
|
||||
|
||||
$(function(){
|
||||
fnc_datepick();
|
||||
$(".select2").select2();
|
||||
|
||||
// 품번/품명 Select2 AJAX 초기화
|
||||
initPartSelect2();
|
||||
|
||||
// 저장 버튼
|
||||
$("#btnSave").click(function(){
|
||||
fn_save();
|
||||
});
|
||||
|
||||
// S/N 클릭 시 팝업 오픈
|
||||
$("#SERIAL_NO").click(function() {
|
||||
fn_openSnManagePopup();
|
||||
}).attr("placeholder", "클릭하여 S/N 추가").attr("readonly", true);
|
||||
|
||||
// 페이지 로드 시 기존 S/N 데이터가 있으면 파싱
|
||||
var initialSnValue = $("#SERIAL_NO").val();
|
||||
if(initialSnValue && initialSnValue.trim() != '') {
|
||||
var snArray = initialSnValue.split(',');
|
||||
var initialSnList = [];
|
||||
for(var i = 0; i < snArray.length; i++) {
|
||||
if(snArray[i].trim() != '') {
|
||||
initialSnList.push({
|
||||
id: i + 1,
|
||||
value: snArray[i].trim()
|
||||
});
|
||||
}
|
||||
}
|
||||
if(initialSnList.length > 0) {
|
||||
snList = initialSnList;
|
||||
snCounter = initialSnList.length + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 프로젝트번호 변경 시 관련 정보 자동 로드 (Select2 이벤트)
|
||||
$("#PROJECT_NO").on("change select2:select", function(){
|
||||
var projectObjid = $(this).val();
|
||||
@@ -74,6 +124,94 @@ $(function(){
|
||||
<% } %>
|
||||
});
|
||||
|
||||
// 품번/품명 Select2 AJAX 초기화
|
||||
function initPartSelect2() {
|
||||
// 품번 Select2
|
||||
$("#PART_NO").select2({
|
||||
placeholder: "품번 검색...",
|
||||
allowClear: true,
|
||||
width: '100%',
|
||||
minimumInputLength: 1,
|
||||
language: {
|
||||
inputTooShort: function() { return "1글자 이상 입력하세요"; },
|
||||
searching: function() { return "검색 중..."; },
|
||||
noResults: function() { return "검색 결과가 없습니다"; }
|
||||
},
|
||||
ajax: {
|
||||
url: '/contractMgmt/searchPartList.do',
|
||||
dataType: 'json',
|
||||
type: 'POST',
|
||||
delay: 250,
|
||||
data: function(params) { return { searchTerm: params.term }; },
|
||||
processResults: function(data) {
|
||||
return {
|
||||
results: $.map(data, function(item) {
|
||||
return {
|
||||
id: item.PART_NO || item.part_no,
|
||||
text: item.PART_NO || item.part_no,
|
||||
partName: item.PART_NAME || item.part_name,
|
||||
partObjid: item.OBJID || item.objid
|
||||
};
|
||||
})
|
||||
};
|
||||
},
|
||||
cache: true
|
||||
}
|
||||
}).on('select2:select', function(e) {
|
||||
var data = e.params.data;
|
||||
// 품명 자동 설정
|
||||
if(data.partName) {
|
||||
// 품명 Select2에 옵션 추가 및 선택
|
||||
var newOption = new Option(data.partName, data.partName, true, true);
|
||||
$("#PART_NAME").append(newOption).trigger('change');
|
||||
}
|
||||
// hidden 필드에 OBJID 저장
|
||||
$("#PART_OBJID").val(data.partObjid);
|
||||
});
|
||||
|
||||
// 품명 Select2
|
||||
$("#PART_NAME").select2({
|
||||
placeholder: "품명 검색...",
|
||||
allowClear: true,
|
||||
width: '100%',
|
||||
minimumInputLength: 1,
|
||||
language: {
|
||||
inputTooShort: function() { return "1글자 이상 입력하세요"; },
|
||||
searching: function() { return "검색 중..."; },
|
||||
noResults: function() { return "검색 결과가 없습니다"; }
|
||||
},
|
||||
ajax: {
|
||||
url: '/contractMgmt/searchPartList.do',
|
||||
dataType: 'json',
|
||||
type: 'POST',
|
||||
delay: 250,
|
||||
data: function(params) { return { searchTerm: params.term }; },
|
||||
processResults: function(data) {
|
||||
return {
|
||||
results: $.map(data, function(item) {
|
||||
return {
|
||||
id: item.PART_NAME || item.part_name,
|
||||
text: item.PART_NAME || item.part_name,
|
||||
partNo: item.PART_NO || item.part_no,
|
||||
partObjid: item.OBJID || item.objid
|
||||
};
|
||||
})
|
||||
};
|
||||
},
|
||||
cache: true
|
||||
}
|
||||
}).on('select2:select', function(e) {
|
||||
var data = e.params.data;
|
||||
// 품번 자동 설정
|
||||
if(data.partNo) {
|
||||
var newOption = new Option(data.partNo, data.partNo, true, true);
|
||||
$("#PART_NO").append(newOption).trigger('change');
|
||||
}
|
||||
// hidden 필드에 OBJID 저장
|
||||
$("#PART_OBJID").val(data.partObjid);
|
||||
});
|
||||
}
|
||||
|
||||
// 날짜 선택기 초기화
|
||||
function fnc_datepick(){
|
||||
var $dateinput = $("input.date_icon");
|
||||
@@ -136,11 +274,19 @@ function fn_loadProjectInfo(projectObjid){
|
||||
$("#CUSTOMER_OBJID").trigger("change.select2");
|
||||
}
|
||||
|
||||
// 품번
|
||||
$("#PART_NO").val(fnc_checkNull(info.part_no));
|
||||
// 품번 (Select2)
|
||||
var partNo = fnc_checkNull(info.part_no);
|
||||
if(partNo != "") {
|
||||
var newOption = new Option(partNo, partNo, true, true);
|
||||
$("#PART_NO").append(newOption).trigger('change');
|
||||
}
|
||||
|
||||
// 품명
|
||||
$("#PART_NAME").val(fnc_checkNull(info.part_name));
|
||||
// 품명 (Select2)
|
||||
var partName = fnc_checkNull(info.part_name);
|
||||
if(partName != "") {
|
||||
var newOption = new Option(partName, partName, true, true);
|
||||
$("#PART_NAME").append(newOption).trigger('change');
|
||||
}
|
||||
|
||||
// 요청납기
|
||||
$("#REQ_DEL_DATE").val(fnc_checkNull(info.req_del_date));
|
||||
@@ -171,8 +317,9 @@ function fn_clearProjectInfo(){
|
||||
$("#PRODUCT_CODE").val("").trigger("change");
|
||||
$("#CATEGORY_CODE").val("").trigger("change");
|
||||
$("#CUSTOMER_OBJID").val("").trigger("change");
|
||||
$("#PART_NO").val("");
|
||||
$("#PART_NAME").val("");
|
||||
$("#PART_NO").val(null).trigger("change");
|
||||
$("#PART_NAME").val(null).trigger("change");
|
||||
$("#PART_OBJID").val("");
|
||||
$("#REQ_DEL_DATE").val("");
|
||||
$("#SERIAL_NO").val("");
|
||||
$("#ORDER_QTY").val("");
|
||||
@@ -277,6 +424,216 @@ function fn_save(){
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ========== S/N 관리 함수 ==========
|
||||
|
||||
// S/N 관리 팝업 열기
|
||||
function fn_openSnManagePopup() {
|
||||
// 기존 데이터 로드
|
||||
var serialNoValue = $("#SERIAL_NO").val();
|
||||
if(serialNoValue && serialNoValue.trim() != '' && snList.length == 0) {
|
||||
var snArray = serialNoValue.split(',');
|
||||
for(var i = 0; i < snArray.length; i++) {
|
||||
if(snArray[i].trim() != '') {
|
||||
snList.push({
|
||||
id: snCounter++,
|
||||
value: snArray[i].trim()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 팝업 HTML 생성
|
||||
var popupHtml = '<div style="padding:10px; color:#333;">';
|
||||
popupHtml += ' <h3 style="margin:0 0 15px 0; text-align:center; color:#333;">S/N 관리</h3>';
|
||||
popupHtml += ' <div id="snListContainer" style="margin-bottom:15px; max-height:300px; overflow-y:auto; color:#333;"></div>';
|
||||
popupHtml += ' <div style="margin-bottom:15px; display:flex; gap:5px;">';
|
||||
popupHtml += ' <input type="text" id="newSnInput" placeholder="S/N 입력" style="flex:1; padding:8px; border:1px solid #ddd; border-radius:4px; color:#333;">';
|
||||
popupHtml += ' <button type="button" onclick="fn_addSn()" class="plm_btns">추가</button>';
|
||||
popupHtml += ' </div>';
|
||||
popupHtml += ' <div style="text-align:center; margin-top:20px; display:flex; gap:10px; justify-content:center;">';
|
||||
popupHtml += ' <button type="button" onclick="fn_openSequentialSnPopup()" class="plm_btns">연속번호생성</button>';
|
||||
popupHtml += ' <button type="button" onclick="fn_confirmSnList()" class="plm_btns">확인</button>';
|
||||
popupHtml += ' <button type="button" onclick="fn_closeSnPopup()" class="plm_btns">취소</button>';
|
||||
popupHtml += ' </div>';
|
||||
popupHtml += '</div>';
|
||||
|
||||
// 팝업 오픈
|
||||
Swal.fire({
|
||||
html: popupHtml,
|
||||
width: '700px',
|
||||
showConfirmButton: false,
|
||||
showCloseButton: true,
|
||||
didOpen: function() {
|
||||
setTimeout(function() {
|
||||
fn_renderSnList();
|
||||
// 엔터키로 추가
|
||||
$("#newSnInput").keypress(function(e) {
|
||||
if(e.which == 13) {
|
||||
fn_addSn();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}, 50);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// S/N 목록 렌더링
|
||||
function fn_renderSnList() {
|
||||
var html = '<table style="width:100%; margin-bottom:10px; border-collapse:collapse; border:1px solid #ddd; color:#333;">';
|
||||
html += '<colgroup><col width="15%"><col width="65%"><col width="20%"></colgroup>';
|
||||
html += '<thead><tr style="background:#f5f5f5; color:#333;">';
|
||||
html += '<th style="padding:10px; border:1px solid #ddd; text-align:center; color:#333;">번호</th>';
|
||||
html += '<th style="padding:10px; border:1px solid #ddd; text-align:center; color:#333;">S/N</th>';
|
||||
html += '<th style="padding:10px; border:1px solid #ddd; text-align:center; color:#333;">삭제</th>';
|
||||
html += '</tr></thead>';
|
||||
html += '<tbody>';
|
||||
|
||||
if(snList.length == 0) {
|
||||
html += '<tr><td colspan="3" style="text-align:center; padding:30px; color:#999; border:1px solid #ddd;">등록된 S/N이 없습니다.</td></tr>';
|
||||
} else {
|
||||
for(var i = 0; i < snList.length; i++) {
|
||||
html += '<tr>';
|
||||
html += '<td style="text-align:center; padding:8px; border:1px solid #ddd; color:#333;">' + (i+1) + '</td>';
|
||||
html += '<td style="padding:8px; border:1px solid #ddd; color:#333;">' + snList[i].value + '</td>';
|
||||
html += '<td style="text-align:center; padding:8px; border:1px solid #ddd;">';
|
||||
html += '<button type="button" onclick="fn_deleteSn(' + snList[i].id + ')" class="plm_btns" style="padding:5px 10px; font-size:12px;">삭제</button>';
|
||||
html += '</td>';
|
||||
html += '</tr>';
|
||||
}
|
||||
}
|
||||
html += '</tbody></table>';
|
||||
|
||||
$("#snListContainer").html(html);
|
||||
}
|
||||
|
||||
// S/N 추가
|
||||
function fn_addSn() {
|
||||
var newSn = $("#newSnInput").val().trim();
|
||||
if(newSn == '') {
|
||||
Swal.fire("S/N을 입력해주세요.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 중복 체크
|
||||
for(var i = 0; i < snList.length; i++) {
|
||||
if(snList[i].value == newSn) {
|
||||
Swal.fire("이미 등록된 S/N입니다.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
snList.push({
|
||||
id: snCounter++,
|
||||
value: newSn
|
||||
});
|
||||
|
||||
$("#newSnInput").val('');
|
||||
fn_renderSnList();
|
||||
}
|
||||
|
||||
// S/N 삭제
|
||||
function fn_deleteSn(id) {
|
||||
for(var i = 0; i < snList.length; i++) {
|
||||
if(snList[i].id == id) {
|
||||
snList.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fn_renderSnList();
|
||||
}
|
||||
|
||||
// S/N 목록 확인 및 적용
|
||||
function fn_confirmSnList() {
|
||||
var snValues = [];
|
||||
for(var i = 0; i < snList.length; i++) {
|
||||
snValues.push(snList[i].value);
|
||||
}
|
||||
|
||||
$("#SERIAL_NO").val(snValues.join(', '));
|
||||
Swal.close();
|
||||
}
|
||||
|
||||
// S/N 팝업 닫기
|
||||
function fn_closeSnPopup() {
|
||||
Swal.close();
|
||||
}
|
||||
|
||||
// 연속번호 생성 팝업
|
||||
function fn_openSequentialSnPopup() {
|
||||
var seqHtml = '<div style="padding:10px; color:#333;">';
|
||||
seqHtml += '<h3 style="margin:0 0 15px 0; text-align:center; color:#333;">연속번호 생성</h3>';
|
||||
seqHtml += '<table style="width:100%; border-collapse:collapse;">';
|
||||
seqHtml += '<tr><td style="padding:8px; text-align:right; width:30%;">접두어:</td>';
|
||||
seqHtml += '<td style="padding:8px;"><input type="text" id="seqPrefix" style="width:100%; padding:5px;" placeholder="예: SN-"></td></tr>';
|
||||
seqHtml += '<tr><td style="padding:8px; text-align:right;">시작번호:</td>';
|
||||
seqHtml += '<td style="padding:8px;"><input type="number" id="seqStart" style="width:100%; padding:5px;" value="1"></td></tr>';
|
||||
seqHtml += '<tr><td style="padding:8px; text-align:right;">종료번호:</td>';
|
||||
seqHtml += '<td style="padding:8px;"><input type="number" id="seqEnd" style="width:100%; padding:5px;" value="10"></td></tr>';
|
||||
seqHtml += '<tr><td style="padding:8px; text-align:right;">자릿수:</td>';
|
||||
seqHtml += '<td style="padding:8px;"><input type="number" id="seqDigits" style="width:100%; padding:5px;" value="3" min="1" max="10"></td></tr>';
|
||||
seqHtml += '</table>';
|
||||
seqHtml += '<div style="text-align:center; margin-top:15px;">';
|
||||
seqHtml += '<button type="button" onclick="fn_generateSequentialSn()" class="plm_btns">생성</button>';
|
||||
seqHtml += '<button type="button" onclick="fn_closeSeqPopup()" class="plm_btns" style="margin-left:10px;">취소</button>';
|
||||
seqHtml += '</div></div>';
|
||||
|
||||
Swal.fire({
|
||||
html: seqHtml,
|
||||
width: '400px',
|
||||
showConfirmButton: false,
|
||||
showCloseButton: true
|
||||
});
|
||||
}
|
||||
|
||||
// 연속번호 생성
|
||||
function fn_generateSequentialSn() {
|
||||
var prefix = $("#seqPrefix").val();
|
||||
var start = parseInt($("#seqStart").val()) || 1;
|
||||
var end = parseInt($("#seqEnd").val()) || 10;
|
||||
var digits = parseInt($("#seqDigits").val()) || 3;
|
||||
|
||||
if(start > end) {
|
||||
Swal.fire("시작번호가 종료번호보다 클 수 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(end - start > 999) {
|
||||
Swal.fire("한 번에 1000개 이상 생성할 수 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
for(var i = start; i <= end; i++) {
|
||||
var numStr = String(i).padStart(digits, '0');
|
||||
var newSn = prefix + numStr;
|
||||
|
||||
// 중복 체크
|
||||
var isDup = false;
|
||||
for(var j = 0; j < snList.length; j++) {
|
||||
if(snList[j].value == newSn) {
|
||||
isDup = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isDup) {
|
||||
snList.push({
|
||||
id: snCounter++,
|
||||
value: newSn
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Swal.close();
|
||||
fn_openSnManagePopup();
|
||||
}
|
||||
|
||||
// 연속번호 팝업 닫기
|
||||
function fn_closeSeqPopup() {
|
||||
Swal.close();
|
||||
fn_openSnManagePopup();
|
||||
}
|
||||
</script>
|
||||
<body>
|
||||
<form name="form1" id="form1" method="post">
|
||||
@@ -353,11 +710,22 @@ function fn_save(){
|
||||
<tr>
|
||||
<td class="input_title"><label>품번<span class="required-mark">*</span></label></td>
|
||||
<td>
|
||||
<input type="text" name="PART_NO" id="PART_NO" value="${resultMap.part_no}">
|
||||
<select name="PART_NO" id="PART_NO" style="width:100%;">
|
||||
<option value="">선택</option>
|
||||
<c:if test="${not empty resultMap.part_no}">
|
||||
<option value="${resultMap.part_no}" selected>${resultMap.part_no}</option>
|
||||
</c:if>
|
||||
</select>
|
||||
<input type="hidden" name="PART_OBJID" id="PART_OBJID" value="${resultMap.part_objid}">
|
||||
</td>
|
||||
<td class="input_title"><label>품명<span class="required-mark">*</span></label></td>
|
||||
<td>
|
||||
<input type="text" name="PART_NAME" id="PART_NAME" value="${resultMap.part_name}">
|
||||
<select name="PART_NAME" id="PART_NAME" style="width:100%;">
|
||||
<option value="">선택</option>
|
||||
<c:if test="${not empty resultMap.part_name}">
|
||||
<option value="${resultMap.part_name}" selected>${resultMap.part_name}</option>
|
||||
</c:if>
|
||||
</select>
|
||||
</td>
|
||||
<td class="input_title"><label>S/N</label></td>
|
||||
<td>
|
||||
|
||||
@@ -13,40 +13,107 @@
|
||||
<title><%=Constants.SYSTEM_NAME%></title>
|
||||
<style>
|
||||
.input_title {border-left:1px solid #ccc; background-color:#f5f5f5; font-weight:bold;}
|
||||
.pmsPopupForm tr:last-child td{border-bottom:1px solid #ccc;}
|
||||
.pmsPopupForm td { padding: 5px 8px; }
|
||||
.required-mark { color: red; font-weight: bold; margin-left: 2px; }
|
||||
.readonly-field { background-color: #eee !important; }
|
||||
/* 공통 버튼 숨기기 */
|
||||
.resetBtn, .excelBtn { display: none !important; }
|
||||
body { min-height: auto !important; }
|
||||
|
||||
/* 정보 테이블 스타일 */
|
||||
.info-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.info-table th {
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px 15px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
width: 12%;
|
||||
}
|
||||
.info-table td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px 15px;
|
||||
text-align: left;
|
||||
width: 21%;
|
||||
}
|
||||
.info-value {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 실적등록 테이블 스타일 */
|
||||
.result-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.result-table th {
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #ccc;
|
||||
padding: 8px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
.result-table td {
|
||||
border: 1px solid #ccc;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
.result-table input[type="text"],
|
||||
.result-table input[type="number"] {
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
border: 1px solid #ddd;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
}
|
||||
.result-table input[type="number"] {
|
||||
text-align: right;
|
||||
}
|
||||
.result-table .total-row {
|
||||
background-color: #f8f9fa;
|
||||
font-weight: bold;
|
||||
}
|
||||
.result-table .total-row td {
|
||||
padding: 10px 5px;
|
||||
}
|
||||
.result-table .total-label {
|
||||
background-color: #e9ecef;
|
||||
font-weight: bold;
|
||||
}
|
||||
.result-table .total-value {
|
||||
color: #0066cc;
|
||||
font-weight: bold;
|
||||
}
|
||||
.result-table .delete-btn {
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 3px 8px;
|
||||
cursor: pointer;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.result-table .delete-btn:hover {
|
||||
background-color: #c82333;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<script type="text/javascript" src="/js/tabulator/tabulator_custom.js"></script>
|
||||
<script>
|
||||
var grid;
|
||||
<script type="text/javascript">
|
||||
var _projectObjid = "${param.projectObjid}";
|
||||
var _resultType = "${param.resultType}";
|
||||
|
||||
// 실적유형 목록
|
||||
var _RESULT_TYPE_LIST = [
|
||||
{"CODE": "ASSEMBLY", "NAME": "완조립"},
|
||||
{"CODE": "INSPECTION", "NAME": "검사"},
|
||||
{"CODE": "SHIP_WAIT", "NAME": "출하대기"}
|
||||
];
|
||||
var _rowIndex = 0;
|
||||
|
||||
$(function(){
|
||||
fnc_datepick();
|
||||
$(".select2").select2();
|
||||
|
||||
// 프로젝트 정보 로드
|
||||
if(_projectObjid) {
|
||||
fn_loadProjectInfo();
|
||||
}
|
||||
|
||||
// 그리드 초기화
|
||||
fn_initGrid();
|
||||
|
||||
// 실적 목록 조회
|
||||
fn_search();
|
||||
|
||||
@@ -55,11 +122,6 @@ $(function(){
|
||||
fn_addRow();
|
||||
});
|
||||
|
||||
// 행삭제 버튼
|
||||
$("#btnDelRow").click(function(){
|
||||
fn_delRow();
|
||||
});
|
||||
|
||||
// 저장 버튼
|
||||
$("#btnSave").click(function(){
|
||||
fn_save();
|
||||
@@ -68,14 +130,13 @@ $(function(){
|
||||
|
||||
// 날짜 선택기 초기화
|
||||
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
|
||||
$(document).on('focus', '.date-input', function(){
|
||||
$(this).datepicker({
|
||||
changeMonth: true,
|
||||
changeYear: true,
|
||||
dateFormat: 'yy-mm-dd'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 프로젝트 정보 로드
|
||||
@@ -87,136 +148,152 @@ function fn_loadProjectInfo() {
|
||||
dataType: "json",
|
||||
async: false,
|
||||
success: function(data){
|
||||
console.log("프로젝트 정보 응답:", data);
|
||||
if(data && data.result == "success" && data.info){
|
||||
var info = data.info;
|
||||
$("#PROJECT_NO").text(fnc_checkNull(info.project_no));
|
||||
$("#PART_NO").text(fnc_checkNull(info.part_no));
|
||||
$("#PART_NAME").text(fnc_checkNull(info.part_name));
|
||||
$("#ORDER_QTY").text(fnc_checkNull(info.order_qty));
|
||||
console.log("info 데이터:", info);
|
||||
|
||||
// 대소문자 모두 체크
|
||||
var partNo = info.part_no || info.PART_NO || '-';
|
||||
var partName = info.part_name || info.PART_NAME || '-';
|
||||
var orderQty = info.order_qty || info.ORDER_QTY || 0;
|
||||
var extraProdQty = info.extra_prod_qty || info.EXTRA_PROD_QTY || 0;
|
||||
|
||||
$("#PART_NO").text(partNo);
|
||||
$("#PART_NAME").text(partName);
|
||||
$("#ORDER_QTY").text(fnc_formatNumber(orderQty));
|
||||
$("#EXTRA_PROD_QTY").text(fnc_formatNumber(extraProdQty));
|
||||
|
||||
// 총생산수량 = 수주수량 + 추가생산수량
|
||||
var orderQtyNum = parseInt(orderQty) || 0;
|
||||
var extraProdQtyNum = parseInt(extraProdQty) || 0;
|
||||
$("#TOTAL_PROD_QTY").text(fnc_formatNumber(orderQtyNum + extraProdQtyNum));
|
||||
}
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
console.error("프로젝트 정보 조회 실패:", error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 그리드 컬럼 정의
|
||||
var columns = [
|
||||
{formatter:"rowSelection", titleFormatter:"rowSelection", headerHozAlign:'center', hozAlign:"center", headerSort:false, width:30},
|
||||
{title:'OBJID', field:'OBJID', visible: false},
|
||||
{title:'실적유형', field:'RESULT_TYPE', headerHozAlign:'center', hozAlign:'center', width:100,
|
||||
editor: "list",
|
||||
editorParams: {
|
||||
values: {"ASSEMBLY":"완조립", "INSPECTION":"검사", "SHIP_WAIT":"출하대기"}
|
||||
},
|
||||
formatter: function(cell) {
|
||||
var val = cell.getValue();
|
||||
if(val == 'ASSEMBLY') return '완조립';
|
||||
if(val == 'INSPECTION') return '검사';
|
||||
if(val == 'SHIP_WAIT') return '출하대기';
|
||||
return val;
|
||||
}
|
||||
},
|
||||
{title:'실적일자', field:'RESULT_DATE', headerHozAlign:'center', hozAlign:'center', width:110,
|
||||
editor: "input"
|
||||
},
|
||||
{title:'실적수량', field:'RESULT_QTY', headerHozAlign:'center', hozAlign:'right', width:90,
|
||||
editor: "number",
|
||||
formatter: "money", formatterParams: {thousand:",", precision:false}
|
||||
},
|
||||
{title:'S/N', field:'SERIAL_NO', headerHozAlign:'center', hozAlign:'left', width:120,
|
||||
editor: "input"
|
||||
},
|
||||
{title:'작업자', field:'WORKER_NAME', headerHozAlign:'center', hozAlign:'center', width:100,
|
||||
editor: "input"
|
||||
},
|
||||
{title:'비고', field:'REMARK', headerHozAlign:'center', hozAlign:'left', minWidth:150,
|
||||
editor: "input"
|
||||
}
|
||||
];
|
||||
|
||||
// 그리드 초기화
|
||||
function fn_initGrid() {
|
||||
grid = new Tabulator("#grid", {
|
||||
layout: "fitColumns",
|
||||
height: "calc(100vh - 200px)",
|
||||
columns: columns,
|
||||
data: [],
|
||||
selectableRows: true,
|
||||
placeholder: "데이터가 없습니다."
|
||||
});
|
||||
// 숫자 포맷팅
|
||||
function fnc_formatNumber(num) {
|
||||
if(num == null || num == '') return '0';
|
||||
return parseInt(num).toLocaleString();
|
||||
}
|
||||
|
||||
// 실적 목록 조회
|
||||
function fn_search() {
|
||||
var params = {
|
||||
projectObjid: _projectObjid,
|
||||
resultType: _resultType
|
||||
projectObjid: _projectObjid
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
url: "/productionplanning/getProdResultList.do",
|
||||
url: "/productionplanning/getProdResultListByDate.do",
|
||||
type: "POST",
|
||||
data: params,
|
||||
dataType: "json",
|
||||
success: function(data){
|
||||
if(data && data.list) {
|
||||
grid.setData(data.list);
|
||||
console.log("실적 데이터 응답:", data);
|
||||
if(data && data.list && data.list.length > 0) {
|
||||
// 기존 데이터 로드
|
||||
for(var i = 0; i < data.list.length; i++) {
|
||||
var row = data.list[i];
|
||||
// 대소문자 모두 체크
|
||||
var resultDate = row.result_date || row.RESULT_DATE || '';
|
||||
var assemblyQty = row.assembly_qty || row.ASSEMBLY_QTY || 0;
|
||||
var inspectionQty = row.inspection_qty || row.INSPECTION_QTY || 0;
|
||||
var shipWaitQty = row.ship_wait_qty || row.SHIP_WAIT_QTY || 0;
|
||||
fn_addRow(resultDate, assemblyQty, inspectionQty, shipWaitQty);
|
||||
}
|
||||
} else {
|
||||
// 데이터 없으면 빈 행 하나 추가
|
||||
fn_addRow();
|
||||
}
|
||||
fn_updateTotals();
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
console.error("실적 조회 실패:", error);
|
||||
fn_addRow();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 행 추가
|
||||
function fn_addRow() {
|
||||
var newRow = {
|
||||
OBJID: '',
|
||||
RESULT_TYPE: _resultType || 'ASSEMBLY',
|
||||
RESULT_DATE: '${today}',
|
||||
RESULT_QTY: '',
|
||||
SERIAL_NO: '',
|
||||
WORKER_NAME: '${connectUserName}',
|
||||
REMARK: ''
|
||||
};
|
||||
grid.addRow(newRow);
|
||||
function fn_addRow(resultDate, assemblyQty, inspectionQty, shipWaitQty) {
|
||||
_rowIndex++;
|
||||
var today = '${today}';
|
||||
|
||||
var html = '<tr id="row_' + _rowIndex + '" data-row-index="' + _rowIndex + '">';
|
||||
html += '<td><input type="text" class="date-input" name="RESULT_DATE_' + _rowIndex + '" value="' + (resultDate || today) + '" placeholder="YYYY-MM-DD"></td>';
|
||||
html += '<td><input type="number" class="qty-input assembly-qty" name="ASSEMBLY_QTY_' + _rowIndex + '" value="' + (assemblyQty || 0) + '" min="0" onchange="fn_updateTotals()"></td>';
|
||||
html += '<td><input type="number" class="qty-input inspection-qty" name="INSPECTION_QTY_' + _rowIndex + '" value="' + (inspectionQty || 0) + '" min="0" onchange="fn_updateTotals()"></td>';
|
||||
html += '<td><input type="number" class="qty-input ship-wait-qty" name="SHIP_WAIT_QTY_' + _rowIndex + '" value="' + (shipWaitQty || 0) + '" min="0" onchange="fn_updateTotals()"></td>';
|
||||
html += '<td><button type="button" class="delete-btn" onclick="fn_deleteRow(' + _rowIndex + ')">삭제</button></td>';
|
||||
html += '</tr>';
|
||||
|
||||
$("#resultTableBody").append(html);
|
||||
fn_updateTotals();
|
||||
}
|
||||
|
||||
// 행 삭제
|
||||
function fn_delRow() {
|
||||
var selectedRows = grid.getSelectedRows();
|
||||
if(selectedRows.length === 0) {
|
||||
Swal.fire('삭제할 행을 선택해주세요.');
|
||||
return;
|
||||
}
|
||||
function fn_deleteRow(rowIndex) {
|
||||
$("#row_" + rowIndex).remove();
|
||||
fn_updateTotals();
|
||||
}
|
||||
|
||||
// 총수량 업데이트
|
||||
function fn_updateTotals() {
|
||||
var totalAssembly = 0;
|
||||
var totalInspection = 0;
|
||||
var totalShipWait = 0;
|
||||
|
||||
selectedRows.forEach(function(row) {
|
||||
row.delete();
|
||||
$(".assembly-qty").each(function() {
|
||||
totalAssembly += parseInt($(this).val()) || 0;
|
||||
});
|
||||
$(".inspection-qty").each(function() {
|
||||
totalInspection += parseInt($(this).val()) || 0;
|
||||
});
|
||||
$(".ship-wait-qty").each(function() {
|
||||
totalShipWait += parseInt($(this).val()) || 0;
|
||||
});
|
||||
|
||||
$("#TOTAL_ASSEMBLY").text(totalAssembly.toLocaleString());
|
||||
$("#TOTAL_INSPECTION").text(totalInspection.toLocaleString());
|
||||
$("#TOTAL_SHIP_WAIT").text(totalShipWait.toLocaleString());
|
||||
}
|
||||
|
||||
// 저장
|
||||
function fn_save() {
|
||||
var allData = grid.getData();
|
||||
var resultList = [];
|
||||
|
||||
if(allData.length === 0) {
|
||||
$("#resultTableBody tr").each(function() {
|
||||
var rowIndex = $(this).data('row-index');
|
||||
var resultDate = $("input[name='RESULT_DATE_" + rowIndex + "']").val();
|
||||
var assemblyQty = parseInt($("input[name='ASSEMBLY_QTY_" + rowIndex + "']").val()) || 0;
|
||||
var inspectionQty = parseInt($("input[name='INSPECTION_QTY_" + rowIndex + "']").val()) || 0;
|
||||
var shipWaitQty = parseInt($("input[name='SHIP_WAIT_QTY_" + rowIndex + "']").val()) || 0;
|
||||
|
||||
if(resultDate) {
|
||||
resultList.push({
|
||||
RESULT_DATE: resultDate,
|
||||
ASSEMBLY_QTY: assemblyQty,
|
||||
INSPECTION_QTY: inspectionQty,
|
||||
SHIP_WAIT_QTY: shipWaitQty
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if(resultList.length === 0) {
|
||||
Swal.fire('저장할 데이터가 없습니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 유효성 검사
|
||||
for(var i = 0; i < allData.length; i++) {
|
||||
var row = allData[i];
|
||||
if(!row.RESULT_TYPE) {
|
||||
Swal.fire('실적유형을 선택해주세요. (행 ' + (i+1) + ')');
|
||||
return;
|
||||
}
|
||||
for(var i = 0; i < resultList.length; i++) {
|
||||
var row = resultList[i];
|
||||
if(!row.RESULT_DATE) {
|
||||
Swal.fire('실적일자를 입력해주세요. (행 ' + (i+1) + ')');
|
||||
return;
|
||||
}
|
||||
if(!row.RESULT_QTY || row.RESULT_QTY <= 0) {
|
||||
Swal.fire('실적수량을 입력해주세요. (행 ' + (i+1) + ')');
|
||||
Swal.fire('날짜를 입력해주세요. (행 ' + (i+1) + ')');
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -224,12 +301,12 @@ function fn_save() {
|
||||
if(!confirm('저장하시겠습니까?')) return;
|
||||
|
||||
$.ajax({
|
||||
url: "/productionplanning/saveProdResultList.do",
|
||||
url: "/productionplanning/saveProdResultByDate.do",
|
||||
type: "POST",
|
||||
contentType: "application/json",
|
||||
data: JSON.stringify({
|
||||
projectObjid: _projectObjid,
|
||||
resultList: allData
|
||||
resultList: resultList
|
||||
}),
|
||||
dataType: "json",
|
||||
success: function(data){
|
||||
@@ -238,7 +315,7 @@ function fn_save() {
|
||||
if(opener && opener.fn_search) {
|
||||
opener.fn_search();
|
||||
}
|
||||
fn_search(); // 새로고침
|
||||
window.close(); // 저장 성공 시 자동 닫기
|
||||
} else {
|
||||
Swal.fire(data.msg || "저장에 실패했습니다.");
|
||||
}
|
||||
@@ -260,42 +337,77 @@ window.addEventListener('unload', function() {
|
||||
<body style="overflow-x: hidden;">
|
||||
<form name="form1" id="form1" method="post">
|
||||
<input type="hidden" name="PROJECT_OBJID" id="PROJECT_OBJID" value="${param.projectObjid}">
|
||||
<input type="hidden" name="RESULT_TYPE" id="RESULT_TYPE_HIDDEN" value="${param.resultType}">
|
||||
|
||||
<section>
|
||||
<div class="plm_menu_name" style="display:flex;">
|
||||
<h2 style="width:100%;height:50px;text-align:center;margin-top:10px;">
|
||||
<span style="font-size:20px;">생산실적 등록/수정</span>
|
||||
<span style="font-size:20px;">생산실적 등록</span>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<!-- 프로젝트 정보 표시 -->
|
||||
<div style="padding:10px; background:#f5f5f5; border-bottom:1px solid #ddd;">
|
||||
<table style="width:100%;">
|
||||
<div style="padding:10px 10px 0 10px;">
|
||||
<table class="info-table">
|
||||
<colgroup>
|
||||
<col width="15%" />
|
||||
<col width="35%" />
|
||||
<col width="15%" />
|
||||
<col width="35%" />
|
||||
</colgroup>
|
||||
<tr>
|
||||
<td style="width:70px; font-weight:bold;">프로젝트:</td>
|
||||
<td style="width:150px;"><span id="PROJECT_NO">-</span></td>
|
||||
<td style="width:50px; font-weight:bold;">품번:</td>
|
||||
<td style="width:150px;"><span id="PART_NO">-</span></td>
|
||||
<td style="width:50px; font-weight:bold;">품명:</td>
|
||||
<td><span id="PART_NAME">-</span></td>
|
||||
<td style="width:70px; font-weight:bold;">수주수량:</td>
|
||||
<td style="width:70px;"><span id="ORDER_QTY">-</span></td>
|
||||
<th>품번 <span style="color:red;">*</span></th>
|
||||
<td><span id="PART_NO" class="info-value">-</span></td>
|
||||
<th>품명 <span style="color:red;">*</span></th>
|
||||
<td><span id="PART_NAME" class="info-value">-</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>수주수량 <span style="color:red;">*</span></th>
|
||||
<td><span id="ORDER_QTY" class="info-value">0</span></td>
|
||||
<th>추가생산수량 <span style="color:red;">*</span></th>
|
||||
<td><span id="EXTRA_PROD_QTY" class="info-value">0</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>총생산수량 <span style="color:red;">*</span></th>
|
||||
<td colspan="3"><span id="TOTAL_PROD_QTY" class="info-value" style="color:#0066cc;">0</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="plm_menu_name_gdnsi">
|
||||
<h2><span>실적 목록</span></h2>
|
||||
<div class="btnArea">
|
||||
<div class="plm_menu_name_gdnsi" style="display:flex; justify-content:space-between; align-items:center; padding:0 10px; margin:10px 0;">
|
||||
<h2 style="margin:0;"><span>실적등록</span></h2>
|
||||
<div class="btnArea" style="margin:0;">
|
||||
<input type="button" value="행추가" class="plm_btns" id="btnAddRow">
|
||||
<input type="button" value="행삭제" class="plm_btns" id="btnDelRow">
|
||||
<input type="button" value="저장" class="plm_btns" id="btnSave">
|
||||
<input type="button" value="닫기" class="plm_btns" onclick="window.close();">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="grid" style="margin: 10px;"></div>
|
||||
<!-- 실적등록 테이블 -->
|
||||
<div style="padding: 0 10px 10px 10px;">
|
||||
<table class="result-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:150px;">날짜</th>
|
||||
<th style="width:120px;">완조립</th>
|
||||
<th style="width:120px;">검사</th>
|
||||
<th style="width:120px;">출하대기</th>
|
||||
<th style="width:60px;">삭제</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="resultTableBody">
|
||||
<!-- 동적으로 행 추가 -->
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr class="total-row">
|
||||
<td class="total-label">총수량</td>
|
||||
<td class="total-value"><span id="TOTAL_ASSEMBLY">0</span></td>
|
||||
<td class="total-value"><span id="TOTAL_INSPECTION">0</span></td>
|
||||
<td class="total-value"><span id="TOTAL_SHIP_WAIT">0</span></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
</body>
|
||||
|
||||
@@ -46,8 +46,11 @@ var resultGrid;
|
||||
var grid;
|
||||
// 입력 행 번호
|
||||
var rowSeq = 0;
|
||||
// M-BOM 옵션 데이터
|
||||
var mbomOptionsData = {};
|
||||
// M-BOM 옵션 데이터 (셀렉트박스용) - 배열로 순서 보장
|
||||
var mbomOptionsData = [];
|
||||
var mbomOptionsMap = {};
|
||||
// M-BOM 품명 데이터 (OBJID -> PART_NAME 매핑)
|
||||
var mbomPartNameData = {};
|
||||
|
||||
$(document).ready(function(){
|
||||
$('.select2').select2();
|
||||
@@ -79,15 +82,26 @@ $(document).ready(function(){
|
||||
|
||||
// M-BOM 옵션 데이터 초기화
|
||||
function fn_initMbomOptions() {
|
||||
mbomOptionsData = {"": "선택"};
|
||||
// 배열로 순서 보장 - "선택"을 맨 위에
|
||||
mbomOptionsData = [{label: "선택", value: ""}];
|
||||
mbomOptionsMap = {"": "선택"};
|
||||
|
||||
$("#MBOM_SELECT_HIDDEN option").each(function(){
|
||||
var val = $(this).val();
|
||||
var text = $(this).text();
|
||||
if(val !== '') {
|
||||
mbomOptionsData[val] = text;
|
||||
mbomOptionsData.push({label: text, value: val});
|
||||
mbomOptionsMap[val] = text;
|
||||
}
|
||||
});
|
||||
|
||||
// M-BOM 품명 데이터 초기화 (서버에서 전달받은 데이터)
|
||||
<c:forEach var="item" items="${mbom_part_name_list}">
|
||||
mbomPartNameData["${item.OBJID}"] = "${item.PART_NAME}";
|
||||
</c:forEach>
|
||||
|
||||
console.log("M-BOM 옵션:", mbomOptionsData);
|
||||
console.log("M-BOM 품명:", mbomPartNameData);
|
||||
}
|
||||
|
||||
// 입력 그리드 초기화
|
||||
@@ -133,15 +147,15 @@ function fn_initInputGrid() {
|
||||
},
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
return mbomOptionsData[value] || "";
|
||||
return mbomOptionsMap[value] || "";
|
||||
},
|
||||
cellEdited: function(cell) {
|
||||
// M-BOM 선택 시 품명 자동 입력
|
||||
// M-BOM 선택 시 품명 자동 입력 (MBOM_HEADER.PART_NAME 사용)
|
||||
var mbomObjid = cell.getValue();
|
||||
var row = cell.getRow();
|
||||
if(mbomObjid) {
|
||||
var mbomName = mbomOptionsData[mbomObjid] || "";
|
||||
row.update({PART_NAME: mbomName});
|
||||
var partName = mbomPartNameData[mbomObjid] || "";
|
||||
row.update({PART_NAME: partName});
|
||||
} else {
|
||||
row.update({PART_NAME: ""});
|
||||
}
|
||||
|
||||
@@ -46,8 +46,11 @@ var resultGrid;
|
||||
var grid;
|
||||
// 입력 행 번호
|
||||
var rowSeq = 0;
|
||||
// M-BOM 옵션 데이터
|
||||
var mbomOptionsData = {};
|
||||
// M-BOM 옵션 데이터 (셀렉트박스용) - 배열로 순서 보장
|
||||
var mbomOptionsData = [];
|
||||
var mbomOptionsMap = {};
|
||||
// M-BOM 품명 데이터 (OBJID -> PART_NAME 매핑)
|
||||
var mbomPartNameData = {};
|
||||
|
||||
$(document).ready(function(){
|
||||
$('.select2').select2();
|
||||
@@ -79,15 +82,26 @@ $(document).ready(function(){
|
||||
|
||||
// M-BOM 옵션 데이터 초기화
|
||||
function fn_initMbomOptions() {
|
||||
mbomOptionsData = {"": "선택"};
|
||||
// 배열로 순서 보장 - "선택"을 맨 위에
|
||||
mbomOptionsData = [{label: "선택", value: ""}];
|
||||
mbomOptionsMap = {"": "선택"};
|
||||
|
||||
$("#MBOM_SELECT_HIDDEN option").each(function(){
|
||||
var val = $(this).val();
|
||||
var text = $(this).text();
|
||||
if(val !== '') {
|
||||
mbomOptionsData[val] = text;
|
||||
mbomOptionsData.push({label: text, value: val});
|
||||
mbomOptionsMap[val] = text;
|
||||
}
|
||||
});
|
||||
|
||||
// M-BOM 품명 데이터 초기화 (서버에서 전달받은 데이터)
|
||||
<c:forEach var="item" items="${mbom_part_name_list}">
|
||||
mbomPartNameData["${item.OBJID}"] = "${item.PART_NAME}";
|
||||
</c:forEach>
|
||||
|
||||
console.log("M-BOM 옵션:", mbomOptionsData);
|
||||
console.log("M-BOM 품명:", mbomPartNameData);
|
||||
}
|
||||
|
||||
// 입력 그리드 초기화
|
||||
@@ -133,15 +147,15 @@ function fn_initInputGrid() {
|
||||
},
|
||||
formatter: function(cell) {
|
||||
var value = cell.getValue();
|
||||
return mbomOptionsData[value] || "";
|
||||
return mbomOptionsMap[value] || "";
|
||||
},
|
||||
cellEdited: function(cell) {
|
||||
// M-BOM 선택 시 품명 자동 입력
|
||||
// M-BOM 선택 시 품명 자동 입력 (MBOM_HEADER.PART_NAME 사용)
|
||||
var mbomObjid = cell.getValue();
|
||||
var row = cell.getRow();
|
||||
if(mbomObjid) {
|
||||
var mbomName = mbomOptionsData[mbomObjid] || "";
|
||||
row.update({PART_NAME: mbomName});
|
||||
var partName = mbomPartNameData[mbomObjid] || "";
|
||||
row.update({PART_NAME: partName});
|
||||
} else {
|
||||
row.update({PART_NAME: ""});
|
||||
}
|
||||
|
||||
@@ -53,6 +53,9 @@ String connector = person.getUserId();
|
||||
$(document).ready(function(){
|
||||
$('.select2').select2();
|
||||
|
||||
// 품번/품명 Select2 AJAX 초기화
|
||||
initPartSelect2Ajax("#product_item_code", "#product_item_name", "#search_part_objid");
|
||||
|
||||
// 요청납기일 datepicker 적용
|
||||
$('#contract_start_date, #contract_end_date').datepicker({
|
||||
changeMonth: true,
|
||||
@@ -279,12 +282,17 @@ function openProjectFormPopUp(objId){
|
||||
|
||||
<td><label for="product_item_code">품번</label></td>
|
||||
<td>
|
||||
<input type="text" name="product_item_code" id="product_item_code" style="width:150px;" autocomplete="off" value="${param.product_item_code}">
|
||||
<select name="product_item_code" id="product_item_code" class="select2-part" style="width:150px;">
|
||||
<option value="">품번 선택</option>
|
||||
</select>
|
||||
<input type="hidden" name="search_part_objid" id="search_part_objid" value="">
|
||||
</td>
|
||||
|
||||
<td><label for="product_item_name">품명</label></td>
|
||||
<td>
|
||||
<input type="text" name="product_item_name" id="product_item_name" style="width:150px;" autocomplete="off" value="${param.product_item_name}">
|
||||
<select name="product_item_name" id="product_item_name" class="select2-part" style="width:150px;">
|
||||
<option value="">품명 선택</option>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
<td><label for="serial_no">S/N</label></td>
|
||||
|
||||
@@ -48,6 +48,9 @@ $(document).ready(function(){
|
||||
$('.select2').select2();
|
||||
fnc_datepick();
|
||||
|
||||
// 품번/품명 Select2 AJAX 초기화
|
||||
initPartSelect2Ajax("#SEARCH_PART_NO", "#SEARCH_PART_NAME", "#SEARCH_PART_OBJID");
|
||||
|
||||
$("input").keyup(function(e){
|
||||
if(e.keyCode == 13){
|
||||
$("#page").val("1");
|
||||
@@ -86,7 +89,9 @@ $(document).ready(function(){
|
||||
var columns = [
|
||||
// 요구사항: 품의서 No, 발주서 No, 프로젝트번호, 품번, 품명, 공급업체, 발주수량, 입고수량, 미입고수량, 검사성적서, 입고결과
|
||||
{title:'TOTAL_SUPPLY_PRICE' ,field:'TOTAL_SUPPLY_PRICE' ,visible:false, frozen:true},
|
||||
{title:'TOTAL_DELIVERY_PRICE' ,field:'TOTAL_DELIVERY_PRICE' ,visible:false, frozen:true},
|
||||
{title:'TOTAL_DELIVERY_PRICE' ,field:'TOTAL_DELIVERY_PRICE' ,visible:false, frozen:true},
|
||||
{title:'TOTAL_NOT_DELIVERY_PRICE',field:'TOTAL_NOT_DELIVERY_PRICE',visible:false, frozen:true},
|
||||
{title:'FORM_TYPE' ,field:'FORM_TYPE' ,visible:false, frozen:true},
|
||||
{headerHozAlign : 'center', hozAlign : 'center', minWidth : 130, widthGrow : 1, title : '품의서 No', field : 'PROPOSAL_NO',
|
||||
formatter: fnc_createGridAnchorTag,
|
||||
cellClick : function(e, cell) {
|
||||
@@ -97,7 +102,8 @@ var columns = [
|
||||
formatter:fnc_createGridAnchorTag,
|
||||
cellClick:function(e, cell){
|
||||
var objId = fnc_checkNull(cell.getData().OBJID);
|
||||
fn_formPopUp(objId);
|
||||
var formType = fnc_checkNull(cell.getData().FORM_TYPE, 'general');
|
||||
fn_formPopUp(objId, formType);
|
||||
}
|
||||
},
|
||||
{headerHozAlign : 'center', hozAlign : 'center', minWidth : 140, widthGrow : 1, title : '프로젝트번호', field : 'PROJECT_NO'},
|
||||
@@ -179,17 +185,18 @@ function fn_calculateTotalAmount(){
|
||||
|
||||
// 현재 그리드에 표시된 데이터 가져오기
|
||||
var data = _tabulGrid.getData();
|
||||
var totalOrderAmount = 0; // 총 발주금액
|
||||
var totalOrderAmount = 0; // 총 발주금액
|
||||
var totalDeliveredAmount = 0; // 입고금액
|
||||
var totalNotDeliveredAmount = 0; // 미입고금액
|
||||
|
||||
if(data.length > 0) {
|
||||
data.forEach(function(row) {
|
||||
var rowTotalPrice = parseFloat(row.TOTAL_SUPPLY_PRICE || 0);
|
||||
// SQL에서 계산된 값 사용
|
||||
var rowSupplyPrice = parseFloat(row.TOTAL_SUPPLY_PRICE || 0);
|
||||
var rowDeliveredPrice = parseFloat(row.TOTAL_DELIVERY_PRICE || 0);
|
||||
var rowNotDeliveredPrice = rowTotalPrice - rowDeliveredPrice;
|
||||
var rowNotDeliveredPrice = parseFloat(row.TOTAL_NOT_DELIVERY_PRICE || 0);
|
||||
|
||||
totalOrderAmount += rowTotalPrice;
|
||||
totalOrderAmount += rowSupplyPrice;
|
||||
totalDeliveredAmount += rowDeliveredPrice;
|
||||
totalNotDeliveredAmount += rowNotDeliveredPrice;
|
||||
});
|
||||
@@ -323,14 +330,36 @@ function fn_deliveryResultPopUp(objId,purchaseOrderNo){
|
||||
fn_centerPopup(popup_width, popup_height, url, target);
|
||||
}
|
||||
|
||||
//등록,수정,뷰
|
||||
function fn_formPopUp(objId){
|
||||
//등록,수정,뷰 - 발주서 타입에 따라 다른 팝업 열기
|
||||
function fn_formPopUp(objId, formType){
|
||||
var popup_width = 1460;
|
||||
var popup_height = 1050;
|
||||
|
||||
var popup_height = 1050;
|
||||
|
||||
// 양식 타입에 따라 다른 팝업 열기
|
||||
formType = fnc_checkNull(formType, 'general');
|
||||
|
||||
var hiddenForm = document.hiddenForm;
|
||||
var target = "purchaseOrderFormPopup_new";
|
||||
var url = "/purchaseOrder/purchaseOrderFormPopup_new.do";
|
||||
var target = "";
|
||||
var url = "";
|
||||
|
||||
if(formType == 'outsourcing'){
|
||||
// 외주가공 발주서 양식
|
||||
target = "purchaseOrderFormPopup_outsourcing";
|
||||
url = "/purchaseOrder/purchaseOrderFormPopup_outsourcing.do";
|
||||
popup_width = 1200;
|
||||
popup_height = 900;
|
||||
} else if(formType == 'general'){
|
||||
// 일반 발주서 양식
|
||||
target = "purchaseOrderFormPopup_general";
|
||||
url = "/purchaseOrder/purchaseOrderFormPopup_general.do";
|
||||
popup_width = 1000;
|
||||
popup_height = 900;
|
||||
} else {
|
||||
// 기존 발주서 양식 (FORM_TYPE이 없거나 기존 데이터)
|
||||
target = "purchaseOrderFormPopup_new";
|
||||
url = "/purchaseOrder/purchaseOrderFormPopup_new.do";
|
||||
}
|
||||
|
||||
fn_centerPopup(popup_width, popup_height, "", target);
|
||||
|
||||
hiddenForm.PURCHASE_ORDER_MASTER_OBJID.value = objId;
|
||||
@@ -466,7 +495,7 @@ function fn_purchaseClose(){
|
||||
|
||||
<td><label for="project_no">프로젝트번호</label></td>
|
||||
<td>
|
||||
<select name="project_no" id="project_no" style="width:260px;" class="select2" autocomplete="off" multiple="multiple">
|
||||
<select name="project_no" id="project_no" style="width:253px;" class="select2" autocomplete="off" multiple="multiple">
|
||||
<option value="">선택</option>
|
||||
${code_map.project_no}
|
||||
</select>
|
||||
@@ -480,11 +509,13 @@ function fn_purchaseClose(){
|
||||
<td><select name="type" id="type" class="select2" autocomplete="off" style="width:130px;"><option value="">선택</option>${code_map.type}</select></td>
|
||||
--%>
|
||||
<td><label for="">규격</label></td>
|
||||
<td><input type="text" name="SEARCH_PART_SPEC" id="SEARCH_PART_SPEC" autocomplete="off" value="${param.SEARCH_PART_SPEC }" style="width:120px;"/></td>
|
||||
<td><input type="text" name="SEARCH_PART_SPEC" id="SEARCH_PART_SPEC" autocomplete="off" value="${param.SEARCH_PART_SPEC }" style=""/></td>
|
||||
|
||||
<td><label for="">품명</label></td>
|
||||
<td>
|
||||
<input type="text" name="SEARCH_PART_NAME" id="SEARCH_PART_NAME" style="width:130px;" autocomplete="off" value="${param.SEARCH_PART_NAME}">
|
||||
<select name="SEARCH_PART_NAME" id="SEARCH_PART_NAME" class="select2-part" style="">
|
||||
<option value="">품명 선택</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -496,8 +527,8 @@ function fn_purchaseClose(){
|
||||
|
||||
<td class=""><label>입고요청일</label></td>
|
||||
<td>
|
||||
<input type="text" name="delivery_start_date" id="delivery_start_date" style="width:90px;" autocomplete="off" value="${param.delivery_start_date}" class="date_icon">~
|
||||
<input type="text" name="delivery_end_date" id="delivery_end_date" style="width:90px;" autocomplete="off" value="${param.delivery_end_date }" class="date_icon">
|
||||
<input type="text" name="delivery_start_date" id="delivery_start_date" style="width:120px;" autocomplete="off" value="${param.delivery_start_date}" class="date_icon">~
|
||||
<input type="text" name="delivery_end_date" id="delivery_end_date" style="width:120px;" autocomplete="off" value="${param.delivery_end_date }" class="date_icon">
|
||||
</td>
|
||||
|
||||
<td class=""><label>발주일</label></td>
|
||||
@@ -508,7 +539,7 @@ function fn_purchaseClose(){
|
||||
|
||||
<td><label for="">입고결과</label></td>
|
||||
<td>
|
||||
<select name="delivery_status" id="delivery_status" class="select2" autocomplete="off" style="width:130px;">
|
||||
<select name="delivery_status" id="delivery_status" class="select2" autocomplete="off" style="">
|
||||
<option value="">선택</option>
|
||||
<option value="입고중">입고중</option>
|
||||
<option value="입고완료">입고완료</option>
|
||||
@@ -516,7 +547,12 @@ function fn_purchaseClose(){
|
||||
</select>
|
||||
</td>
|
||||
<td><label for="">품번</label></td>
|
||||
<td><input type="text" name="SEARCH_PART_NO" id="SEARCH_PART_NO" autocomplete="off" value="${param.SEARCH_PART_NO }" style="width:120px;"/></td>
|
||||
<td>
|
||||
<select name="SEARCH_PART_NO" id="SEARCH_PART_NO" class="select2-part" style="width:120px;">
|
||||
<option value="">품번 선택</option>
|
||||
</select>
|
||||
<input type="hidden" name="SEARCH_PART_OBJID" id="SEARCH_PART_OBJID" value="">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -42,6 +42,9 @@ $(document).ready(function(){
|
||||
$('.select2').select2();
|
||||
fnc_datepick();
|
||||
|
||||
// 품번/품명 Select2 AJAX 초기화
|
||||
initPartSelect2Ajax("#SEARCH_PART_NO", "#SEARCH_PART_NAME", "#SEARCH_PART_OBJID");
|
||||
|
||||
//조회
|
||||
|
||||
|
||||
@@ -872,12 +875,17 @@ function fn_openMailFormPopup(purchaseOrderObjId){
|
||||
|
||||
<td><label for="">품번</label></td>
|
||||
<td>
|
||||
<input type="text" name="SEARCH_PART_NO" id="SEARCH_PART_NO" style="" autocomplete="off" value="${param.SEARCH_PART_NO}">
|
||||
<select name="SEARCH_PART_NO" id="SEARCH_PART_NO" class="select2-part" style="width:150px;">
|
||||
<option value="">품번 선택</option>
|
||||
</select>
|
||||
<input type="hidden" name="SEARCH_PART_OBJID" id="SEARCH_PART_OBJID" value="">
|
||||
</td>
|
||||
|
||||
<td><label for="">품명</label></td>
|
||||
<td>
|
||||
<input type="text" name="SEARCH_PART_NAME" id="SEARCH_PART_NAME" style="" autocomplete="off" value="${param.SEARCH_PART_NAME}">
|
||||
<select name="SEARCH_PART_NAME" id="SEARCH_PART_NAME" class="select2-part" style="width:150px;">
|
||||
<option value="">품명 선택</option>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
<%-- 발주부품, 발주구분 주석처리
|
||||
|
||||
@@ -147,8 +147,10 @@ function fn_reset(){
|
||||
$("#search_receipt_date_to").val("");
|
||||
$("#search_customer_name").val("");
|
||||
$("#search_model_name").val("");
|
||||
$("#search_product_no").val("");
|
||||
$("#search_product_name").val("");
|
||||
$("#search_part_no").val("");
|
||||
$("#search_part_name").val("");
|
||||
$("#search_serial_no").val("");
|
||||
$("#search_manufacturer").val("");
|
||||
$("#search_blame_decision").val("");
|
||||
@@ -263,7 +265,7 @@ function fn_FileRegist(objId, docType, docTypeName){
|
||||
</td>
|
||||
<td><label>고객사</label></td>
|
||||
<td>
|
||||
<select name="search_customer_objid" id="search_customer_objid" class="select2" autocomplete="off" style="width:180px;">
|
||||
<select name="search_customer_objid" id="search_customer_objid" class="select2" autocomplete="off" style="width:230px;">
|
||||
<option value="">전체</option>
|
||||
${code_map.customer_cd}
|
||||
</select>
|
||||
@@ -276,9 +278,9 @@ function fn_FileRegist(objId, docType, docTypeName){
|
||||
</select>
|
||||
</td> -->
|
||||
<td><label>품번</label></td>
|
||||
<td><input type="text" name="search_product_no" id="search_product_no" style="" autocomplete="off"></td>
|
||||
<td><input type="text" name="search_product_no" id="search_product_no" style="width:150px;" autocomplete="off"></td>
|
||||
<td><label>품명</label></td>
|
||||
<td><input type="text" name="search_product_name" id="search_product_name" style="" autocomplete="off"></td>
|
||||
<td><input type="text" name="search_product_name" id="search_product_name" style="width:150px;" autocomplete="off"></td>
|
||||
<td><label>부품품번</label></td>
|
||||
<td><input type="text" name="search_part_no" id="search_part_no" style="width:215px;" autocomplete="off"></td>
|
||||
<td><label>부품품명</label></td>
|
||||
|
||||
@@ -58,6 +58,9 @@ $(document).ready(function(){
|
||||
$('.select2').select2();
|
||||
fnc_datepick();
|
||||
|
||||
// 품번/품명 Select2 AJAX 초기화
|
||||
initPartSelect2Ajax("#search_part_no", "#search_part_name", "#search_part_objid");
|
||||
|
||||
$("input").keyup(function(e){
|
||||
if(e.keyCode == 13){
|
||||
$("#page").val("1");
|
||||
@@ -239,10 +242,19 @@ function fn_deliveryAcceptanceViewPopUp(objId,DELIVERY_STATUS){
|
||||
</td>
|
||||
|
||||
<td><label for="">품번</label></td>
|
||||
<td><input type="text" name="search_part_no" id="search_part_no" style="width:170px;" autocomplete="off" value="${param.search_part_no}"></td>
|
||||
<td>
|
||||
<select name="search_part_no" id="search_part_no" class="select2-part" style="width:210px;">
|
||||
<option value="">품번 선택</option>
|
||||
</select>
|
||||
<input type="hidden" name="search_part_objid" id="search_part_objid" value="">
|
||||
</td>
|
||||
|
||||
<td><label for="">품명</label></td>
|
||||
<td><input type="text" name="search_part_name" id="search_part_name" style="width:170px;" autocomplete="off" value="${param.search_part_name}"></td>
|
||||
<td>
|
||||
<select name="search_part_name" id="search_part_name" class="select2-part" style="width:210px;">
|
||||
<option value="">품명 선택</option>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
<td><label for="">공급업체</label></td>
|
||||
<td><select name="search_partner" id="search_partner" class="select2" autocomplete="off" style="width:250px;"><option value="">선택</option>${code_map.partner_objid}</select></td>
|
||||
@@ -269,7 +281,7 @@ function fn_deliveryAcceptanceViewPopUp(objId,DELIVERY_STATUS){
|
||||
|
||||
<td><label for="">검사여부</label></td>
|
||||
<td>
|
||||
<select name="search_inspection_yn" id="search_inspection_yn" class="select2" autocomplete="off" style="width:120px;">
|
||||
<select name="search_inspection_yn" id="search_inspection_yn" class="select2" autocomplete="off" style="width:210px;">
|
||||
<option value="">전체</option>
|
||||
<option value="검사">검사</option>
|
||||
<option value="스킵">스킵</option>
|
||||
@@ -278,7 +290,7 @@ function fn_deliveryAcceptanceViewPopUp(objId,DELIVERY_STATUS){
|
||||
|
||||
<td><label for="">요청현황</label></td>
|
||||
<td>
|
||||
<select name="search_request_status" id="search_request_status" class="select2" autocomplete="off" style="width:120px;">
|
||||
<select name="search_request_status" id="search_request_status" class="select2" autocomplete="off" style="width:140px;">
|
||||
<option value="">전체</option>
|
||||
<option value="미요청">미요청</option>
|
||||
<option value="요청중">요청중</option>
|
||||
@@ -287,12 +299,12 @@ function fn_deliveryAcceptanceViewPopUp(objId,DELIVERY_STATUS){
|
||||
</td>
|
||||
|
||||
<td><label for="">요청자</label></td>
|
||||
<td><select name="request_user_id" id="request_user_id" class="select2" autocomplete="off" style="width:120px;"><option value="">선택</option>${code_map.request_user_id}</select></td>
|
||||
<td><select name="request_user_id" id="request_user_id" class="select2" autocomplete="off" style="width:140px;"><option value="">선택</option>${code_map.request_user_id}</select></td>
|
||||
|
||||
<td class=""><label>요청일</label></td>
|
||||
<td>
|
||||
<input type="text" name="request_start_date" id="request_start_date" style="width:100px;" autocomplete="off" value="${param.request_start_date}" class="date_icon">~
|
||||
<input type="text" name="request_end_date" id="request_end_date" style="width:100px;" autocomplete="off" value="${param.request_end_date }" class="date_icon">
|
||||
<input type="text" name="request_start_date" id="request_start_date" style="width:120px;" autocomplete="off" value="${param.request_start_date}" class="date_icon">~
|
||||
<input type="text" name="request_end_date" id="request_end_date" style="width:120px;" autocomplete="off" value="${param.request_end_date }" class="date_icon">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -58,6 +58,9 @@ $(document).ready(function(){
|
||||
$('.select2').select2();
|
||||
fnc_datepick();
|
||||
|
||||
// 품번/품명 Select2 AJAX 초기화
|
||||
initPartSelect2Ajax("#search_part_no", "#search_part_name", "#search_part_objid");
|
||||
|
||||
$("input").keyup(function(e){
|
||||
if(e.keyCode == 13){
|
||||
$("#page").val("1");
|
||||
@@ -300,10 +303,19 @@ function fn_deliveryAcceptanceViewPopUp(objId,DELIVERY_STATUS){
|
||||
</td>
|
||||
|
||||
<td><label for="">품번</label></td>
|
||||
<td><input type="text" name="search_part_no" id="search_part_no" style="width:170px;" autocomplete="off" value="${param.search_part_no}"></td>
|
||||
<td>
|
||||
<select name="search_part_no" id="search_part_no" class="select2-part" style="width:170px;">
|
||||
<option value="">품번 선택</option>
|
||||
</select>
|
||||
<input type="hidden" name="search_part_objid" id="search_part_objid" value="">
|
||||
</td>
|
||||
|
||||
<td><label for="">품명</label></td>
|
||||
<td><input type="text" name="search_part_name" id="search_part_name" style="width:170px;" autocomplete="off" value="${param.search_part_name}"></td>
|
||||
<td>
|
||||
<select name="search_part_name" id="search_part_name" class="select2-part" style="width:170px;">
|
||||
<option value="">품명 선택</option>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
<td><label for="">공급업체</label></td>
|
||||
<td><select name="search_partner" id="search_partner" class="select2" autocomplete="off" style="width:250px;"><option value="">선택</option>${code_map.partner_objid}</select></td>
|
||||
|
||||
@@ -83,6 +83,11 @@ $(document).ready(function(){
|
||||
fn_registPopUp();
|
||||
});
|
||||
|
||||
// 엑셀 다운로드
|
||||
$("#btnExcel").click(function(){
|
||||
fn_excelDownload();
|
||||
});
|
||||
|
||||
fn_search();
|
||||
});
|
||||
|
||||
@@ -169,6 +174,126 @@ function fn_openAttachFilePopUp(objId) {
|
||||
fn_watchPopupClose(popup, objId, 'ATTACH_FILE_CNT', 'PROCESS_INSPECTION_FILE');
|
||||
}
|
||||
|
||||
// 엑셀 다운로드 (전체 데이터 풀어서 - ExcelJS)
|
||||
function fn_excelDownload(){
|
||||
var params = {
|
||||
search_project_no: $("#search_project_no").val() || "",
|
||||
productType: $("#productType").val() || "",
|
||||
search_part_no: $("#search_part_no").val() || "",
|
||||
search_part_name: $("#search_part_name").val() || "",
|
||||
search_inspection_date_from: $("#search_inspection_date_from").val() || "",
|
||||
search_inspection_date_to: $("#search_inspection_date_to").val() || "",
|
||||
search_inspector: $("#search_inspector").val() || "",
|
||||
search_inspection_result: $("#search_inspection_result").val() || ""
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
url: "/quality/getProcessInspectionListForExcel.do",
|
||||
type: "POST",
|
||||
data: params,
|
||||
dataType: "json",
|
||||
success: function(result){
|
||||
console.log("엑셀 데이터:", result);
|
||||
if(result && result.list && result.list.length > 0){
|
||||
fn_createExcelFile(result.list);
|
||||
} else {
|
||||
Swal.fire("다운로드할 데이터가 없습니다.");
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error){
|
||||
console.error("엑셀 데이터 조회 실패:", error);
|
||||
console.error("상태:", status);
|
||||
console.error("응답:", xhr.responseText);
|
||||
Swal.fire("엑셀 데이터 조회 중 오류가 발생했습니다.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ExcelJS로 엑셀 파일 생성 (전체 풀어서)
|
||||
async function fn_createExcelFile(data){
|
||||
try {
|
||||
var pageTitle = "공정검사관리";
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
const worksheet = workbook.addWorksheet(pageTitle);
|
||||
|
||||
// 헤더 설정 (모든 컬럼 포함: 제품구분, 공정명, 부서, 작업자, 디테일비고, 조치현황)
|
||||
var headers = ["No", "검사일", "검사자", "제품구분", "공정명", "프로젝트번호", "품번", "품명",
|
||||
"검사수량", "불량수량", "불량율(%)", "작업환경상태", "측정기", "부서", "작업자", "디테일비고", "조치현황", "검사결과"];
|
||||
|
||||
// 열 너비 설정
|
||||
var colWidths = [6, 12, 12, 15, 12, 18, 18, 22, 12, 12, 10, 14, 10, 12, 12, 15, 12, 10];
|
||||
colWidths.forEach(function(width, idx){
|
||||
worksheet.getColumn(idx + 1).width = width;
|
||||
});
|
||||
|
||||
// 헤더 행 추가
|
||||
var headerRow = worksheet.addRow(headers);
|
||||
|
||||
// 헤더 스타일 (노란색 배경)
|
||||
headerRow.eachCell(function(cell){
|
||||
cell.fill = {
|
||||
type: 'pattern',
|
||||
pattern: 'solid',
|
||||
fgColor: { argb: 'FFFFFF00' } // 노란색
|
||||
};
|
||||
cell.font = { bold: true };
|
||||
cell.alignment = { vertical: 'middle', horizontal: 'center' };
|
||||
cell.border = {
|
||||
top: { style: 'thin' },
|
||||
left: { style: 'thin' },
|
||||
bottom: { style: 'thin' },
|
||||
right: { style: 'thin' }
|
||||
};
|
||||
});
|
||||
|
||||
// 데이터 추가 (모든 컬럼 포함)
|
||||
data.forEach(function(item, index){
|
||||
var row = worksheet.addRow([
|
||||
index + 1,
|
||||
item.inspection_date || item.INSPECTION_DATE || "",
|
||||
item.inspector_name || item.INSPECTOR_NAME || "",
|
||||
item.product_type || item.PRODUCT_TYPE || "",
|
||||
item.process_name || item.PROCESS_NAME || "",
|
||||
item.project_no || item.PROJECT_NO || "",
|
||||
item.part_no || item.PART_NO || "",
|
||||
item.part_name || item.PART_NAME || "",
|
||||
item.inspection_qty || item.INSPECTION_QTY || 0,
|
||||
item.defect_qty || item.DEFECT_QTY || 0,
|
||||
item.defect_rate || item.DEFECT_RATE || 0,
|
||||
item.work_env_status || item.WORK_ENV_STATUS || "",
|
||||
item.measuring_device || item.MEASURING_DEVICE || "",
|
||||
item.dept_name || item.DEPT_NAME || "",
|
||||
item.user_name || item.USER_NAME || "",
|
||||
item.detail_remark || item.DETAIL_REMARK || "",
|
||||
item.action_status || item.ACTION_STATUS || "",
|
||||
item.inspection_result || item.INSPECTION_RESULT || ""
|
||||
]);
|
||||
|
||||
// 데이터 행 스타일
|
||||
row.eachCell(function(cell){
|
||||
cell.border = {
|
||||
top: { style: 'thin' },
|
||||
left: { style: 'thin' },
|
||||
bottom: { style: 'thin' },
|
||||
right: { style: 'thin' }
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
// 파일명 생성
|
||||
var today = new Date();
|
||||
var dateStr = today.getFullYear() + ("0" + (today.getMonth()+1)).slice(-2) + ("0" + today.getDate()).slice(-2);
|
||||
var fileName = pageTitle + "_" + dateStr + ".xlsx";
|
||||
|
||||
// 다운로드
|
||||
const buffer = await workbook.xlsx.writeBuffer();
|
||||
saveAs(new Blob([buffer]), fileName);
|
||||
} catch(e) {
|
||||
console.error("엑셀 생성 오류:", e);
|
||||
Swal.fire("엑셀 파일 생성 중 오류가 발생했습니다.");
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<body>
|
||||
@@ -187,6 +312,7 @@ function fn_openAttachFilePopUp(objId) {
|
||||
<div class="btnArea">
|
||||
<input type="button" class="plm_btns" value="공정검사 등록" id="btnRegist">
|
||||
<input type="button" class="plm_btns" value="조회" id="btnSearch">
|
||||
<input type="button" class="plm_btns" value="Excel Download" id="btnExcel">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -84,9 +84,8 @@ $(document).ready(function(){
|
||||
fn_search();
|
||||
});
|
||||
|
||||
// 엑셀 다운로드 (원본 데이터 - 외 N건 풀어서)
|
||||
// 엑셀 다운로드 (전체 데이터 풀어서 - ExcelJS)
|
||||
function fn_excelDownload(){
|
||||
// 서버에서 원본 데이터 가져오기
|
||||
var params = {
|
||||
search_model_name: $("#search_model_name").val() || "",
|
||||
search_work_order_no: $("#search_work_order_no").val() || "",
|
||||
@@ -102,132 +101,110 @@ function fn_excelDownload(){
|
||||
data: params,
|
||||
dataType: "json",
|
||||
success: function(result){
|
||||
console.log("엑셀 데이터:", result);
|
||||
if(result && result.list && result.list.length > 0){
|
||||
createExcelFile(result.list);
|
||||
fn_createExcelFile(result.list);
|
||||
} else {
|
||||
Swal.fire("다운로드할 데이터가 없습니다.");
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error){
|
||||
console.error("엑셀 데이터 조회 실패:", error);
|
||||
console.error("상태:", status);
|
||||
console.error("응답:", xhr.responseText);
|
||||
Swal.fire("엑셀 데이터 조회 중 오류가 발생했습니다.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ExcelJS로 원본 데이터 엑셀 파일 생성 (공통 스타일 적용)
|
||||
async function createExcelFile(data){
|
||||
var pageTitle = "반제품검사관리";
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
const worksheet = workbook.addWorksheet(pageTitle);
|
||||
|
||||
// 헤더 설정 (컬럼 순서 변경: 검사일, 검사자를 앞으로)
|
||||
var headers = ["No", "검사일", "검사자", "품명(모델명)", "작업지시번호", "부품품번", "부품명",
|
||||
"입고수량 합계", "양품수량 합계", "불량수량 합계", "불량율(%)", "재생수량 합계", "최종양품수량 합계",
|
||||
"불량유형", "불량원인", "귀책부서", "처리현황", "처리결과", "비고"];
|
||||
|
||||
// 열 너비 설정
|
||||
var colWidths = [6, 12, 12, 25, 18, 20, 25, 15, 15, 15, 12, 15, 18, 15, 15, 12, 12, 12, 20];
|
||||
colWidths.forEach(function(width, idx){
|
||||
worksheet.getColumn(idx + 1).width = width;
|
||||
});
|
||||
|
||||
// 제목 행 추가
|
||||
worksheet.mergeCells('A1:S1');
|
||||
var titleCell = worksheet.getCell('A1');
|
||||
titleCell.value = pageTitle;
|
||||
titleCell.font = { size: 16, bold: true };
|
||||
titleCell.alignment = { vertical: 'middle', horizontal: 'center' };
|
||||
worksheet.getRow(1).height = 30;
|
||||
|
||||
// 빈 행 추가
|
||||
worksheet.addRow([]);
|
||||
|
||||
// 헤더 행 추가 (3행)
|
||||
var headerRow = worksheet.addRow(headers);
|
||||
|
||||
// 헤더 스타일 (공통 스타일: 파란색 배경, 흰색 글자)
|
||||
headerRow.eachCell(function(cell){
|
||||
cell.fill = {
|
||||
type: 'pattern',
|
||||
pattern: 'solid',
|
||||
fgColor: { argb: 'FF4472C4' } // 파란색
|
||||
};
|
||||
cell.font = {
|
||||
color: { argb: 'FFFFFFFF' }, // 흰색 글자
|
||||
bold: true
|
||||
};
|
||||
cell.alignment = {
|
||||
vertical: 'middle',
|
||||
horizontal: 'center',
|
||||
wrapText: true
|
||||
};
|
||||
cell.border = {
|
||||
top: { style: 'thin' },
|
||||
left: { style: 'thin' },
|
||||
bottom: { style: 'thin' },
|
||||
right: { style: 'thin' }
|
||||
};
|
||||
});
|
||||
headerRow.height = 25;
|
||||
|
||||
// 데이터 추가 (컬럼 순서 변경: 검사일, 검사자를 앞으로)
|
||||
data.forEach(function(item, index){
|
||||
var row = worksheet.addRow([
|
||||
index + 1,
|
||||
item.inspection_date || item.INSPECTION_DATE || "",
|
||||
item.writer_name || item.WRITER_NAME || "",
|
||||
item.model_name || item.MODEL_NAME || "",
|
||||
item.work_order_no || item.WORK_ORDER_NO || "",
|
||||
item.part_no || item.PART_NO || "",
|
||||
item.part_name || item.PART_NAME || "",
|
||||
item.receipt_qty || item.RECEIPT_QTY || 0,
|
||||
item.good_qty || item.GOOD_QTY || 0,
|
||||
item.defect_qty || item.DEFECT_QTY || 0,
|
||||
item.defect_rate || item.DEFECT_RATE || 0,
|
||||
item.regeneration_qty || item.REGENERATION_QTY || 0,
|
||||
item.final_good_qty || item.FINAL_GOOD_QTY || 0,
|
||||
item.defect_type || item.DEFECT_TYPE || "",
|
||||
item.defect_cause || item.DEFECT_CAUSE || "",
|
||||
item.responsible_dept || item.RESPONSIBLE_DEPT || "",
|
||||
item.process_status || item.PROCESS_STATUS || "",
|
||||
item.disposition_type || item.DISPOSITION_TYPE || "",
|
||||
item.remark || item.REMARK || ""
|
||||
]);
|
||||
// ExcelJS로 엑셀 파일 생성 (전체 풀어서)
|
||||
async function fn_createExcelFile(data){
|
||||
try {
|
||||
var pageTitle = "반제품검사관리";
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
const worksheet = workbook.addWorksheet(pageTitle);
|
||||
|
||||
// 데이터 행 스타일 (테두리)
|
||||
row.eachCell(function(cell, colNumber){
|
||||
// 헤더 설정 (DATA_TYPE, PRODUCT_TYPE, INSPECTION_GROUP_ID 추가)
|
||||
var headers = ["No", "검사일", "검사자", "품명(모델명)", "제품구분", "작업지시번호", "부품품번", "부품명",
|
||||
"입고수량", "양품수량", "불량수량", "불량율(%)", "재생수량", "최종양품수량",
|
||||
"불량유형", "불량원인", "귀책부서", "처리현황", "처리결과", "비고", "데이터타입", "검사그룹ID"];
|
||||
|
||||
// 열 너비 설정
|
||||
var colWidths = [6, 12, 12, 20, 12, 15, 18, 20, 12, 12, 12, 10, 12, 14, 12, 12, 10, 10, 10, 15, 10, 15];
|
||||
colWidths.forEach(function(width, idx){
|
||||
worksheet.getColumn(idx + 1).width = width;
|
||||
});
|
||||
|
||||
// 헤더 행 추가
|
||||
var headerRow = worksheet.addRow(headers);
|
||||
|
||||
// 헤더 스타일 (노란색 배경)
|
||||
headerRow.eachCell(function(cell){
|
||||
cell.fill = {
|
||||
type: 'pattern',
|
||||
pattern: 'solid',
|
||||
fgColor: { argb: 'FFFFFF00' } // 노란색
|
||||
};
|
||||
cell.font = { bold: true };
|
||||
cell.alignment = { vertical: 'middle', horizontal: 'center' };
|
||||
cell.border = {
|
||||
top: { style: 'thin' },
|
||||
left: { style: 'thin' },
|
||||
bottom: { style: 'thin' },
|
||||
right: { style: 'thin' }
|
||||
};
|
||||
// 숫자 컬럼 오른쪽 정렬 (8~13번 컬럼: 수량, 불량율)
|
||||
if(colNumber >= 8 && colNumber <= 13){
|
||||
cell.alignment = { horizontal: 'right' };
|
||||
// 숫자에 천단위 구분자 (불량율 제외)
|
||||
if(colNumber !== 11 && typeof cell.value === 'number'){
|
||||
cell.numFmt = '#,##0';
|
||||
}
|
||||
} else if(colNumber === 1 || colNumber === 2 || colNumber === 3){
|
||||
cell.alignment = { horizontal: 'center' };
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 파일명 생성
|
||||
var date = new Date();
|
||||
var currentDate = date.getFullYear() +
|
||||
("0" + (date.getMonth() + 1)).slice(-2) +
|
||||
("0" + date.getDate()).slice(-2) + "_" +
|
||||
("0" + date.getHours()).slice(-2) +
|
||||
("0" + date.getMinutes()).slice(-2);
|
||||
var fileName = pageTitle + "_" + currentDate + ".xlsx";
|
||||
|
||||
// 다운로드
|
||||
const buffer = await workbook.xlsx.writeBuffer();
|
||||
saveAs(new Blob([buffer]), fileName);
|
||||
|
||||
// 데이터 추가 (DATA_TYPE, PRODUCT_TYPE, INSPECTION_GROUP_ID 추가)
|
||||
data.forEach(function(item, index){
|
||||
var row = worksheet.addRow([
|
||||
index + 1,
|
||||
item.inspection_date || item.INSPECTION_DATE || "",
|
||||
item.writer_name || item.WRITER_NAME || "",
|
||||
item.model_name || item.MODEL_NAME || "",
|
||||
item.product_type || item.PRODUCT_TYPE || "",
|
||||
item.work_order_no || item.WORK_ORDER_NO || "",
|
||||
item.part_no || item.PART_NO || "",
|
||||
item.part_name || item.PART_NAME || "",
|
||||
item.receipt_qty || item.RECEIPT_QTY || 0,
|
||||
item.good_qty || item.GOOD_QTY || 0,
|
||||
item.defect_qty || item.DEFECT_QTY || 0,
|
||||
item.defect_rate || item.DEFECT_RATE || 0,
|
||||
item.regeneration_qty || item.REGENERATION_QTY || 0,
|
||||
item.final_good_qty || item.FINAL_GOOD_QTY || 0,
|
||||
item.defect_type || item.DEFECT_TYPE || "",
|
||||
item.defect_cause || item.DEFECT_CAUSE || "",
|
||||
item.responsible_dept || item.RESPONSIBLE_DEPT || "",
|
||||
item.process_status || item.PROCESS_STATUS || "",
|
||||
item.disposition_type || item.DISPOSITION_TYPE || "",
|
||||
item.remark || item.REMARK || "",
|
||||
item.data_type || item.DATA_TYPE || "",
|
||||
item.inspection_group_id || item.INSPECTION_GROUP_ID || ""
|
||||
]);
|
||||
|
||||
// 데이터 행 스타일
|
||||
row.eachCell(function(cell){
|
||||
cell.border = {
|
||||
top: { style: 'thin' },
|
||||
left: { style: 'thin' },
|
||||
bottom: { style: 'thin' },
|
||||
right: { style: 'thin' }
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
// 파일명 생성
|
||||
var today = new Date();
|
||||
var dateStr = today.getFullYear() + ("0" + (today.getMonth()+1)).slice(-2) + ("0" + today.getDate()).slice(-2);
|
||||
var fileName = pageTitle + "_" + dateStr + ".xlsx";
|
||||
|
||||
// 다운로드
|
||||
const buffer = await workbook.xlsx.writeBuffer();
|
||||
saveAs(new Blob([buffer]), fileName);
|
||||
} catch(e) {
|
||||
console.error("엑셀 생성 오류:", e);
|
||||
Swal.fire("엑셀 파일 생성 중 오류가 발생했습니다.");
|
||||
}
|
||||
}
|
||||
|
||||
// 컬럼: 검사일, 검사자, 품명(모델명), 작업지시번호, 부품품번, 부품명, 입고수량 합계, 양품수량 합계, 불량수량 합계, 불량율, 재생수량 합계, 최종양품수량 합계
|
||||
|
||||
@@ -45,6 +45,9 @@ String menuName = CommonUtils.getMenuName(menuObjId, "구매관리_구매요청
|
||||
$(document).ready(function(){
|
||||
$('.select2').select2();
|
||||
|
||||
// 품번/품명 Select2 AJAX 초기화
|
||||
initPartSelect2Ajax("#SEARCH_PART_NO", "#SEARCH_PART_NAME", "#SEARCH_PART_OBJID");
|
||||
|
||||
$("input[type=text]").keyup(function(e){
|
||||
if(e.keyCode == 13){
|
||||
$("#btnSearch").trigger("click");
|
||||
@@ -710,20 +713,25 @@ function fn_executeCreateProposal(salesRequestObjid, targetParts) {
|
||||
<select name="SEARCH_PRODUCT_CODE" id="SEARCH_PRODUCT_CODE" style="" class="select2" autocomplete="off"></select>
|
||||
</td> -->
|
||||
|
||||
<%-- 품번 활성화 --%>
|
||||
<td class="align_r">
|
||||
<label for="" class="">품번</label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="SEARCH_PART_NO" id="SEARCH_PART_NO" value="${param.SEARCH_PART_NO}" style="width:200px;"/>
|
||||
</td>
|
||||
<%-- 품명 활성화 --%>
|
||||
<td class="align_r">
|
||||
<label for="" class="">품명</label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="SEARCH_PART_NAME" id="SEARCH_PART_NAME" value="${param.SEARCH_PART_NAME}" style="width:200px;"/>
|
||||
</td>
|
||||
<%-- 품번 활성화 --%>
|
||||
<td class="align_r">
|
||||
<label for="" class="">품번</label>
|
||||
</td>
|
||||
<td>
|
||||
<select name="SEARCH_PART_NO" id="SEARCH_PART_NO" class="select2-part" style="width:200px;">
|
||||
<option value="">품번 선택</option>
|
||||
</select>
|
||||
<input type="hidden" name="SEARCH_PART_OBJID" id="SEARCH_PART_OBJID" value="">
|
||||
</td>
|
||||
<%-- 품명 활성화 --%>
|
||||
<td class="align_r">
|
||||
<label for="" class="">품명</label>
|
||||
</td>
|
||||
<td>
|
||||
<select name="SEARCH_PART_NAME" id="SEARCH_PART_NAME" class="select2-part" style="width:200px;">
|
||||
<option value="">품명 선택</option>
|
||||
</select>
|
||||
</td>
|
||||
<%-- 상태 주석처리
|
||||
<td class="align_r">
|
||||
<label for="" class="">상태</label>
|
||||
|
||||
@@ -1223,10 +1223,122 @@ public class ProductionPlanningController extends BaseService {
|
||||
}
|
||||
|
||||
if(mbomDetailList != null && !mbomDetailList.isEmpty()) {
|
||||
// 할당된 E-BOM/M-BOM인 경우: 프로젝트의 PART_OBJID로 PART_MNG에서 파트 정보 조회하여 1레벨로 사용
|
||||
if("ASSIGNED_EBOM".equals(bomDataType) || "ASSIGNED_MBOM".equals(bomDataType)) {
|
||||
String partObjId = CommonUtils.checkNull(projectInfo.get("PART_OBJID"));
|
||||
|
||||
// PART_OBJID가 있으면 PART_MNG 테이블에서 파트 정보 조회
|
||||
String projectPartNo = "";
|
||||
String projectPartName = "";
|
||||
String projectPartObjId = "";
|
||||
|
||||
if(!"".equals(partObjId)) {
|
||||
Map<String, Object> partParam = new HashMap<>();
|
||||
partParam.put("partObjId", partObjId);
|
||||
Map<String, Object> partInfo = commonService.selectOne("partMng.getPartInfoByObjId", request, partParam);
|
||||
|
||||
if(partInfo != null) {
|
||||
projectPartNo = CommonUtils.checkNull(partInfo.get("PART_NO"));
|
||||
projectPartName = CommonUtils.checkNull(partInfo.get("PART_NAME"));
|
||||
projectPartObjId = partObjId;
|
||||
System.out.println("PART_MNG에서 파트 정보 조회 - PART_OBJID: " + partObjId + ", PART_NO: " + projectPartNo + ", PART_NAME: " + projectPartName);
|
||||
}
|
||||
}
|
||||
|
||||
// PART_OBJID로 조회 실패 시 PROJECT_MGMT의 PART_NO, PART_NAME 사용 (fallback)
|
||||
if("".equals(projectPartNo)) {
|
||||
projectPartNo = CommonUtils.checkNull(projectInfo.get("PART_NO"));
|
||||
projectPartName = CommonUtils.checkNull(projectInfo.get("PART_NAME"));
|
||||
System.out.println("PROJECT_MGMT의 파트 정보 사용 (fallback) - PART_NO: " + projectPartNo + ", PART_NAME: " + projectPartName);
|
||||
}
|
||||
|
||||
// 프로젝트에 파트 정보가 있고, PART_OBJID가 유효한 경우에만 1레벨 교체
|
||||
// PART_OBJID가 없으면 외래키 제약조건 위반으로 저장 불가
|
||||
if(!"".equals(projectPartNo) && !"".equals(projectPartName) && !"".equals(projectPartObjId)) {
|
||||
List<Map<String, Object>> newMbomDetailList = new ArrayList<>();
|
||||
|
||||
// 1레벨의 CHILD_OBJID 생성 (부모-자식 관계 연결용)
|
||||
String newLevel1ChildObjid = CommonUtils.createObjId();
|
||||
|
||||
// 1레벨: PART_MNG 테이블의 파트 정보로 생성
|
||||
Map<String, Object> level1Item = new HashMap<>();
|
||||
level1Item.put("LEVEL", 1);
|
||||
level1Item.put("PART_NO", projectPartNo);
|
||||
level1Item.put("PART_NAME", projectPartName);
|
||||
level1Item.put("QTY", 1); // 1레벨 수량은 항상 1
|
||||
level1Item.put("PART_OBJID", projectPartObjId); // 실제 PART_MNG의 OBJID 사용
|
||||
level1Item.put("CHILD_OBJID", newLevel1ChildObjid); // 부모-자식 연결용
|
||||
level1Item.put("PARENT_OBJID", ""); // 1레벨은 부모 없음
|
||||
newMbomDetailList.add(level1Item);
|
||||
|
||||
// 기존 BOM의 1레벨 CHILD_OBJID 찾기 (2레벨의 PARENT_OBJID 매핑용)
|
||||
String originalLevel1ChildObjid = "";
|
||||
String originalLevel1PartNo = "";
|
||||
for(Map<String, Object> item : mbomDetailList) {
|
||||
Integer level = null;
|
||||
Object levelObj = item.get("LEVEL");
|
||||
if(levelObj instanceof Integer) {
|
||||
level = (Integer) levelObj;
|
||||
} else if(levelObj instanceof Long) {
|
||||
level = ((Long) levelObj).intValue();
|
||||
} else if(levelObj instanceof String) {
|
||||
try { level = Integer.parseInt((String) levelObj); } catch(Exception e) {}
|
||||
}
|
||||
|
||||
if(level != null && level == 1) {
|
||||
originalLevel1ChildObjid = CommonUtils.checkNull(item.get("CHILD_OBJID"));
|
||||
originalLevel1PartNo = CommonUtils.checkNull(item.get("PART_NO"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 2레벨 이상 데이터 추가 (레벨 조정 없이 그대로)
|
||||
// 단, 원래 1레벨의 자식(2레벨)은 프로젝트 파트의 자식이 됨
|
||||
for(Map<String, Object> item : mbomDetailList) {
|
||||
Integer level = null;
|
||||
Object levelObj = item.get("LEVEL");
|
||||
if(levelObj instanceof Integer) {
|
||||
level = (Integer) levelObj;
|
||||
} else if(levelObj instanceof Long) {
|
||||
level = ((Long) levelObj).intValue();
|
||||
} else if(levelObj instanceof String) {
|
||||
try { level = Integer.parseInt((String) levelObj); } catch(Exception e) {}
|
||||
}
|
||||
|
||||
if(level != null && level >= 2) {
|
||||
Map<String, Object> newItem = new HashMap<>(item);
|
||||
// 원래 2레벨(1레벨의 직접 자식)은 부모를 프로젝트 파트로 변경
|
||||
if(level == 2) {
|
||||
String parentObjid = CommonUtils.checkNull(item.get("PARENT_OBJID"));
|
||||
String parentPartNo = CommonUtils.checkNull(item.get("PARENT_PART_NO"));
|
||||
// PARENT_OBJID가 원래 1레벨의 CHILD_OBJID와 같으면 새 1레벨로 변경
|
||||
if(parentObjid.equals(originalLevel1ChildObjid) || parentPartNo.equals(originalLevel1PartNo)) {
|
||||
newItem.put("PARENT_OBJID", newLevel1ChildObjid);
|
||||
newItem.put("PARENT_PART_NO", projectPartNo);
|
||||
}
|
||||
}
|
||||
newMbomDetailList.add(newItem);
|
||||
}
|
||||
}
|
||||
|
||||
mbomDetailList = newMbomDetailList;
|
||||
System.out.println("프로젝트 파트 정보로 1레벨 교체 완료 - " + projectPartNo + " / " + projectPartName + " / CHILD_OBJID: " + newLevel1ChildObjid);
|
||||
}
|
||||
}
|
||||
|
||||
// 저장된 M-BOM 데이터가 있으면 이를 표시
|
||||
int maxLevel = 1;
|
||||
for(Map<String, Object> item : mbomDetailList) {
|
||||
Integer level = (Integer) item.get("LEVEL");
|
||||
Integer level = null;
|
||||
Object levelObj = item.get("LEVEL");
|
||||
if(levelObj instanceof Integer) {
|
||||
level = (Integer) levelObj;
|
||||
} else if(levelObj instanceof Long) {
|
||||
level = ((Long) levelObj).intValue();
|
||||
} else if(levelObj instanceof String) {
|
||||
try { level = Integer.parseInt((String) levelObj); } catch(Exception e) {}
|
||||
}
|
||||
|
||||
if(level != null && level > maxLevel) {
|
||||
maxLevel = level;
|
||||
}
|
||||
@@ -1863,6 +1975,10 @@ public class ProductionPlanningController extends BaseService {
|
||||
// M-BOM 목록 (셀렉트박스용)
|
||||
code_map.put("mbom_list", commonService.bizMakeOptionList("", "", "productionplanning.getMbomListForSelect2"));
|
||||
|
||||
// M-BOM 목록 (품명 포함) - 품명 자동 입력용
|
||||
List<Map> mbomListWithPartName = productionPlanningService.getMbomListWithPartName();
|
||||
request.setAttribute("mbom_part_name_list", mbomListWithPartName);
|
||||
|
||||
request.setAttribute("code_map", code_map);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -1902,6 +2018,10 @@ public class ProductionPlanningController extends BaseService {
|
||||
// M-BOM 목록 (셀렉트박스용)
|
||||
code_map.put("mbom_list", commonService.bizMakeOptionList("", "", "productionplanning.getMbomListForSelect2"));
|
||||
|
||||
// M-BOM 목록 (품명 포함) - 품명 자동 입력용
|
||||
List<Map> mbomListWithPartName = productionPlanningService.getMbomListWithPartName();
|
||||
request.setAttribute("mbom_part_name_list", mbomListWithPartName);
|
||||
|
||||
request.setAttribute("code_map", code_map);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -1931,4 +2051,60 @@ public class ProductionPlanningController extends BaseService {
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 생산실적 날짜별 조회
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/productionplanning/getProdResultListByDate.do")
|
||||
public Map getProdResultListByDate(HttpServletRequest request, @RequestParam Map<String, Object> paramMap) {
|
||||
Map<String, Object> resultMap = new HashMap<String, Object>();
|
||||
try {
|
||||
List list = productionPlanningService.getProdResultListByDate(paramMap);
|
||||
resultMap.put("result", "success");
|
||||
resultMap.put("list", list);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
resultMap.put("result", "fail");
|
||||
resultMap.put("msg", "조회 실패");
|
||||
}
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 생산실적 날짜별 저장
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping(value="/productionplanning/saveProdResultByDate.do", produces="application/json;charset=UTF-8")
|
||||
public Map saveProdResultByDate(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);
|
||||
|
||||
// 세션 정보가 없는 경우 기본값 설정
|
||||
String userId = "";
|
||||
String userName = "";
|
||||
if(person != null) {
|
||||
userId = person.getUserId();
|
||||
userName = person.getUserName();
|
||||
}
|
||||
paramMap.put("userId", userId);
|
||||
paramMap.put("userName", userName);
|
||||
|
||||
boolean success = productionPlanningService.saveProdResultByDate(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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -597,7 +597,7 @@ public class QualityController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 공정검사 엑셀 다운로드
|
||||
* 공정검사 엑셀 다운로드 (JSP 방식)
|
||||
*/
|
||||
@RequestMapping("/quality/processInspectionExcelDownload.do")
|
||||
public String processInspectionExcelDownload(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
@@ -606,6 +606,18 @@ public class QualityController {
|
||||
return "/quality/processInspectionExcel";
|
||||
}
|
||||
|
||||
/**
|
||||
* 공정검사 엑셀 데이터 조회 (AJAX JSON) - 전체 풀어서 다운로드
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/quality/getProcessInspectionListForExcel.do")
|
||||
public Map getProcessInspectionListForExcel(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
Map result = new HashMap();
|
||||
List list = service.getProcessInspectionListForExcel(paramMap);
|
||||
result.put("list", list);
|
||||
return result;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// 반제품검사 관리
|
||||
// =====================================================
|
||||
|
||||
@@ -8115,4 +8115,21 @@ SELECT PM.OBJID
|
||||
ORDER BY REGDATE DESC, PART_NO
|
||||
</select>
|
||||
|
||||
<!-- PART_OBJID로 PART_MNG 테이블에서 파트 정보 조회 -->
|
||||
<select id="getPartInfoByObjId" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
SELECT
|
||||
OBJID,
|
||||
PART_NO,
|
||||
PART_NAME,
|
||||
PART_TYPE,
|
||||
UNIT,
|
||||
MATERIAL,
|
||||
SPEC,
|
||||
MAKER,
|
||||
SUPPLY_CODE
|
||||
FROM PART_MNG
|
||||
WHERE OBJID::VARCHAR = #{partObjId}
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -3137,6 +3137,7 @@
|
||||
PM.CONTRACT_OBJID,
|
||||
PM.PROJECT_NO,
|
||||
PM.BOM_REPORT_OBJID,
|
||||
PM.PART_OBJID,
|
||||
PM.PART_NO,
|
||||
PM.PART_NAME,
|
||||
PM.SOURCE_BOM_TYPE,
|
||||
@@ -3958,12 +3959,22 @@
|
||||
ORDER BY REGDATE DESC, MBOM_NO
|
||||
</select>
|
||||
|
||||
<!-- M-BOM 목록 (bizMakeOptionList용) -->
|
||||
<!-- M-BOM 목록 (bizMakeOptionList용) - (E-BOM) 텍스트 제거 -->
|
||||
<select id="getMbomListForSelect2" parameterType="map" resultType="map">
|
||||
SELECT
|
||||
OBJID AS CODE,
|
||||
COALESCE(MBOM_NO, '') ||
|
||||
CASE WHEN SOURCE_BOM_TYPE IS NOT NULL AND SOURCE_BOM_TYPE != '' THEN ' (' || SOURCE_BOM_TYPE || ')' ELSE '' END AS NAME
|
||||
COALESCE(MBOM_NO, '') AS NAME
|
||||
FROM MBOM_HEADER
|
||||
WHERE STATUS = 'Y'
|
||||
ORDER BY REGDATE DESC, MBOM_NO
|
||||
</select>
|
||||
|
||||
<!-- M-BOM 목록 (품명 포함, 원자재소요량/반제품소요량용) -->
|
||||
<select id="getMbomListWithPartName" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
SELECT
|
||||
OBJID,
|
||||
MBOM_NO,
|
||||
COALESCE(PART_NAME, '') AS PART_NAME
|
||||
FROM MBOM_HEADER
|
||||
WHERE STATUS = 'Y'
|
||||
ORDER BY REGDATE DESC, MBOM_NO
|
||||
@@ -4500,9 +4511,9 @@
|
||||
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,
|
||||
COALESCE((SELECT SUM(RESULT_QTY) FROM PRODUCTION_RESULT PR WHERE PR.PROJECT_OBJID = PM.OBJID::VARCHAR AND PR.RESULT_TYPE = 'ASSEMBLY' AND PR.STATUS = 'active'), 0) AS ASSEMBLY_QTY,
|
||||
COALESCE((SELECT SUM(RESULT_QTY) FROM PRODUCTION_RESULT PR WHERE PR.PROJECT_OBJID = PM.OBJID::VARCHAR AND PR.RESULT_TYPE = 'INSPECTION' AND PR.STATUS = 'active'), 0) AS INSPECTION_QTY,
|
||||
COALESCE((SELECT SUM(RESULT_QTY) FROM PRODUCTION_RESULT PR WHERE PR.PROJECT_OBJID = PM.OBJID::VARCHAR AND PR.RESULT_TYPE = 'SHIP_WAIT' AND PR.STATUS = 'active'), 0) AS SHIP_WAIT_QTY,
|
||||
'' AS EQUIPMENT_WBS,
|
||||
PP.OBJID AS PROD_PLAN_OBJID,
|
||||
PM.REGDATE AS SORT_DATE
|
||||
@@ -4550,9 +4561,9 @@
|
||||
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,
|
||||
COALESCE((SELECT SUM(RESULT_QTY) FROM PRODUCTION_RESULT PR WHERE PR.PROJECT_OBJID = PP.OBJID::VARCHAR AND PR.RESULT_TYPE = 'ASSEMBLY' AND PR.STATUS = 'active'), 0) AS ASSEMBLY_QTY,
|
||||
COALESCE((SELECT SUM(RESULT_QTY) FROM PRODUCTION_RESULT PR WHERE PR.PROJECT_OBJID = PP.OBJID::VARCHAR AND PR.RESULT_TYPE = 'INSPECTION' AND PR.STATUS = 'active'), 0) AS INSPECTION_QTY,
|
||||
COALESCE((SELECT SUM(RESULT_QTY) FROM PRODUCTION_RESULT PR WHERE PR.PROJECT_OBJID = PP.OBJID::VARCHAR AND PR.RESULT_TYPE = 'SHIP_WAIT' AND PR.STATUS = 'active'), 0) AS SHIP_WAIT_QTY,
|
||||
'' AS EQUIPMENT_WBS,
|
||||
PP.OBJID AS PROD_PLAN_OBJID,
|
||||
PP.REGDATE AS SORT_DATE
|
||||
@@ -4610,31 +4621,54 @@
|
||||
ORDER BY T.SORT_DATE DESC, T.PROJECT_NO DESC
|
||||
</select>
|
||||
|
||||
<!-- 프로젝트 정보 조회 (생산계획 폼용) -->
|
||||
<!-- 프로젝트 정보 조회 (생산계획 폼용) - PROJECT_MGMT 또는 PRODUCTION_PLAN에서 조회 -->
|
||||
<select id="getProdPlanProjectInfo" parameterType="map" resultType="map">
|
||||
SELECT
|
||||
PM.OBJID,
|
||||
PM.PROJECT_NO,
|
||||
COALESCE(CI.PART_NO, PM.PART_NO) AS PART_NO,
|
||||
COALESCE(CI.PART_NAME, PM.PART_NAME) AS PART_NAME,
|
||||
COALESCE(CM.PRODUCT, PM.PRODUCT) AS PRODUCT_CODE,
|
||||
COALESCE(CM.CATEGORY_CD, '') AS CATEGORY_CODE,
|
||||
COALESCE(CM.CUSTOMER_OBJID, PM.CUSTOMER_OBJID) AS CUSTOMER_OBJID,
|
||||
COALESCE(CI.DUE_DATE, PM.DUE_DATE, CM.REQ_DEL_DATE) AS REQ_DEL_DATE,
|
||||
PM.QUANTITY AS ORDER_QTY,
|
||||
CM.CUSTOMER_REQUEST,
|
||||
(
|
||||
SELECT STRING_AGG(CIS.SERIAL_NO, ', ' ORDER BY CIS.SERIAL_NO)
|
||||
FROM CONTRACT_ITEM_SERIAL CIS
|
||||
WHERE CIS.ITEM_OBJID = CI.OBJID
|
||||
AND UPPER(CIS.STATUS) = 'ACTIVE'
|
||||
) AS SERIAL_NO
|
||||
FROM PROJECT_MGMT PM
|
||||
LEFT JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
|
||||
LEFT JOIN CONTRACT_ITEM CI ON CI.CONTRACT_OBJID = PM.CONTRACT_OBJID
|
||||
AND CI.PART_OBJID = PM.PART_OBJID
|
||||
AND CI.STATUS = 'ACTIVE'
|
||||
WHERE PM.OBJID = #{projectObjid}
|
||||
SELECT * FROM (
|
||||
-- 1. PROJECT_MGMT 기반 조회
|
||||
SELECT
|
||||
PM.OBJID::VARCHAR AS OBJID,
|
||||
COALESCE(PM.PROJECT_NO, '') AS PROJECT_NO,
|
||||
COALESCE(CI.PART_NO, PM.PART_NO, '') AS PART_NO,
|
||||
COALESCE(CI.PART_NAME, PM.PART_NAME, '') AS PART_NAME,
|
||||
COALESCE(CM.PRODUCT, PM.PRODUCT, '') AS PRODUCT_CODE,
|
||||
COALESCE(CM.CATEGORY_CD, '') AS CATEGORY_CODE,
|
||||
COALESCE(CM.CUSTOMER_OBJID, PM.CUSTOMER_OBJID, '')::VARCHAR AS CUSTOMER_OBJID,
|
||||
COALESCE(CI.DUE_DATE, PM.DUE_DATE, CM.REQ_DEL_DATE, '') AS REQ_DEL_DATE,
|
||||
COALESCE(NULLIF(PM.QUANTITY, '')::numeric, 0) AS ORDER_QTY,
|
||||
COALESCE((SELECT NULLIF(PP.EXTRA_PROD_QTY, '')::numeric FROM PRODUCTION_PLAN PP WHERE PP.PROJECT_OBJID = PM.OBJID AND UPPER(PP.STATUS) = 'ACTIVE' LIMIT 1), 0) AS EXTRA_PROD_QTY,
|
||||
COALESCE(CM.CUSTOMER_REQUEST, '') AS CUSTOMER_REQUEST,
|
||||
COALESCE((
|
||||
SELECT STRING_AGG(CIS.SERIAL_NO, ', ' ORDER BY CIS.SERIAL_NO)
|
||||
FROM CONTRACT_ITEM_SERIAL CIS
|
||||
WHERE CIS.ITEM_OBJID = CI.OBJID
|
||||
AND UPPER(CIS.STATUS) = 'ACTIVE'
|
||||
), '') AS SERIAL_NO
|
||||
FROM PROJECT_MGMT PM
|
||||
LEFT JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
|
||||
LEFT JOIN CONTRACT_ITEM CI ON CI.CONTRACT_OBJID = PM.CONTRACT_OBJID
|
||||
AND CI.PART_OBJID = PM.PART_OBJID
|
||||
AND CI.STATUS = 'ACTIVE'
|
||||
WHERE PM.OBJID::VARCHAR = #{projectObjid}
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- 2. PRODUCTION_PLAN 기반 조회 (OBJID로 직접 조회)
|
||||
SELECT
|
||||
PP.OBJID::VARCHAR AS OBJID,
|
||||
'' AS PROJECT_NO,
|
||||
COALESCE(PP.PART_NO, '') AS PART_NO,
|
||||
COALESCE(PP.PART_NAME, '') AS PART_NAME,
|
||||
COALESCE(PP.PRODUCT_CODE, '') AS PRODUCT_CODE,
|
||||
COALESCE(PP.CATEGORY_CODE, '') AS CATEGORY_CODE,
|
||||
COALESCE(PP.CUSTOMER_OBJID, '')::VARCHAR AS CUSTOMER_OBJID,
|
||||
COALESCE(PP.REQ_DEL_DATE, '') AS REQ_DEL_DATE,
|
||||
COALESCE(NULLIF(PP.ORDER_QTY, '')::numeric, 0) AS ORDER_QTY,
|
||||
COALESCE(NULLIF(PP.EXTRA_PROD_QTY, '')::numeric, 0) AS EXTRA_PROD_QTY,
|
||||
COALESCE(PP.CUSTOMER_REQUEST, '') AS CUSTOMER_REQUEST,
|
||||
COALESCE(PP.SERIAL_NO, '') AS SERIAL_NO
|
||||
FROM PRODUCTION_PLAN PP
|
||||
WHERE PP.OBJID::VARCHAR = #{projectObjid}
|
||||
) T
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
@@ -4754,6 +4788,7 @@
|
||||
RESULT_TYPE,
|
||||
RESULT_DATE,
|
||||
RESULT_QTY,
|
||||
ROW_SEQ,
|
||||
SERIAL_NO,
|
||||
WORKER_ID,
|
||||
WORKER_NAME,
|
||||
@@ -4767,6 +4802,7 @@
|
||||
#{RESULT_TYPE},
|
||||
#{RESULT_DATE},
|
||||
#{RESULT_QTY},
|
||||
#{ROW_SEQ},
|
||||
#{SERIAL_NO},
|
||||
#{userId},
|
||||
#{WORKER_NAME},
|
||||
@@ -4860,4 +4896,40 @@
|
||||
ORDER BY MD.RAW_MATERIAL_PART_NO
|
||||
</select>
|
||||
|
||||
<!-- 생산실적 날짜별 조회 (피봇) -->
|
||||
<select id="getProdResultListByDate" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
SELECT
|
||||
ROW_SEQ,
|
||||
RESULT_DATE,
|
||||
COALESCE(SUM(CASE WHEN RESULT_TYPE = 'ASSEMBLY' THEN RESULT_QTY ELSE 0 END), 0) AS ASSEMBLY_QTY,
|
||||
COALESCE(SUM(CASE WHEN RESULT_TYPE = 'INSPECTION' THEN RESULT_QTY ELSE 0 END), 0) AS INSPECTION_QTY,
|
||||
COALESCE(SUM(CASE WHEN RESULT_TYPE = 'SHIP_WAIT' THEN RESULT_QTY ELSE 0 END), 0) AS SHIP_WAIT_QTY,
|
||||
MAX(REMARK) AS REMARK
|
||||
FROM PRODUCTION_RESULT
|
||||
WHERE PROJECT_OBJID = #{projectObjid}
|
||||
AND STATUS = 'active'
|
||||
GROUP BY ROW_SEQ, RESULT_DATE
|
||||
ORDER BY ROW_SEQ ASC
|
||||
</select>
|
||||
|
||||
<!-- 생산실적 행별 삭제 -->
|
||||
<delete id="deleteProdResultByRowSeq" parameterType="map">
|
||||
DELETE FROM PRODUCTION_RESULT
|
||||
WHERE PROJECT_OBJID = #{projectObjid}
|
||||
AND ROW_SEQ = #{rowSeq}
|
||||
</delete>
|
||||
|
||||
<!-- 생산실적 날짜별 삭제 (기존 데이터 삭제 후 재입력용) -->
|
||||
<delete id="deleteProdResultByDate" parameterType="map">
|
||||
DELETE FROM PRODUCTION_RESULT
|
||||
WHERE PROJECT_OBJID = #{projectObjid}
|
||||
AND RESULT_DATE = #{resultDate}
|
||||
</delete>
|
||||
|
||||
<!-- 생산실적 프로젝트 전체 삭제 -->
|
||||
<delete id="deleteProdResultByProject" parameterType="map">
|
||||
DELETE FROM PRODUCTION_RESULT
|
||||
WHERE PROJECT_OBJID = #{projectObjid}
|
||||
</delete>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -4293,17 +4293,20 @@ SELECT POM.OBJID
|
||||
,POM.TOTAL_PRICE
|
||||
,POM.DISCOUNT_PRICE
|
||||
,POM.TOTAL_SUPPLY_UNIT_PRICE
|
||||
,POM.TOTAL_SUPPLY_PRICE
|
||||
-- ,POM.TOTAL_SUPPLY_PRICE
|
||||
,S1.TOTAL_SUPPLY_PRICE
|
||||
,POM.NEGO_RATE
|
||||
,POM.MULTI_MASTER_YN
|
||||
,POM.MULTI_YN
|
||||
,CASE WHEN POM.MULTI_MASTER_YN = 'Y' THEN '' ELSE POM.MULTI_YN END MULTI_YN_MAKED
|
||||
,COALESCE(POM.FORM_TYPE, '') AS FORM_TYPE
|
||||
<!-- ,S1.TOTAL_PO_QTY -->
|
||||
,(SELECT SUM(ORDER_QTY::NUMERIC) FROM PURCHASE_ORDER_PART AS O WHERE POM.OBJID::VARCHAR = O.PURCHASE_ORDER_MASTER_OBJID) AS TOTAL_PO_QTY
|
||||
<!--,(SELECT SUM(REAL_ORDER_QTY::NUMERIC) FROM PURCHASE_ORDER_PART AS O WHERE POM.OBJID::VARCHAR = O.PURCHASE_ORDER_MASTER_OBJID) AS TOTAL_PO_QTY -->
|
||||
,S1.CUR_DELIVERY_DATE
|
||||
,S1.TOTAL_DELIVERY_QTY
|
||||
,S1.TOTAL_DELIVERY_PRICE
|
||||
,S1.TOTAL_NOT_DELIVERY_PRICE
|
||||
<!-- ,(S1.TOTAL_PO_QTY - S1.TOTAL_DELIVERY_QTY - S1.TOTAL_DEFECT_QTY) AS NON_DELIVERY_QTY -->
|
||||
,((SELECT SUM(ORDER_QTY::NUMERIC) FROM PURCHASE_ORDER_PART AS O WHERE POM.OBJID::VARCHAR = O.PURCHASE_ORDER_MASTER_OBJID) - (S1.TOTAL_DELIVERY_QTY <!-- - S1.TOTAL_DEFECT_QTY --> )) AS NON_DELIVERY_QTY
|
||||
<!-- ,S1.TOTAL_DEFECT_QTY -->
|
||||
@@ -4355,19 +4358,23 @@ SELECT POM.OBJID
|
||||
LEFT OUTER JOIN(
|
||||
SELECT POP.PURCHASE_ORDER_MASTER_OBJID
|
||||
,SUM(POP.ORDER_QTY::NUMERIC) AS TOTAL_PO_QTY
|
||||
,MAX(DH.RECEIPT_DATE) AS CUR_DELIVERY_DATE
|
||||
,SUM(DH.RECEIPT_QTY::NUMERIC) AS TOTAL_DELIVERY_QTY
|
||||
,SUM(pop.partner_price::NUMERIC * DH.RECEIPT_QTY::NUMERIC) AS TOTAL_DELIVERY_PRICE
|
||||
|
||||
<!-- ,SUM(DH.ERROR_QTY::NUMERIC) AS TOTAL_DEFECT_QTY -->
|
||||
<!-- ,MAX(DH.DELIVERY_DATE) AS CUR_DELIVERY_DATE
|
||||
,SUM(DH.DELIVERY_QTY::NUMERIC) AS TOTAL_DELIVERY_QTY
|
||||
,SUM(DH.DEFECT_QTY::NUMERIC) AS TOTAL_DEFECT_QTY -->
|
||||
,MAX(AP_AGG.MAX_RECEIPT_DATE) AS CUR_DELIVERY_DATE
|
||||
,SUM(COALESCE(AP_AGG.SUM_RECEIPT_QTY, 0)) AS TOTAL_DELIVERY_QTY
|
||||
-- 발주금액 = 단가 × 발주수량
|
||||
,SUM(COALESCE(POP.PARTNER_PRICE::NUMERIC, 0) * COALESCE(POP.ORDER_QTY::NUMERIC, 0)) AS TOTAL_SUPPLY_PRICE
|
||||
-- 입고금액 = 단가 × 입고수량
|
||||
,SUM(COALESCE(POP.PARTNER_PRICE::NUMERIC, 0) * COALESCE(AP_AGG.SUM_RECEIPT_QTY, 0)) AS TOTAL_DELIVERY_PRICE
|
||||
-- 미입고금액 = 단가 × (발주수량 - 입고수량)
|
||||
,SUM(COALESCE(POP.PARTNER_PRICE::NUMERIC, 0) * (COALESCE(POP.ORDER_QTY::NUMERIC, 0) - COALESCE(AP_AGG.SUM_RECEIPT_QTY, 0))) AS TOTAL_NOT_DELIVERY_PRICE
|
||||
FROM PURCHASE_ORDER_PART POP
|
||||
LEFT OUTER JOIN ARRIVAL_PLAN DH
|
||||
ON POP.OBJID = DH.ORDER_PART_OBJID
|
||||
<!-- LEFT OUTER JOIN DELIVERY_HISTORY DH -->
|
||||
<!-- ON POP.PART_OBJID = DH.PART_OBJID -->
|
||||
LEFT OUTER JOIN (
|
||||
-- ARRIVAL_PLAN을 ORDER_PART_OBJID별로 먼저 집계
|
||||
SELECT ORDER_PART_OBJID
|
||||
,SUM(RECEIPT_QTY::NUMERIC) AS SUM_RECEIPT_QTY
|
||||
,MAX(RECEIPT_DATE) AS MAX_RECEIPT_DATE
|
||||
FROM ARRIVAL_PLAN
|
||||
GROUP BY ORDER_PART_OBJID
|
||||
) AP_AGG ON POP.OBJID = AP_AGG.ORDER_PART_OBJID
|
||||
GROUP BY POP.PURCHASE_ORDER_MASTER_OBJID
|
||||
) AS S1 ON POM.OBJID::VARCHAR = S1.PURCHASE_ORDER_MASTER_OBJID
|
||||
LEFT OUTER JOIN PROJECT_MGMT AS CM
|
||||
|
||||
@@ -1358,30 +1358,32 @@
|
||||
DELETE FROM PROCESS_INSPECTION_DETAIL WHERE MASTER_OBJID = #{MASTER_OBJID}
|
||||
</delete>
|
||||
|
||||
<!-- 공정검사 목록 조회 (엑셀용) - 상세 정보 포함 -->
|
||||
<!-- 공정검사 목록 조회 (엑셀용) - 상세 정보 포함 (디테일 기준) -->
|
||||
<select id="getProcessInspectionListForExcel" parameterType="map" resultType="map">
|
||||
SELECT
|
||||
/* 공정검사 마스터 정보 */
|
||||
PIM.INSPECTION_DATE
|
||||
, (SELECT U.USER_NAME FROM USER_INFO U WHERE U.USER_ID = PIM.INSPECTOR_ID) AS INSPECTOR_NAME
|
||||
, PIM.REMARK AS MASTER_REMARK
|
||||
/* 검사일, 검사자는 디테일에서 가져옴 */
|
||||
COALESCE(PID.INSPECTION_DATE, '') AS INSPECTION_DATE
|
||||
, COALESCE((SELECT U.USER_NAME FROM USER_INFO U WHERE U.USER_ID = PID.INSPECTOR_ID), '') AS INSPECTOR_NAME
|
||||
, COALESCE((SELECT CODE_NAME(PM.PRODUCT) FROM PROJECT_MGMT PM WHERE PM.OBJID = PID.PROJECT_OBJID), '') AS PRODUCT_TYPE
|
||||
/* 공정검사 디테일 정보 */
|
||||
, (SELECT CC.CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = PID.PROCESS_CD) AS PROCESS_NAME
|
||||
, (SELECT PM.PROJECT_NO FROM PROJECT_MGMT PM WHERE PM.OBJID = PID.PROJECT_OBJID) AS PROJECT_NO
|
||||
, PID.PART_NO
|
||||
, PID.PART_NAME
|
||||
, PID.INSPECTION_QTY
|
||||
, PID.DEFECT_QTY
|
||||
, COALESCE((SELECT CC.CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = PID.PROCESS_CD), '') AS PROCESS_NAME
|
||||
, COALESCE((SELECT PM.PROJECT_NO FROM PROJECT_MGMT PM WHERE PM.OBJID = PID.PROJECT_OBJID), '') AS PROJECT_NO
|
||||
, COALESCE(PID.PART_NO, '') AS PART_NO
|
||||
, COALESCE(PID.PART_NAME, '') AS PART_NAME
|
||||
, COALESCE(PID.INSPECTION_QTY, 0) AS INSPECTION_QTY
|
||||
, COALESCE(PID.DEFECT_QTY, 0) AS DEFECT_QTY
|
||||
, CASE WHEN COALESCE(PID.INSPECTION_QTY, 0) > 0
|
||||
THEN ROUND((COALESCE(PID.DEFECT_QTY, 0)::NUMERIC / PID.INSPECTION_QTY::NUMERIC) * 100, 2)
|
||||
ELSE NULL END AS DEFECT_RATE
|
||||
, PID.WORK_ENV_STATUS
|
||||
, PID.MEASURING_DEVICE
|
||||
, (SELECT DEPT_NAME FROM DEPT_INFO WHERE DEPT_CODE = PID.DEPT_CD) AS DEPT_NAME
|
||||
, (SELECT U2.USER_NAME FROM USER_INFO U2 WHERE U2.USER_ID = PID.USER_ID) AS USER_NAME
|
||||
, PID.REMARK AS DETAIL_REMARK
|
||||
, PID.ACTION_STATUS
|
||||
, PID.INSPECTION_RESULT
|
||||
ELSE 0 END AS DEFECT_RATE
|
||||
, COALESCE(PID.WORK_ENV_STATUS, '') AS WORK_ENV_STATUS
|
||||
, COALESCE(PID.MEASURING_DEVICE, '') AS MEASURING_DEVICE
|
||||
, COALESCE((SELECT DI.DEPT_NAME FROM DEPT_INFO DI WHERE DI.DEPT_CODE = PID.DEPT_CD), '') AS DEPT_NAME
|
||||
, COALESCE((SELECT U2.USER_NAME FROM USER_INFO U2 WHERE U2.USER_ID = PID.USER_ID), '') AS USER_NAME
|
||||
, COALESCE(PID.REMARK, '') AS DETAIL_REMARK
|
||||
, COALESCE(PID.ACTION_STATUS, '') AS ACTION_STATUS
|
||||
, COALESCE(NULLIF(PID.INSPECTION_RESULT, ''),
|
||||
(SELECT CASE WHEN COUNT(CASE WHEN PID2.INSPECTION_RESULT = 'NG' THEN 1 END) > 0 THEN 'NG' ELSE 'OK' END
|
||||
FROM PROCESS_INSPECTION_DETAIL PID2 WHERE PID2.MASTER_OBJID = PIM.OBJID), '') AS INSPECTION_RESULT
|
||||
FROM PROCESS_INSPECTION_MASTER PIM
|
||||
INNER JOIN PROCESS_INSPECTION_DETAIL PID ON PID.MASTER_OBJID = PIM.OBJID
|
||||
WHERE 1=1
|
||||
@@ -1396,15 +1398,15 @@
|
||||
</if>
|
||||
<if test="search_inspector != null and search_inspector != ''">
|
||||
AND (
|
||||
UPPER(PIM.INSPECTOR_ID) LIKE UPPER('%' || #{search_inspector} || '%')
|
||||
OR UPPER((SELECT USER_NAME FROM USER_INFO WHERE USER_ID = PIM.INSPECTOR_ID)) LIKE UPPER('%' || #{search_inspector} || '%')
|
||||
UPPER(PID.INSPECTOR_ID) LIKE UPPER('%' || #{search_inspector} || '%')
|
||||
OR UPPER((SELECT USER_NAME FROM USER_INFO WHERE USER_ID = PID.INSPECTOR_ID)) LIKE UPPER('%' || #{search_inspector} || '%')
|
||||
)
|
||||
</if>
|
||||
<if test="search_inspection_date_from != null and search_inspection_date_from != ''">
|
||||
AND PIM.INSPECTION_DATE <![CDATA[>=]]> #{search_inspection_date_from}
|
||||
AND PID.INSPECTION_DATE <![CDATA[>=]]> #{search_inspection_date_from}
|
||||
</if>
|
||||
<if test="search_inspection_date_to != null and search_inspection_date_to != ''">
|
||||
AND PIM.INSPECTION_DATE <![CDATA[<=]]> #{search_inspection_date_to}
|
||||
AND PID.INSPECTION_DATE <![CDATA[<=]]> #{search_inspection_date_to}
|
||||
</if>
|
||||
<if test="search_inspection_result != null and search_inspection_result != ''">
|
||||
AND PID.INSPECTION_RESULT = #{search_inspection_result}
|
||||
@@ -1540,96 +1542,62 @@
|
||||
ORDER BY MIN(T.INSPECTION_DATE) DESC, T.INSPECTION_GROUP_ID
|
||||
</select>
|
||||
|
||||
<!-- 반제품검사 엑셀 다운로드용 데이터 조회 (그룹화 후 쉼표로 나열) -->
|
||||
<!-- 반제품검사 엑셀 다운로드용 데이터 조회 (전체 풀어서 개별 행으로) -->
|
||||
<select id="getSemiProductInspectionListForExcel" parameterType="map" resultType="map">
|
||||
SELECT T.INSPECTION_GROUP_ID
|
||||
, MIN(T.OBJID) AS OBJID
|
||||
<!-- 품명(모델명): 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.MODEL_NAME, ''), ', ' ORDER BY NULLIF(T.MODEL_NAME, '')) AS MODEL_NAME
|
||||
<!-- 제품구분: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.PRODUCT_TYPE, ''), ', ' ORDER BY NULLIF(T.PRODUCT_TYPE, '')) AS PRODUCT_TYPE
|
||||
<!-- 작업지시번호: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.WORK_ORDER_NO, ''), ', ' ORDER BY NULLIF(T.WORK_ORDER_NO, '')) AS WORK_ORDER_NO
|
||||
<!-- 부품품번: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.PART_NO, ''), ', ' ORDER BY NULLIF(T.PART_NO, '')) AS PART_NO
|
||||
<!-- 부품명: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.PART_NAME, ''), ', ' ORDER BY NULLIF(T.PART_NAME, '')) AS PART_NAME
|
||||
<!-- 수량 집계 -->
|
||||
, SUM(T.RECEIPT_QTY) AS RECEIPT_QTY
|
||||
, SUM(T.GOOD_QTY) AS GOOD_QTY
|
||||
, SUM(T.DEFECT_QTY) AS DEFECT_QTY
|
||||
SELECT SPI.OBJID
|
||||
, COALESCE(TO_CHAR(SPI.INSPECTION_DATE, 'YYYY-MM-DD'), TO_CHAR(SPI.REG_DATE, 'YYYY-MM-DD')) AS INSPECTION_DATE
|
||||
, COALESCE((SELECT USER_NAME FROM USER_INFO WHERE USER_ID = SPI.INSPECTOR),
|
||||
(SELECT USER_NAME FROM USER_INFO WHERE USER_ID = SPI.WRITER), '') AS WRITER_NAME
|
||||
, COALESCE(SPI.MODEL_NAME, '') AS MODEL_NAME
|
||||
, COALESCE(SPI.PRODUCT_TYPE, '') AS PRODUCT_TYPE
|
||||
, COALESCE(SPI.WORK_ORDER_NO, '') AS WORK_ORDER_NO
|
||||
, COALESCE(SPI.PART_NO, '') AS PART_NO
|
||||
, COALESCE(SPI.PART_NAME, '') AS PART_NAME
|
||||
, COALESCE(SPI.RECEIPT_QTY, 0) AS RECEIPT_QTY
|
||||
, COALESCE(SPI.GOOD_QTY, 0) AS GOOD_QTY
|
||||
, COALESCE(SPI.DEFECT_QTY, 0) AS DEFECT_QTY
|
||||
, CASE
|
||||
WHEN SUM(T.RECEIPT_QTY) > 0
|
||||
THEN ROUND(SUM(T.DEFECT_QTY) * 100.0 / SUM(T.RECEIPT_QTY), 2)
|
||||
WHEN COALESCE(SPI.RECEIPT_QTY, 0) > 0
|
||||
THEN ROUND(COALESCE(SPI.DEFECT_QTY, 0) * 100.0 / SPI.RECEIPT_QTY, 2)
|
||||
ELSE 0
|
||||
END AS DEFECT_RATE
|
||||
, SUM(CASE WHEN T.DISPOSITION_TYPE = '수정' THEN T.DEFECT_QTY ELSE 0 END) AS REGENERATION_QTY
|
||||
, SUM(T.GOOD_QTY) + SUM(CASE WHEN T.DISPOSITION_TYPE = '수정' THEN T.DEFECT_QTY ELSE 0 END) AS FINAL_GOOD_QTY
|
||||
<!-- 검사일: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT T.INSPECTION_DATE_STR, ', ' ORDER BY T.INSPECTION_DATE_STR) AS INSPECTION_DATE
|
||||
<!-- 검사자: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.WRITER_NAME, ''), ', ' ORDER BY NULLIF(T.WRITER_NAME, '')) AS WRITER_NAME
|
||||
<!-- 불량유형: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.DEFECT_TYPE, ''), ', ' ORDER BY NULLIF(T.DEFECT_TYPE, '')) AS DEFECT_TYPE
|
||||
<!-- 불량원인: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.DEFECT_CAUSE, ''), ', ' ORDER BY NULLIF(T.DEFECT_CAUSE, '')) AS DEFECT_CAUSE
|
||||
<!-- 귀책부서: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.RESPONSIBLE_DEPT, ''), ', ' ORDER BY NULLIF(T.RESPONSIBLE_DEPT, '')) AS RESPONSIBLE_DEPT
|
||||
<!-- 처리현황: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.PROCESS_STATUS, ''), ', ' ORDER BY NULLIF(T.PROCESS_STATUS, '')) AS PROCESS_STATUS
|
||||
<!-- 처리결과: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.DISPOSITION_TYPE, ''), ', ' ORDER BY NULLIF(T.DISPOSITION_TYPE, '')) AS DISPOSITION_TYPE
|
||||
<!-- 비고: 쉼표로 나열 -->
|
||||
, STRING_AGG(DISTINCT NULLIF(T.REMARK, ''), ', ' ORDER BY NULLIF(T.REMARK, '')) AS REMARK
|
||||
FROM (
|
||||
SELECT SPI.OBJID
|
||||
, COALESCE(SPI.INSPECTION_GROUP_ID, SPI.OBJID::VARCHAR) AS INSPECTION_GROUP_ID
|
||||
, COALESCE(SPI.MODEL_NAME, '') AS MODEL_NAME
|
||||
, COALESCE(SPI.PRODUCT_TYPE, '') AS PRODUCT_TYPE
|
||||
, COALESCE(SPI.WORK_ORDER_NO, '') AS WORK_ORDER_NO
|
||||
, COALESCE(SPI.PART_NO, '') AS PART_NO
|
||||
, COALESCE(SPI.PART_NAME, '') AS PART_NAME
|
||||
, COALESCE(SPI.RECEIPT_QTY, 0) AS RECEIPT_QTY
|
||||
, COALESCE(SPI.GOOD_QTY, 0) AS GOOD_QTY
|
||||
, COALESCE(SPI.DEFECT_QTY, 0) AS DEFECT_QTY
|
||||
, COALESCE(TO_CHAR(SPI.INSPECTION_DATE, 'YYYY-MM-DD'), TO_CHAR(SPI.REG_DATE, 'YYYY-MM-DD')) AS INSPECTION_DATE_STR
|
||||
, COALESCE((SELECT USER_NAME FROM USER_INFO WHERE USER_ID = SPI.INSPECTOR),
|
||||
(SELECT USER_NAME FROM USER_INFO WHERE USER_ID = SPI.WRITER), '') AS WRITER_NAME
|
||||
, COALESCE(SPI.DEFECT_TYPE, '') AS DEFECT_TYPE
|
||||
, COALESCE(SPI.DEFECT_CAUSE, '') AS DEFECT_CAUSE
|
||||
, COALESCE(SPI.RESPONSIBLE_DEPT, '') AS RESPONSIBLE_DEPT
|
||||
, COALESCE(SPI.PROCESS_STATUS, '') AS PROCESS_STATUS
|
||||
, COALESCE(SPI.DISPOSITION_TYPE, '') AS DISPOSITION_TYPE
|
||||
, COALESCE(SPI.REMARK, '') AS REMARK
|
||||
FROM PMS_QUALITY_SEMI_PRODUCT_INSPECTION SPI
|
||||
WHERE 1=1
|
||||
<!-- 품명(모델명) 검색 -->
|
||||
<if test="search_model_name != null and search_model_name != ''">
|
||||
AND UPPER(SPI.MODEL_NAME) LIKE UPPER('%' || #{search_model_name} || '%')
|
||||
</if>
|
||||
<!-- 작업지시번호 검색 -->
|
||||
<if test="search_work_order_no != null and search_work_order_no != ''">
|
||||
AND UPPER(SPI.WORK_ORDER_NO) LIKE UPPER('%' || #{search_work_order_no} || '%')
|
||||
</if>
|
||||
<!-- 부품품번 검색 -->
|
||||
<if test="search_part_no != null and search_part_no != ''">
|
||||
AND UPPER(SPI.PART_NO) LIKE UPPER('%' || #{search_part_no} || '%')
|
||||
</if>
|
||||
<!-- 부품명 검색 -->
|
||||
<if test="search_part_name != null and search_part_name != ''">
|
||||
AND UPPER(SPI.PART_NAME) LIKE UPPER('%' || #{search_part_name} || '%')
|
||||
</if>
|
||||
<!-- 검사일 검색 -->
|
||||
<if test="search_inspection_date != null and search_inspection_date != ''">
|
||||
AND TO_CHAR(SPI.REG_DATE, 'YYYY-MM-DD') = #{search_inspection_date}
|
||||
</if>
|
||||
<!-- 검사자 검색 -->
|
||||
<if test="search_writer != null and search_writer != ''">
|
||||
AND SPI.WRITER = #{search_writer}
|
||||
</if>
|
||||
) T
|
||||
GROUP BY T.INSPECTION_GROUP_ID
|
||||
ORDER BY MIN(T.INSPECTION_DATE_STR) DESC, T.INSPECTION_GROUP_ID
|
||||
, CASE WHEN SPI.DISPOSITION_TYPE = '수정' THEN COALESCE(SPI.DEFECT_QTY, 0) ELSE 0 END AS REGENERATION_QTY
|
||||
, COALESCE(SPI.GOOD_QTY, 0) + CASE WHEN SPI.DISPOSITION_TYPE = '수정' THEN COALESCE(SPI.DEFECT_QTY, 0) ELSE 0 END AS FINAL_GOOD_QTY
|
||||
, COALESCE(SPI.DEFECT_TYPE, '') AS DEFECT_TYPE
|
||||
, COALESCE(SPI.DEFECT_CAUSE, '') AS DEFECT_CAUSE
|
||||
, COALESCE(SPI.RESPONSIBLE_DEPT, '') AS RESPONSIBLE_DEPT
|
||||
, COALESCE(SPI.PROCESS_STATUS, '') AS PROCESS_STATUS
|
||||
, COALESCE(SPI.DISPOSITION_TYPE, '') AS DISPOSITION_TYPE
|
||||
, COALESCE(SPI.REMARK, '') AS REMARK
|
||||
, COALESCE(SPI.DATA_TYPE, '') AS DATA_TYPE
|
||||
, COALESCE(SPI.INSPECTION_GROUP_ID::VARCHAR, '') AS INSPECTION_GROUP_ID
|
||||
FROM PMS_QUALITY_SEMI_PRODUCT_INSPECTION SPI
|
||||
WHERE 1=1
|
||||
<!-- 품명(모델명) 검색 -->
|
||||
<if test="search_model_name != null and search_model_name != ''">
|
||||
AND UPPER(SPI.MODEL_NAME) LIKE UPPER('%' || #{search_model_name} || '%')
|
||||
</if>
|
||||
<!-- 작업지시번호 검색 -->
|
||||
<if test="search_work_order_no != null and search_work_order_no != ''">
|
||||
AND UPPER(SPI.WORK_ORDER_NO) LIKE UPPER('%' || #{search_work_order_no} || '%')
|
||||
</if>
|
||||
<!-- 부품품번 검색 -->
|
||||
<if test="search_part_no != null and search_part_no != ''">
|
||||
AND UPPER(SPI.PART_NO) LIKE UPPER('%' || #{search_part_no} || '%')
|
||||
</if>
|
||||
<!-- 부품명 검색 -->
|
||||
<if test="search_part_name != null and search_part_name != ''">
|
||||
AND UPPER(SPI.PART_NAME) LIKE UPPER('%' || #{search_part_name} || '%')
|
||||
</if>
|
||||
<!-- 검사일 검색 -->
|
||||
<if test="search_inspection_date != null and search_inspection_date != ''">
|
||||
AND TO_CHAR(SPI.REG_DATE, 'YYYY-MM-DD') = #{search_inspection_date}
|
||||
</if>
|
||||
<!-- 검사자 검색 -->
|
||||
<if test="search_writer != null and search_writer != ''">
|
||||
AND SPI.WRITER = #{search_writer}
|
||||
</if>
|
||||
ORDER BY SPI.INSPECTION_DATE DESC, SPI.REG_DATE DESC
|
||||
</select>
|
||||
|
||||
<!-- 반제품검사 품명(모델명) 드롭박스 목록 (CODE, NAME 형태) -->
|
||||
|
||||
@@ -2102,4 +2102,141 @@ public class ProductionPlanningService {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* M-BOM 목록 조회 (품명 포함)
|
||||
* 원자재소요량/반제품소요량 화면에서 품명 자동 입력용
|
||||
* @return M-BOM 목록 (OBJID, MBOM_NO, PART_NAME)
|
||||
*/
|
||||
public List<Map> getMbomListWithPartName() {
|
||||
List<Map> resultList = new ArrayList<>();
|
||||
SqlSession sqlSession = null;
|
||||
|
||||
try {
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession();
|
||||
resultList = sqlSession.selectList("productionplanning.getMbomListWithPartName", new HashMap<>());
|
||||
// JSP에서 대문자 키로 접근하므로 변환
|
||||
resultList = CommonUtils.keyChangeUpperList(resultList);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if(sqlSession != null) sqlSession.close();
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 생산실적 날짜별 조회
|
||||
*/
|
||||
public List getProdResultListByDate(Map<String, Object> paramMap) {
|
||||
List resultList = new ArrayList();
|
||||
SqlSession sqlSession = null;
|
||||
|
||||
try {
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession();
|
||||
resultList = sqlSession.selectList("productionplanning.getProdResultListByDate", paramMap);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if(sqlSession != null) {
|
||||
sqlSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 생산실적 날짜별 저장
|
||||
* - 기존 데이터 전체 삭제 후 새로 입력
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean saveProdResultByDate(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"));
|
||||
String userName = CommonUtils.nullToEmpty((String)paramMap.get("userName"));
|
||||
List<Map<String, Object>> resultList = (List<Map<String, Object>>)paramMap.get("resultList");
|
||||
|
||||
// 기존 데이터 전체 삭제
|
||||
Map<String, Object> deleteParam = new HashMap<String, Object>();
|
||||
deleteParam.put("projectObjid", projectObjid);
|
||||
sqlSession.delete("productionplanning.deleteProdResultByProject", deleteParam);
|
||||
|
||||
// 새로 입력 (행별로 ROW_SEQ 부여)
|
||||
if(resultList != null && resultList.size() > 0) {
|
||||
int rowSeq = 1; // 행 순번
|
||||
for(Map<String, Object> row : resultList) {
|
||||
String resultDate = CommonUtils.nullToEmpty((String)row.get("RESULT_DATE"));
|
||||
if("".equals(resultDate)) continue;
|
||||
|
||||
int assemblyQty = getIntValue(row.get("ASSEMBLY_QTY"));
|
||||
int inspectionQty = getIntValue(row.get("INSPECTION_QTY"));
|
||||
int shipWaitQty = getIntValue(row.get("SHIP_WAIT_QTY"));
|
||||
String remark = CommonUtils.nullToEmpty((String)row.get("REMARK"));
|
||||
|
||||
// 완조립 수량 입력 (0이어도 입력)
|
||||
Map<String, Object> insertParam = new HashMap<String, Object>();
|
||||
insertParam.put("OBJID", CommonUtils.createObjId());
|
||||
insertParam.put("PROJECT_OBJID", projectObjid);
|
||||
insertParam.put("RESULT_TYPE", "ASSEMBLY");
|
||||
insertParam.put("RESULT_DATE", resultDate);
|
||||
insertParam.put("RESULT_QTY", assemblyQty);
|
||||
insertParam.put("ROW_SEQ", rowSeq);
|
||||
insertParam.put("WORKER_NAME", userName);
|
||||
insertParam.put("REMARK", remark);
|
||||
insertParam.put("userId", userId);
|
||||
sqlSession.insert("productionplanning.insertProdResult", insertParam);
|
||||
|
||||
// 검사 수량 입력 (0이어도 입력)
|
||||
insertParam = new HashMap<String, Object>();
|
||||
insertParam.put("OBJID", CommonUtils.createObjId());
|
||||
insertParam.put("PROJECT_OBJID", projectObjid);
|
||||
insertParam.put("RESULT_TYPE", "INSPECTION");
|
||||
insertParam.put("RESULT_DATE", resultDate);
|
||||
insertParam.put("RESULT_QTY", inspectionQty);
|
||||
insertParam.put("ROW_SEQ", rowSeq);
|
||||
insertParam.put("WORKER_NAME", userName);
|
||||
insertParam.put("REMARK", remark);
|
||||
insertParam.put("userId", userId);
|
||||
sqlSession.insert("productionplanning.insertProdResult", insertParam);
|
||||
|
||||
// 출하대기 수량 입력 (0이어도 입력)
|
||||
insertParam = new HashMap<String, Object>();
|
||||
insertParam.put("OBJID", CommonUtils.createObjId());
|
||||
insertParam.put("PROJECT_OBJID", projectObjid);
|
||||
insertParam.put("RESULT_TYPE", "SHIP_WAIT");
|
||||
insertParam.put("RESULT_DATE", resultDate);
|
||||
insertParam.put("RESULT_QTY", shipWaitQty);
|
||||
insertParam.put("ROW_SEQ", rowSeq);
|
||||
insertParam.put("WORKER_NAME", userName);
|
||||
insertParam.put("REMARK", remark);
|
||||
insertParam.put("userId", userId);
|
||||
sqlSession.insert("productionplanning.insertProdResult", insertParam);
|
||||
|
||||
rowSeq++; // 다음 행
|
||||
}
|
||||
}
|
||||
|
||||
sqlSession.commit();
|
||||
result = true;
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
if(sqlSession != null) {
|
||||
sqlSession.rollback();
|
||||
}
|
||||
} finally {
|
||||
if(sqlSession != null) {
|
||||
sqlSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2955,7 +2955,6 @@ public class PurchaseOrderService {
|
||||
|
||||
try {
|
||||
String targetObjId = CommonUtils.checkNull(paramMap.get("objId"));
|
||||
String pdfSessionId = CommonUtils.checkNull(paramMap.get("pdfSessionId")); // PDF 세션 ID 추가
|
||||
String toEmails = CommonUtils.checkNull(paramMap.get("toEmails"));
|
||||
String ccEmails = CommonUtils.checkNull(paramMap.get("ccEmails"));
|
||||
String subject = CommonUtils.checkNull(paramMap.get("subject"));
|
||||
@@ -2988,7 +2987,9 @@ public class PurchaseOrderService {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
String todayKor = frm.format(cal.getTime());
|
||||
String poNo = CommonUtils.checkNull((String)masterInfo.get("PURCHASE_ORDER_NO"));
|
||||
String excelName = "발주서_" + poNo + "_" + todayKor + ".xls";
|
||||
String zipName = "도면_" + poNo + "_" + todayKor + ".zip";
|
||||
masterInfo.put("EXCELFILE_NAME", excelName);
|
||||
masterInfo.put("APPR_COMPLETE_DATE", frm2.format(cal.getTime()));
|
||||
|
||||
// 발주서 테이블 내용 생성
|
||||
@@ -3028,30 +3029,11 @@ public class PurchaseOrderService {
|
||||
// 첨부파일 목록 생성
|
||||
ArrayList<HashMap> attachFileList = new ArrayList<HashMap>();
|
||||
|
||||
// 1. 발주서 PDF 파일 첨부
|
||||
if(!"".equals(pdfSessionId)) {
|
||||
File pdfFile = getPdfFromSession(pdfSessionId, poNo);
|
||||
if(pdfFile != null && pdfFile.exists()) {
|
||||
HashMap<String, String> pdfFileMap = new HashMap<String, String>();
|
||||
pdfFileMap.put(Constants.Db.COL_FILE_REAL_NAME, pdfFile.getName());
|
||||
pdfFileMap.put(Constants.Db.COL_FILE_SAVED_NAME, pdfFile.getName());
|
||||
pdfFileMap.put(Constants.Db.COL_FILE_PATH, pdfFile.getParent());
|
||||
attachFileList.add(pdfFileMap);
|
||||
System.out.println("발주서 PDF 파일 첨부 완료: " + pdfFile.getAbsolutePath());
|
||||
} else {
|
||||
System.out.println("발주서 PDF 파일을 찾을 수 없습니다: " + pdfSessionId);
|
||||
}
|
||||
}
|
||||
|
||||
/* 엑셀 첨부 주석처리 - PDF로 대체
|
||||
// 1. 발주서 엑셀 파일 첨부
|
||||
String excelName = "발주서_" + poNo + "_" + todayKor + ".xls";
|
||||
masterInfo.put("EXCELFILE_NAME", excelName);
|
||||
HashMap excelFile = this.makeMailAttachFileOrderSheet(masterInfo, contents_table);
|
||||
if(excelFile != null) {
|
||||
attachFileList.add(excelFile);
|
||||
}
|
||||
*/
|
||||
|
||||
// 2. 도면 파일 압축 첨부
|
||||
if(partFileList != null && partFileList.size() > 0) {
|
||||
@@ -3061,7 +3043,7 @@ public class PurchaseOrderService {
|
||||
hm.put(Constants.Db.COL_FILE_REAL_NAME, zf.getName());
|
||||
hm.put(Constants.Db.COL_FILE_SAVED_NAME, zf.getName());
|
||||
// 파일 경로에서 파일명을 제거하고 디렉토리 경로만 추출 (OS 독립적)
|
||||
hm.put(Constants.Db.COL_FILE_PATH, zf.getParent());
|
||||
hm.put(Constants.Db.COL_FILE_PATH, zf.getParent());
|
||||
attachFileList.add(hm);
|
||||
}
|
||||
}
|
||||
@@ -3076,8 +3058,7 @@ public class PurchaseOrderService {
|
||||
fromUser = CommonUtils.checkNull((String)masterInfo.get("WRITER"));
|
||||
}
|
||||
|
||||
// 구매팀 계정(PURCHASE) 사용
|
||||
boolean sendResult = MailUtil.sendMailWithAttachFile(fromUser, fromEmail, toUserIdList, toEmailList, ccEmailList, null, null, subject, mailContents, attachFileList, "PURCHASE_ORDER", Constants.Mail.ACCOUNT_TYPE_PURCHASE);
|
||||
boolean sendResult = MailUtil.sendMailWithAttachFile(fromUser, fromEmail, toUserIdList, toEmailList, ccEmailList, null, null, subject, mailContents, attachFileList, "PURCHASE_ORDER");
|
||||
|
||||
if(sendResult) {
|
||||
// 메일 발송 성공 시 DB 업데이트
|
||||
@@ -3138,7 +3119,6 @@ public class PurchaseOrderService {
|
||||
sb.append(userContents.replace("\n", "<br>"));
|
||||
sb.append("</div>");
|
||||
|
||||
/* 발주서 테이블 본문 표시 주석처리 - PDF 첨부로 대체
|
||||
// 구분선
|
||||
sb.append("<hr style='border: 1px solid #ddd; margin: 20px 0;'>");
|
||||
|
||||
@@ -3147,7 +3127,6 @@ public class PurchaseOrderService {
|
||||
sb.append("<h3 style='margin-bottom: 10px;'>[ 발주서 상세 ]</h3>");
|
||||
sb.append(poContentsTable);
|
||||
sb.append("</div>");
|
||||
*/
|
||||
|
||||
sb.append("<div style='margin-top: 20px; color: #666;'>※발신전용 메일입니다.</div>");
|
||||
sb.append("</body>");
|
||||
@@ -3198,45 +3177,4 @@ public class PurchaseOrderService {
|
||||
}
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 세션 ID로 저장된 PDF 파일 가져오기
|
||||
* @param sessionId PDF 세션 ID
|
||||
* @param poNo 발주번호 (파일명에 사용)
|
||||
* @return PDF 파일
|
||||
*/
|
||||
private File getPdfFromSession(String sessionId, String poNo) {
|
||||
try {
|
||||
String tempDir = System.getProperty("java.io.tmpdir");
|
||||
File pdfFile = new File(tempDir + File.separator + sessionId + ".pdf");
|
||||
|
||||
if(pdfFile.exists()) {
|
||||
// 발주번호로 파일명 변경
|
||||
if("".equals(poNo)) poNo = "발주서";
|
||||
|
||||
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyyMMddHHmmss");
|
||||
String timestamp = sdf.format(new java.util.Date());
|
||||
String newFileName = "발주서_" + poNo + "_" + timestamp + ".pdf";
|
||||
File renamedFile = new File(tempDir + File.separator + newFileName);
|
||||
|
||||
// 파일 복사
|
||||
java.nio.file.Files.copy(pdfFile.toPath(), renamedFile.toPath(),
|
||||
java.nio.file.StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
renamedFile.deleteOnExit();
|
||||
|
||||
// 원본 파일 삭제
|
||||
pdfFile.delete();
|
||||
|
||||
return renamedFile;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
} catch(Exception e) {
|
||||
System.out.println("PDF 파일 가져오기 중 오류: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user