diff --git a/backend-node/src/routes/qualityRoutes.ts b/backend-node/src/routes/qualityRoutes.ts index 60061750..54dac3aa 100644 --- a/backend-node/src/routes/qualityRoutes.ts +++ b/backend-node/src/routes/qualityRoutes.ts @@ -37,17 +37,17 @@ router.get("/incoming-request", async (req: Request, res: Response) => { const params: any[] = []; 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_proposal_no) add("COALESCE(srm.request_mng_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_product_cd) add("pom.product_code::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.request_start_date) add("COALESCE(NULLIF(iid.request_date, ''), TO_CHAR(pom.regdate, 'YYYY-MM-DD')) >= ?", q.request_start_date); + if (q.request_end_date) add("COALESCE(NULLIF(iid.request_date, ''), TO_CHAR(pom.regdate, 'YYYY-MM-DD')) <= ?", q.request_end_date); if (q.search_request_status) { const s = q.search_request_status; if (s === "미요청") where.push("iid.objid IS NULL"); @@ -58,15 +58,15 @@ router.get("/incoming-request", async (req: Request, res: Response) => { const sql = ` SELECT pom.objid::text AS objid, - COALESCE(srm.proposal_no, '') AS proposal_no, + COALESCE(srm.request_mng_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, + COALESCE(client.client_nm, '') AS partner_name, '-' AS delivery_status, - TO_CHAR(COALESCE(iid.request_date, pom.regdate::date), 'YYYY-MM-DD') AS request_date, + COALESCE(NULLIF(iid.request_date, ''), TO_CHAR(pom.regdate, 'YYYY-MM-DD')) AS request_date, COALESCE(ui.user_name, '') AS request_user_name, COALESCE(iid.inspection_yn, '-') AS inspection_yn, CASE @@ -76,10 +76,11 @@ router.get("/incoming-request", async (req: Request, res: Response) => { 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 contract_mgmt cm ON cm.objid = pom.contract_mgmt_objid + LEFT JOIN code_info ci ON ci.code_value = pom.product_code LEFT JOIN client_mng client ON client.objid = pom.partner_objid - LEFT JOIN part_mng pm ON pm.objid = pom.part_objid + -- purchase_order_master 에 part_objid 가 없어 part_mng 직접 조인 불가. part_no/name 은 빈값으로 표시. + LEFT JOIN part_mng pm ON FALSE LEFT JOIN incoming_inspection_detail iid ON iid.purchase_order_master_objid = pom.objid::text LEFT JOIN user_info ui ON ui.user_id = COALESCE(iid.request_user_id, pom.writer) WHERE ${where.join(" AND ")} @@ -108,16 +109,16 @@ router.get("/incoming-mgmt", async (req: Request, res: Response) => { const params: any[] = []; 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_proposal_no) add("COALESCE(srm.request_mng_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_product_cd) add("pom.product_code::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.inspection_start_date) add("COALESCE(NULLIF(iid.inspection_date, ''), TO_CHAR(iid.reg_date, 'YYYY-MM-DD')) >= ?", q.inspection_start_date); + if (q.inspection_end_date) add("COALESCE(NULLIF(iid.inspection_date, ''), TO_CHAR(iid.reg_date, 'YYYY-MM-DD')) <= ?", 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, '') <> ''"); @@ -127,16 +128,16 @@ router.get("/incoming-mgmt", async (req: Request, res: Response) => { const sql = ` SELECT iid.objid::text AS objid, - TO_CHAR(iid.inspection_date, 'YYYY-MM-DD') AS inspection_date, + COALESCE(NULLIF(iid.inspection_date, ''), TO_CHAR(iid.reg_date, 'YYYY-MM-DD')) AS inspection_date, COALESCE(ui_ins.user_name, '') AS inspector_name, - COALESCE(srm.proposal_no, '') AS proposal_no, + COALESCE(srm.request_mng_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.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, + COALESCE(client.client_nm, '') AS partner_name, TO_CHAR(iid.reg_date, 'YYYY-MM-DD') AS delivery_date, iid.inspection_qty AS delivery_qty, '-' AS delivery_status, @@ -155,13 +156,13 @@ router.get("/incoming-mgmt", async (req: Request, res: Response) => { FROM incoming_inspection_detail iid 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 contract_mgmt cm ON cm.objid = pom.contract_mgmt_objid + LEFT JOIN code_info ci ON ci.code_value = pom.product_code 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.inspection_date DESC NULLS LAST, iid.objid DESC + ORDER BY COALESCE(NULLIF(iid.inspection_date, ''), TO_CHAR(iid.reg_date, 'YYYY-MM-DD')) DESC NULLS LAST, iid.objid DESC LIMIT 500 `; const r = await pool.query(sql, params); @@ -183,8 +184,8 @@ router.get("/process-inspection", async (req: Request, res: Response) => { const params: any[] = []; 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_project_no) add("EXISTS (SELECT 1 FROM process_inspection_detail pid2 LEFT JOIN project_mgmt pj ON pj.objid::text = NULLIF(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::text = NULLIF(pid2.project_objid, '') WHERE pid2.master_objid = pim.objid AND pj.product::text = ?)", 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); @@ -195,11 +196,13 @@ router.get("/process-inspection", async (req: Request, res: Response) => { 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); + // pim.inspection_date 가 varchar 이고 빈 문자열인 경우가 많아 reg_date 로 fallback. + // pid.project_objid 도 varchar 빈 문자열이 다수라 NULLIF + 안전 캐스트 필요. 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(NULLIF(pim.inspection_date, ''), TO_CHAR(pim.reg_date, 'YYYY-MM-DD')) AS inspection_date, + COALESCE(ui_ins.user_name, ui_w.user_name, pim.writer, '') AS inspector_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, @@ -216,12 +219,13 @@ router.get("/process-inspection", async (req: Request, res: Response) => { 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 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 + LEFT JOIN project_mgmt pj ON pj.objid::text = NULLIF(pid.project_objid, '') + LEFT JOIN code_info ci ON ci.objid::text = pj.product::text + LEFT JOIN user_info ui_ins ON ui_ins.user_id = NULLIF(pim.inspector_id, '') + LEFT JOIN user_info ui_w ON ui_w.user_id = pim.writer 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 + GROUP BY pim.objid, pim.inspection_date, pim.reg_date, pim.writer, ui_ins.user_name, ui_w.user_name + ORDER BY COALESCE(NULLIF(pim.inspection_date, ''), TO_CHAR(pim.reg_date, 'YYYY-MM-DD')) DESC NULLS LAST, pim.objid DESC LIMIT 500 `; const r = await pool.query(sql, params); @@ -248,8 +252,9 @@ router.get("/semi-product-inspection", async (req: Request, res: Response) => { 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); + // 반제품 inspection_date 는 date 타입 → reg_date 와 동일 도메인. + if (q.inspection_start_date) add("COALESCE(g.inspection_date, g.reg_date::date) >= ?::date", q.inspection_start_date); + if (q.inspection_end_date) add("COALESCE(g.inspection_date, g.reg_date::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); @@ -257,7 +262,7 @@ router.get("/semi-product-inspection", async (req: Request, res: Response) => { const sql = ` SELECT g.objid::text AS objid, - TO_CHAR(g.inspection_date, 'YYYY-MM-DD') AS inspection_date, + TO_CHAR(COALESCE(g.inspection_date, g.reg_date::date), 'YYYY-MM-DD') AS inspection_date, COALESCE(ui.user_name, g.writer, '') AS writer_name, COALESCE(g.product_type, '') AS product_type, COALESCE(g.model_name, '') AS model_name,