diff --git a/backend-node/src/controllers/analyticsReportController.ts b/backend-node/src/controllers/analyticsReportController.ts index 1f8cfd7c..e2f73653 100644 --- a/backend-node/src/controllers/analyticsReportController.ts +++ b/backend-node/src/controllers/analyticsReportController.ts @@ -56,47 +56,75 @@ export async function getProductionReportData(req: any, res: Response): Promise< const params: any[] = []; let idx = 1; - const cf = buildCompanyFilter(companyCode, "wi", idx); + const cf = buildCompanyFilter(companyCode, "wop", idx); if (cf.condition) { conditions.push(cf.condition); params.push(...cf.params); idx = cf.nextIdx; } - const df = buildDateFilter(startDate, endDate, "COALESCE(wi.start_date, wi.created_date::date::text)", idx); + const dateExpr = "COALESCE(NULLIF(wop.started_at, ''), wop.created_date::date::text)"; + const df = buildDateFilter(startDate, endDate, dateExpr, idx); conditions.push(...df.conditions); params.push(...df.params); idx = df.nextIdx; const whereClause = buildWhereClause(conditions); + // 실제 공정별 생산 데이터는 work_order_process에 있음 + // (work_instruction.routing은 routing_version_id UUID일 뿐이라 공정명이 아님) const dataQuery = ` SELECT - COALESCE(wi.start_date, wi.created_date::date::text) as date, - COALESCE(NULLIF(rv.version_name, ''), '미지정') as process, - COALESCE(ei.equipment_name, wi.equipment_id, '미지정') as equipment, - COALESCE(ii.item_name, wi.item_id, '미지정') as item, - COALESCE(wi.worker, '미지정') as worker, - CAST(COALESCE(NULLIF(wi.qty, ''), '0') AS numeric) as "planQty", - COALESCE(pr.production_qty, 0) as "prodQty", - COALESCE(pr.defect_qty, 0) as "defectQty", - 0 as "runTime", - 0 as "downTime", - wi.status, - wi.company_code - FROM work_instruction wi - LEFT JOIN item_routing_version rv - ON wi.routing = rv.id AND wi.company_code = rv.company_code - LEFT JOIN ( - SELECT wo_id, company_code, - SUM(CAST(COALESCE(NULLIF(production_qty, ''), '0') AS numeric)) as production_qty, - SUM(CAST(COALESCE(NULLIF(defect_qty, ''), '0') AS numeric)) as defect_qty - FROM production_record GROUP BY wo_id, company_code - ) pr ON wi.id = pr.wo_id AND wi.company_code = pr.company_code - LEFT JOIN ( - SELECT DISTINCT ON (equipment_code, company_code) - equipment_code, equipment_name, equipment_type, company_code - FROM equipment_info ORDER BY equipment_code, company_code, created_date DESC - ) ei ON wi.equipment_id = ei.equipment_code AND wi.company_code = ei.company_code - LEFT JOIN ( - SELECT DISTINCT ON (item_number, company_code) - item_number, item_name, company_code - FROM item_info ORDER BY item_number, company_code, created_date DESC - ) ii ON wi.item_id = ii.item_number AND wi.company_code = ii.company_code + COALESCE(NULLIF(wop.started_at, ''), wop.created_date::date::text) as date, + COALESCE(NULLIF(wop.process_name, ''), NULLIF(wop.process_code, ''), '미지정') as process, + COALESCE(NULLIF(em.equipment_name, ''), NULLIF(em.equipment_code, ''), '미지정') as equipment, + COALESCE(NULLIF(ii.item_name, ''), NULLIF(ii.item_number, ''), '미지정') as item, + COALESCE(NULLIF(wi.worker, ''), '미지정') as worker, + CAST(COALESCE(NULLIF(wop.plan_qty, ''), '0') AS numeric) as "planQty", + CAST(COALESCE(NULLIF(wop.good_qty, ''), '0') AS numeric) as "prodQty", + CAST(COALESCE(NULLIF(wop.defect_qty, ''), '0') AS numeric) as "defectQty", + CASE + WHEN NULLIF(wop.started_at, '') IS NOT NULL + AND NULLIF(wop.completed_at, '') IS NOT NULL + THEN GREATEST( + EXTRACT(EPOCH FROM (wop.completed_at::timestamp - wop.started_at::timestamp)) / 3600.0, + 0 + ) + ELSE 0 + END as "runTime", + CAST(COALESCE(NULLIF(wop.total_paused_time, ''), '0') AS numeric) / 3600.0 as "downTime", + wop.status, + wop.company_code + FROM work_order_process wop + LEFT JOIN work_instruction wi + ON wop.wo_id = wi.id AND wop.company_code = wi.company_code + LEFT JOIN LATERAL ( + SELECT equipment_code, equipment_name + FROM equipment_mng + WHERE company_code = wi.company_code + AND (id = wi.equipment_id OR equipment_code = wi.equipment_id + OR id = wop.equipment_code OR equipment_code = wop.equipment_code) + ORDER BY (id = wi.equipment_id OR id = wop.equipment_code) DESC, created_date DESC + LIMIT 1 + ) em ON true + LEFT JOIN LATERAL ( + SELECT ii_inner.item_number, ii_inner.item_name + FROM item_info ii_inner + WHERE ii_inner.company_code = wi.company_code + AND ( + (NULLIF(wi.item_id, '') IS NOT NULL + AND (ii_inner.id = wi.item_id OR ii_inner.item_number = wi.item_id)) + OR ii_inner.item_number = ( + SELECT wid.item_number + FROM work_instruction_detail wid + WHERE wid.work_instruction_id = wi.id + AND wid.company_code = wi.company_code + AND NULLIF(wid.item_number, '') IS NOT NULL + ORDER BY wid.created_date ASC + LIMIT 1 + ) + ) + ORDER BY + CASE WHEN ii_inner.id = wi.item_id THEN 1 + WHEN ii_inner.item_number = wi.item_id THEN 2 + ELSE 3 END, + ii_inner.created_date DESC + LIMIT 1 + ) ii ON true ${whereClause} ORDER BY date DESC NULLS LAST `;