diff --git a/WebContent/WEB-INF/classes/com/pms/mapper/quality.xml b/WebContent/WEB-INF/classes/com/pms/mapper/quality.xml
index 4d6357e..5179bf6 100644
--- a/WebContent/WEB-INF/classes/com/pms/mapper/quality.xml
+++ b/WebContent/WEB-INF/classes/com/pms/mapper/quality.xml
@@ -666,7 +666,7 @@
,POM.PURCHASE_ORDER_NO
,CM.PROJECT_NO
-
+ ,CODE_NAME(CM.PRODUCT) AS PRODUCT_NAME
,(SELECT
CASE
@@ -702,24 +702,85 @@
ELSE '입고중'
END) AS DELIVERY_STATUS
-
- ,(SELECT U.USER_NAME FROM USER_INFO U WHERE U.USER_ID = IID.INSPECTOR_ID) AS INSPECTOR_NAME
- ,IID.INSPECTION_DATE
- ,(CASE WHEN IID.NG_COUNT > 0 THEN 'NG'
- WHEN IID.TOTAL_COUNT > 0 AND IID.TOTAL_COUNT = IID.INSPECTED_COUNT THEN 'OK'
- WHEN IID.INSPECTED_COUNT > 0 THEN '검사중'
+
+ ,(SELECT U.USER_NAME FROM USER_INFO U WHERE U.USER_ID = IID.REQUEST_USER_ID) AS REQUEST_USER_NAME
+ ,IID.REQUEST_DATE
+
+
+ /* 검사자: XXX 외 N건 형태 */
+ ,DEFECT.INSPECTOR_NAME_DISPLAY AS INSPECTOR_NAME
+ /* 검사일: YYYY-MM-DD 외 N건 형태 */
+ ,DEFECT.INSPECTION_DATE_DISPLAY AS INSPECTION_DATE
+ /* 검사결과: 하나라도 NG면 NG, 검사 대상(스킵 제외) 모두 검사완료면 OK, 일부만 검사면 검사중 */
+ ,(CASE WHEN DEFECT.NG_COUNT > 0 THEN 'NG'
+ WHEN DEFECT.INSPECTION_TARGET_COUNT > 0 AND DEFECT.INSPECTION_TARGET_COUNT = DEFECT.INSPECTED_COUNT THEN 'OK'
+ WHEN DEFECT.INSPECTED_COUNT > 0 THEN '검사중'
ELSE '' END) AS INSPECTION_RESULT
+
+ /* 검사여부: 검사가 하나라도 있으면 '검사', 모두 스킵이면 '스킵', 아무것도 없으면 빈값 */
+ ,(CASE WHEN IID.INSPECTION_YN_COUNT > 0 THEN '검사'
+ WHEN IID.SKIP_YN_COUNT > 0 AND IID.INSPECTION_YN_COUNT = 0 THEN '스킵'
+ ELSE '' END) AS INSPECTION_YN
+
+ /* 요청현황: 입고내역 기준으로 검사여부 선택 현황 계산
+ 미요청: 입고건이 있지만 전부 검사여부 미선택
+ 요청중: 일부만 검사여부 선택됨
+ 요청완료: 전부 검사여부 선택됨 */
+ ,(CASE WHEN REQ.DELIVERY_TOTAL_COUNT IS NULL OR REQ.DELIVERY_TOTAL_COUNT = 0 THEN ''
+ WHEN REQ.SELECTED_COUNT = 0 THEN '미요청'
+ WHEN REQ.SELECTED_COUNT REQ.DELIVERY_TOTAL_COUNT THEN '요청중'
+ ELSE '요청완료' END) AS REQUEST_STATUS
+ ,(SELECT COUNT(1) FROM ATTACH_FILE_INFO AF WHERE AF.TARGET_OBJID = POM.OBJID AND AF.DOC_TYPE = 'INSPECTION_FILE' AND UPPER(AF.STATUS) = 'ACTIVE') AS INSPECTION_FILE_CNT
FROM PURCHASE_ORDER_MASTER AS POM
LEFT OUTER JOIN (
SELECT PURCHASE_ORDER_MASTER_OBJID
- ,MAX(INSPECTOR_ID) AS INSPECTOR_ID
- ,MAX(INSPECTION_DATE) AS INSPECTION_DATE
+ ,MAX(REQUEST_USER_ID) AS REQUEST_USER_ID
+ ,MAX(REQUEST_DATE) AS REQUEST_DATE
,COUNT(*) AS TOTAL_COUNT
- ,COUNT(CASE WHEN INSPECTION_RESULT IS NOT NULL AND INSPECTION_RESULT != '' THEN 1 END) AS INSPECTED_COUNT
- ,COUNT(CASE WHEN INSPECTION_RESULT = 'NG' THEN 1 END) AS NG_COUNT
+ /* 검사여부 카운트: 검사 선택 건수, 스킵 선택 건수 */
+ ,COUNT(CASE WHEN INSPECTION_YN = '검사' THEN 1 END) AS INSPECTION_YN_COUNT
+ ,COUNT(CASE WHEN INSPECTION_YN = '스킵' THEN 1 END) AS SKIP_YN_COUNT
FROM INCOMING_INSPECTION_DETAIL
GROUP BY PURCHASE_ORDER_MASTER_OBJID
) AS IID ON POM.OBJID::VARCHAR = IID.PURCHASE_ORDER_MASTER_OBJID
+ /* 불량상세 테이블에서 검사일/검사자/검사결과 집계 (스킵 항목 제외) */
+ LEFT OUTER JOIN (
+ SELECT IID2.PURCHASE_ORDER_MASTER_OBJID
+ /* 검사자: 여러명이면 "XXX 외 N건" 형태로 표시 */
+ ,CASE
+ WHEN COUNT(DISTINCT IDF.INSPECTOR_ID) > 1
+ THEN (SELECT USER_NAME FROM USER_INFO WHERE USER_ID = MIN(IDF.INSPECTOR_ID)) || ' 외 ' || (COUNT(DISTINCT IDF.INSPECTOR_ID) - 1) || '건'
+ WHEN COUNT(DISTINCT IDF.INSPECTOR_ID) = 1
+ THEN (SELECT USER_NAME FROM USER_INFO WHERE USER_ID = MIN(IDF.INSPECTOR_ID))
+ ELSE ''
+ END AS INSPECTOR_NAME_DISPLAY
+ /* 검사일: 여러개면 "YYYY-MM-DD 외 N건" 형태로 표시 */
+ ,CASE
+ WHEN COUNT(DISTINCT IDF.INSPECTION_DATE) > 1
+ THEN TO_CHAR(MIN(IDF.INSPECTION_DATE), 'YYYY-MM-DD') || ' 외 ' || (COUNT(DISTINCT IDF.INSPECTION_DATE) - 1) || '건'
+ WHEN COUNT(DISTINCT IDF.INSPECTION_DATE) = 1
+ THEN TO_CHAR(MIN(IDF.INSPECTION_DATE), 'YYYY-MM-DD')
+ ELSE ''
+ END AS INSPECTION_DATE_DISPLAY
+ /* 검사 대상 건수 (스킵 제외, 검사인 항목만) */
+ ,COUNT(CASE WHEN IID2.INSPECTION_YN = '검사' THEN 1 END) AS INSPECTION_TARGET_COUNT
+ /* 검사결과 입력된 건수 */
+ ,COUNT(CASE WHEN IDF.INSPECTION_RESULT IS NOT NULL AND IDF.INSPECTION_RESULT != '' THEN 1 END) AS INSPECTED_COUNT
+ ,COUNT(CASE WHEN IDF.INSPECTION_RESULT = 'NG' THEN 1 END) AS NG_COUNT
+ FROM INCOMING_INSPECTION_DETAIL IID2
+ LEFT JOIN INCOMING_INSPECTION_DEFECT IDF ON IDF.INSPECTION_DETAIL_OBJID = IID2.OBJID
+ GROUP BY IID2.PURCHASE_ORDER_MASTER_OBJID
+ ) AS DEFECT ON POM.OBJID::VARCHAR = DEFECT.PURCHASE_ORDER_MASTER_OBJID
+ /* 입고내역 기준 검사여부 선택 현황 (요청현황 계산용) */
+ LEFT OUTER JOIN (
+ SELECT IMI.PURCHASE_ORDER_MASTER_OBJID
+ ,COUNT(*) AS DELIVERY_TOTAL_COUNT
+ ,COUNT(CASE WHEN IID.INSPECTION_YN IS NOT NULL AND IID.INSPECTION_YN != '' THEN 1 END) AS SELECTED_COUNT
+ FROM INVENTORY_MGMT_IN IMI
+ LEFT JOIN INCOMING_INSPECTION_DETAIL IID ON IID.INVENTORY_IN_OBJID = IMI.OBJID
+ WHERE IMI.PURCHASE_ORDER_MASTER_OBJID IS NOT NULL
+ GROUP BY IMI.PURCHASE_ORDER_MASTER_OBJID
+ ) AS REQ ON POM.OBJID::VARCHAR = REQ.PURCHASE_ORDER_MASTER_OBJID
LEFT OUTER JOIN (
SELECT POP.PURCHASE_ORDER_MASTER_OBJID
,SUM(POP.ORDER_QTY::NUMERIC) AS TOTAL_PO_QTY
@@ -792,6 +853,11 @@
WHEN IID.INSPECTED_COUNT > 0 THEN '검사중'
ELSE '' END) = #{search_inspection_result}
+
+
+ AND REQ.DELIVERY_TOTAL_COUNT = REQ.SELECTED_COUNT
+ AND REQ.SELECTED_COUNT > 0
+
ORDER BY POM.REGDATE DESC
@@ -1497,6 +1563,7 @@
+
+
+
@@ -2062,6 +2224,8 @@
OBJID
, INVENTORY_IN_OBJID
, PURCHASE_ORDER_MASTER_OBJID
+ , REQUEST_DATE
+ , REQUEST_USER_ID
, INSPECTION_DATE
, INSPECTOR_ID
, INSPECTION_TYPE
@@ -2080,6 +2244,8 @@
#{NEW_OBJID}
, #{OBJID}
, #{PURCHASE_ORDER_MASTER_OBJID}
+ , #{REQUEST_DATE}
+ , #{REQUEST_USER_ID}
, #{INSPECTION_DATE}
, #{INSPECTOR_ID}
, #{INSPECTION_TYPE}
@@ -2096,20 +2262,120 @@
, NOW()
)
ON CONFLICT (INVENTORY_IN_OBJID) DO UPDATE SET
- INSPECTION_DATE = #{INSPECTION_DATE}
- , INSPECTOR_ID = #{INSPECTOR_ID}
- , INSPECTION_TYPE = #{INSPECTION_TYPE}
- , INSPECTION_YN = #{INSPECTION_YN}
- , DEFECT_TYPE = #{DEFECT_TYPE}
- , DEFECT_REASON = #{DEFECT_REASON}
- , ACTION_STATUS = #{ACTION_STATUS}
- , INSPECTION_QTY = #{INSPECTION_QTY}
- , DEFECT_QTY = #{DEFECT_QTY}
- , INSPECTION_RESULT = #{INSPECTION_RESULT}
- , ATTACH_FILE_OBJID = #{ATTACH_FILE_OBJID}
- , REMARK = #{REMARK}
+ REQUEST_DATE = COALESCE(#{REQUEST_DATE}, INCOMING_INSPECTION_DETAIL.REQUEST_DATE)
+ , REQUEST_USER_ID = COALESCE(#{REQUEST_USER_ID}, INCOMING_INSPECTION_DETAIL.REQUEST_USER_ID)
+ , INSPECTION_DATE = COALESCE(#{INSPECTION_DATE}, INCOMING_INSPECTION_DETAIL.INSPECTION_DATE)
+ , INSPECTOR_ID = COALESCE(#{INSPECTOR_ID}, INCOMING_INSPECTION_DETAIL.INSPECTOR_ID)
+ , INSPECTION_TYPE = COALESCE(#{INSPECTION_TYPE}, INCOMING_INSPECTION_DETAIL.INSPECTION_TYPE)
+ , INSPECTION_YN = COALESCE(#{INSPECTION_YN}, INCOMING_INSPECTION_DETAIL.INSPECTION_YN)
+ , DEFECT_TYPE = COALESCE(#{DEFECT_TYPE}, INCOMING_INSPECTION_DETAIL.DEFECT_TYPE)
+ , DEFECT_REASON = COALESCE(#{DEFECT_REASON}, INCOMING_INSPECTION_DETAIL.DEFECT_REASON)
+ , ACTION_STATUS = COALESCE(#{ACTION_STATUS}, INCOMING_INSPECTION_DETAIL.ACTION_STATUS)
+ , INSPECTION_QTY = COALESCE(#{INSPECTION_QTY}, INCOMING_INSPECTION_DETAIL.INSPECTION_QTY)
+ , DEFECT_QTY = COALESCE(#{DEFECT_QTY}, INCOMING_INSPECTION_DETAIL.DEFECT_QTY)
+ , INSPECTION_RESULT = COALESCE(#{INSPECTION_RESULT}, INCOMING_INSPECTION_DETAIL.INSPECTION_RESULT)
+ , ATTACH_FILE_OBJID = COALESCE(#{ATTACH_FILE_OBJID}, INCOMING_INSPECTION_DETAIL.ATTACH_FILE_OBJID)
+ , REMARK = COALESCE(#{REMARK}, INCOMING_INSPECTION_DETAIL.REMARK)
, MODIFIER = #{WRITER}
, MOD_DATE = NOW()
+
+
+
+
+
+
+
+ INSERT INTO INCOMING_INSPECTION_DEFECT (
+ OBJID
+ , INSPECTION_DETAIL_OBJID
+ , INSPECTION_TYPE
+ , INSPECTION_DATE
+ , INSPECTOR_ID
+ , DEFECT_TYPE
+ , DEFECT_REASON
+ , ACTION_STATUS
+ , ACTION_RESULT
+ , INSPECTION_QTY
+ , DEFECT_QTY
+ , INSPECTION_RESULT
+ , REMARK
+ , WRITER
+ , REG_DATE
+ ) VALUES (
+ #{OBJID}
+ , #{INSPECTION_DETAIL_OBJID}
+ , #{INSPECTION_TYPE}
+ , #{INSPECTION_DATE}::DATE
+ , #{INSPECTOR_ID}
+ , #{DEFECT_TYPE}
+ , #{DEFECT_REASON}
+ , #{ACTION_STATUS}
+ , #{ACTION_RESULT}
+ , #{INSPECTION_QTY}
+ , #{DEFECT_QTY}
+ , #{INSPECTION_RESULT}
+ , #{REMARK}
+ , #{WRITER}
+ , NOW()
+ )
+ ON CONFLICT (OBJID) DO UPDATE SET
+ INSPECTION_TYPE = #{INSPECTION_TYPE}
+ , INSPECTION_DATE = #{INSPECTION_DATE}::DATE
+ , INSPECTOR_ID = #{INSPECTOR_ID}
+ , DEFECT_TYPE = #{DEFECT_TYPE}
+ , DEFECT_REASON = #{DEFECT_REASON}
+ , ACTION_STATUS = #{ACTION_STATUS}
+ , ACTION_RESULT = #{ACTION_RESULT}
+ , INSPECTION_QTY = #{INSPECTION_QTY}
+ , DEFECT_QTY = #{DEFECT_QTY}
+ , INSPECTION_RESULT = #{INSPECTION_RESULT}
+ , REMARK = #{REMARK}
+ , MODIFIER = #{WRITER}
+ , MOD_DATE = NOW()
+
+
+
+
+ DELETE FROM INCOMING_INSPECTION_DEFECT
+ WHERE OBJID = #{OBJID}
+
+
+
+
+ DELETE FROM INCOMING_INSPECTION_DEFECT
+ WHERE INSPECTION_DETAIL_OBJID = #{INSPECTION_DETAIL_OBJID}
+
+
\ No newline at end of file
diff --git a/WebContent/WEB-INF/view/quality/semiProductInspectionFormPopUp.jsp b/WebContent/WEB-INF/view/quality/semiProductInspectionFormPopUp.jsp
index 4ea2d53..924e006 100644
--- a/WebContent/WEB-INF/view/quality/semiProductInspectionFormPopUp.jsp
+++ b/WebContent/WEB-INF/view/quality/semiProductInspectionFormPopUp.jsp
@@ -18,6 +18,8 @@ PersonBean person = (PersonBean)session.getAttribute(Constants.PERSON_BEAN);
String loginUserName = CommonUtils.checkNull(person.getUserName());
String loginUserId = CommonUtils.checkNull(person.getUserId());
%>
+
+
@@ -48,7 +50,8 @@ String loginUserId = CommonUtils.checkNull(person.getUserId());
justify-content: space-between;
align-items: center;
padding: 10px 15px;
- background: #f5f5f5;
+ background: #4a5568;
+ color: white;
border-bottom: 1px solid #ddd;
}
@@ -62,57 +65,59 @@ String loginUserId = CommonUtils.checkNull(person.getUserId());
display: flex;
flex: 1;
overflow: hidden;
+ gap: 10px;
+ padding: 10px;
}
- /* 왼쪽 영역 */
- .left_section {
- width: 50%;
+ /* 좌측 패널 (35%) */
+ .left_panel {
+ width: 35%;
display: flex;
flex-direction: column;
- border-right: 2px solid #ccc;
- padding: 10px;
- box-sizing: border-box;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ overflow: hidden;
}
- /* 오른쪽 영역 */
- .right_section {
- width: 50%;
+ /* 우측 패널 (65%) */
+ .right_panel {
+ width: 65%;
display: flex;
flex-direction: column;
- padding: 10px;
- box-sizing: border-box;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ overflow: hidden;
}
- .section_header {
+ .panel_header {
display: flex;
justify-content: space-between;
align-items: center;
- margin-bottom: 8px;
- padding-bottom: 5px;
- border-bottom: 1px solid #e0e0e0;
- }
-
- .section_header h3 {
- margin: 0;
- font-size: 14px;
+ padding: 8px 12px;
+ background: #4a5568;
+ color: white;
font-weight: bold;
- color: #333;
+ font-size: 13px;
}
- .section_header .btn_area {
+ .panel_header .btn_group {
display: flex;
gap: 5px;
}
- .grid_wrap {
+ .panel_body {
flex: 1;
- overflow: hidden;
+ overflow: auto;
+ }
+
+ .grid_wrap {
+ height: 100%;
}
/* 버튼 스타일 */
.btn_add {
- padding: 4px 12px;
- background: #4CAF50;
+ padding: 4px 10px;
+ background: #48bb78;
color: white;
border: none;
border-radius: 3px;
@@ -121,12 +126,12 @@ String loginUserId = CommonUtils.checkNull(person.getUserId());
}
.btn_add:hover {
- background: #45a049;
+ background: #38a169;
}
.btn_del {
- padding: 4px 12px;
- background: #f44336;
+ padding: 4px 10px;
+ background: #e53e3e;
color: white;
border: none;
border-radius: 3px;
@@ -135,12 +140,12 @@ String loginUserId = CommonUtils.checkNull(person.getUserId());
}
.btn_del:hover {
- background: #da190b;
+ background: #c53030;
}
.btn_save {
padding: 6px 20px;
- background: #2196F3;
+ background: #3182ce;
color: white;
border: none;
border-radius: 3px;
@@ -150,12 +155,12 @@ String loginUserId = CommonUtils.checkNull(person.getUserId());
}
.btn_save:hover {
- background: #1976D2;
+ background: #2b6cb0;
}
.btn_close {
padding: 6px 20px;
- background: #757575;
+ background: #718096;
color: white;
border: none;
border-radius: 3px;
@@ -165,7 +170,7 @@ String loginUserId = CommonUtils.checkNull(person.getUserId());
}
.btn_close:hover {
- background: #616161;
+ background: #4a5568;
}
/* 헤더 버튼 영역 */
@@ -174,9 +179,20 @@ String loginUserId = CommonUtils.checkNull(person.getUserId());
gap: 8px;
}
- /* Tabulator 편집 가능 셀 스타일 */
- .tabulator .tabulator-cell.editable-cell {
- background-color: #fffde7;
+ /* 선택된 행 하이라이트 */
+ .tabulator-row.tabulator-selected {
+ background-color: #e3f2fd !important;
+ }
+
+ /* 비활성화 안내 */
+ .disabled_notice {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ color: #999;
+ font-size: 14px;
+ background: #f5f5f5;
}
/* Select2 스타일 */
@@ -202,54 +218,69 @@ String loginUserId = CommonUtils.checkNull(person.getUserId());