diff options
| author | joonhoekim <26rote@gmail.com> | 2025-08-11 09:34:40 +0000 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-08-11 09:34:40 +0000 |
| commit | bcd462d6e60871b86008e072f4b914138fc5c328 (patch) | |
| tree | c22876fd6c6e7e48254587848b9dff50cdb8b032 /db/schema | |
| parent | cbb4c7fe0b94459162ad5e998bc05cd293e0ff96 (diff) | |
(김준회) 리치텍스트에디터 (결재템플릿을 위한 공통컴포넌트), command-menu 에러 수정, 결재 템플릿 관리, 결재선 관리, ECC RFQ+PR Item 수신시 비즈니스테이블(ProcurementRFQ) 데이터 적재, WSDL 오류 수정
Diffstat (limited to 'db/schema')
| -rw-r--r-- | db/schema/knox/approvals.ts | 98 | ||||
| -rw-r--r-- | db/schema/procurementRFQ.ts | 28 | ||||
| -rw-r--r-- | db/schema/projects.ts | 2 |
3 files changed, 109 insertions, 19 deletions
diff --git a/db/schema/knox/approvals.ts b/db/schema/knox/approvals.ts index 27332ed6..0f8ee90a 100644 --- a/db/schema/knox/approvals.ts +++ b/db/schema/knox/approvals.ts @@ -1,7 +1,36 @@ -import { boolean, jsonb, text, timestamp, } from "drizzle-orm/pg-core"; +import { boolean, jsonb, text, timestamp, integer, uuid } from "drizzle-orm/pg-core"; import { knoxSchema } from "./employee"; +import { users } from '@/db/schema/users'; -export const approval = knoxSchema.table("approval", { +/** + * 결재 관련 테이블 정의 + * + * 템플릿 관리 + * 결재선 관리 + * 결재 로그 관리 (히스토리 관리) + * + */ + +// 결재 템플릿 히스토리 +export const approvalTemplateHistory = knoxSchema.table('approval_template_history', { + id: uuid().primaryKey().defaultRandom(), // 히스토리 아이디 UUID + templateId: uuid() + .references(() => approvalTemplates.id, { onDelete: 'cascade' }) + .notNull(), + version: integer().notNull(), // 히스토리 버전 + subject: text().notNull(), // 템플릿 제목 + content: text().notNull(), // 템플릿 내용 + changeDescription: text(), // 변경 사항 설명 + changedBy: integer() // 변경자 - eVCP 유저 아이디 기반 참조 + .notNull() + .references(() => users.id, { onDelete: 'set null' }), + createdAt: timestamp().defaultNow().notNull(), + // 히스토리는 업데이트 없음. 생성 시점만 기록. +}); + + +// 실제 결재 상신 로그 +export const approvalLogs = knoxSchema.table("approval_logs", { apInfId: text("ap_inf_id").primaryKey(), userId: text("user_id").notNull(), epId: text("ep_id").notNull(), @@ -9,8 +38,69 @@ export const approval = knoxSchema.table("approval", { subject: text("subject").notNull(), content: text("content").notNull(), status: text("status").notNull(), - aplns: jsonb("aplns").notNull(), + aplns: jsonb("aplns").notNull(), // approval lines = 결재선 isDeleted: boolean("is_deleted").notNull().default(false), createdAt: timestamp("created_at").notNull().defaultNow(), updatedAt: timestamp("updated_at").notNull().defaultNow(), -});
\ No newline at end of file +}); + + +// 결재 템플릿 +export const approvalTemplates = knoxSchema.table('approval_templates', { + id: uuid().primaryKey().defaultRandom(), // 템플릿 아이디 UUID + name: text().notNull(), // 템플릿 이름 + // slug: text('slug').notNull().unique(), // 템플릿 슬러그는 UUID로 대체하기 + subject: text().notNull(), // 템플릿 제목 + content: text().notNull(), // 템플릿 내용 + description: text(), // 템플릿 설명 + category: text(), // 템플릿 카테고리 설명 + + // 선택된 결재선 참조 (nullable, 결재선은 별도에서 관리) + approvalLineId: uuid().references(() => approvalLines.id, { onDelete: 'set null' }), + + // 메타데이터 + createdBy: integer() // 템플릿 생성자 - eVCP 유저 아이디 기반 참조 + .notNull() + .references(() => users.id, { onDelete: 'set null' }), + createdAt: timestamp().defaultNow().notNull(), + updatedAt: timestamp().defaultNow().notNull(), +}); + +// 결재선 템플릿 +export const approvalLines = knoxSchema.table('approval_lines', { + id: uuid().primaryKey().defaultRandom(), // 결재선 아이디 UUID + name: text().notNull(), // 결재선 이름 + description: text(), // 결재선 설명 + category: text(), + + // 핵심 + aplns: jsonb().notNull(), // 결재선 구성 + + // 메타데이터 + createdBy: integer() // 결재선 생성자 - eVCP 유저 아이디 기반 참조 + .notNull() + .references(() => users.id, { onDelete: 'set null' }), + createdAt: timestamp().defaultNow().notNull(), + updatedAt: timestamp().defaultNow().notNull(), +}); + +// + +// 결재 템플릿 변수 +export const approvalTemplateVariables = knoxSchema.table('approval_template_variables', { + id: uuid().primaryKey().defaultRandom(), // 변수 아이디 UUID + approvalTemplateId: uuid() + .references(() => approvalTemplates.id, { onDelete: 'cascade' }), + variableName: text().notNull(), // 변수 이름 + variableType: text().notNull(), // 변수 타입 + defaultValue: text(), // 변수 기본값 + description: text(), // 변수 설명 + + // 메타데이터 + createdBy: integer() // 변수 생성자 - eVCP 유저 아이디 기반 참조 + .notNull() + .references(() => users.id, { onDelete: 'set null' }), + createdAt: timestamp().defaultNow().notNull(), + updatedAt: timestamp().defaultNow().notNull(), +}); + diff --git a/db/schema/procurementRFQ.ts b/db/schema/procurementRFQ.ts index 18cf5f9d..fe60bb0e 100644 --- a/db/schema/procurementRFQ.ts +++ b/db/schema/procurementRFQ.ts @@ -1,5 +1,5 @@ import { foreignKey, pgTable, pgView, serial, varchar, text, timestamp, boolean, integer, numeric, date, alias, check } from "drizzle-orm/pg-core"; -import { eq, sql, and, or, relations } from "drizzle-orm"; +import { eq, sql, relations } from "drizzle-orm"; import { projects } from "./projects"; import { users } from "./users"; import { vendors } from "./vendors"; @@ -12,25 +12,25 @@ export const procurementRfqs = pgTable( // RFQ 고유 코드 rfqCode: varchar("rfq_code", { length: 50 }).unique(), // ex) "RFQ-2025-001" - // 프로젝트 참조 - projectId: integer("project_id") - .references(() => projects.id, { onDelete: "set null" }), + // 프로젝트: ECC RFQ는 프로젝트 테이블과 1:N 관계를 가져야 함 + // WHY?: 여러 프로젝트 혹은 여러 시리즈의 동일 품목을 PR로 묶어 올리기 때문 + projectId: varchar("project_id", { length: 1000 }), + // SS, II, null 값을 가질 수 있음. + // SS = 시리즈 통합, II = 품목 통합, 공란 = 통합 없음 series: varchar("series", { length: 50 }), - // itemId: integer("item_id") - // .notNull() - // .references(() => items.id, { onDelete: "cascade" }), - - itemCode: varchar("item_code", { length: 100 }), - itemName: varchar("item_name", { length: 255 }), + // 자재코드, 자재명: ECC RFQ는 자재코드, 자재명을 가지지 않음 + // WHY?: 여러 프로젝트 혹은 여러 시리즈의 동일 품목을 PR로 묶어 올리기 때문 + // 아래 컬럼은 대표 자재코드, 대표 자재명으로 사용 + itemCode: varchar("item_code", { length: 100 }), + itemName: varchar("item_name", { length: 255 }), dueDate: date("due_date", { mode: "date" }) - .$type<Date>() - .notNull(), + .$type<Date>(), // 인터페이스한 값은 dueDate가 없으므로 notNull 제약조건 제거 rfqSendDate: date("rfq_send_date", { mode: "date" }) - .$type<Date | null>(), // notNull() 제약조건 제거, null 허용 + .$type<Date | null>(), // notNull() 제약조건 제거, null 허용 (ECC에서 수신 후 보내지 않은 RFQ) status: varchar("status", { length: 30 }) .$type<"RFQ Created" | "RFQ Vendor Assignned" | "RFQ Sent" | "Quotation Analysis" | "PO Transfer" | "PO Create">() @@ -38,7 +38,7 @@ export const procurementRfqs = pgTable( .notNull(), rfqSealedYn: boolean("rfq_sealed_yn").default(false), - picCode: varchar("pic_code", { length: 50 }), + picCode: varchar("pic_code", { length: 50 }), // 구매그룹에 대응시킴 (담당자 코드로 3자리) remark: text("remark"), // 생성자 diff --git a/db/schema/projects.ts b/db/schema/projects.ts index a67b2c33..ee3dbf27 100644 --- a/db/schema/projects.ts +++ b/db/schema/projects.ts @@ -5,7 +5,7 @@ export const projects = pgTable("projects", { code: varchar("code", { length: 50 }).notNull(), name: text("name").notNull(), type: varchar("type", { length: 20 }).default("ship").notNull(), - + pspid: char('pspid', { length: 24 }).unique(), // 프로젝트ID (ECC), TODO: 매핑 필요 createdAt: timestamp("created_at").defaultNow().notNull(), updatedAt: timestamp("updated_at").defaultNow().notNull(), }) |
