summaryrefslogtreecommitdiff
path: root/db
diff options
context:
space:
mode:
Diffstat (limited to 'db')
-rw-r--r--db/schema/knox/approvals.ts98
-rw-r--r--db/schema/procurementRFQ.ts28
-rw-r--r--db/schema/projects.ts2
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(),
})