/** * 채번 규칙 관리 컨트롤러 */ import { Router, Response } from "express"; import { authenticateToken, AuthenticatedRequest } from "../middleware/authMiddleware"; import { numberingRuleService } from "../services/numberingRuleService"; import { logger } from "../utils/logger"; const router = Router(); // 규칙 목록 조회 (전체) router.get("/", authenticateToken, async (req: AuthenticatedRequest, res: Response) => { const companyCode = req.user!.companyCode; try { const rules = await numberingRuleService.getRuleList(companyCode); return res.json({ success: true, data: rules }); } catch (error: any) { logger.error("규칙 목록 조회 실패", { error: error.message }); return res.status(500).json({ success: false, error: error.message }); } }); // 메뉴별 사용 가능한 규칙 조회 router.get("/available/:menuObjid?", authenticateToken, async (req: AuthenticatedRequest, res: Response) => { const companyCode = req.user!.companyCode; const menuObjid = req.params.menuObjid ? parseInt(req.params.menuObjid) : undefined; logger.info("📥 메뉴별 채번 규칙 조회 요청", { companyCode, menuObjid }); try { const rules = await numberingRuleService.getAvailableRulesForMenu(companyCode, menuObjid); logger.info("✅ 메뉴별 채번 규칙 조회 성공 (컨트롤러)", { companyCode, menuObjid, rulesCount: rules.length }); return res.json({ success: true, data: rules }); } catch (error: any) { logger.error("❌ 메뉴별 사용 가능한 규칙 조회 실패 (컨트롤러)", { error: error.message, errorCode: error.code, errorStack: error.stack, companyCode, menuObjid, }); return res.status(500).json({ success: false, error: error.message }); } }); // 화면용 채번 규칙 조회 (테이블 기반 필터링 - 간소화) router.get("/available-for-screen", authenticateToken, async (req: AuthenticatedRequest, res: Response) => { const companyCode = req.user!.companyCode; const { tableName } = req.query; try { // tableName 필수 검증 if (!tableName || typeof tableName !== "string") { return res.status(400).json({ success: false, error: "tableName is required", }); } const rules = await numberingRuleService.getAvailableRulesForScreen( companyCode, tableName ); logger.info("화면용 채번 규칙 조회 성공", { companyCode, tableName, count: rules.length, }); return res.json({ success: true, data: rules }); } catch (error: any) { logger.error("화면용 채번 규칙 조회 실패", { error: error.message, tableName, }); return res.status(500).json({ success: false, error: error.message, }); } }); // 특정 규칙 조회 router.get("/:ruleId", authenticateToken, async (req: AuthenticatedRequest, res: Response) => { const companyCode = req.user!.companyCode; const { ruleId } = req.params; try { const rule = await numberingRuleService.getRuleById(ruleId, companyCode); if (!rule) { return res.status(404).json({ success: false, error: "규칙을 찾을 수 없습니다" }); } return res.json({ success: true, data: rule }); } catch (error: any) { logger.error("규칙 조회 실패", { error: error.message }); return res.status(500).json({ success: false, error: error.message }); } }); // 규칙 생성 router.post("/", authenticateToken, async (req: AuthenticatedRequest, res: Response) => { const companyCode = req.user!.companyCode; const userId = req.user!.userId; const ruleConfig = req.body; try { if (!ruleConfig.ruleId || !ruleConfig.ruleName) { return res.status(400).json({ success: false, error: "규칙 ID와 규칙명은 필수입니다" }); } if (!Array.isArray(ruleConfig.parts) || ruleConfig.parts.length === 0) { return res.status(400).json({ success: false, error: "최소 1개 이상의 규칙 파트가 필요합니다" }); } const newRule = await numberingRuleService.createRule(ruleConfig, companyCode, userId); return res.status(201).json({ success: true, data: newRule }); } catch (error: any) { if (error.code === "23505") { return res.status(409).json({ success: false, error: "이미 존재하는 규칙 ID입니다" }); } logger.error("규칙 생성 실패", { error: error.message }); return res.status(500).json({ success: false, error: error.message }); } }); // 규칙 수정 router.put("/:ruleId", authenticateToken, async (req: AuthenticatedRequest, res: Response) => { const companyCode = req.user!.companyCode; const { ruleId } = req.params; const updates = req.body; try { const updatedRule = await numberingRuleService.updateRule(ruleId, updates, companyCode); return res.json({ success: true, data: updatedRule }); } catch (error: any) { if (error.message.includes("찾을 수 없거나")) { return res.status(404).json({ success: false, error: error.message }); } logger.error("규칙 수정 실패", { error: error.message }); return res.status(500).json({ success: false, error: error.message }); } }); // 규칙 삭제 router.delete("/:ruleId", authenticateToken, async (req: AuthenticatedRequest, res: Response) => { const companyCode = req.user!.companyCode; const { ruleId } = req.params; try { await numberingRuleService.deleteRule(ruleId, companyCode); return res.json({ success: true, message: "규칙이 삭제되었습니다" }); } catch (error: any) { if (error.message.includes("찾을 수 없거나")) { return res.status(404).json({ success: false, error: error.message }); } logger.error("규칙 삭제 실패", { error: error.message }); return res.status(500).json({ success: false, error: error.message }); } }); // 코드 미리보기 (순번 증가 없음) router.post("/:ruleId/preview", authenticateToken, async (req: AuthenticatedRequest, res: Response) => { const companyCode = req.user!.companyCode; const { ruleId } = req.params; try { const previewCode = await numberingRuleService.previewCode(ruleId, companyCode); return res.json({ success: true, data: { generatedCode: previewCode } }); } catch (error: any) { logger.error("코드 미리보기 실패", { error: error.message }); return res.status(500).json({ success: false, error: error.message }); } }); // 코드 할당 (저장 시점에 실제 순번 증가) router.post("/:ruleId/allocate", authenticateToken, async (req: AuthenticatedRequest, res: Response) => { const companyCode = req.user!.companyCode; const { ruleId } = req.params; try { const allocatedCode = await numberingRuleService.allocateCode(ruleId, companyCode); return res.json({ success: true, data: { generatedCode: allocatedCode } }); } catch (error: any) { logger.error("코드 할당 실패", { error: error.message }); return res.status(500).json({ success: false, error: error.message }); } }); // 코드 생성 (기존 호환성 유지, deprecated) router.post("/:ruleId/generate", authenticateToken, async (req: AuthenticatedRequest, res: Response) => { const companyCode = req.user!.companyCode; const { ruleId } = req.params; try { const generatedCode = await numberingRuleService.generateCode(ruleId, companyCode); return res.json({ success: true, data: { generatedCode } }); } catch (error: any) { logger.error("코드 생성 실패", { error: error.message }); return res.status(500).json({ success: false, error: error.message }); } }); // 시퀀스 초기화 router.post("/:ruleId/reset", authenticateToken, async (req: AuthenticatedRequest, res: Response) => { const companyCode = req.user!.companyCode; const { ruleId } = req.params; try { await numberingRuleService.resetSequence(ruleId, companyCode); return res.json({ success: true, message: "시퀀스가 초기화되었습니다" }); } catch (error: any) { logger.error("시퀀스 초기화 실패", { error: error.message }); return res.status(500).json({ success: false, error: error.message }); } }); export default router;