ERP-node/backend-node/src/services/commonCodeService.ts

860 lines
24 KiB
TypeScript
Raw Normal View History

import { query, queryOne, transaction } from "../database/db";
2025-09-02 11:30:19 +09:00
import { logger } from "../utils/logger";
export interface CodeCategory {
category_code: string;
category_name: string;
category_name_eng?: string | null;
description?: string | null;
sort_order: number;
is_active: string;
company_code: string; // 추가
2025-09-02 11:30:19 +09:00
created_date?: Date | null;
created_by?: string | null;
updated_date?: Date | null;
updated_by?: string | null;
}
export interface CodeInfo {
code_category: string;
code_value: string;
code_name: string;
code_name_eng?: string | null;
description?: string | null;
sort_order: number;
is_active: string;
company_code: string; // 추가
2025-09-02 11:30:19 +09:00
created_date?: Date | null;
created_by?: string | null;
updated_date?: Date | null;
updated_by?: string | null;
}
export interface GetCategoriesParams {
search?: string;
isActive?: boolean;
page?: number;
size?: number;
}
export interface GetCodesParams {
search?: string;
isActive?: boolean;
2025-09-03 18:23:23 +09:00
page?: number;
size?: number;
2025-09-02 11:30:19 +09:00
}
export interface CreateCategoryData {
categoryCode: string;
categoryName: string;
categoryNameEng?: string;
description?: string;
sortOrder?: number;
isActive?: string;
2025-09-02 11:30:19 +09:00
}
export interface CreateCodeData {
codeValue: string;
codeName: string;
codeNameEng?: string;
description?: string;
sortOrder?: number;
isActive?: string;
2025-09-02 11:30:19 +09:00
}
export class CommonCodeService {
/**
*
*/
async getCategories(params: GetCategoriesParams, userCompanyCode?: string, menuObjid?: number) {
2025-09-02 11:30:19 +09:00
try {
const { search, isActive, page = 1, size = 20 } = params;
const whereConditions: string[] = [];
const values: any[] = [];
let paramIndex = 1;
2025-09-02 11:30:19 +09:00
// 메뉴별 필터링 (형제 메뉴 포함)
if (menuObjid) {
const { getSiblingMenuObjids } = await import('./menuService');
const siblingMenuObjids = await getSiblingMenuObjids(menuObjid);
whereConditions.push(`menu_objid = ANY($${paramIndex})`);
values.push(siblingMenuObjids);
paramIndex++;
logger.info(`메뉴별 코드 카테고리 필터링: ${menuObjid}, 형제 메뉴: ${siblingMenuObjids.join(', ')}`);
}
// 회사별 필터링 (최고 관리자가 아닌 경우)
if (userCompanyCode && userCompanyCode !== "*") {
whereConditions.push(`company_code = $${paramIndex}`);
values.push(userCompanyCode);
paramIndex++;
logger.info(`회사별 코드 카테고리 필터링: ${userCompanyCode}`);
} else if (userCompanyCode === "*") {
// 최고 관리자는 모든 데이터 조회 가능
logger.info(`최고 관리자: 모든 코드 카테고리 조회`);
}
2025-09-02 11:30:19 +09:00
if (search) {
whereConditions.push(
`(category_name ILIKE $${paramIndex} OR category_code ILIKE $${paramIndex})`
);
values.push(`%${search}%`);
paramIndex++;
2025-09-02 11:30:19 +09:00
}
if (isActive !== undefined) {
whereConditions.push(`is_active = $${paramIndex++}`);
values.push(isActive ? "Y" : "N");
2025-09-02 11:30:19 +09:00
}
const whereClause =
whereConditions.length > 0
? `WHERE ${whereConditions.join(" AND ")}`
: "";
2025-09-02 11:30:19 +09:00
const offset = (page - 1) * size;
// 카테고리 조회
const categories = await query<CodeCategory>(
`SELECT * FROM code_category
${whereClause}
ORDER BY sort_order ASC, category_code ASC
LIMIT $${paramIndex++} OFFSET $${paramIndex++}`,
[...values, size, offset]
);
// 전체 개수 조회
const countResult = await queryOne<{ count: string }>(
`SELECT COUNT(*) as count FROM code_category ${whereClause}`,
values
);
const total = parseInt(countResult?.count || "0");
2025-09-02 11:30:19 +09:00
logger.info(
`카테고리 조회 완료: ${categories.length}개, 전체: ${total}개 (회사: ${userCompanyCode || "전체"})`
2025-09-02 11:30:19 +09:00
);
return {
data: categories,
total,
};
} catch (error) {
logger.error("카테고리 조회 중 오류:", error);
throw error;
}
}
/**
*
*/
async getCodes(
categoryCode: string,
params: GetCodesParams,
userCompanyCode?: string,
menuObjid?: number
) {
2025-09-02 11:30:19 +09:00
try {
2025-09-03 18:23:23 +09:00
const { search, isActive, page = 1, size = 20 } = params;
2025-09-02 11:30:19 +09:00
logger.info(`🔍 [getCodes] 코드 조회 시작:`, {
categoryCode,
menuObjid,
hasMenuObjid: !!menuObjid,
userCompanyCode,
search,
isActive,
page,
size,
});
const whereConditions: string[] = ["code_category = $1"];
const values: any[] = [categoryCode];
let paramIndex = 2;
2025-09-02 11:30:19 +09:00
// 메뉴별 필터링 (형제 메뉴 포함)
if (menuObjid) {
const { getSiblingMenuObjids } = await import('./menuService');
const siblingMenuObjids = await getSiblingMenuObjids(menuObjid);
whereConditions.push(`menu_objid = ANY($${paramIndex})`);
values.push(siblingMenuObjids);
paramIndex++;
logger.info(`📋 [getCodes] 메뉴별 코드 필터링:`, {
menuObjid,
siblingMenuObjids,
siblingCount: siblingMenuObjids.length,
});
} else {
logger.warn(`⚠️ [getCodes] menuObjid 없음 - 전역 코드 조회`);
}
// 회사별 필터링 (최고 관리자가 아닌 경우)
if (userCompanyCode && userCompanyCode !== "*") {
whereConditions.push(`company_code = $${paramIndex}`);
values.push(userCompanyCode);
paramIndex++;
logger.info(`회사별 코드 필터링: ${userCompanyCode}`);
} else if (userCompanyCode === "*") {
logger.info(`최고 관리자: 모든 코드 조회`);
}
2025-09-02 11:30:19 +09:00
if (search) {
whereConditions.push(
`(code_name ILIKE $${paramIndex} OR code_value ILIKE $${paramIndex})`
);
values.push(`%${search}%`);
paramIndex++;
2025-09-02 11:30:19 +09:00
}
if (isActive !== undefined) {
whereConditions.push(`is_active = $${paramIndex++}`);
values.push(isActive ? "Y" : "N");
2025-09-02 11:30:19 +09:00
}
const whereClause = `WHERE ${whereConditions.join(" AND ")}`;
2025-09-03 18:23:23 +09:00
const offset = (page - 1) * size;
logger.info(`📝 [getCodes] 실행할 쿼리:`, {
whereClause,
values,
whereConditions,
paramIndex,
});
// 코드 조회
const codes = await query<CodeInfo>(
`SELECT * FROM code_info
${whereClause}
ORDER BY sort_order ASC, code_value ASC
LIMIT $${paramIndex++} OFFSET $${paramIndex++}`,
[...values, size, offset]
);
// 전체 개수 조회
const countResult = await queryOne<{ count: string }>(
`SELECT COUNT(*) as count FROM code_info ${whereClause}`,
values
);
const total = parseInt(countResult?.count || "0");
2025-09-02 11:30:19 +09:00
2025-09-03 18:23:23 +09:00
logger.info(
`✅ [getCodes] 코드 조회 완료: ${categoryCode} - ${codes.length}개, 전체: ${total}개 (회사: ${userCompanyCode || "전체"}, menuObjid: ${menuObjid || "없음"})`
2025-09-03 18:23:23 +09:00
);
2025-09-02 11:30:19 +09:00
logger.info(`📊 [getCodes] 조회된 코드 상세:`, {
categoryCode,
menuObjid,
codes: codes.map((c) => ({
code_value: c.code_value,
code_name: c.code_name,
menu_objid: c.menu_objid,
company_code: c.company_code,
})),
});
2025-09-03 18:23:23 +09:00
return { data: codes, total };
2025-09-02 11:30:19 +09:00
} catch (error) {
logger.error(`코드 조회 중 오류 (${categoryCode}):`, error);
throw error;
}
}
/**
*
*/
async createCategory(
data: CreateCategoryData,
createdBy: string,
companyCode: string,
menuObjid: number
) {
2025-09-02 11:30:19 +09:00
try {
const category = await queryOne<CodeCategory>(
`INSERT INTO code_category
(category_code, category_name, category_name_eng, description, sort_order,
is_active, menu_objid, company_code, created_by, updated_by, created_date, updated_date)
VALUES ($1, $2, $3, $4, $5, 'Y', $6, $7, $8, $9, NOW(), NOW())
RETURNING *`,
[
data.categoryCode,
data.categoryName,
data.categoryNameEng || null,
data.description || null,
data.sortOrder || 0,
menuObjid,
companyCode,
createdBy,
createdBy,
]
);
2025-09-02 11:30:19 +09:00
logger.info(
`카테고리 생성 완료: ${data.categoryCode} (메뉴: ${menuObjid}, 회사: ${companyCode})`
);
2025-09-02 11:30:19 +09:00
return category;
} catch (error) {
logger.error("카테고리 생성 중 오류:", error);
throw error;
}
}
/**
*
*/
async updateCategory(
categoryCode: string,
data: Partial<CreateCategoryData>,
updatedBy: string,
companyCode?: string
2025-09-02 11:30:19 +09:00
) {
try {
// 디버깅: 받은 데이터 로그
logger.info(`카테고리 수정 데이터:`, { categoryCode, data, companyCode });
// 동적 UPDATE 쿼리 생성
const updateFields: string[] = [
"updated_by = $1",
"updated_date = NOW()",
];
const values: any[] = [updatedBy];
let paramIndex = 2;
if (data.categoryName !== undefined) {
updateFields.push(`category_name = $${paramIndex++}`);
values.push(data.categoryName);
}
if (data.categoryNameEng !== undefined) {
updateFields.push(`category_name_eng = $${paramIndex++}`);
values.push(data.categoryNameEng);
}
if (data.description !== undefined) {
updateFields.push(`description = $${paramIndex++}`);
values.push(data.description);
}
if (data.sortOrder !== undefined) {
updateFields.push(`sort_order = $${paramIndex++}`);
values.push(data.sortOrder);
}
if (data.isActive !== undefined) {
const activeValue =
typeof data.isActive === "boolean"
? data.isActive
? "Y"
: "N"
: data.isActive;
updateFields.push(`is_active = $${paramIndex++}`);
values.push(activeValue);
}
// WHERE 절 구성
let whereClause = `WHERE category_code = $${paramIndex}`;
values.push(categoryCode);
// 회사 필터링 (최고 관리자가 아닌 경우)
if (companyCode && companyCode !== "*") {
paramIndex++;
whereClause += ` AND company_code = $${paramIndex}`;
values.push(companyCode);
}
const category = await queryOne<CodeCategory>(
`UPDATE code_category
SET ${updateFields.join(", ")}
${whereClause}
RETURNING *`,
values
);
2025-09-02 11:30:19 +09:00
logger.info(
`카테고리 수정 완료: ${categoryCode} (회사: ${companyCode || "전체"})`
);
2025-09-02 11:30:19 +09:00
return category;
} catch (error) {
logger.error(`카테고리 수정 중 오류 (${categoryCode}):`, error);
throw error;
}
}
/**
*
*/
async deleteCategory(categoryCode: string, companyCode?: string) {
2025-09-02 11:30:19 +09:00
try {
let sql = `DELETE FROM code_category WHERE category_code = $1`;
const values: any[] = [categoryCode];
2025-09-02 11:30:19 +09:00
// 회사 필터링 (최고 관리자가 아닌 경우)
if (companyCode && companyCode !== "*") {
sql += ` AND company_code = $2`;
values.push(companyCode);
}
await query(sql, values);
logger.info(
`카테고리 삭제 완료: ${categoryCode} (회사: ${companyCode || "전체"})`
);
2025-09-02 11:30:19 +09:00
} catch (error) {
logger.error(`카테고리 삭제 중 오류 (${categoryCode}):`, error);
throw error;
}
}
/**
*
*/
async createCode(
categoryCode: string,
data: CreateCodeData,
createdBy: string,
companyCode: string,
menuObjid: number
2025-09-02 11:30:19 +09:00
) {
try {
const code = await queryOne<CodeInfo>(
`INSERT INTO code_info
(code_category, code_value, code_name, code_name_eng, description, sort_order,
is_active, menu_objid, company_code, created_by, updated_by, created_date, updated_date)
VALUES ($1, $2, $3, $4, $5, $6, 'Y', $7, $8, $9, $10, NOW(), NOW())
RETURNING *`,
[
categoryCode,
data.codeValue,
data.codeName,
data.codeNameEng || null,
data.description || null,
data.sortOrder || 0,
menuObjid,
companyCode,
createdBy,
createdBy,
]
);
2025-09-02 11:30:19 +09:00
logger.info(
`코드 생성 완료: ${categoryCode}.${data.codeValue} (메뉴: ${menuObjid}, 회사: ${companyCode})`
);
2025-09-02 11:30:19 +09:00
return code;
} catch (error) {
logger.error(
`코드 생성 중 오류 (${categoryCode}.${data.codeValue}):`,
error
);
throw error;
}
}
/**
*
*/
async updateCode(
categoryCode: string,
codeValue: string,
data: Partial<CreateCodeData>,
updatedBy: string,
companyCode?: string
2025-09-02 11:30:19 +09:00
) {
try {
// 디버깅: 받은 데이터 로그
logger.info(`코드 수정 데이터:`, {
categoryCode,
codeValue,
data,
companyCode,
});
// 동적 UPDATE 쿼리 생성
const updateFields: string[] = [
"updated_by = $1",
"updated_date = NOW()",
];
const values: any[] = [updatedBy];
let paramIndex = 2;
if (data.codeName !== undefined) {
updateFields.push(`code_name = $${paramIndex++}`);
values.push(data.codeName);
}
if (data.codeNameEng !== undefined) {
updateFields.push(`code_name_eng = $${paramIndex++}`);
values.push(data.codeNameEng);
}
if (data.description !== undefined) {
updateFields.push(`description = $${paramIndex++}`);
values.push(data.description);
}
if (data.sortOrder !== undefined) {
updateFields.push(`sort_order = $${paramIndex++}`);
values.push(data.sortOrder);
}
if (data.isActive !== undefined) {
const activeValue =
typeof data.isActive === "boolean"
? data.isActive
? "Y"
: "N"
: data.isActive;
updateFields.push(`is_active = $${paramIndex++}`);
values.push(activeValue);
}
// WHERE 절 구성
let whereClause = `WHERE code_category = $${paramIndex++} AND code_value = $${paramIndex}`;
values.push(categoryCode, codeValue);
// 회사 필터링 (최고 관리자가 아닌 경우)
if (companyCode && companyCode !== "*") {
paramIndex++;
whereClause += ` AND company_code = $${paramIndex}`;
values.push(companyCode);
}
const code = await queryOne<CodeInfo>(
`UPDATE code_info
SET ${updateFields.join(", ")}
${whereClause}
RETURNING *`,
values
);
2025-09-02 11:30:19 +09:00
logger.info(
`코드 수정 완료: ${categoryCode}.${codeValue} (회사: ${companyCode || "전체"})`
);
2025-09-02 11:30:19 +09:00
return code;
} catch (error) {
logger.error(`코드 수정 중 오류 (${categoryCode}.${codeValue}):`, error);
throw error;
}
}
/**
*
*/
async deleteCode(
categoryCode: string,
codeValue: string,
companyCode?: string
) {
2025-09-02 11:30:19 +09:00
try {
let sql = `DELETE FROM code_info WHERE code_category = $1 AND code_value = $2`;
const values: any[] = [categoryCode, codeValue];
2025-09-02 11:30:19 +09:00
// 회사 필터링 (최고 관리자가 아닌 경우)
if (companyCode && companyCode !== "*") {
sql += ` AND company_code = $3`;
values.push(companyCode);
}
await query(sql, values);
logger.info(
`코드 삭제 완료: ${categoryCode}.${codeValue} (회사: ${companyCode || "전체"})`
);
2025-09-02 11:30:19 +09:00
} catch (error) {
logger.error(`코드 삭제 중 오류 (${categoryCode}.${codeValue}):`, error);
throw error;
}
}
/**
* ()
*/
async getCodeOptions(categoryCode: string, userCompanyCode?: string) {
2025-09-02 11:30:19 +09:00
try {
let sql = `SELECT code_value, code_name, code_name_eng, sort_order
FROM code_info
WHERE code_category = $1 AND is_active = 'Y'`;
const values: any[] = [categoryCode];
// 회사별 필터링 (최고 관리자가 아닌 경우)
if (userCompanyCode && userCompanyCode !== "*") {
sql += ` AND company_code = $2`;
values.push(userCompanyCode);
logger.info(`회사별 코드 옵션 필터링: ${userCompanyCode}`);
} else if (userCompanyCode === "*") {
logger.info(`최고 관리자: 모든 코드 옵션 조회`);
}
sql += ` ORDER BY sort_order ASC, code_value ASC`;
const codes = await query<{
code_value: string;
code_name: string;
code_name_eng: string | null;
sort_order: number;
}>(sql, values);
2025-09-02 11:30:19 +09:00
const options = codes.map((code) => ({
value: code.code_value,
label: code.code_name,
labelEng: code.code_name_eng,
}));
logger.info(
`코드 옵션 조회 완료: ${categoryCode} - ${options.length}개 (회사: ${userCompanyCode || "전체"})`
);
2025-09-02 11:30:19 +09:00
return options;
} catch (error) {
logger.error(`코드 옵션 조회 중 오류 (${categoryCode}):`, error);
throw error;
}
}
/**
*
*/
async reorderCodes(
categoryCode: string,
codes: Array<{ codeValue: string; sortOrder: number }>,
updatedBy: string
) {
try {
// 먼저 존재하는 코드들을 확인
const codeValues = codes.map((c) => c.codeValue);
const placeholders = codeValues.map((_, i) => `$${i + 2}`).join(", ");
const existingCodes = await query<{ code_value: string }>(
`SELECT code_value FROM code_info
WHERE code_category = $1 AND code_value IN (${placeholders})`,
[categoryCode, ...codeValues]
);
const existingCodeValues = existingCodes.map((c) => c.code_value);
const validCodes = codes.filter((c) =>
existingCodeValues.includes(c.codeValue)
);
if (validCodes.length === 0) {
throw new Error(
`카테고리 ${categoryCode}에 순서를 변경할 유효한 코드가 없습니다.`
);
}
// 트랜잭션으로 업데이트
await transaction(async (client) => {
for (const { codeValue, sortOrder } of validCodes) {
await client.query(
`UPDATE code_info
SET sort_order = $1, updated_by = $2, updated_date = NOW()
WHERE code_category = $3 AND code_value = $4`,
[sortOrder, updatedBy, categoryCode, codeValue]
);
}
});
const skippedCodes = codes.filter(
(c) => !existingCodeValues.includes(c.codeValue)
);
if (skippedCodes.length > 0) {
logger.warn(
`코드 순서 변경 시 존재하지 않는 코드들을 건너뜀: ${skippedCodes.map((c) => c.codeValue).join(", ")}`
);
}
logger.info(
`코드 순서 변경 완료: ${categoryCode} - ${validCodes.length}개 (전체 ${codes.length}개 중)`
);
2025-09-02 11:30:19 +09:00
} catch (error) {
logger.error(`코드 순서 변경 중 오류 (${categoryCode}):`, error);
throw error;
}
}
/**
2025-10-28 11:54:44 +09:00
* ()
*/
async checkCategoryDuplicate(
2025-09-03 16:44:36 +09:00
field: "categoryCode" | "categoryName" | "categoryNameEng",
value: string,
2025-10-28 11:54:44 +09:00
excludeCategoryCode?: string,
userCompanyCode?: string
): Promise<{ isDuplicate: boolean; message: string }> {
try {
if (!value || !value.trim()) {
return {
isDuplicate: false,
2025-09-03 16:44:36 +09:00
message: "값을 입력해주세요.",
};
}
const trimmedValue = value.trim();
let whereCondition: any = {};
// 필드별 검색 조건 설정
switch (field) {
2025-09-03 16:44:36 +09:00
case "categoryCode":
whereCondition.category_code = trimmedValue;
break;
2025-09-03 16:44:36 +09:00
case "categoryName":
whereCondition.category_name = trimmedValue;
break;
2025-09-03 16:44:36 +09:00
case "categoryNameEng":
whereCondition.category_name_eng = trimmedValue;
break;
}
// SQL 쿼리 생성
let sql = "";
const values: any[] = [];
let paramIndex = 1;
switch (field) {
case "categoryCode":
sql = `SELECT category_code FROM code_category WHERE category_code = $${paramIndex++}`;
values.push(trimmedValue);
break;
case "categoryName":
sql = `SELECT category_code FROM code_category WHERE category_name = $${paramIndex++}`;
values.push(trimmedValue);
break;
case "categoryNameEng":
sql = `SELECT category_code FROM code_category WHERE category_name_eng = $${paramIndex++}`;
values.push(trimmedValue);
break;
}
2025-10-28 11:54:44 +09:00
// 회사별 필터링 (최고 관리자가 아닌 경우)
if (userCompanyCode && userCompanyCode !== "*") {
sql += ` AND company_code = $${paramIndex++}`;
values.push(userCompanyCode);
}
// 수정 시 자기 자신 제외
if (excludeCategoryCode) {
sql += ` AND category_code != $${paramIndex++}`;
values.push(excludeCategoryCode);
}
sql += ` LIMIT 1`;
const existingCategory = await queryOne<{ category_code: string }>(
sql,
values
);
const isDuplicate = !!existingCategory;
const fieldNames = {
2025-09-03 16:44:36 +09:00
categoryCode: "카테고리 코드",
categoryName: "카테고리명",
categoryNameEng: "카테고리 영문명",
};
2025-10-28 11:54:44 +09:00
logger.info(
`카테고리 중복 검사: ${field}=${value}, 회사=${userCompanyCode}, 중복=${isDuplicate}`
);
return {
isDuplicate,
2025-09-03 16:44:36 +09:00
message: isDuplicate
? `이미 사용 중인 ${fieldNames[field]}입니다.`
2025-09-03 16:44:36 +09:00
: `사용 가능한 ${fieldNames[field]}입니다.`,
};
} catch (error) {
logger.error(`카테고리 중복 검사 중 오류 (${field}: ${value}):`, error);
throw error;
}
}
/**
2025-10-28 11:54:44 +09:00
* ()
*/
async checkCodeDuplicate(
categoryCode: string,
2025-09-03 16:44:36 +09:00
field: "codeValue" | "codeName" | "codeNameEng",
value: string,
2025-10-28 11:54:44 +09:00
excludeCodeValue?: string,
userCompanyCode?: string
): Promise<{ isDuplicate: boolean; message: string }> {
try {
if (!value || !value.trim()) {
return {
isDuplicate: false,
2025-09-03 16:44:36 +09:00
message: "값을 입력해주세요.",
};
}
const trimmedValue = value.trim();
let whereCondition: any = {
2025-09-03 16:44:36 +09:00
code_category: categoryCode,
};
// 필드별 검색 조건 설정
switch (field) {
2025-09-03 16:44:36 +09:00
case "codeValue":
whereCondition.code_value = trimmedValue;
break;
2025-09-03 16:44:36 +09:00
case "codeName":
whereCondition.code_name = trimmedValue;
break;
2025-09-03 16:44:36 +09:00
case "codeNameEng":
whereCondition.code_name_eng = trimmedValue;
break;
}
// SQL 쿼리 생성
let sql =
"SELECT code_value FROM code_info WHERE code_category = $1 AND ";
const values: any[] = [categoryCode];
let paramIndex = 2;
switch (field) {
case "codeValue":
sql += `code_value = $${paramIndex++}`;
values.push(trimmedValue);
break;
case "codeName":
sql += `code_name = $${paramIndex++}`;
values.push(trimmedValue);
break;
case "codeNameEng":
sql += `code_name_eng = $${paramIndex++}`;
values.push(trimmedValue);
break;
}
2025-10-28 11:54:44 +09:00
// 회사별 필터링 (최고 관리자가 아닌 경우)
if (userCompanyCode && userCompanyCode !== "*") {
sql += ` AND company_code = $${paramIndex++}`;
values.push(userCompanyCode);
}
// 수정 시 자기 자신 제외
if (excludeCodeValue) {
sql += ` AND code_value != $${paramIndex++}`;
values.push(excludeCodeValue);
}
sql += ` LIMIT 1`;
const existingCode = await queryOne<{ code_value: string }>(sql, values);
const isDuplicate = !!existingCode;
const fieldNames = {
2025-09-03 16:44:36 +09:00
codeValue: "코드값",
codeName: "코드명",
codeNameEng: "코드 영문명",
};
2025-10-28 11:54:44 +09:00
logger.info(
`코드 중복 검사: ${categoryCode}.${field}=${value}, 회사=${userCompanyCode}, 중복=${isDuplicate}`
);
return {
isDuplicate,
2025-09-03 16:44:36 +09:00
message: isDuplicate
? `이미 사용 중인 ${fieldNames[field]}입니다.`
2025-09-03 16:44:36 +09:00
: `사용 가능한 ${fieldNames[field]}입니다.`,
};
} catch (error) {
2025-09-03 16:44:36 +09:00
logger.error(
`코드 중복 검사 중 오류 (${categoryCode}, ${field}: ${value}):`,
error
);
throw error;
}
}
2025-09-02 11:30:19 +09:00
}