ERP-node/backend-node/src/controllers/dataflowDiagramController.ts

413 lines
12 KiB
TypeScript

import { Request, Response } from "express";
import { AuthenticatedRequest } from "../types/auth";
import {
getDataflowDiagrams as getDataflowDiagramsService,
getDataflowDiagramById as getDataflowDiagramByIdService,
createDataflowDiagram as createDataflowDiagramService,
updateDataflowDiagram as updateDataflowDiagramService,
deleteDataflowDiagram as deleteDataflowDiagramService,
copyDataflowDiagram as copyDataflowDiagramService,
} from "../services/dataflowDiagramService";
import { logger } from "../utils/logger";
/**
* 관계도 목록 조회 (페이지네이션)
*/
export const getDataflowDiagrams = async (
req: AuthenticatedRequest,
res: Response
) => {
try {
const page = parseInt(req.query.page as string) || 1;
const size = parseInt(req.query.size as string) || 20;
const searchTerm = req.query.searchTerm as string;
const userCompanyCode = req.user?.companyCode;
// 슈퍼 관리자는 쿼리 파라미터로 회사 지정 가능, 일반/회사 관리자는 자신의 회사만
let companyCode: string;
if (userCompanyCode === "*") {
// 슈퍼 관리자: 쿼리 파라미터 사용 또는 전체
companyCode = (req.query.companyCode as string) || "*";
} else {
// 회사 관리자/일반 사용자: 강제로 자신의 회사 코드 적용
companyCode = userCompanyCode || "*";
}
logger.info("관계도 목록 조회", {
userId: req.user?.userId,
userCompanyCode,
filterCompanyCode: companyCode,
page,
size,
});
const result = await getDataflowDiagramsService(
companyCode,
page,
size,
searchTerm
);
res.json({
success: true,
data: result,
});
} catch (error) {
logger.error("관계도 목록 조회 실패:", error);
res.status(500).json({
success: false,
message: "관계도 목록 조회 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "Unknown error",
});
}
};
/**
* 특정 관계도 조회
*/
export const getDataflowDiagramById = async (
req: AuthenticatedRequest,
res: Response
) => {
try {
const diagramId = parseInt(req.params.diagramId);
const userCompanyCode = req.user?.companyCode;
// 슈퍼 관리자는 쿼리 파라미터로 회사 지정 가능, 일반/회사 관리자는 자신의 회사만
let companyCode: string;
if (userCompanyCode === "*") {
companyCode = (req.query.companyCode as string) || "*";
} else {
companyCode = userCompanyCode || "*";
}
if (isNaN(diagramId)) {
return res.status(400).json({
success: false,
message: "유효하지 않은 관계도 ID입니다.",
});
}
const diagram = await getDataflowDiagramByIdService(diagramId, companyCode);
if (!diagram) {
return res.status(404).json({
success: false,
message: "관계도를 찾을 수 없습니다.",
});
}
return res.json({
success: true,
data: diagram,
});
} catch (error) {
logger.error("관계도 조회 실패:", error);
return res.status(500).json({
success: false,
message: "관계도 조회 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "Unknown error",
});
}
};
/**
* 새로운 관계도 생성
*/
export const createDataflowDiagram = async (
req: AuthenticatedRequest,
res: Response
) => {
try {
const {
diagram_name,
relationships,
node_positions,
category,
control,
plan,
} = req.body;
const userCompanyCode = req.user?.companyCode;
const userId = req.user?.userId || "SYSTEM";
// 회사 코드는 로그인한 사용자의 회사 코드 사용 (슈퍼 관리자는 요청 body에서 지정 가능)
let companyCode: string;
if (userCompanyCode === "*" && req.body.company_code) {
// 슈퍼 관리자가 특정 회사로 생성하는 경우
companyCode = req.body.company_code;
} else {
// 일반 사용자/회사 관리자는 자신의 회사로 생성
companyCode = userCompanyCode || "*";
}
logger.info(`새 관계도 생성 요청:`, {
diagram_name,
companyCode,
userId,
userCompanyCode,
});
logger.info(`node_positions:`, node_positions);
logger.info(`category:`, category);
logger.info(`control:`, control);
logger.info(`plan:`, plan);
if (!diagram_name || !relationships) {
return res.status(400).json({
success: false,
message: "관계도 이름과 관계 정보는 필수입니다.",
});
}
const newDiagram = await createDataflowDiagramService({
diagram_name,
relationships,
node_positions,
category,
control,
plan,
company_code: companyCode,
created_by: userId,
updated_by: userId,
});
return res.status(201).json({
success: true,
data: newDiagram,
message: "관계도가 성공적으로 생성되었습니다.",
});
} catch (error) {
// 디버깅을 위한 에러 정보 출력
logger.error("에러 디버깅:", {
errorType: typeof error,
errorCode: (error as any)?.code,
errorMessage: error instanceof Error ? error.message : "Unknown error",
errorName: (error as any)?.name,
errorMeta: (error as any)?.meta,
});
// 중복 이름 에러인지 먼저 확인 (로그 출력 전에)
const isDuplicateError =
(error && typeof error === "object" && (error as any).code === "23505") || // PostgreSQL unique_violation
(error instanceof Error &&
(error.message.includes("unique constraint") ||
error.message.includes("Unique constraint") ||
error.message.includes("duplicate key") ||
error.message.includes("UNIQUE constraint failed") ||
error.message.includes("unique_diagram_name_per_company")));
if (isDuplicateError) {
// 중복 에러는 콘솔에 로그 출력하지 않음
return res.status(409).json({
success: false,
message: "중복된 이름입니다.",
});
}
// 다른 에러만 로그 출력
logger.error("관계도 생성 실패:", error);
return res.status(500).json({
success: false,
message: "관계도 생성 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "Unknown error",
});
}
};
/**
* 관계도 수정
*/
export const updateDataflowDiagram = async (
req: AuthenticatedRequest,
res: Response
) => {
try {
const diagramId = parseInt(req.params.diagramId);
const userCompanyCode = req.user?.companyCode;
const userId = req.user?.userId || "SYSTEM";
// 슈퍼 관리자는 쿼리 파라미터로 회사 지정 가능, 일반/회사 관리자는 자신의 회사만
let companyCode: string;
if (userCompanyCode === "*") {
companyCode = (req.query.companyCode as string) || "*";
} else {
companyCode = userCompanyCode || "*";
}
logger.info(`관계도 수정 요청`, {
diagramId,
companyCode,
userId,
userCompanyCode,
});
logger.info(`요청 Body:`, JSON.stringify(req.body, null, 2));
logger.info(`node_positions:`, req.body.node_positions);
if (isNaN(diagramId)) {
return res.status(400).json({
success: false,
message: "유효하지 않은 관계도 ID입니다.",
});
}
const updateData = {
...req.body,
updated_by: userId,
};
const updatedDiagram = await updateDataflowDiagramService(
diagramId,
updateData,
companyCode
);
if (!updatedDiagram) {
return res.status(404).json({
success: false,
message: "관계도를 찾을 수 없습니다.",
});
}
return res.json({
success: true,
data: updatedDiagram,
message: "관계도가 성공적으로 수정되었습니다.",
});
} catch (error) {
// 중복 이름 에러인지 먼저 확인 (로그 출력 전에)
const isDuplicateError =
(error && typeof error === "object" && (error as any).code === "23505") || // PostgreSQL unique_violation
(error instanceof Error &&
(error.message.includes("unique constraint") ||
error.message.includes("Unique constraint") ||
error.message.includes("duplicate key") ||
error.message.includes("UNIQUE constraint failed") ||
error.message.includes("unique_diagram_name_per_company")));
if (isDuplicateError) {
// 중복 에러는 콘솔에 로그 출력하지 않음
return res.status(409).json({
success: false,
message: "중복된 이름입니다.",
});
}
// 다른 에러만 로그 출력
logger.error("관계도 수정 실패:", error);
return res.status(500).json({
success: false,
message: "관계도 수정 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "Unknown error",
});
}
};
/**
* 관계도 삭제
*/
export const deleteDataflowDiagram = async (
req: AuthenticatedRequest,
res: Response
) => {
try {
const diagramId = parseInt(req.params.diagramId);
const userCompanyCode = req.user?.companyCode;
// 슈퍼 관리자는 쿼리 파라미터로 회사 지정 가능, 일반/회사 관리자는 자신의 회사만
let companyCode: string;
if (userCompanyCode === "*") {
companyCode = (req.query.companyCode as string) || "*";
} else {
companyCode = userCompanyCode || "*";
}
if (isNaN(diagramId)) {
return res.status(400).json({
success: false,
message: "유효하지 않은 관계도 ID입니다.",
});
}
const deleted = await deleteDataflowDiagramService(diagramId, companyCode);
if (!deleted) {
return res.status(404).json({
success: false,
message: "관계도를 찾을 수 없습니다.",
});
}
return res.json({
success: true,
message: "관계도가 성공적으로 삭제되었습니다.",
});
} catch (error) {
logger.error("관계도 삭제 실패:", error);
return res.status(500).json({
success: false,
message: "관계도 삭제 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "Unknown error",
});
}
};
/**
* 관계도 복제
*/
export const copyDataflowDiagram = async (
req: AuthenticatedRequest,
res: Response
) => {
try {
const diagramId = parseInt(req.params.diagramId);
const { new_name } = req.body;
const userCompanyCode = req.user?.companyCode;
const userId = req.user?.userId || "SYSTEM";
// 회사 코드는 로그인한 사용자의 회사 코드 사용
let companyCode: string;
if (userCompanyCode === "*" && req.body.companyCode) {
// 슈퍼 관리자가 특정 회사로 복제하는 경우
companyCode = req.body.companyCode;
} else {
// 일반 사용자/회사 관리자는 자신의 회사로 복제
companyCode = userCompanyCode || "*";
}
if (isNaN(diagramId)) {
return res.status(400).json({
success: false,
message: "유효하지 않은 관계도 ID입니다.",
});
}
const copiedDiagram = await copyDataflowDiagramService(
diagramId,
companyCode,
new_name,
userId
);
if (!copiedDiagram) {
return res.status(404).json({
success: false,
message: "복제할 관계도를 찾을 수 없습니다.",
});
}
return res.status(201).json({
success: true,
data: copiedDiagram,
message: "관계도가 성공적으로 복제되었습니다.",
});
} catch (error) {
logger.error("관계도 복제 실패:", error);
return res.status(500).json({
success: false,
message: "관계도 복제 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "Unknown error",
});
}
};