summaryrefslogtreecommitdiff
path: root/db/schema
diff options
context:
space:
mode:
Diffstat (limited to 'db/schema')
-rw-r--r--db/schema/basicContractDocumnet.ts15
-rw-r--r--db/schema/bidding.ts15
-rw-r--r--db/schema/generalContract.ts2
-rw-r--r--db/schema/index.ts4
-rw-r--r--db/schema/menu-v2.ts88
5 files changed, 120 insertions, 4 deletions
diff --git a/db/schema/basicContractDocumnet.ts b/db/schema/basicContractDocumnet.ts
index 944c4b2c..e571c7e0 100644
--- a/db/schema/basicContractDocumnet.ts
+++ b/db/schema/basicContractDocumnet.ts
@@ -67,6 +67,12 @@ export const basicContract = pgTable('basic_contract', {
legalReviewRegNo: varchar('legal_review_reg_no', { length: 100 }), // 법무 시스템 REG_NO
legalReviewProgressStatus: varchar('legal_review_progress_status', { length: 255 }), // PRGS_STAT_DSC 값
+ // 준법문의 관련 필드
+ complianceReviewRequestedAt: timestamp('compliance_review_requested_at'), // 준법문의 요청일
+ complianceReviewCompletedAt: timestamp('compliance_review_completed_at'), // 준법문의 완료일
+ complianceReviewRegNo: varchar('compliance_review_reg_no', { length: 100 }), // 준법문의 시스템 REG_NO
+ complianceReviewProgressStatus: varchar('compliance_review_progress_status', { length: 255 }), // 준법문의 PRGS_STAT_DSC 값
+
createdAt: timestamp('created_at').defaultNow(),
updatedAt: timestamp('updated_at').defaultNow(),
completedAt: timestamp('completed_at'), // 계약 체결 완료 날짜
@@ -99,6 +105,12 @@ export const basicContractView = pgView('basic_contract_view').as((qb) => {
legalReviewRegNo: sql<string | null>`${basicContract.legalReviewRegNo}`.as('legal_review_reg_no'),
legalReviewProgressStatus: sql<string | null>`${basicContract.legalReviewProgressStatus}`.as('legal_review_progress_status'),
+ // 준법문의 관련 필드
+ complianceReviewRequestedAt: sql<Date | null>`${basicContract.complianceReviewRequestedAt}`.as('compliance_review_requested_at'),
+ complianceReviewCompletedAt: sql<Date | null>`${basicContract.complianceReviewCompletedAt}`.as('compliance_review_completed_at'),
+ complianceReviewRegNo: sql<string | null>`${basicContract.complianceReviewRegNo}`.as('compliance_review_reg_no'),
+ complianceReviewProgressStatus: sql<string | null>`${basicContract.complianceReviewProgressStatus}`.as('compliance_review_progress_status'),
+
createdAt: sql<Date>`${basicContract.createdAt}`.as('created_at'),
updatedAt: sql<Date>`${basicContract.updatedAt}`.as('updated_at'),
completedAt: sql<Date | null>`${basicContract.completedAt}`.as('completed_at'),
@@ -121,6 +133,9 @@ export const basicContractView = pgView('basic_contract_view').as((qb) => {
// 법무검토 상태 (PRGS_STAT_DSC 동기화 값)
legalReviewStatus: sql<string | null>`${basicContract.legalReviewProgressStatus}`.as('legal_review_status'),
+
+ // 준법문의 상태 (PRGS_STAT_DSC 동기화 값)
+ complianceReviewStatus: sql<string | null>`${basicContract.complianceReviewProgressStatus}`.as('compliance_review_status'),
// 템플릿 파일 정보
templateFilePath: sql<string | null>`${basicContractTemplates.filePath}`.as('template_file_path'),
diff --git a/db/schema/bidding.ts b/db/schema/bidding.ts
index c08ea921..8e5fe823 100644
--- a/db/schema/bidding.ts
+++ b/db/schema/bidding.ts
@@ -176,8 +176,10 @@ export const biddings = pgTable('biddings', {
// 일정 관리
preQuoteDate: date('pre_quote_date'), // 사전견적일
biddingRegistrationDate: date('bidding_registration_date'), // 입찰등록일
- submissionStartDate: timestamp('submission_start_date'), // 입찰서제출기간 시작
- submissionEndDate: timestamp('submission_end_date'), // 입찰서제출기간 끝
+ submissionStartDate: timestamp('submission_start_date'), // 입찰서제출기간 시작 (시간만 저장, 결재완료 후 실제 날짜로 계산)
+ submissionEndDate: timestamp('submission_end_date'), // 입찰서제출기간 끝 (시간만 저장, 결재완료 후 실제 날짜로 계산)
+ submissionStartOffset: integer('submission_start_offset'), // 시작일 오프셋 (결재완료일 + n일)
+ submissionDurationDays: integer('submission_duration_days'), // 입찰 기간 (시작일 + n일)
evaluationDate: timestamp('evaluation_date'),
// 사양설명회
@@ -188,11 +190,13 @@ export const biddings = pgTable('biddings', {
budget: decimal('budget', { precision: 15, scale: 2 }), // 예산
targetPrice: decimal('target_price', { precision: 15, scale: 2 }), // 내정가
targetPriceCalculationCriteria: text('target_price_calculation_criteria'), // 내정가 산정 기준
+ actualPrice: decimal('actual_price', { precision: 15, scale: 2 }), // 실적가
finalBidPrice: decimal('final_bid_price', { precision: 15, scale: 2 }), // 최종입찰가
// PR 정보
prNumber: varchar('pr_number', { length: 50 }), // PR No.
hasPrDocument: boolean('has_pr_document').default(false), // PR 문서 여부
+ plant: varchar('plant', { length: 10 }), // 플랜트 코드(WERKS), ECC 연동 시 설정
// 상태 및 설정
status: biddingStatusEnum('status').default('bidding_generated').notNull(),
@@ -297,7 +301,7 @@ export const prItemsForBidding = pgTable('pr_items_for_bidding', {
// 수량 및 중량
quantity: decimal('quantity', { precision: 10, scale: 3 }), // 수량
- quantityUnit: varchar('quantity_unit', { length: 50 }), // 수량단위 (구매단위)
+ quantityUnit: varchar('quantity_unit', { length: 50 }), // 수량단위
totalWeight: decimal('total_weight', { precision: 10, scale: 3 }), // 총 중량
weightUnit: varchar('weight_unit', { length: 50 }), // 중량단위 (자재순중량)
@@ -403,6 +407,11 @@ export const biddingCompanies = pgTable('bidding_companies', {
//연동제 적용요건 문의 여부
isPriceAdjustmentApplicableQuestion: boolean('is_price_adjustment_applicable_question').default(false), // 연동제 적용요건 문의 여부
+ // SHI 연동제 적용여부 및 관련 정보
+ shiPriceAdjustmentApplied: boolean('shi_price_adjustment_applied'), // SHI 연동제 적용여부 (null: 미정, true: 적용, false: 미적용)
+ priceAdjustmentNote: text('price_adjustment_note'), // 연동제 Note (textarea)
+ hasChemicalSubstance: boolean('has_chemical_substance'), // 화학물질여부
+
// 기타
notes: text('notes'), // 특이사항
contactPerson: varchar('contact_person', { length: 100 }), // 업체 담당자
diff --git a/db/schema/generalContract.ts b/db/schema/generalContract.ts
index 6f48581f..7cc6cd6e 100644
--- a/db/schema/generalContract.ts
+++ b/db/schema/generalContract.ts
@@ -37,7 +37,7 @@ export const generalContracts = pgTable('general_contracts', {
// ═══════════════════════════════════════════════════════════════
// 계약 분류 및 상태
// ═══════════════════════════════════════════════════════════════
- status: varchar('status', { length: 50 }).notNull(), // 계약 상태 (Draft, Complete the Contract, Contract Delete 등)
+ status: varchar('status', { length: 50 }).notNull(), // 계약 상태 (Draft, Complete the Contract, Contract Delete, approval request 등)
category: varchar('category', { length: 50 }).notNull(), // 계약구분 (단가계약, 일반계약, 매각계약)
type: varchar('type', { length: 50 }), // 계약종류 (UP, LE, IL, AL 등)
executionMethod: varchar('execution_method', { length: 50 }), // 체결방식 (오프라인, 온라인 등)
diff --git a/db/schema/index.ts b/db/schema/index.ts
index 459cc9e4..da17b069 100644
--- a/db/schema/index.ts
+++ b/db/schema/index.ts
@@ -29,7 +29,11 @@ export * from './evaluation';
export * from './evaluationTarget';
export * from './evaluationCriteria';
export * from './projectGtc';
+// 기존 menu 스키마 (deprecated - menu-v2로 대체됨)
export * from './menu';
+
+// 새로운 메뉴 트리 스키마 (v2)
+export * from './menu-v2';
export * from './information';
export * from './qna';
export * from './notice';
diff --git a/db/schema/menu-v2.ts b/db/schema/menu-v2.ts
new file mode 100644
index 00000000..2d0282fa
--- /dev/null
+++ b/db/schema/menu-v2.ts
@@ -0,0 +1,88 @@
+// db/schema/menu-v2.ts
+import { pgTable, pgEnum, integer, varchar, text, timestamp, boolean, index, uniqueIndex } from "drizzle-orm/pg-core";
+import { relations } from "drizzle-orm";
+import { users } from "./users";
+
+export const menuTreeNodeTypeEnum = pgEnum('menu_tree_node_type', [
+ 'menu_group', // 메뉴그룹 (1단계) - 헤더에 표시되는 드롭다운 트리거
+ 'group', // 그룹 (2단계) - 드롭다운 내 구분 영역
+ 'menu', // 메뉴 (3단계) - 드롭다운 내 링크
+ 'additional' // 추가 메뉴 - 최상위 단일 링크 (Dashboard, QNA, FAQ 등)
+]);
+
+export const menuDomainEnum = pgEnum('menu_domain', [
+ 'evcp', // 내부 사용자용
+ 'partners' // 협력업체용
+]);
+
+export const menuTreeNodes = pgTable("menu_tree_nodes", {
+ id: integer("id").primaryKey().generatedAlwaysAsIdentity(),
+
+ // 도메인 구분
+ domain: menuDomainEnum("domain").notNull(),
+
+ // 트리 구조
+ parentId: integer("parent_id").references((): any => menuTreeNodes.id, { onDelete: "cascade" }),
+ nodeType: menuTreeNodeTypeEnum("node_type").notNull(),
+ sortOrder: integer("sort_order").notNull().default(0),
+
+ // 다국어 텍스트 (DB 직접 관리)
+ titleKo: varchar("title_ko", { length: 255 }).notNull(),
+ titleEn: varchar("title_en", { length: 255 }),
+ descriptionKo: text("description_ko"),
+ descriptionEn: text("description_en"),
+
+ // 메뉴 전용 필드 (nodeType === 'menu' 또는 'additional'일 때)
+ menuPath: varchar("menu_path", { length: 255 }), // href 값 (예: /evcp/projects)
+ icon: varchar("icon", { length: 100 }),
+
+ // 권한 연동
+ // evcp: Oracle DB SCR_ID 참조
+ // partners: 자체 권한 시스템 (TODO)
+ scrId: varchar("scr_id", { length: 100 }),
+
+ // 상태
+ isActive: boolean("is_active").default(true).notNull(),
+
+ // 담당자 (evcp 전용)
+ manager1Id: integer("manager1_id").references(() => users.id, { onDelete: "set null" }),
+ manager2Id: integer("manager2_id").references(() => users.id, { onDelete: "set null" }),
+
+ createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
+ updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull(),
+}, (table) => ({
+ domainIdx: index("menu_tree_domain_idx").on(table.domain),
+ parentIdx: index("menu_tree_parent_idx").on(table.parentId),
+ sortOrderIdx: index("menu_tree_sort_order_idx").on(table.sortOrder),
+ menuPathUnique: uniqueIndex("menu_tree_path_unique_idx").on(table.menuPath),
+ scrIdIdx: index("menu_tree_scr_id_idx").on(table.scrId),
+}));
+
+// Relations 정의
+export const menuTreeNodesRelations = relations(menuTreeNodes, ({ one, many }) => ({
+ parent: one(menuTreeNodes, {
+ fields: [menuTreeNodes.parentId],
+ references: [menuTreeNodes.id],
+ relationName: "parentChild",
+ }),
+ children: many(menuTreeNodes, {
+ relationName: "parentChild",
+ }),
+ manager1: one(users, {
+ fields: [menuTreeNodes.manager1Id],
+ references: [users.id],
+ relationName: "menuManager1",
+ }),
+ manager2: one(users, {
+ fields: [menuTreeNodes.manager2Id],
+ references: [users.id],
+ relationName: "menuManager2",
+ }),
+}));
+
+// Type exports
+export type MenuTreeNode = typeof menuTreeNodes.$inferSelect;
+export type NewMenuTreeNode = typeof menuTreeNodes.$inferInsert;
+export type NodeType = (typeof menuTreeNodeTypeEnum.enumValues)[number];
+export type MenuDomain = (typeof menuDomainEnum.enumValues)[number];
+