import { Response } from "express"; import { AuthenticatedRequest } from "../types/auth"; import { query } from "../database/db"; import { logger } from "../utils/logger"; // ============================================ // 금형 마스터 CRUD // ============================================ export async function getMoldList(req: AuthenticatedRequest, res: Response): Promise { try { const companyCode = req.user!.companyCode; const { mold_code, mold_name, mold_type, operation_status } = req.query; const conditions: string[] = []; const params: any[] = []; let paramIndex = 1; if (companyCode === "*") { // 최고 관리자: 전체 조회 } else { conditions.push(`company_code = $${paramIndex}`); params.push(companyCode); paramIndex++; } if (mold_code) { conditions.push(`mold_code ILIKE $${paramIndex}`); params.push(`%${mold_code}%`); paramIndex++; } if (mold_name) { conditions.push(`mold_name ILIKE $${paramIndex}`); params.push(`%${mold_name}%`); paramIndex++; } if (mold_type) { conditions.push(`mold_type = $${paramIndex}`); params.push(mold_type); paramIndex++; } if (operation_status) { conditions.push(`operation_status = $${paramIndex}`); params.push(operation_status); paramIndex++; } const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : ""; const sql = `SELECT * FROM mold_mng ${whereClause} ORDER BY created_date DESC`; const result = await query(sql, params); logger.info("금형 목록 조회", { companyCode, count: result.length }); res.json({ success: true, data: result }); } catch (error: any) { logger.error("금형 목록 조회 오류", error); res.status(500).json({ success: false, message: error.message }); } } export async function getMoldDetail(req: AuthenticatedRequest, res: Response): Promise { try { const companyCode = req.user!.companyCode; const { moldCode } = req.params; let sql: string; let params: any[]; if (companyCode === "*") { sql = `SELECT * FROM mold_mng WHERE mold_code = $1 LIMIT 1`; params = [moldCode]; } else { sql = `SELECT * FROM mold_mng WHERE mold_code = $1 AND company_code = $2 LIMIT 1`; params = [moldCode, companyCode]; } const result = await query(sql, params); if (result.length === 0) { res.status(404).json({ success: false, message: "금형을 찾을 수 없습니다." }); return; } res.json({ success: true, data: result[0] }); } catch (error: any) { logger.error("금형 상세 조회 오류", error); res.status(500).json({ success: false, message: error.message }); } } export async function createMold(req: AuthenticatedRequest, res: Response): Promise { try { const companyCode = req.user!.companyCode; const userId = req.user!.userId; const { mold_code, mold_name, mold_type, category, manufacturer, manufacturing_number, manufacturing_date, cavity_count, shot_count, mold_quantity, base_input_qty, operation_status, remarks, image_path, memo, } = req.body; if (!mold_code || !mold_name) { res.status(400).json({ success: false, message: "금형코드와 금형명은 필수입니다." }); return; } const sql = ` INSERT INTO mold_mng ( company_code, mold_code, mold_name, mold_type, category, manufacturer, manufacturing_number, manufacturing_date, cavity_count, shot_count, mold_quantity, base_input_qty, operation_status, remarks, image_path, memo, writer ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17) RETURNING * `; const params = [ companyCode, mold_code, mold_name, mold_type || null, category || null, manufacturer || null, manufacturing_number || null, manufacturing_date || null, cavity_count || 0, shot_count || 0, mold_quantity || 1, base_input_qty || 0, operation_status || "ACTIVE", remarks || null, image_path || null, memo || null, userId, ]; const result = await query(sql, params); logger.info("금형 생성", { companyCode, moldCode: mold_code }); res.json({ success: true, data: result[0], message: "금형이 등록되었습니다." }); } catch (error: any) { if (error.code === "23505") { res.status(409).json({ success: false, message: "이미 존재하는 금형코드입니다." }); return; } logger.error("금형 생성 오류", error); res.status(500).json({ success: false, message: error.message }); } } export async function updateMold(req: AuthenticatedRequest, res: Response): Promise { try { const companyCode = req.user!.companyCode; const { moldCode } = req.params; const { mold_name, mold_type, category, manufacturer, manufacturing_number, manufacturing_date, cavity_count, shot_count, mold_quantity, base_input_qty, operation_status, remarks, image_path, memo, } = req.body; const sql = ` UPDATE mold_mng SET mold_name = COALESCE($1, mold_name), mold_type = $2, category = $3, manufacturer = $4, manufacturing_number = $5, manufacturing_date = $6, cavity_count = COALESCE($7, cavity_count), shot_count = COALESCE($8, shot_count), mold_quantity = COALESCE($9, mold_quantity), base_input_qty = COALESCE($10, base_input_qty), operation_status = COALESCE($11, operation_status), remarks = $12, image_path = $13, memo = $14, updated_date = NOW() WHERE mold_code = $15 AND company_code = $16 RETURNING * `; const params = [ mold_name, mold_type, category, manufacturer, manufacturing_number, manufacturing_date, cavity_count, shot_count, mold_quantity, base_input_qty, operation_status, remarks, image_path, memo, moldCode, companyCode, ]; const result = await query(sql, params); if (result.length === 0) { res.status(404).json({ success: false, message: "금형을 찾을 수 없습니다." }); return; } logger.info("금형 수정", { companyCode, moldCode }); res.json({ success: true, data: result[0], message: "금형이 수정되었습니다." }); } catch (error: any) { logger.error("금형 수정 오류", error); res.status(500).json({ success: false, message: error.message }); } } export async function deleteMold(req: AuthenticatedRequest, res: Response): Promise { try { const companyCode = req.user!.companyCode; const { moldCode } = req.params; // 관련 데이터 먼저 삭제 await query(`DELETE FROM mold_serial WHERE mold_code = $1 AND company_code = $2`, [moldCode, companyCode]); await query(`DELETE FROM mold_inspection_item WHERE mold_code = $1 AND company_code = $2`, [moldCode, companyCode]); await query(`DELETE FROM mold_part WHERE mold_code = $1 AND company_code = $2`, [moldCode, companyCode]); const result = await query( `DELETE FROM mold_mng WHERE mold_code = $1 AND company_code = $2 RETURNING id`, [moldCode, companyCode] ); if (result.length === 0) { res.status(404).json({ success: false, message: "금형을 찾을 수 없습니다." }); return; } logger.info("금형 삭제", { companyCode, moldCode }); res.json({ success: true, message: "금형이 삭제되었습니다." }); } catch (error: any) { logger.error("금형 삭제 오류", error); res.status(500).json({ success: false, message: error.message }); } } // ============================================ // 일련번호 CRUD // ============================================ export async function getMoldSerials(req: AuthenticatedRequest, res: Response): Promise { try { const companyCode = req.user!.companyCode; const { moldCode } = req.params; const sql = `SELECT * FROM mold_serial WHERE mold_code = $1 AND company_code = $2 ORDER BY serial_number`; const result = await query(sql, [moldCode, companyCode]); res.json({ success: true, data: result }); } catch (error: any) { logger.error("일련번호 목록 조회 오류", error); res.status(500).json({ success: false, message: error.message }); } } export async function createMoldSerial(req: AuthenticatedRequest, res: Response): Promise { try { const companyCode = req.user!.companyCode; const userId = req.user!.userId; const { moldCode } = req.params; const { serial_number, status, progress, work_description, manager, completion_date, remarks } = req.body; if (!serial_number) { res.status(400).json({ success: false, message: "일련번호는 필수입니다." }); return; } const sql = ` INSERT INTO mold_serial (company_code, mold_code, serial_number, status, progress, work_description, manager, completion_date, remarks, writer) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10) RETURNING * `; const params = [ companyCode, moldCode, serial_number, status || "STORED", progress || 0, work_description || null, manager || null, completion_date || null, remarks || null, userId, ]; const result = await query(sql, params); res.json({ success: true, data: result[0], message: "일련번호가 등록되었습니다." }); } catch (error: any) { if (error.code === "23505") { res.status(409).json({ success: false, message: "이미 존재하는 일련번호입니다." }); return; } logger.error("일련번호 생성 오류", error); res.status(500).json({ success: false, message: error.message }); } } export async function deleteMoldSerial(req: AuthenticatedRequest, res: Response): Promise { try { const companyCode = req.user!.companyCode; const { id } = req.params; const result = await query( `DELETE FROM mold_serial WHERE id = $1 AND company_code = $2 RETURNING id`, [id, companyCode] ); if (result.length === 0) { res.status(404).json({ success: false, message: "일련번호를 찾을 수 없습니다." }); return; } res.json({ success: true, message: "일련번호가 삭제되었습니다." }); } catch (error: any) { logger.error("일련번호 삭제 오류", error); res.status(500).json({ success: false, message: error.message }); } } // ============================================ // 점검항목 CRUD // ============================================ export async function getMoldInspections(req: AuthenticatedRequest, res: Response): Promise { try { const companyCode = req.user!.companyCode; const { moldCode } = req.params; const sql = `SELECT * FROM mold_inspection_item WHERE mold_code = $1 AND company_code = $2 ORDER BY created_date`; const result = await query(sql, [moldCode, companyCode]); res.json({ success: true, data: result }); } catch (error: any) { logger.error("점검항목 조회 오류", error); res.status(500).json({ success: false, message: error.message }); } } export async function createMoldInspection(req: AuthenticatedRequest, res: Response): Promise { try { const companyCode = req.user!.companyCode; const userId = req.user!.userId; const { moldCode } = req.params; const { inspection_item, inspection_cycle, inspection_method, inspection_content, lower_limit, upper_limit, unit, is_active, checklist, remarks, } = req.body; if (!inspection_item) { res.status(400).json({ success: false, message: "점검항목명은 필수입니다." }); return; } const sql = ` INSERT INTO mold_inspection_item ( company_code, mold_code, inspection_item, inspection_cycle, inspection_method, inspection_content, lower_limit, upper_limit, unit, is_active, checklist, remarks, writer ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13) RETURNING * `; const params = [ companyCode, moldCode, inspection_item, inspection_cycle || null, inspection_method || null, inspection_content || null, lower_limit || null, upper_limit || null, unit || null, is_active || "Y", checklist || null, remarks || null, userId, ]; const result = await query(sql, params); res.json({ success: true, data: result[0], message: "점검항목이 등록되었습니다." }); } catch (error: any) { logger.error("점검항목 생성 오류", error); res.status(500).json({ success: false, message: error.message }); } } export async function deleteMoldInspection(req: AuthenticatedRequest, res: Response): Promise { try { const companyCode = req.user!.companyCode; const { id } = req.params; const result = await query( `DELETE FROM mold_inspection_item WHERE id = $1 AND company_code = $2 RETURNING id`, [id, companyCode] ); if (result.length === 0) { res.status(404).json({ success: false, message: "점검항목을 찾을 수 없습니다." }); return; } res.json({ success: true, message: "점검항목이 삭제되었습니다." }); } catch (error: any) { logger.error("점검항목 삭제 오류", error); res.status(500).json({ success: false, message: error.message }); } } // ============================================ // 부품 CRUD // ============================================ export async function getMoldParts(req: AuthenticatedRequest, res: Response): Promise { try { const companyCode = req.user!.companyCode; const { moldCode } = req.params; const sql = `SELECT * FROM mold_part WHERE mold_code = $1 AND company_code = $2 ORDER BY created_date`; const result = await query(sql, [moldCode, companyCode]); res.json({ success: true, data: result }); } catch (error: any) { logger.error("부품 목록 조회 오류", error); res.status(500).json({ success: false, message: error.message }); } } export async function createMoldPart(req: AuthenticatedRequest, res: Response): Promise { try { const companyCode = req.user!.companyCode; const userId = req.user!.userId; const { moldCode } = req.params; const { part_name, replacement_cycle, unit, specification, manufacturer, manufacturer_code, image_path, remarks, } = req.body; if (!part_name) { res.status(400).json({ success: false, message: "부품명은 필수입니다." }); return; } const sql = ` INSERT INTO mold_part ( company_code, mold_code, part_name, replacement_cycle, unit, specification, manufacturer, manufacturer_code, image_path, remarks, writer ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11) RETURNING * `; const params = [ companyCode, moldCode, part_name, replacement_cycle || null, unit || null, specification || null, manufacturer || null, manufacturer_code || null, image_path || null, remarks || null, userId, ]; const result = await query(sql, params); res.json({ success: true, data: result[0], message: "부품이 등록되었습니다." }); } catch (error: any) { logger.error("부품 생성 오류", error); res.status(500).json({ success: false, message: error.message }); } } export async function deleteMoldPart(req: AuthenticatedRequest, res: Response): Promise { try { const companyCode = req.user!.companyCode; const { id } = req.params; const result = await query( `DELETE FROM mold_part WHERE id = $1 AND company_code = $2 RETURNING id`, [id, companyCode] ); if (result.length === 0) { res.status(404).json({ success: false, message: "부품을 찾을 수 없습니다." }); return; } res.json({ success: true, message: "부품이 삭제되었습니다." }); } catch (error: any) { logger.error("부품 삭제 오류", error); res.status(500).json({ success: false, message: error.message }); } } // ============================================ // 일련번호 현황 집계 // ============================================ export async function getMoldSerialSummary(req: AuthenticatedRequest, res: Response): Promise { try { const companyCode = req.user!.companyCode; const { moldCode } = req.params; const sql = ` SELECT COUNT(*) as total, COUNT(*) FILTER (WHERE status = 'IN_USE') as in_use, COUNT(*) FILTER (WHERE status = 'REPAIR') as repair, COUNT(*) FILTER (WHERE status = 'STORED') as stored, COUNT(*) FILTER (WHERE status = 'DISPOSED') as disposed FROM mold_serial WHERE mold_code = $1 AND company_code = $2 `; const result = await query(sql, [moldCode, companyCode]); res.json({ success: true, data: result[0] }); } catch (error: any) { logger.error("일련번호 현황 조회 오류", error); res.status(500).json({ success: false, message: error.message }); } }