summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--db/migrations/0262_remove_project_id_from_combo_box_settings.sql14
-rw-r--r--db/migrations/0263_remove_project_id_from_document_number_type_configs.sql14
-rw-r--r--db/migrations/0264_fix_duplicate_document_number_type_configs.sql16
-rw-r--r--db/schema/docu-list-rule.ts22
-rw-r--r--lib/docu-list-rule/combo-box-settings/service.ts18
-rw-r--r--lib/docu-list-rule/combo-box-settings/table/combo-box-options-add-dialog.tsx6
-rw-r--r--lib/docu-list-rule/combo-box-settings/table/combo-box-options-detail-sheet.tsx4
-rw-r--r--lib/docu-list-rule/number-type-configs/service.ts55
8 files changed, 118 insertions, 31 deletions
diff --git a/db/migrations/0262_remove_project_id_from_combo_box_settings.sql b/db/migrations/0262_remove_project_id_from_combo_box_settings.sql
new file mode 100644
index 00000000..804b471a
--- /dev/null
+++ b/db/migrations/0262_remove_project_id_from_combo_box_settings.sql
@@ -0,0 +1,14 @@
+-- Remove projectId column and related constraints from combo_box_settings table
+-- Since codeGroupId already references codeGroups which has projectId, this is redundant
+
+-- First, drop the unique constraint that includes projectId
+DROP INDEX IF EXISTS "unique_project_code_group_code";
+
+-- Then drop the foreign key constraint for projectId
+ALTER TABLE "combo_box_settings" DROP CONSTRAINT IF EXISTS "combo_box_settings_project_id_projects_id_fk";
+
+-- Finally, drop the projectId column
+ALTER TABLE "combo_box_settings" DROP COLUMN IF EXISTS "project_id";
+
+-- Add a new unique constraint without projectId (since codeGroupId + code should be unique within a code group)
+ALTER TABLE "combo_box_settings" ADD CONSTRAINT "unique_code_group_code" UNIQUE ("code_group_id", "code"); \ No newline at end of file
diff --git a/db/migrations/0263_remove_project_id_from_document_number_type_configs.sql b/db/migrations/0263_remove_project_id_from_document_number_type_configs.sql
new file mode 100644
index 00000000..27522555
--- /dev/null
+++ b/db/migrations/0263_remove_project_id_from_document_number_type_configs.sql
@@ -0,0 +1,14 @@
+-- Remove projectId column and related constraints from document_number_type_configs table
+-- Since documentNumberTypeId already references documentNumberTypes which has projectId, this is redundant
+
+-- First, drop the unique constraint that includes projectId
+DROP INDEX IF EXISTS "unique_project_number_type_sdq";
+
+-- Then drop the foreign key constraint for projectId
+ALTER TABLE "document_number_type_configs" DROP CONSTRAINT IF EXISTS "document_number_type_configs_project_id_projects_id_fk";
+
+-- Finally, drop the projectId column
+ALTER TABLE "document_number_type_configs" DROP COLUMN IF EXISTS "project_id";
+
+-- Add a new unique constraint without projectId (since documentNumberTypeId + sdq should be unique within a document number type)
+ALTER TABLE "document_number_type_configs" ADD CONSTRAINT "unique_document_number_type_sdq" UNIQUE ("document_number_type_id", "sdq"); \ No newline at end of file
diff --git a/db/migrations/0264_fix_duplicate_document_number_type_configs.sql b/db/migrations/0264_fix_duplicate_document_number_type_configs.sql
new file mode 100644
index 00000000..45269a5e
--- /dev/null
+++ b/db/migrations/0264_fix_duplicate_document_number_type_configs.sql
@@ -0,0 +1,16 @@
+-- Fix duplicate document_number_type_configs data before applying unique constraint
+-- Remove duplicates keeping only the most recent one for each document_number_type_id + sdq combination
+
+-- First, identify and remove duplicates
+DELETE FROM "document_number_type_configs"
+WHERE id NOT IN (
+ SELECT MAX(id)
+ FROM "document_number_type_configs"
+ GROUP BY "document_number_type_id", "sdq"
+);
+
+-- Now we can safely apply the unique constraint
+-- (This should already be applied by the previous migration, but just in case)
+ALTER TABLE "document_number_type_configs"
+ADD CONSTRAINT "unique_document_number_type_sdq"
+UNIQUE ("document_number_type_id", "sdq"); \ No newline at end of file
diff --git a/db/schema/docu-list-rule.ts b/db/schema/docu-list-rule.ts
index ec20ab7a..505b1c0d 100644
--- a/db/schema/docu-list-rule.ts
+++ b/db/schema/docu-list-rule.ts
@@ -72,7 +72,6 @@ export const documentClassOptions = pgTable("document_class_options_new", {
// ===== ComboBox Settings 테이블 =====
export const comboBoxSettings = pgTable("combo_box_settings", {
id: serial("id").primaryKey(),
- projectId: integer("project_id").notNull().references(() => projects.id), // 프로젝트 ID 참조
codeGroupId: integer("code_group_id").notNull().references(() => codeGroups.id), // Code Group과 연결
code: varchar("code", { length: 50 }).notNull(), // CODE (예: 100, 201, 202)
description: varchar("description", { length: 200 }).notNull(), // Description (예: General, Feed Gas Reveive)
@@ -81,9 +80,8 @@ export const comboBoxSettings = pgTable("combo_box_settings", {
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull(),
}, (table) => {
return {
- // 같은 프로젝트 내에서 codeGroupId와 code 조합은 유니크해야 함
- uniqueProjectCodeGroupCode: unique("unique_project_code_group_code").on(
- table.projectId,
+ // 같은 codeGroupId 내에서 code는 유니크해야 함
+ uniqueCodeGroupCode: unique("unique_code_group_code").on(
table.codeGroupId,
table.code
),
@@ -112,7 +110,6 @@ export const documentNumberTypes = pgTable("document_number_types", {
// ===== Document Number Type Configs 테이블 =====
export const documentNumberTypeConfigs = pgTable("document_number_type_configs", {
id: serial("id").primaryKey(),
- projectId: integer("project_id").notNull().references(() => projects.id), // 프로젝트 ID 참조
documentNumberTypeId: integer("document_number_type_id").notNull().references(() => documentNumberTypes.id),
codeGroupId: integer("code_group_id").references(() => codeGroups.id), // Code Group 참조
sdq: integer("sdq").notNull(), // 순서 번호 (1, 2, 3, 4, 5, 6)
@@ -123,9 +120,8 @@ export const documentNumberTypeConfigs = pgTable("document_number_type_configs",
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull(),
}, (table) => {
return {
- // 같은 프로젝트 내에서 documentNumberTypeId와 sdq 조합은 유니크해야 함
- uniqueProjectNumberTypeSdq: unique("unique_project_number_type_sdq").on(
- table.projectId,
+ // 같은 documentNumberTypeId 내에서 sdq는 유니크해야 함
+ uniqueDocumentNumberTypeSdq: unique("unique_document_number_type_sdq").on(
table.documentNumberTypeId,
table.sdq
),
@@ -138,9 +134,7 @@ export const documentNumberTypeConfigs = pgTable("document_number_type_configs",
export const projectsRelations = relations(projects, ({ many }) => ({
codeGroups: many(codeGroups),
documentClasses: many(documentClasses),
- comboBoxSettings: many(comboBoxSettings),
documentNumberTypes: many(documentNumberTypes),
- documentNumberTypeConfigs: many(documentNumberTypeConfigs),
}))
// Code Groups 관계
@@ -177,10 +171,6 @@ export const documentClassOptionsRelations = relations(documentClassOptions, ({
// ComboBox Settings 관계
export const comboBoxSettingsRelations = relations(comboBoxSettings, ({ one }) => ({
- project: one(projects, {
- fields: [comboBoxSettings.projectId],
- references: [projects.id],
- }),
codeGroup: one(codeGroups, {
fields: [comboBoxSettings.codeGroupId],
references: [codeGroups.id],
@@ -198,10 +188,6 @@ export const documentNumberTypesRelations = relations(documentNumberTypes, ({ ma
// Document Number Type Configs 관계
export const documentNumberTypeConfigsRelations = relations(documentNumberTypeConfigs, ({ one }) => ({
- project: one(projects, {
- fields: [documentNumberTypeConfigs.projectId],
- references: [projects.id],
- }),
documentNumberType: one(documentNumberTypes, {
fields: [documentNumberTypeConfigs.documentNumberTypeId],
references: [documentNumberTypes.id],
diff --git a/lib/docu-list-rule/combo-box-settings/service.ts b/lib/docu-list-rule/combo-box-settings/service.ts
index 96daefe4..7a003327 100644
--- a/lib/docu-list-rule/combo-box-settings/service.ts
+++ b/lib/docu-list-rule/combo-box-settings/service.ts
@@ -4,7 +4,7 @@ import { revalidatePath } from "next/cache"
import db from "@/db/db"
import { codeGroups, comboBoxSettings } from "@/db/schema/docu-list-rule"
import { projects } from "@/db/schema/projects"
-import { eq, sql, count } from "drizzle-orm"
+import { eq, sql } from "drizzle-orm"
import { unstable_noStore } from "next/cache"
// Control Type이 combobox인 Code Groups 목록 조회
@@ -153,7 +153,7 @@ export async function getComboBoxOptions(codeGroupId: number, input?: {
const { page = 1, perPage = 10, sort, search } = input || {}
const offset = (page - 1) * perPage
- // 기본 조건: codeGroupId
+ // 기본 조건: codeGroupId만으로 조회 (projectId는 codeGroups를 통해 간접 참조)
let whereConditions = eq(comboBoxSettings.codeGroupId, codeGroupId)
// 검색 조건
@@ -195,12 +195,12 @@ export async function getComboBoxOptions(codeGroupId: number, input?: {
remark: comboBoxSettings.remark,
createdAt: comboBoxSettings.createdAt,
updatedAt: comboBoxSettings.updatedAt,
- projectId: comboBoxSettings.projectId,
projectCode: projects.code,
projectName: projects.name,
})
.from(comboBoxSettings)
- .leftJoin(projects, eq(comboBoxSettings.projectId, projects.id))
+ .leftJoin(codeGroups, eq(comboBoxSettings.codeGroupId, codeGroups.id))
+ .leftJoin(projects, eq(codeGroups.projectId, projects.id))
.where(whereConditions)
.orderBy(orderBy)
.limit(perPage)
@@ -210,12 +210,14 @@ export async function getComboBoxOptions(codeGroupId: number, input?: {
const totalCountResult = await db
.select({ count: sql<number>`count(*)` })
.from(comboBoxSettings)
- .leftJoin(projects, eq(comboBoxSettings.projectId, projects.id))
+ .leftJoin(codeGroups, eq(comboBoxSettings.codeGroupId, codeGroups.id))
+ .leftJoin(projects, eq(codeGroups.projectId, projects.id))
.where(whereConditions)
const totalCount = totalCountResult[0]?.count || 0
return {
+ success: true,
data,
totalCount,
pageCount: Math.ceil(totalCount / perPage),
@@ -223,9 +225,11 @@ export async function getComboBoxOptions(codeGroupId: number, input?: {
} catch (error) {
console.error("Error fetching combo box options:", error)
return {
+ success: false,
data: [],
totalCount: 0,
pageCount: 0,
+ error: "Failed to fetch combo box options"
}
}
}
@@ -240,7 +244,9 @@ export async function createComboBoxOption(input: {
try {
// 해당 Code Group의 정보 가져오기
const codeGroup = await db
- .select({ description: codeGroups.description })
+ .select({
+ description: codeGroups.description
+ })
.from(codeGroups)
.where(eq(codeGroups.id, input.codeGroupId))
.limit(1)
diff --git a/lib/docu-list-rule/combo-box-settings/table/combo-box-options-add-dialog.tsx b/lib/docu-list-rule/combo-box-settings/table/combo-box-options-add-dialog.tsx
index a0535b43..9a3f8a86 100644
--- a/lib/docu-list-rule/combo-box-settings/table/combo-box-options-add-dialog.tsx
+++ b/lib/docu-list-rule/combo-box-settings/table/combo-box-options-add-dialog.tsx
@@ -59,6 +59,7 @@ export function ComboBoxOptionsAddDialog({ codeGroupId, onSuccess }: ComboBoxOpt
const handleCodeChange = (value: string) => {
form.setValue("code", value)
form.setValue("description", value) // 코드값을 description에도 자동 설정
+ form.trigger() // 폼 유효성 검사 트리거
}
const handleSubmit = (data: CreateOptionSchema) => {
@@ -155,7 +156,10 @@ export function ComboBoxOptionsAddDialog({ codeGroupId, onSuccess }: ComboBoxOpt
<Button type="button" variant="outline" onClick={handleCancel}>
취소
</Button>
- <Button type="submit" disabled={isPending || !form.formState.isValid}>
+ <Button
+ type="submit"
+ disabled={isPending || !form.formState.isValid || !form.watch("code")}
+ >
추가
</Button>
</DialogFooter>
diff --git a/lib/docu-list-rule/combo-box-settings/table/combo-box-options-detail-sheet.tsx b/lib/docu-list-rule/combo-box-settings/table/combo-box-options-detail-sheet.tsx
index 22806ae8..286acfbf 100644
--- a/lib/docu-list-rule/combo-box-settings/table/combo-box-options-detail-sheet.tsx
+++ b/lib/docu-list-rule/combo-box-settings/table/combo-box-options-detail-sheet.tsx
@@ -61,16 +61,20 @@ export function ComboBoxOptionsDetailSheet({
filters: [],
joinOperator: "and",
})
+ console.log("getComboBoxOptions result:", result)
if (result.success && result.data) {
// isActive 필드가 없는 경우 기본값 true로 설정
const optionsWithIsActive = result.data.map(option => ({
...option,
isActive: (option as any).isActive ?? true
}))
+ console.log("Processed data:", optionsWithIsActive)
setRawData({
data: optionsWithIsActive,
pageCount: result.pageCount || 1
})
+ } else {
+ console.log("No data or error:", result)
}
} catch (error) {
console.error("Error refreshing data:", error)
diff --git a/lib/docu-list-rule/number-type-configs/service.ts b/lib/docu-list-rule/number-type-configs/service.ts
index ef25aecb..14cfc2f0 100644
--- a/lib/docu-list-rule/number-type-configs/service.ts
+++ b/lib/docu-list-rule/number-type-configs/service.ts
@@ -3,7 +3,7 @@
import { revalidatePath } from "next/cache"
import db from "@/db/db"
import { unstable_noStore } from "next/cache"
-import { documentNumberTypeConfigs, codeGroups } from "@/db/schema/docu-list-rule"
+import { documentNumberTypeConfigs, codeGroups, documentNumberTypes } from "@/db/schema/docu-list-rule"
import { projects } from "@/db/schema/projects"
import { asc, eq, sql, and } from "drizzle-orm"
import { GetNumberTypeConfigsSchema } from "./validation"
@@ -122,13 +122,12 @@ export async function getNumberTypeConfigs(input: GetNumberTypeConfigsSchema) {
updatedAt: documentNumberTypeConfigs.updatedAt,
codeGroupName: codeGroups.description,
codeGroupControlType: codeGroups.controlType,
- projectId: documentNumberTypeConfigs.projectId,
projectCode: projects.code,
projectName: projects.name,
})
.from(documentNumberTypeConfigs)
.leftJoin(codeGroups, eq(documentNumberTypeConfigs.codeGroupId, codeGroups.id))
- .leftJoin(projects, eq(documentNumberTypeConfigs.projectId, projects.id))
+ .leftJoin(projects, eq(codeGroups.projectId, projects.id))
.where(whereConditions)
.orderBy(orderBy)
.limit(perPage)
@@ -139,7 +138,7 @@ export async function getNumberTypeConfigs(input: GetNumberTypeConfigsSchema) {
.select({ count: sql<number>`count(*)` })
.from(documentNumberTypeConfigs)
.leftJoin(codeGroups, eq(documentNumberTypeConfigs.codeGroupId, codeGroups.id))
- .leftJoin(projects, eq(documentNumberTypeConfigs.projectId, projects.id))
+ .leftJoin(projects, eq(codeGroups.projectId, projects.id))
.where(whereConditions)
const totalCount = totalCountResult[0]?.count || 0
@@ -166,9 +165,24 @@ export async function createNumberTypeConfig(input: {
sdq: number
description?: string
remark?: string
- projectId: number
}) {
try {
+ // 중복 체크: 같은 documentNumberTypeId와 sdq 조합이 이미 존재하는지 확인
+ const existingConfig = await db
+ .select({ id: documentNumberTypeConfigs.id })
+ .from(documentNumberTypeConfigs)
+ .where(
+ sql`${documentNumberTypeConfigs.documentNumberTypeId} = ${input.documentNumberTypeId} AND ${documentNumberTypeConfigs.sdq} = ${input.sdq}`
+ )
+ .limit(1)
+
+ if (existingConfig.length > 0) {
+ return {
+ success: false,
+ error: "이미 존재하는 순서 번호입니다."
+ }
+ }
+
const [result] = await db
.insert(documentNumberTypeConfigs)
.values({
@@ -177,7 +191,6 @@ export async function createNumberTypeConfig(input: {
sdq: input.sdq,
description: input.description,
remark: input.remark,
- projectId: input.projectId,
})
.returning({ id: documentNumberTypeConfigs.id })
@@ -206,6 +219,36 @@ export async function updateNumberTypeConfig(input: {
remark?: string
}) {
try {
+ // 현재 수정 중인 항목의 documentNumberTypeId 가져오기
+ const currentConfig = await db
+ .select({ documentNumberTypeId: documentNumberTypeConfigs.documentNumberTypeId })
+ .from(documentNumberTypeConfigs)
+ .where(eq(documentNumberTypeConfigs.id, input.id))
+ .limit(1)
+
+ if (currentConfig.length === 0) {
+ return {
+ success: false,
+ error: "Config not found"
+ }
+ }
+
+ // 중복 체크: 같은 documentNumberTypeId와 sdq 조합이 이미 존재하는지 확인 (현재 수정 중인 항목 제외)
+ const existingConfig = await db
+ .select({ id: documentNumberTypeConfigs.id })
+ .from(documentNumberTypeConfigs)
+ .where(
+ sql`${documentNumberTypeConfigs.documentNumberTypeId} = ${currentConfig[0].documentNumberTypeId} AND ${documentNumberTypeConfigs.sdq} = ${input.sdq} AND ${documentNumberTypeConfigs.id} != ${input.id}`
+ )
+ .limit(1)
+
+ if (existingConfig.length > 0) {
+ return {
+ success: false,
+ error: "이미 존재하는 순서 번호입니다."
+ }
+ }
+
const [result] = await db
.update(documentNumberTypeConfigs)
.set({