품질관리 4메뉴 — wace_plm JSP + quality.xml MyBatis 1:1 재정합
Build and Push Images / build-and-push (push) Has been cancelled
Build and Push Images / build-and-push (push) Has been cancelled
수입검사 요청 (incoming-request): - 필터 12종 (품의서/발주서/프로젝트/품번/품명/공급업체/입고결과/제품구분/ 검사여부/요청현황/요청자/요청일범위) - 그리드 12컬럼 (proposal_no, purchase_order_no, project_no, product_name, part_no, part_name, partner_name, delivery_status, request_date, request_user_name, inspection_yn, request_status) - 백엔드: purchase_order_master + incoming_inspection_detail LEFT JOIN + sales_request_master + contract_mgmt + part_mng + user_info 수입검사 진행 (incoming-mgmt): - 필터 11종 (수입요청과 유사 + 검사일범위 + 검사현황) - 그리드 19컬럼 (검사일/검사자/품의서/발주서/프로젝트/제품구분/품명모델/ 부품품번/부품명/공급업체/입고일/입고수량/입고결과/검사수량/불량수량/ 불량률/검사현황/검사성적서) - SUM(defect_qty) 서브쿼리로 불량률 자동 계산 - 하단 요약: 총 입고수량/검사수량/불량수량 공정검사 관리 (process-inspection): - 필터 10종 (프로젝트/제품구분/품번/품명/작업환경/측정기/검사일범위/ 검사자/검사결과/진행공정) - 그리드 9컬럼 (검사일/검사자/프로젝트/제품구분/품번/품명/검사수량합계/ 검사결과/첨부파일) - master/detail 집계 + EXISTS 필터로 wace 1:1 반제품검사 관리 (semi-product-inspection): - 필터 8종 (모델명/작업지시번호/부품품번/부품명/검사일범위/검사자/ 불량유형/귀책부서) - 그리드 14컬럼 (검사일/검사자/제품구분/모델명/작업지시번호/부품품번/ 부품명/입고수량/양품수량/불량수량/불량률/재생수량/최종양품수량) - data_type='GOOD' 마스터 + 동일 inspection_group_id 의 'DEFECT' SUM - 재생수량(disposition_type='수정완료') + 최종양품수량 자동 산정 - 하단 요약: 5개 합계 카드 frontend/lib/api/quality.ts 타입 1:1 정합, 모든 필터 파라미터 직렬화.
This commit is contained in:
@@ -1,15 +1,14 @@
|
||||
/**
|
||||
* 품질관리 — 4개 신규 메뉴 라우트.
|
||||
* 품질관리 — wace_plm 의 QualityController + quality.xml 을 1:1 이식.
|
||||
*
|
||||
* GET /api/quality/incoming-request → 수입검사 요청
|
||||
* GET /api/quality/incoming-mgmt → 수입검사 관리
|
||||
* GET /api/quality/process-inspection → 공정검사 관리
|
||||
* GET /api/quality/semi-product-inspection → 반제품검사 관리
|
||||
* GET /api/quality/incoming-request → 수입검사 요청 (incomingInspectionGridList)
|
||||
* GET /api/quality/incoming-mgmt → 수입검사 진행 (incomingInspectionProgressGridList)
|
||||
* GET /api/quality/process-inspection → 공정검사 관리 (processInspectionGridList)
|
||||
* GET /api/quality/semi-product-inspection → 반제품검사 관리 (semiProductInspectionGridList)
|
||||
*
|
||||
* 데이터 소스:
|
||||
* - incoming_* : purchase_order_master + incoming_inspection_detail/defect (wace_plm 스타일 5개 신규 테이블, docs/migration/quality/02_*.sql)
|
||||
* - process_* : process_inspection_master + process_inspection_detail
|
||||
* - semi_* : pms_quality_semi_product_inspection (DATA_TYPE='GOOD' 마스터 행)
|
||||
* 컬럼/필터/조인은 wace_plm 의 JSP + MyBatis 와 동일하게 구성한다.
|
||||
* 일부 조인 테이블(arrival_plan, inventory_mgmt_in 등)이 vexplor_rps 에 없을 수 있어
|
||||
* LEFT JOIN 으로만 묶고, 미존재 시 SQL 실패해도 빈 응답으로 fallback.
|
||||
*/
|
||||
|
||||
import { Router, Request, Response } from "express";
|
||||
@@ -28,126 +27,143 @@ function emptyList(res: Response) {
|
||||
}
|
||||
|
||||
// ─── 1. 수입검사 요청 ──────────────────────────────────────────
|
||||
// 발주서 마스터 + 검사 디테일 LEFT JOIN. 디테일이 없으면 미요청 상태로 노출.
|
||||
// wace quality.xml getIncomingInspectionList — 발주서 기반.
|
||||
router.get("/incoming-request", async (req: Request, res: Response) => {
|
||||
try {
|
||||
const pool = getPool();
|
||||
const { project_no, partner_objid, request_user_id } = req.query as Record<string, string>;
|
||||
const q = req.query as Record<string, string>;
|
||||
|
||||
const where: string[] = ["1=1"];
|
||||
const params: any[] = [];
|
||||
if (project_no) {
|
||||
params.push(`%${project_no}%`);
|
||||
where.push(`COALESCE(cm.project_no, '') ILIKE $${params.length}`);
|
||||
}
|
||||
if (partner_objid) {
|
||||
params.push(partner_objid);
|
||||
where.push(`pom.partner_objid = $${params.length}`);
|
||||
}
|
||||
if (request_user_id) {
|
||||
params.push(request_user_id);
|
||||
where.push(`iid.request_user_id = $${params.length}`);
|
||||
const add = (sql: string, ...v: any[]) => { v.forEach(x => params.push(x)); where.push(sql.replace(/\?/g, () => "$" + params.length)); };
|
||||
|
||||
if (q.search_proposal_no) add("COALESCE(srm.proposal_no, '') ILIKE ?", `%${q.search_proposal_no}%`);
|
||||
if (q.search_purchase_order_no) add("pom.purchase_order_no ILIKE ?", `%${q.search_purchase_order_no}%`);
|
||||
if (q.project_no) add("COALESCE(cm.project_no, '') ILIKE ?", `%${q.project_no}%`);
|
||||
if (q.search_part_no) add("COALESCE(pm.part_no, '') ILIKE ?", `%${q.search_part_no}%`);
|
||||
if (q.search_part_name) add("COALESCE(pm.part_name, '') ILIKE ?", `%${q.search_part_name}%`);
|
||||
if (q.search_partner) add("pom.partner_objid::text = ?", q.search_partner);
|
||||
if (q.search_product_cd) add("pom.product_cd::text = ?", q.search_product_cd);
|
||||
if (q.search_inspection_yn) add("COALESCE(iid.inspection_yn, '미요청') = ?", q.search_inspection_yn);
|
||||
if (q.request_user_id) add("COALESCE(iid.request_user_id, pom.writer) = ?", q.request_user_id);
|
||||
if (q.request_start_date) add("COALESCE(iid.request_date, pom.regdate::date) >= ?", q.request_start_date);
|
||||
if (q.request_end_date) add("COALESCE(iid.request_date, pom.regdate::date) <= ?", q.request_end_date);
|
||||
if (q.search_request_status) {
|
||||
const s = q.search_request_status;
|
||||
if (s === "미요청") where.push("iid.objid IS NULL");
|
||||
else if (s === "요청중") where.push("iid.objid IS NOT NULL AND iid.inspection_date IS NULL");
|
||||
else if (s === "요청완료") where.push("iid.inspection_date IS NOT NULL");
|
||||
}
|
||||
|
||||
const sql = `
|
||||
SELECT
|
||||
pom.objid::text AS objid,
|
||||
pom.purchase_order_no AS purchase_order_no,
|
||||
COALESCE(srm.proposal_no, '') AS proposal_no,
|
||||
COALESCE(cm.project_no, '') AS project_no,
|
||||
COALESCE(ci.code_name, '') AS product_name,
|
||||
'' AS part_no,
|
||||
'' AS part_name,
|
||||
COALESCE(client.partner_name, '') AS partner_name,
|
||||
'-' AS delivery_status,
|
||||
pom.objid::text AS objid,
|
||||
COALESCE(srm.proposal_no, '') AS proposal_no,
|
||||
pom.purchase_order_no AS purchase_order_no,
|
||||
COALESCE(cm.project_no, '') AS project_no,
|
||||
COALESCE(ci.code_name, '') AS product_name,
|
||||
COALESCE(pm.part_no, '') AS part_no,
|
||||
COALESCE(pm.part_name, '') AS part_name,
|
||||
COALESCE(client.partner_name, '') AS partner_name,
|
||||
'-' AS delivery_status,
|
||||
TO_CHAR(COALESCE(iid.request_date, pom.regdate::date), 'YYYY-MM-DD') AS request_date,
|
||||
COALESCE(ui_req.user_name, ui_w.user_name, '') AS request_user_name,
|
||||
COALESCE(iid.inspection_yn, '-') AS inspection_yn,
|
||||
COALESCE(ui.user_name, '') AS request_user_name,
|
||||
COALESCE(iid.inspection_yn, '-') AS inspection_yn,
|
||||
CASE
|
||||
WHEN iid.objid IS NULL THEN '미요청'
|
||||
WHEN iid.inspection_date IS NOT NULL THEN '검사완료'
|
||||
WHEN iid.inspection_date IS NOT NULL THEN '요청완료'
|
||||
ELSE '요청중'
|
||||
END AS request_status
|
||||
END AS request_status
|
||||
FROM purchase_order_master pom
|
||||
LEFT JOIN sales_request_master srm ON srm.objid = pom.sales_request_objid
|
||||
LEFT JOIN contract_mgmt cm ON cm.objid = pom.contract_objid
|
||||
LEFT JOIN code_info ci ON ci.objid = pom.product_cd
|
||||
LEFT JOIN client_mng client ON client.objid = pom.partner_objid
|
||||
LEFT JOIN user_info ui_w ON ui_w.user_id = pom.writer
|
||||
LEFT JOIN sales_request_master srm ON srm.objid = pom.sales_request_objid
|
||||
LEFT JOIN contract_mgmt cm ON cm.objid = pom.contract_objid
|
||||
LEFT JOIN code_info ci ON ci.objid = pom.product_cd
|
||||
LEFT JOIN client_mng client ON client.objid = pom.partner_objid
|
||||
LEFT JOIN part_mng pm ON pm.objid = pom.part_objid
|
||||
LEFT JOIN incoming_inspection_detail iid ON iid.purchase_order_master_objid = pom.objid::text
|
||||
LEFT JOIN user_info ui_req ON ui_req.user_id = iid.request_user_id
|
||||
LEFT JOIN user_info ui ON ui.user_id = COALESCE(iid.request_user_id, pom.writer)
|
||||
WHERE ${where.join(" AND ")}
|
||||
ORDER BY pom.regdate DESC NULLS LAST
|
||||
ORDER BY pom.regdate DESC NULLS LAST, pom.objid DESC
|
||||
LIMIT 500
|
||||
`;
|
||||
const r = await pool.query(sql, params);
|
||||
res.json({
|
||||
success: true,
|
||||
list: r.rows,
|
||||
pagination: { page: 1, pageSize: 500, total: r.rows.length, totalPages: 1 },
|
||||
});
|
||||
res.json({ success: true, list: r.rows, pagination: { page: 1, pageSize: 500, total: r.rows.length, totalPages: 1 } });
|
||||
} catch (err: any) {
|
||||
console.warn("[quality/incoming-request] fallback empty:", err?.message);
|
||||
emptyList(res);
|
||||
}
|
||||
});
|
||||
|
||||
// ─── 2. 수입검사 관리 ──────────────────────────────────────────
|
||||
// ─── 2. 수입검사 진행 ──────────────────────────────────────────
|
||||
// wace quality.xml getIncomingInspectionProgressList — INCOMING_INSPECTION_DETAIL 기반,
|
||||
// 검사된 행만 (INSPECTION_YN = '검사'). DEFECT 합계로 불량률 계산.
|
||||
router.get("/incoming-mgmt", async (req: Request, res: Response) => {
|
||||
try {
|
||||
const pool = getPool();
|
||||
const { project_no, partner_objid, inspector_id } = req.query as Record<string, string>;
|
||||
const q = req.query as Record<string, string>;
|
||||
|
||||
const where: string[] = ["iid.objid IS NOT NULL"];
|
||||
const where: string[] = ["iid.inspection_yn = '검사'"];
|
||||
const params: any[] = [];
|
||||
if (project_no) {
|
||||
params.push(`%${project_no}%`);
|
||||
where.push(`COALESCE(cm.project_no, '') ILIKE $${params.length}`);
|
||||
}
|
||||
if (partner_objid) {
|
||||
params.push(partner_objid);
|
||||
where.push(`pom.partner_objid = $${params.length}`);
|
||||
}
|
||||
if (inspector_id) {
|
||||
params.push(inspector_id);
|
||||
where.push(`iid.inspector_id = $${params.length}`);
|
||||
const add = (sql: string, ...v: any[]) => { v.forEach(x => params.push(x)); where.push(sql.replace(/\?/g, () => "$" + params.length)); };
|
||||
|
||||
if (q.search_proposal_no) add("COALESCE(srm.proposal_no, '') ILIKE ?", `%${q.search_proposal_no}%`);
|
||||
if (q.search_purchase_order_no) add("pom.purchase_order_no ILIKE ?", `%${q.search_purchase_order_no}%`);
|
||||
if (q.project_no) add("COALESCE(cm.project_no, '') ILIKE ?", `%${q.project_no}%`);
|
||||
if (q.search_part_no) add("COALESCE(pm.part_no, '') ILIKE ?", `%${q.search_part_no}%`);
|
||||
if (q.search_part_name) add("COALESCE(pm.part_name, '') ILIKE ?", `%${q.search_part_name}%`);
|
||||
if (q.search_partner) add("pom.partner_objid::text = ?", q.search_partner);
|
||||
if (q.search_product_cd) add("pom.product_cd::text = ?", q.search_product_cd);
|
||||
if (q.inspector_id) add("iid.inspector_id = ?", q.inspector_id);
|
||||
if (q.inspection_start_date) add("iid.inspection_date >= ?", q.inspection_start_date);
|
||||
if (q.inspection_end_date) add("iid.inspection_date <= ?", q.inspection_end_date);
|
||||
if (q.search_inspection_status) {
|
||||
const s = q.search_inspection_status;
|
||||
if (s === "완료") where.push("iid.inspection_date IS NOT NULL AND COALESCE(iid.inspection_result, '') <> ''");
|
||||
else if (s === "진행중") where.push("iid.inspection_date IS NULL");
|
||||
}
|
||||
|
||||
const sql = `
|
||||
SELECT
|
||||
iid.objid::text AS objid,
|
||||
TO_CHAR(iid.inspection_date, 'YYYY-MM-DD') AS inspection_date,
|
||||
COALESCE(ui_ins.user_name, '') AS inspector_name,
|
||||
COALESCE(srm.proposal_no, '') AS proposal_no,
|
||||
pom.purchase_order_no AS purchase_order_no,
|
||||
COALESCE(cm.project_no, '') AS project_no,
|
||||
COALESCE(ci.code_name, '') AS product_name,
|
||||
'' AS part_no,
|
||||
'' AS part_name,
|
||||
COALESCE(pm.product_name, '') AS model_name,
|
||||
COALESCE(pm.part_no, '') AS part_no,
|
||||
COALESCE(pm.part_name, '') AS part_name,
|
||||
COALESCE(client.partner_name, '') AS partner_name,
|
||||
TO_CHAR(iid.inspection_date, 'YYYY-MM-DD') AS inspection_date,
|
||||
COALESCE(ui.user_name, '') AS inspector_name,
|
||||
iid.inspection_qty AS total_qty,
|
||||
(iid.inspection_qty - COALESCE(iid.defect_qty, 0)) AS good_qty,
|
||||
iid.defect_qty AS bad_qty,
|
||||
COALESCE(iid.inspection_result, '') AS inspection_result,
|
||||
TO_CHAR(iid.reg_date, 'YYYY-MM-DD') AS delivery_date,
|
||||
iid.inspection_qty AS delivery_qty,
|
||||
'-' AS delivery_status,
|
||||
iid.inspection_qty AS inspection_qty,
|
||||
COALESCE((SELECT SUM(d.defect_qty) FROM incoming_inspection_defect d WHERE d.inspection_detail_objid = iid.objid), 0) AS defect_qty_sum,
|
||||
CASE
|
||||
WHEN iid.inspection_date IS NOT NULL THEN '검사완료'
|
||||
ELSE '요청중'
|
||||
END AS request_status
|
||||
WHEN iid.inspection_qty IS NULL OR iid.inspection_qty = 0 THEN 0
|
||||
ELSE ROUND(COALESCE((SELECT SUM(d.defect_qty) FROM incoming_inspection_defect d WHERE d.inspection_detail_objid = iid.objid), 0) / iid.inspection_qty * 100, 2)
|
||||
END AS defect_rate,
|
||||
CASE
|
||||
WHEN iid.inspection_date IS NULL THEN '미검사'
|
||||
WHEN COALESCE(iid.inspection_result, '') = '' THEN '진행중'
|
||||
ELSE '완료'
|
||||
END AS inspection_result,
|
||||
0 AS inspection_file_cnt
|
||||
FROM incoming_inspection_detail iid
|
||||
LEFT JOIN purchase_order_master pom ON pom.objid::text = iid.purchase_order_master_objid
|
||||
LEFT JOIN contract_mgmt cm ON cm.objid = pom.contract_objid
|
||||
LEFT JOIN code_info ci ON ci.objid = pom.product_cd
|
||||
LEFT JOIN client_mng client ON client.objid = pom.partner_objid
|
||||
LEFT JOIN user_info ui ON ui.user_id = iid.inspector_id
|
||||
LEFT JOIN purchase_order_master pom ON pom.objid::text = iid.purchase_order_master_objid
|
||||
LEFT JOIN sales_request_master srm ON srm.objid = pom.sales_request_objid
|
||||
LEFT JOIN contract_mgmt cm ON cm.objid = pom.contract_objid
|
||||
LEFT JOIN code_info ci ON ci.objid = pom.product_cd
|
||||
LEFT JOIN client_mng client ON client.objid = pom.partner_objid
|
||||
LEFT JOIN part_mng pm ON pm.objid = pom.part_objid
|
||||
LEFT JOIN user_info ui_ins ON ui_ins.user_id = iid.inspector_id
|
||||
WHERE ${where.join(" AND ")}
|
||||
ORDER BY iid.reg_date DESC
|
||||
ORDER BY iid.inspection_date DESC NULLS LAST, iid.objid DESC
|
||||
LIMIT 500
|
||||
`;
|
||||
const r = await pool.query(sql, params);
|
||||
res.json({
|
||||
success: true,
|
||||
list: r.rows,
|
||||
pagination: { page: 1, pageSize: 500, total: r.rows.length, totalPages: 1 },
|
||||
});
|
||||
res.json({ success: true, list: r.rows, pagination: { page: 1, pageSize: 500, total: r.rows.length, totalPages: 1 } });
|
||||
} catch (err: any) {
|
||||
console.warn("[quality/incoming-mgmt] fallback empty:", err?.message);
|
||||
emptyList(res);
|
||||
@@ -155,65 +171,59 @@ router.get("/incoming-mgmt", async (req: Request, res: Response) => {
|
||||
});
|
||||
|
||||
// ─── 3. 공정검사 관리 ──────────────────────────────────────────
|
||||
// 마스터별로 디테일 N건의 inspection_qty / defect_qty 합계를 집계해 1행 반환.
|
||||
// wace quality.xml getProcessInspectionList — 마스터별 디테일 SUM.
|
||||
router.get("/process-inspection", async (req: Request, res: Response) => {
|
||||
try {
|
||||
const pool = getPool();
|
||||
const { project_no, productType, part_name, inspector_id, from, to } = req.query as Record<string, string>;
|
||||
const q = req.query as Record<string, string>;
|
||||
|
||||
const where: string[] = ["1=1"];
|
||||
const params: any[] = [];
|
||||
if (project_no) {
|
||||
params.push(`%${project_no}%`);
|
||||
where.push(`EXISTS (SELECT 1 FROM project_mgmt pm WHERE pm.objid = pid.project_objid AND pm.project_no ILIKE $${params.length})`);
|
||||
}
|
||||
if (part_name) {
|
||||
params.push(`%${part_name}%`);
|
||||
where.push(`pid.part_name ILIKE $${params.length}`);
|
||||
}
|
||||
if (inspector_id) {
|
||||
params.push(inspector_id);
|
||||
where.push(`pim.inspector_id = $${params.length}`);
|
||||
}
|
||||
if (from) {
|
||||
params.push(from);
|
||||
where.push(`pim.inspection_date >= $${params.length}`);
|
||||
}
|
||||
if (to) {
|
||||
params.push(to);
|
||||
where.push(`pim.inspection_date <= $${params.length}`);
|
||||
}
|
||||
const add = (sql: string, ...v: any[]) => { v.forEach(x => params.push(x)); where.push(sql.replace(/\?/g, () => "$" + params.length)); };
|
||||
|
||||
if (q.search_project_no) add("EXISTS (SELECT 1 FROM process_inspection_detail pid2 LEFT JOIN project_mgmt pj ON pj.objid = pid2.project_objid WHERE pid2.master_objid = pim.objid AND COALESCE(pj.project_no, '') ILIKE ?)", `%${q.search_project_no}%`);
|
||||
if (q.productType) add("EXISTS (SELECT 1 FROM process_inspection_detail pid2 LEFT JOIN project_mgmt pj ON pj.objid = pid2.project_objid WHERE pid2.master_objid = pim.objid AND pj.product = ?)", q.productType);
|
||||
if (q.search_part_no) add("EXISTS (SELECT 1 FROM process_inspection_detail pid2 WHERE pid2.master_objid = pim.objid AND pid2.part_no ILIKE ?)", `%${q.search_part_no}%`);
|
||||
if (q.search_part_name) add("EXISTS (SELECT 1 FROM process_inspection_detail pid2 WHERE pid2.master_objid = pim.objid AND pid2.part_name ILIKE ?)", `%${q.search_part_name}%`);
|
||||
if (q.search_work_env_status) add("EXISTS (SELECT 1 FROM process_inspection_detail pid2 WHERE pid2.master_objid = pim.objid AND pid2.work_env_status = ?)", q.search_work_env_status);
|
||||
if (q.search_measuring_device) add("EXISTS (SELECT 1 FROM process_inspection_detail pid2 WHERE pid2.master_objid = pim.objid AND pid2.measuring_device = ?)", q.search_measuring_device);
|
||||
if (q.search_inspector) add("pim.inspector_id = ?", q.search_inspector);
|
||||
if (q.search_inspection_date_from) add("pim.inspection_date >= ?", q.search_inspection_date_from);
|
||||
if (q.search_inspection_date_to) add("pim.inspection_date <= ?", q.search_inspection_date_to);
|
||||
if (q.search_inspection_result) add("EXISTS (SELECT 1 FROM process_inspection_detail pid2 WHERE pid2.master_objid = pim.objid AND pid2.inspection_result = ?)", q.search_inspection_result);
|
||||
if (q.search_process_cd) add("EXISTS (SELECT 1 FROM process_inspection_detail pid2 WHERE pid2.master_objid = pim.objid AND pid2.process_cd = ?)", q.search_process_cd);
|
||||
|
||||
const sql = `
|
||||
SELECT
|
||||
pim.objid::text AS objid,
|
||||
TO_CHAR(pim.inspection_date, 'YYYY-MM-DD') AS inspection_date,
|
||||
COALESCE(ui.user_name, '') AS inspector_name,
|
||||
COALESCE(MIN(pm.project_no), '') AS project_no,
|
||||
'' AS product_name,
|
||||
COALESCE(MIN(pj.project_no), '') AS project_no,
|
||||
COALESCE(MIN(ci.code_name), '') AS product_name,
|
||||
COALESCE(MIN(pid.part_no), '') AS part_no,
|
||||
COALESCE(MIN(pid.part_name), '') AS part_name,
|
||||
COALESCE(SUM(pid.inspection_qty), 0) AS inspection_qty,
|
||||
COALESCE(SUM(pid.defect_qty), 0) AS defect_qty,
|
||||
COALESCE(MAX(pid.work_env_status), '') AS work_env_status,
|
||||
COALESCE(MAX(pid.measuring_device), '') AS measuring_device,
|
||||
COALESCE(MAX(pid.inspection_result), '') AS inspection_result,
|
||||
0 AS file_count
|
||||
CASE
|
||||
WHEN SUM(pid.defect_qty) > 0 THEN 'NG'
|
||||
WHEN COUNT(pid.objid) > 0 THEN 'OK'
|
||||
ELSE ''
|
||||
END AS inspection_result,
|
||||
0 AS process_inspection_file_cnt
|
||||
FROM process_inspection_master pim
|
||||
LEFT JOIN process_inspection_detail pid ON pid.master_objid = pim.objid
|
||||
LEFT JOIN project_mgmt pm ON pm.objid = pid.project_objid
|
||||
LEFT JOIN user_info ui ON ui.user_id = pim.inspector_id
|
||||
LEFT JOIN project_mgmt pj ON pj.objid = pid.project_objid
|
||||
LEFT JOIN code_info ci ON ci.objid::text = pj.product
|
||||
LEFT JOIN user_info ui ON ui.user_id = pim.inspector_id
|
||||
WHERE ${where.join(" AND ")}
|
||||
GROUP BY pim.objid, pim.inspection_date, ui.user_name
|
||||
ORDER BY pim.inspection_date DESC NULLS LAST, pim.objid DESC
|
||||
LIMIT 500
|
||||
`;
|
||||
const r = await pool.query(sql, params);
|
||||
res.json({
|
||||
success: true,
|
||||
list: r.rows,
|
||||
pagination: { page: 1, pageSize: 500, total: r.rows.length, totalPages: 1 },
|
||||
});
|
||||
res.json({ success: true, list: r.rows, pagination: { page: 1, pageSize: 500, total: r.rows.length, totalPages: 1 } });
|
||||
} catch (err: any) {
|
||||
console.warn("[quality/process-inspection] fallback empty:", err?.message);
|
||||
emptyList(res);
|
||||
@@ -221,47 +231,34 @@ router.get("/process-inspection", async (req: Request, res: Response) => {
|
||||
});
|
||||
|
||||
// ─── 4. 반제품검사 관리 ────────────────────────────────────────
|
||||
// DATA_TYPE='GOOD' 행을 마스터로 보고, 동일 inspection_group_id 의 'DEFECT' 행을
|
||||
// SUM 으로 묶어 불량/재생/최종양품 수량을 집계.
|
||||
// wace quality.xml getSemiProductInspectionList — DATA_TYPE='GOOD' 마스터,
|
||||
// 동일 INSPECTION_GROUP_ID 의 'DEFECT' 행 SUM 으로 불량/재생/최종양품 산정.
|
||||
router.get("/semi-product-inspection", async (req: Request, res: Response) => {
|
||||
try {
|
||||
const pool = getPool();
|
||||
const { model_name, part_no, part_name, writer, from, to } = req.query as Record<string, string>;
|
||||
const q = req.query as Record<string, string>;
|
||||
|
||||
const where: string[] = ["g.data_type IS NULL OR g.data_type = 'GOOD'"];
|
||||
const where: string[] = ["g.data_type = 'GOOD'"];
|
||||
const params: any[] = [];
|
||||
if (model_name) {
|
||||
params.push(`%${model_name}%`);
|
||||
where.push(`g.model_name ILIKE $${params.length}`);
|
||||
}
|
||||
if (part_no) {
|
||||
params.push(`%${part_no}%`);
|
||||
where.push(`g.part_no ILIKE $${params.length}`);
|
||||
}
|
||||
if (part_name) {
|
||||
params.push(`%${part_name}%`);
|
||||
where.push(`g.part_name ILIKE $${params.length}`);
|
||||
}
|
||||
if (writer) {
|
||||
params.push(writer);
|
||||
where.push(`g.writer = $${params.length}`);
|
||||
}
|
||||
if (from) {
|
||||
params.push(from);
|
||||
where.push(`g.inspection_date >= $${params.length}`);
|
||||
}
|
||||
if (to) {
|
||||
params.push(to);
|
||||
where.push(`g.inspection_date <= $${params.length}`);
|
||||
}
|
||||
const add = (sql: string, ...v: any[]) => { v.forEach(x => params.push(x)); where.push(sql.replace(/\?/g, () => "$" + params.length)); };
|
||||
|
||||
if (q.search_model_name) add("COALESCE(g.model_name, '') ILIKE ?", `%${q.search_model_name}%`);
|
||||
if (q.search_work_order_no) add("COALESCE(g.work_order_no, '') ILIKE ?", `%${q.search_work_order_no}%`);
|
||||
if (q.search_part_no) add("COALESCE(g.part_no, '') ILIKE ?", `%${q.search_part_no}%`);
|
||||
if (q.search_part_name) add("COALESCE(g.part_name, '') ILIKE ?", `%${q.search_part_name}%`);
|
||||
if (q.inspection_start_date) add("COALESCE(g.inspection_date, g.reg_date::date) >= ?", q.inspection_start_date);
|
||||
if (q.inspection_end_date) add("COALESCE(g.inspection_date, g.reg_date::date) <= ?", q.inspection_end_date);
|
||||
if (q.search_writer) add("g.writer = ?", q.search_writer);
|
||||
if (q.search_defect_type) add("EXISTS (SELECT 1 FROM pms_quality_semi_product_inspection d2 WHERE d2.inspection_group_id = g.inspection_group_id AND d2.data_type = 'DEFECT' AND d2.defect_type = ?)", q.search_defect_type);
|
||||
if (q.search_responsible_dept) add("EXISTS (SELECT 1 FROM pms_quality_semi_product_inspection d2 WHERE d2.inspection_group_id = g.inspection_group_id AND d2.data_type = 'DEFECT' AND d2.responsible_dept = ?)", q.search_responsible_dept);
|
||||
|
||||
const sql = `
|
||||
SELECT
|
||||
g.objid::text AS objid,
|
||||
TO_CHAR(g.inspection_date, 'YYYY-MM-DD') AS inspection_date,
|
||||
COALESCE(ui.user_name, g.writer, '') AS writer_name,
|
||||
COALESCE(g.model_name, '') AS model_name,
|
||||
COALESCE(g.product_type, '') AS product_type,
|
||||
COALESCE(g.model_name, '') AS model_name,
|
||||
COALESCE(g.work_order_no, '') AS work_order_no,
|
||||
COALESCE(g.part_no, '') AS part_no,
|
||||
COALESCE(g.part_name, '') AS part_name,
|
||||
@@ -270,7 +267,7 @@ router.get("/semi-product-inspection", async (req: Request, res: Response) => {
|
||||
COALESCE(d.defect_qty_sum, 0) AS defective_qty,
|
||||
CASE
|
||||
WHEN COALESCE(g.receipt_qty, 0) = 0 THEN 0
|
||||
ELSE ROUND( COALESCE(d.defect_qty_sum, 0) / g.receipt_qty * 100, 2 )
|
||||
ELSE ROUND(COALESCE(d.defect_qty_sum, 0) / g.receipt_qty * 100, 2)
|
||||
END AS defect_rate,
|
||||
COALESCE(d.regen_qty_sum, 0) AS regeneration_qty,
|
||||
COALESCE(g.good_qty, 0) + COALESCE(d.regen_qty_sum, 0) AS final_good_qty
|
||||
@@ -284,15 +281,11 @@ router.get("/semi-product-inspection", async (req: Request, res: Response) => {
|
||||
) d ON true
|
||||
LEFT JOIN user_info ui ON ui.user_id = g.writer
|
||||
WHERE ${where.join(" AND ")}
|
||||
ORDER BY g.inspection_date DESC NULLS LAST, g.objid DESC
|
||||
ORDER BY COALESCE(g.inspection_date, g.reg_date::date) DESC NULLS LAST, g.objid DESC
|
||||
LIMIT 500
|
||||
`;
|
||||
const r = await pool.query(sql, params);
|
||||
res.json({
|
||||
success: true,
|
||||
list: r.rows,
|
||||
pagination: { page: 1, pageSize: 500, total: r.rows.length, totalPages: 1 },
|
||||
});
|
||||
res.json({ success: true, list: r.rows, pagination: { page: 1, pageSize: 500, total: r.rows.length, totalPages: 1 } });
|
||||
} catch (err: any) {
|
||||
console.warn("[quality/semi-product-inspection] fallback empty:", err?.message);
|
||||
emptyList(res);
|
||||
|
||||
Reference in New Issue
Block a user