- Added temporary debug response in `numberingRuleController` for better troubleshooting. - Refactored SQL queries in `NumberingRuleService` to enhance parameter handling and improve clarity. - Updated `ItemInfoPage` to correctly handle manual input values for user-generated codes. - Implemented sorting logic in `ItemRoutingTab` to prioritize default routing versions and added functionality to set a version as default. These changes aim to enhance the reliability and user experience in managing numbering rules and item routing processes.
687 lines
21 KiB
TypeScript
687 lines
21 KiB
TypeScript
/**
|
|
* 채번 규칙 관리 컨트롤러
|
|
*/
|
|
|
|
import { Router, Response } from "express";
|
|
import {
|
|
authenticateToken,
|
|
AuthenticatedRequest,
|
|
} from "../middleware/authMiddleware";
|
|
import { numberingRuleService } from "../services/numberingRuleService";
|
|
import { logger } from "../utils/logger";
|
|
import { auditLogService, getClientIp } from "../services/auditLogService";
|
|
|
|
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("메뉴별 채번 규칙 조회 요청", { menuObjid, companyCode });
|
|
|
|
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;
|
|
|
|
logger.info("🔍 [POST /numbering-rules] 채번 규칙 생성 요청:", {
|
|
companyCode,
|
|
userId,
|
|
ruleId: ruleConfig.ruleId,
|
|
ruleName: ruleConfig.ruleName,
|
|
scopeType: ruleConfig.scopeType,
|
|
menuObjid: ruleConfig.menuObjid,
|
|
tableName: ruleConfig.tableName,
|
|
partsCount: ruleConfig.parts?.length,
|
|
});
|
|
|
|
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개 이상의 규칙 파트가 필요합니다",
|
|
});
|
|
}
|
|
|
|
// 🆕 scopeType이 'table'인 경우 tableName 필수 체크
|
|
if (ruleConfig.scopeType === "table") {
|
|
if (!ruleConfig.tableName || ruleConfig.tableName.trim() === "") {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: "테이블 범위 규칙은 테이블명(tableName)이 필수입니다",
|
|
});
|
|
}
|
|
}
|
|
|
|
const newRule = await numberingRuleService.createRule(
|
|
ruleConfig,
|
|
companyCode,
|
|
userId
|
|
);
|
|
|
|
logger.info("✅ [POST /numbering-rules] 채번 규칙 생성 성공:", {
|
|
ruleId: newRule.ruleId,
|
|
menuObjid: newRule.menuObjid,
|
|
});
|
|
|
|
auditLogService.log({
|
|
companyCode,
|
|
userId,
|
|
userName: req.user?.userName,
|
|
action: "CREATE",
|
|
resourceType: "NUMBERING_RULE",
|
|
resourceId: String(newRule.ruleId),
|
|
resourceName: ruleConfig.ruleName,
|
|
summary: `채번 규칙 "${ruleConfig.ruleName}" 생성`,
|
|
changes: { after: { ruleName: ruleConfig.ruleName, prefix: ruleConfig.prefix } },
|
|
ipAddress: getClientIp(req),
|
|
requestPath: req.originalUrl,
|
|
});
|
|
|
|
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("❌ [POST /numbering-rules] 규칙 생성 실패:", {
|
|
error: error.message,
|
|
stack: error.stack,
|
|
code: error.code,
|
|
});
|
|
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;
|
|
|
|
logger.info("채번 규칙 수정 요청", { ruleId, companyCode, updates });
|
|
|
|
try {
|
|
const beforeRule = await numberingRuleService.getRuleById(ruleId, companyCode);
|
|
const updatedRule = await numberingRuleService.updateRule(
|
|
ruleId,
|
|
updates,
|
|
companyCode
|
|
);
|
|
logger.info("채번 규칙 수정 성공", { ruleId, companyCode });
|
|
|
|
auditLogService.log({
|
|
companyCode,
|
|
userId: req.user?.userId || "",
|
|
userName: req.user?.userName,
|
|
action: "UPDATE",
|
|
resourceType: "NUMBERING_RULE",
|
|
resourceId: ruleId,
|
|
summary: `채번 규칙(ID:${ruleId}) 수정`,
|
|
changes: {
|
|
before: { ruleName: beforeRule?.ruleName, separator: beforeRule?.separator },
|
|
after: updates,
|
|
},
|
|
ipAddress: getClientIp(req),
|
|
requestPath: req.originalUrl,
|
|
});
|
|
|
|
return res.json({ success: true, data: updatedRule });
|
|
} catch (error: any) {
|
|
logger.error("채번 규칙 수정 실패", {
|
|
ruleId,
|
|
companyCode,
|
|
error: error.message,
|
|
stack: error.stack,
|
|
});
|
|
if (error.message.includes("찾을 수 없거나")) {
|
|
return res.status(404).json({ success: false, 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);
|
|
|
|
auditLogService.log({
|
|
companyCode,
|
|
userId: req.user?.userId || "",
|
|
userName: req.user?.userName,
|
|
action: "DELETE",
|
|
resourceType: "NUMBERING_RULE",
|
|
resourceId: ruleId,
|
|
summary: `채번 규칙(ID:${ruleId}) 삭제`,
|
|
ipAddress: getClientIp(req),
|
|
requestPath: req.originalUrl,
|
|
});
|
|
|
|
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;
|
|
const { formData, manualInputValue } = req.body;
|
|
|
|
try {
|
|
const previewCode = await numberingRuleService.previewCode(
|
|
ruleId,
|
|
companyCode,
|
|
formData,
|
|
manualInputValue
|
|
);
|
|
// TODO: 디버그용 임시 응답 (나중에 제거)
|
|
const { getPool } = require("../database/db");
|
|
const dbPool = getPool();
|
|
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;
|
|
const { formData, userInputCode } = req.body; // 폼 데이터 + 사용자가 편집한 코드
|
|
|
|
logger.info("코드 할당 요청", {
|
|
ruleId,
|
|
companyCode,
|
|
hasFormData: !!formData,
|
|
userInputCode,
|
|
});
|
|
|
|
try {
|
|
const allocatedCode = await numberingRuleService.allocateCode(
|
|
ruleId,
|
|
companyCode,
|
|
formData,
|
|
userInputCode
|
|
);
|
|
logger.info("코드 할당 성공", { ruleId, allocatedCode });
|
|
return res.json({
|
|
success: true,
|
|
data: { generatedCode: allocatedCode },
|
|
});
|
|
} catch (error: any) {
|
|
logger.error("코드 할당 실패", {
|
|
ruleId,
|
|
companyCode,
|
|
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 });
|
|
}
|
|
}
|
|
);
|
|
|
|
// 테이블+컬럼 기반 채번 규칙 조회 (메인 API)
|
|
router.get(
|
|
"/by-column/:tableName/:columnName",
|
|
authenticateToken,
|
|
async (req: AuthenticatedRequest, res: Response) => {
|
|
const companyCode = req.user!.companyCode;
|
|
const { tableName, columnName } = req.params;
|
|
|
|
try {
|
|
const rule = await numberingRuleService.getNumberingRuleByColumn(
|
|
companyCode,
|
|
tableName,
|
|
columnName
|
|
);
|
|
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 });
|
|
}
|
|
}
|
|
);
|
|
|
|
// ==================== 테스트 테이블용 API ====================
|
|
|
|
// [테스트] 테스트 테이블에서 채번 규칙 목록 조회
|
|
router.get(
|
|
"/test/list/: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.getRulesFromTest(
|
|
companyCode,
|
|
menuObjid
|
|
);
|
|
logger.info("[테스트] 채번 규칙 목록 조회 성공", {
|
|
companyCode,
|
|
menuObjid,
|
|
count: rules.length,
|
|
});
|
|
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(
|
|
"/test/by-column/:tableName/:columnName",
|
|
authenticateToken,
|
|
async (req: AuthenticatedRequest, res: Response) => {
|
|
const companyCode = req.user!.companyCode;
|
|
const { tableName, columnName } = req.params;
|
|
|
|
try {
|
|
const rule = await numberingRuleService.getNumberingRuleByColumn(
|
|
companyCode,
|
|
tableName,
|
|
columnName
|
|
);
|
|
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(
|
|
"/test/save",
|
|
authenticateToken,
|
|
async (req: AuthenticatedRequest, res: Response) => {
|
|
const companyCode = req.user!.companyCode;
|
|
const userId = req.user!.userId;
|
|
const ruleConfig = req.body;
|
|
|
|
logger.info("[테스트] 채번 규칙 저장 요청", {
|
|
ruleId: ruleConfig.ruleId,
|
|
ruleName: ruleConfig.ruleName,
|
|
tableName: ruleConfig.tableName || "(미지정)",
|
|
columnName: ruleConfig.columnName || "(미지정)",
|
|
});
|
|
|
|
try {
|
|
// ruleName만 필수, tableName/columnName은 선택 (나중에 테이블 타입 관리에서 연결)
|
|
if (!ruleConfig.ruleName) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: "ruleName is required",
|
|
});
|
|
}
|
|
|
|
const savedRule = await numberingRuleService.saveRuleToTest(
|
|
ruleConfig,
|
|
companyCode,
|
|
userId
|
|
);
|
|
|
|
const isUpdate = !!ruleConfig.ruleId;
|
|
|
|
const resetPeriodLabel: Record<string, string> = {
|
|
none: "초기화 안함", daily: "일별", monthly: "월별", yearly: "연별",
|
|
};
|
|
const partTypeLabel: Record<string, string> = {
|
|
sequence: "순번", number: "숫자", date: "날짜", text: "문자", category: "카테고리", reference: "참조",
|
|
};
|
|
const partsDescription = (ruleConfig.parts || [])
|
|
.sort((a: any, b: any) => (a.order || 0) - (b.order || 0))
|
|
.map((p: any) => {
|
|
const type = partTypeLabel[p.partType] || p.partType;
|
|
if (p.partType === "text" && p.autoConfig?.textValue) return `${type}("${p.autoConfig.textValue}")`;
|
|
if (p.partType === "sequence" && p.autoConfig?.sequenceLength) return `${type}(${p.autoConfig.sequenceLength}자리)`;
|
|
if (p.partType === "date" && p.autoConfig?.dateFormat) return `${type}(${p.autoConfig.dateFormat})`;
|
|
if (p.partType === "category") return `${type}(${p.autoConfig?.categoryKey || ""})`;
|
|
if (p.partType === "reference") return `${type}(${p.autoConfig?.referenceColumnName || ""})`;
|
|
return type;
|
|
})
|
|
.join(` ${ruleConfig.separator || "-"} `);
|
|
|
|
auditLogService.log({
|
|
companyCode,
|
|
userId,
|
|
userName: req.user?.userName,
|
|
action: isUpdate ? "UPDATE" : "CREATE",
|
|
resourceType: "NUMBERING_RULE",
|
|
resourceId: String(savedRule.ruleId),
|
|
resourceName: ruleConfig.ruleName,
|
|
tableName: "numbering_rules",
|
|
summary: isUpdate
|
|
? `채번 규칙 "${ruleConfig.ruleName}" 수정`
|
|
: `채번 규칙 "${ruleConfig.ruleName}" 생성`,
|
|
changes: {
|
|
after: {
|
|
규칙명: ruleConfig.ruleName,
|
|
적용테이블: ruleConfig.tableName || "(미지정)",
|
|
적용컬럼: ruleConfig.columnName || "(미지정)",
|
|
구분자: ruleConfig.separator || "-",
|
|
리셋주기: resetPeriodLabel[ruleConfig.resetPeriod] || ruleConfig.resetPeriod || "초기화 안함",
|
|
적용범위: ruleConfig.scopeType === "menu" ? "메뉴별" : "전역",
|
|
코드구성: partsDescription || "(파트 없음)",
|
|
파트수: (ruleConfig.parts || []).length,
|
|
},
|
|
},
|
|
ipAddress: getClientIp(req),
|
|
requestPath: req.originalUrl,
|
|
});
|
|
|
|
return res.json({ success: true, data: savedRule });
|
|
} catch (error: any) {
|
|
logger.error("[테스트] 채번 규칙 저장 실패", { error: error.message });
|
|
return res.status(500).json({ success: false, error: error.message });
|
|
}
|
|
}
|
|
);
|
|
|
|
// [테스트] 테스트 테이블에서 채번 규칙 삭제
|
|
router.delete(
|
|
"/test/:ruleId",
|
|
authenticateToken,
|
|
async (req: AuthenticatedRequest, res: Response) => {
|
|
const companyCode = req.user!.companyCode;
|
|
const userId = req.user!.userId;
|
|
const { ruleId } = req.params;
|
|
|
|
try {
|
|
await numberingRuleService.deleteRuleFromTest(ruleId, companyCode);
|
|
|
|
auditLogService.log({
|
|
companyCode,
|
|
userId,
|
|
userName: req.user?.userName,
|
|
action: "DELETE",
|
|
resourceType: "NUMBERING_RULE",
|
|
resourceId: ruleId,
|
|
tableName: "numbering_rules",
|
|
summary: `채번 규칙(ID:${ruleId}) 삭제`,
|
|
ipAddress: getClientIp(req),
|
|
requestPath: req.originalUrl,
|
|
});
|
|
|
|
return res.json({
|
|
success: true,
|
|
message: "테스트 채번 규칙이 삭제되었습니다",
|
|
});
|
|
} catch (error: any) {
|
|
logger.error("[테스트] 채번 규칙 삭제 실패", { error: error.message });
|
|
return res.status(500).json({ success: false, error: error.message });
|
|
}
|
|
}
|
|
);
|
|
|
|
// [테스트] 코드 미리보기 (테스트 테이블 사용)
|
|
router.post(
|
|
"/test/:ruleId/preview",
|
|
authenticateToken,
|
|
async (req: AuthenticatedRequest, res: Response) => {
|
|
const companyCode = req.user!.companyCode;
|
|
const { ruleId } = req.params;
|
|
const { formData } = req.body;
|
|
|
|
try {
|
|
const previewCode = await numberingRuleService.previewCode(
|
|
ruleId,
|
|
companyCode,
|
|
formData
|
|
);
|
|
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 });
|
|
}
|
|
}
|
|
);
|
|
|
|
// ==================== 회사별 채번규칙 복제 API ====================
|
|
|
|
// 회사별 채번규칙 복제
|
|
router.post(
|
|
"/copy-for-company",
|
|
authenticateToken,
|
|
async (req: AuthenticatedRequest, res: Response) => {
|
|
const userCompanyCode = req.user!.companyCode;
|
|
const { sourceCompanyCode, targetCompanyCode } = req.body;
|
|
|
|
// 최고 관리자만 사용 가능
|
|
if (userCompanyCode !== "*") {
|
|
return res.status(403).json({
|
|
success: false,
|
|
error: "최고 관리자만 사용할 수 있습니다",
|
|
});
|
|
}
|
|
|
|
if (!sourceCompanyCode || !targetCompanyCode) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: "sourceCompanyCode와 targetCompanyCode가 필요합니다",
|
|
});
|
|
}
|
|
|
|
try {
|
|
const result = await numberingRuleService.copyRulesForCompany(
|
|
sourceCompanyCode,
|
|
targetCompanyCode
|
|
);
|
|
return res.json({ success: true, data: result });
|
|
} catch (error: any) {
|
|
logger.error("회사별 채번규칙 복제 실패", { error: error.message });
|
|
return res.status(500).json({ success: false, error: error.message });
|
|
}
|
|
}
|
|
);
|
|
|
|
export default router;
|