From a9d2df48bfae8bbfa7edb0779724e5196d4c4c07 Mon Sep 17 00:00:00 2001 From: kjs Date: Thu, 9 Apr 2026 12:18:26 +0900 Subject: [PATCH] fix: Improve numbering rule handling and item routing functionality - 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. --- .../controllers/numberingRuleController.ts | 3 ++ .../src/services/numberingRuleService.ts | 23 ++++++----- .../COMPANY_10/master-data/item-info/page.tsx | 4 +- .../process-info/ItemRoutingTab.tsx | 40 +++++++++++++++++++ .../COMPANY_16/master-data/item-info/page.tsx | 4 +- .../process-info/ItemRoutingTab.tsx | 40 +++++++++++++++++++ .../COMPANY_29/master-data/item-info/page.tsx | 4 +- .../process-info/ItemRoutingTab.tsx | 40 +++++++++++++++++++ .../COMPANY_30/master-data/item-info/page.tsx | 4 +- .../process-info/ItemRoutingTab.tsx | 40 +++++++++++++++++++ .../COMPANY_7/master-data/item-info/page.tsx | 4 +- .../process-info/ItemRoutingTab.tsx | 40 +++++++++++++++++++ .../COMPANY_8/master-data/item-info/page.tsx | 4 +- .../process-info/ItemRoutingTab.tsx | 40 +++++++++++++++++++ .../COMPANY_9/master-data/item-info/page.tsx | 4 +- .../process-info/ItemRoutingTab.tsx | 40 +++++++++++++++++++ 16 files changed, 309 insertions(+), 25 deletions(-) diff --git a/backend-node/src/controllers/numberingRuleController.ts b/backend-node/src/controllers/numberingRuleController.ts index 3764c3bc..2cd27c14 100644 --- a/backend-node/src/controllers/numberingRuleController.ts +++ b/backend-node/src/controllers/numberingRuleController.ts @@ -323,6 +323,9 @@ router.post( 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 }); diff --git a/backend-node/src/services/numberingRuleService.ts b/backend-node/src/services/numberingRuleService.ts index e682d5e7..1179edbe 100644 --- a/backend-node/src/services/numberingRuleService.ts +++ b/backend-node/src/services/numberingRuleService.ts @@ -305,26 +305,26 @@ class NumberingRuleService { if (hasCompanyCode && companyCode !== "*") { sql = ` SELECT MAX( - CAST(SUBSTRING("${columnName}" FROM $1 FOR $2) AS INTEGER) + CAST(SUBSTRING("${columnName}" FROM ${seqStart} FOR ${seqLength}) AS INTEGER) ) as max_seq FROM "${tableName}" - WHERE "${columnName}" LIKE $3 - AND company_code = $4 - AND LENGTH("${columnName}") = $5 - AND SUBSTRING("${columnName}" FROM $1 FOR $2) ~ '^[0-9]+$' + WHERE "${columnName}" LIKE $1 + AND company_code = $2 + AND LENGTH("${columnName}") = $3 + AND SUBSTRING("${columnName}" FROM ${seqStart} FOR ${seqLength}) ~ '^[0-9]+$' `; - params = [seqStart, seqLength, likePattern, companyCode, prefixLen + seqLength + codeSuffix.length]; + params = [likePattern, companyCode, prefixLen + seqLength + codeSuffix.length]; } else { sql = ` SELECT MAX( - CAST(SUBSTRING("${columnName}" FROM $1 FOR $2) AS INTEGER) + CAST(SUBSTRING("${columnName}" FROM ${seqStart} FOR ${seqLength}) AS INTEGER) ) as max_seq FROM "${tableName}" - WHERE "${columnName}" LIKE $3 - AND LENGTH("${columnName}") = $4 - AND SUBSTRING("${columnName}" FROM $1 FOR $2) ~ '^[0-9]+$' + WHERE "${columnName}" LIKE $1 + AND LENGTH("${columnName}") = $2 + AND SUBSTRING("${columnName}" FROM ${seqStart} FOR ${seqLength}) ~ '^[0-9]+$' `; - params = [seqStart, seqLength, likePattern, prefixLen + seqLength + codeSuffix.length]; + params = [likePattern, prefixLen + seqLength + codeSuffix.length]; } const result = await client.query(sql, params); @@ -1436,6 +1436,7 @@ class NumberingRuleService { psInfo.prefix, psInfo.suffix, psInfo.seqLength, companyCode ); + if (maxFromTable > baseSeq) { logger.info("미리보기: 테이블 내 최대값이 카운터보다 높음", { ruleId, companyCode, currentSeq, maxFromTable, diff --git a/frontend/app/(main)/COMPANY_10/master-data/item-info/page.tsx b/frontend/app/(main)/COMPANY_10/master-data/item-info/page.tsx index 19ef9dd9..ad55d2b2 100644 --- a/frontend/app/(main)/COMPANY_10/master-data/item-info/page.tsx +++ b/frontend/app/(main)/COMPANY_10/master-data/item-info/page.tsx @@ -556,8 +556,8 @@ export default function ItemInfoPage() { if (numberingRuleIdRef.current) { try { const hasManual = numberingParts.some(p => p.isManual); - const userInputCode = hasManual - ? buildCodeFromParts(numberingParts, manualInputValue) + const userInputCode = hasManual && manualInputValue + ? manualInputValue : undefined; const allocRes = await apiClient.post( diff --git a/frontend/app/(main)/COMPANY_10/production/process-info/ItemRoutingTab.tsx b/frontend/app/(main)/COMPANY_10/production/process-info/ItemRoutingTab.tsx index a5b136c2..e50e27d5 100644 --- a/frontend/app/(main)/COMPANY_10/production/process-info/ItemRoutingTab.tsx +++ b/frontend/app/(main)/COMPANY_10/production/process-info/ItemRoutingTab.tsx @@ -39,6 +39,7 @@ import { type RoutingVersion, } from "@/lib/api/processInfo"; import { cn } from "@/lib/utils"; +import { apiClient } from "@/lib/api/client"; function normalizeDefaultFlag(v: RoutingVersion): boolean { const raw = v.is_default as unknown; @@ -210,6 +211,7 @@ export function ItemRoutingTab() { return; } const list = res.data.map((v) => ({ ...v, is_default: normalizeDefaultFlag(v) })); + list.sort((a, b) => (a.is_default === b.is_default ? 0 : a.is_default ? -1 : 1)); setVersions(list); const preferred = preferVersionId ? list.find((v) => v.id === preferVersionId) : undefined; const def = list.find((v) => v.is_default); @@ -399,6 +401,38 @@ export function ItemRoutingTab() { } }; + // 선택 버전이 기본인지 + const selectedVersionIsDefault = useMemo(() => { + if (!selectedVersionId) return false; + const v = versions.find((v) => v.id === selectedVersionId); + return v ? normalizeDefaultFlag(v) : false; + }, [selectedVersionId, versions]); + + // 기본 라우팅으로 설정 + const handleSetDefaultVersion = async () => { + if (!selectedVersionId || !selectedItem) return; + try { + // 기존 기본 해제 + for (const v of versions) { + if (normalizeDefaultFlag(v) && v.id !== selectedVersionId) { + await apiClient.put(`/table-management/tables/item_routing_version/edit`, { + originalData: { id: v.id }, + updatedData: { is_default: false }, + }); + } + } + // 선택 버전 기본 설정 + await apiClient.put(`/table-management/tables/item_routing_version/edit`, { + originalData: { id: selectedVersionId }, + updatedData: { is_default: true }, + }); + toast.success("기본 라우팅으로 설정했어요"); + await loadVersions(selectedItem, selectedVersionId); + } catch { + toast.error("기본 설정에 실패했어요"); + } + }; + const submitNewVersion = async () => { if (!selectedItem) return; const name = versionName.trim(); @@ -639,6 +673,12 @@ export function ItemRoutingTab() {
+ {selectedVersionId && !selectedVersionIsDefault && ( + + )}
+ {selectedVersionId && !selectedVersionIsDefault && ( + + )}
+ {selectedVersionId && !selectedVersionIsDefault && ( + + )}
+ {selectedVersionId && !selectedVersionIsDefault && ( + + )}
+ {selectedVersionId && !selectedVersionIsDefault && ( + + )}
+ {selectedVersionId && !selectedVersionIsDefault && ( + + )}
+ {selectedVersionId && !selectedVersionIsDefault && ( + + )}