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.
This commit is contained in:
@@ -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 });
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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() {
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
{selectedVersionId && !selectedVersionIsDefault && (
|
||||
<Button variant="outline" size="sm" className="gap-1" onClick={handleSetDefaultVersion}>
|
||||
<Star className="h-3.5 w-3.5 fill-warning text-warning" />
|
||||
기본 설정
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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() {
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
{selectedVersionId && !selectedVersionIsDefault && (
|
||||
<Button variant="outline" size="sm" className="gap-1" onClick={handleSetDefaultVersion}>
|
||||
<Star className="h-3.5 w-3.5 fill-warning text-warning" />
|
||||
기본 설정
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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() {
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
{selectedVersionId && !selectedVersionIsDefault && (
|
||||
<Button variant="outline" size="sm" className="gap-1" onClick={handleSetDefaultVersion}>
|
||||
<Star className="h-3.5 w-3.5 fill-warning text-warning" />
|
||||
기본 설정
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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() {
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
{selectedVersionId && !selectedVersionIsDefault && (
|
||||
<Button variant="outline" size="sm" className="gap-1" onClick={handleSetDefaultVersion}>
|
||||
<Star className="h-3.5 w-3.5 fill-warning text-warning" />
|
||||
기본 설정
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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() {
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
{selectedVersionId && !selectedVersionIsDefault && (
|
||||
<Button variant="outline" size="sm" className="gap-1" onClick={handleSetDefaultVersion}>
|
||||
<Star className="h-3.5 w-3.5 fill-warning text-warning" />
|
||||
기본 설정
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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() {
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
{selectedVersionId && !selectedVersionIsDefault && (
|
||||
<Button variant="outline" size="sm" className="gap-1" onClick={handleSetDefaultVersion}>
|
||||
<Star className="h-3.5 w-3.5 fill-warning text-warning" />
|
||||
기본 설정
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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() {
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
{selectedVersionId && !selectedVersionIsDefault && (
|
||||
<Button variant="outline" size="sm" className="gap-1" onClick={handleSetDefaultVersion}>
|
||||
<Star className="h-3.5 w-3.5 fill-warning text-warning" />
|
||||
기본 설정
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
|
||||
Reference in New Issue
Block a user