feat: Enhance numbering rule service with separator handling
- Introduced functionality to extract and manage individual separators for numbering rule parts. - Added methods to join parts with their respective separators, improving code generation flexibility. - Updated the numbering rule service to utilize the new separator logic during part processing. - Enhanced the frontend components to support custom separators for each part, allowing for more granular control over numbering formats.
This commit is contained in:
@@ -14,6 +14,35 @@ interface NumberingRulePart {
|
||||
autoConfig?: any;
|
||||
manualConfig?: any;
|
||||
generatedValue?: string;
|
||||
separatorAfter?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 파트 배열에서 autoConfig.separatorAfter를 파트 레벨로 추출
|
||||
*/
|
||||
function extractSeparatorAfterFromParts(parts: any[]): any[] {
|
||||
return parts.map((part) => {
|
||||
if (part.autoConfig?.separatorAfter !== undefined) {
|
||||
part.separatorAfter = part.autoConfig.separatorAfter;
|
||||
}
|
||||
return part;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 파트별 개별 구분자를 사용하여 코드 결합
|
||||
* 마지막 파트의 separatorAfter는 무시됨
|
||||
*/
|
||||
function joinPartsWithSeparators(partValues: string[], sortedParts: any[], globalSeparator: string): string {
|
||||
let result = "";
|
||||
partValues.forEach((val, idx) => {
|
||||
result += val;
|
||||
if (idx < partValues.length - 1) {
|
||||
const sep = sortedParts[idx].separatorAfter ?? sortedParts[idx].autoConfig?.separatorAfter ?? globalSeparator;
|
||||
result += sep;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
interface NumberingRuleConfig {
|
||||
@@ -141,7 +170,7 @@ class NumberingRuleService {
|
||||
}
|
||||
|
||||
const partsResult = await pool.query(partsQuery, partsParams);
|
||||
rule.parts = partsResult.rows;
|
||||
rule.parts = extractSeparatorAfterFromParts(partsResult.rows);
|
||||
}
|
||||
|
||||
logger.info(`채번 규칙 목록 조회 완료: ${result.rows.length}개`, {
|
||||
@@ -274,7 +303,7 @@ class NumberingRuleService {
|
||||
}
|
||||
|
||||
const partsResult = await pool.query(partsQuery, partsParams);
|
||||
rule.parts = partsResult.rows;
|
||||
rule.parts = extractSeparatorAfterFromParts(partsResult.rows);
|
||||
}
|
||||
|
||||
return result.rows;
|
||||
@@ -381,7 +410,7 @@ class NumberingRuleService {
|
||||
}
|
||||
|
||||
const partsResult = await pool.query(partsQuery, partsParams);
|
||||
rule.parts = partsResult.rows;
|
||||
rule.parts = extractSeparatorAfterFromParts(partsResult.rows);
|
||||
|
||||
logger.info("✅ 규칙 파트 조회 성공", {
|
||||
ruleId: rule.ruleId,
|
||||
@@ -517,7 +546,7 @@ class NumberingRuleService {
|
||||
companyCode === "*" ? rule.companyCode : companyCode,
|
||||
]);
|
||||
|
||||
rule.parts = partsResult.rows;
|
||||
rule.parts = extractSeparatorAfterFromParts(partsResult.rows);
|
||||
}
|
||||
|
||||
logger.info(`화면용 채번 규칙 조회 완료: ${result.rows.length}개`, {
|
||||
@@ -633,7 +662,7 @@ class NumberingRuleService {
|
||||
}
|
||||
|
||||
const partsResult = await pool.query(partsQuery, partsParams);
|
||||
rule.parts = partsResult.rows;
|
||||
rule.parts = extractSeparatorAfterFromParts(partsResult.rows);
|
||||
|
||||
return rule;
|
||||
}
|
||||
@@ -708,17 +737,25 @@ class NumberingRuleService {
|
||||
manual_config AS "manualConfig"
|
||||
`;
|
||||
|
||||
// auto_config에 separatorAfter 포함
|
||||
const autoConfigWithSep = { ...(part.autoConfig || {}), separatorAfter: part.separatorAfter ?? "-" };
|
||||
|
||||
const partResult = await client.query(insertPartQuery, [
|
||||
config.ruleId,
|
||||
part.order,
|
||||
part.partType,
|
||||
part.generationMethod,
|
||||
JSON.stringify(part.autoConfig || {}),
|
||||
JSON.stringify(autoConfigWithSep),
|
||||
JSON.stringify(part.manualConfig || {}),
|
||||
companyCode,
|
||||
]);
|
||||
|
||||
parts.push(partResult.rows[0]);
|
||||
const savedPart = partResult.rows[0];
|
||||
// autoConfig에서 separatorAfter를 추출하여 파트 레벨로 이동
|
||||
if (savedPart.autoConfig?.separatorAfter !== undefined) {
|
||||
savedPart.separatorAfter = savedPart.autoConfig.separatorAfter;
|
||||
}
|
||||
parts.push(savedPart);
|
||||
}
|
||||
|
||||
await client.query("COMMIT");
|
||||
@@ -820,17 +857,23 @@ class NumberingRuleService {
|
||||
manual_config AS "manualConfig"
|
||||
`;
|
||||
|
||||
const autoConfigWithSep = { ...(part.autoConfig || {}), separatorAfter: part.separatorAfter ?? "-" };
|
||||
|
||||
const partResult = await client.query(insertPartQuery, [
|
||||
ruleId,
|
||||
part.order,
|
||||
part.partType,
|
||||
part.generationMethod,
|
||||
JSON.stringify(part.autoConfig || {}),
|
||||
JSON.stringify(autoConfigWithSep),
|
||||
JSON.stringify(part.manualConfig || {}),
|
||||
companyCode,
|
||||
]);
|
||||
|
||||
parts.push(partResult.rows[0]);
|
||||
const savedPart = partResult.rows[0];
|
||||
if (savedPart.autoConfig?.separatorAfter !== undefined) {
|
||||
savedPart.separatorAfter = savedPart.autoConfig.separatorAfter;
|
||||
}
|
||||
parts.push(savedPart);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1053,7 +1096,8 @@ class NumberingRuleService {
|
||||
}
|
||||
}));
|
||||
|
||||
const previewCode = parts.join(rule.separator || "");
|
||||
const sortedRuleParts = rule.parts.sort((a: any, b: any) => a.order - b.order);
|
||||
const previewCode = joinPartsWithSeparators(parts, sortedRuleParts, rule.separator || "");
|
||||
logger.info("코드 미리보기 생성", {
|
||||
ruleId,
|
||||
previewCode,
|
||||
@@ -1164,8 +1208,8 @@ class NumberingRuleService {
|
||||
}
|
||||
}));
|
||||
|
||||
const separator = rule.separator || "";
|
||||
const previewTemplate = previewParts.join(separator);
|
||||
const sortedPartsForTemplate = rule.parts.sort((a: any, b: any) => a.order - b.order);
|
||||
const previewTemplate = joinPartsWithSeparators(previewParts, sortedPartsForTemplate, rule.separator || "");
|
||||
|
||||
// 사용자 입력 코드에서 수동 입력 부분 추출
|
||||
// 예: 템플릿 "R-____-XXX", 사용자입력 "R-MYVALUE-012" → "MYVALUE" 추출
|
||||
@@ -1382,7 +1426,8 @@ class NumberingRuleService {
|
||||
}
|
||||
}));
|
||||
|
||||
const allocatedCode = parts.join(rule.separator || "");
|
||||
const sortedPartsForAlloc = rule.parts.sort((a: any, b: any) => a.order - b.order);
|
||||
const allocatedCode = joinPartsWithSeparators(parts, sortedPartsForAlloc, rule.separator || "");
|
||||
|
||||
// 순번이 있는 경우에만 증가
|
||||
const hasSequence = rule.parts.some(
|
||||
@@ -1541,7 +1586,7 @@ class NumberingRuleService {
|
||||
rule.ruleId,
|
||||
companyCode === "*" ? rule.companyCode : companyCode,
|
||||
]);
|
||||
rule.parts = partsResult.rows;
|
||||
rule.parts = extractSeparatorAfterFromParts(partsResult.rows);
|
||||
}
|
||||
|
||||
logger.info("[테스트] 채번 규칙 목록 조회 완료", {
|
||||
@@ -1634,7 +1679,7 @@ class NumberingRuleService {
|
||||
rule.ruleId,
|
||||
companyCode,
|
||||
]);
|
||||
rule.parts = partsResult.rows;
|
||||
rule.parts = extractSeparatorAfterFromParts(partsResult.rows);
|
||||
|
||||
logger.info("테이블+컬럼 기반 채번 규칙 조회 성공 (테스트)", {
|
||||
ruleId: rule.ruleId,
|
||||
@@ -1754,12 +1799,14 @@ class NumberingRuleService {
|
||||
auto_config, manual_config, company_code, created_at
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW())
|
||||
`;
|
||||
const autoConfigWithSep = { ...(part.autoConfig || {}), separatorAfter: part.separatorAfter ?? "-" };
|
||||
|
||||
await client.query(partInsertQuery, [
|
||||
config.ruleId,
|
||||
part.order,
|
||||
part.partType,
|
||||
part.generationMethod,
|
||||
JSON.stringify(part.autoConfig || {}),
|
||||
JSON.stringify(autoConfigWithSep),
|
||||
JSON.stringify(part.manualConfig || {}),
|
||||
companyCode,
|
||||
]);
|
||||
@@ -1914,7 +1961,7 @@ class NumberingRuleService {
|
||||
rule.ruleId,
|
||||
companyCode,
|
||||
]);
|
||||
rule.parts = partsResult.rows;
|
||||
rule.parts = extractSeparatorAfterFromParts(partsResult.rows);
|
||||
|
||||
logger.info("카테고리 조건 매칭 채번 규칙 찾음", {
|
||||
ruleId: rule.ruleId,
|
||||
@@ -1973,7 +2020,7 @@ class NumberingRuleService {
|
||||
rule.ruleId,
|
||||
companyCode,
|
||||
]);
|
||||
rule.parts = partsResult.rows;
|
||||
rule.parts = extractSeparatorAfterFromParts(partsResult.rows);
|
||||
|
||||
logger.info("기본 채번 규칙 찾음 (카테고리 조건 없음)", {
|
||||
ruleId: rule.ruleId,
|
||||
@@ -2056,7 +2103,7 @@ class NumberingRuleService {
|
||||
rule.ruleId,
|
||||
companyCode,
|
||||
]);
|
||||
rule.parts = partsResult.rows;
|
||||
rule.parts = extractSeparatorAfterFromParts(partsResult.rows);
|
||||
}
|
||||
|
||||
return result.rows;
|
||||
|
||||
@@ -1607,7 +1607,8 @@ export class TableManagementService {
|
||||
tableName,
|
||||
columnName,
|
||||
actualValue,
|
||||
paramIndex
|
||||
paramIndex,
|
||||
operator
|
||||
);
|
||||
|
||||
case "entity":
|
||||
@@ -1620,7 +1621,14 @@ export class TableManagementService {
|
||||
);
|
||||
|
||||
default:
|
||||
// 기본 문자열 검색 (actualValue 사용)
|
||||
// operator에 따라 정확 일치 또는 부분 일치 검색
|
||||
if (operator === "equals") {
|
||||
return {
|
||||
whereClause: `${columnName}::text = $${paramIndex}`,
|
||||
values: [String(actualValue)],
|
||||
paramCount: 1,
|
||||
};
|
||||
}
|
||||
return {
|
||||
whereClause: `${columnName}::text ILIKE $${paramIndex}`,
|
||||
values: [`%${actualValue}%`],
|
||||
@@ -1634,10 +1642,19 @@ export class TableManagementService {
|
||||
);
|
||||
// 오류 시 기본 검색으로 폴백
|
||||
let fallbackValue = value;
|
||||
let fallbackOperator = "contains";
|
||||
if (typeof value === "object" && value !== null && "value" in value) {
|
||||
fallbackValue = value.value;
|
||||
fallbackOperator = value.operator || "contains";
|
||||
}
|
||||
|
||||
if (fallbackOperator === "equals") {
|
||||
return {
|
||||
whereClause: `${columnName}::text = $${paramIndex}`,
|
||||
values: [String(fallbackValue)],
|
||||
paramCount: 1,
|
||||
};
|
||||
}
|
||||
return {
|
||||
whereClause: `${columnName}::text ILIKE $${paramIndex}`,
|
||||
values: [`%${fallbackValue}%`],
|
||||
@@ -1784,7 +1801,8 @@ export class TableManagementService {
|
||||
tableName: string,
|
||||
columnName: string,
|
||||
value: any,
|
||||
paramIndex: number
|
||||
paramIndex: number,
|
||||
operator: string = "contains"
|
||||
): Promise<{
|
||||
whereClause: string;
|
||||
values: any[];
|
||||
@@ -1794,7 +1812,14 @@ export class TableManagementService {
|
||||
const codeTypeInfo = await this.getCodeTypeInfo(tableName, columnName);
|
||||
|
||||
if (!codeTypeInfo.isCodeType || !codeTypeInfo.codeCategory) {
|
||||
// 코드 타입이 아니면 기본 검색
|
||||
// 코드 타입이 아니면 operator에 따라 검색
|
||||
if (operator === "equals") {
|
||||
return {
|
||||
whereClause: `${columnName}::text = $${paramIndex}`,
|
||||
values: [String(value)],
|
||||
paramCount: 1,
|
||||
};
|
||||
}
|
||||
return {
|
||||
whereClause: `${columnName}::text ILIKE $${paramIndex}`,
|
||||
values: [`%${value}%`],
|
||||
@@ -1802,6 +1827,15 @@ export class TableManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// select 필터(equals)인 경우 정확한 코드값 매칭만 수행
|
||||
if (operator === "equals") {
|
||||
return {
|
||||
whereClause: `${columnName}::text = $${paramIndex}`,
|
||||
values: [String(value)],
|
||||
paramCount: 1,
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof value === "string" && value.trim() !== "") {
|
||||
// 코드값 또는 코드명으로 검색
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user