summaryrefslogtreecommitdiff
path: root/db/schema/legal.ts
diff options
context:
space:
mode:
Diffstat (limited to 'db/schema/legal.ts')
-rw-r--r--db/schema/legal.ts276
1 files changed, 276 insertions, 0 deletions
diff --git a/db/schema/legal.ts b/db/schema/legal.ts
new file mode 100644
index 00000000..e4880517
--- /dev/null
+++ b/db/schema/legal.ts
@@ -0,0 +1,276 @@
+import { pgView,pgTable, serial, varchar, boolean, date, text, timestamp, integer, decimal } from 'drizzle-orm/pg-core';
+import { vendors } from './vendors';
+import { eq , sql, relations} from "drizzle-orm";
+
+// 법무 업무 테이블
+export const legalWorks = pgTable('legal_works', {
+ id: serial('id').primaryKey(),
+
+ // 구분 (CP, GTC, 기타 등)
+ category: varchar('category', { length: 50 }).notNull(),
+
+ // 상태 (답변완료, 담당자배정, 검토요청 등)
+ status: varchar('status', { length: 100 }).notNull(),
+
+ vendorId: integer("company_id")
+ .references(() => vendors.id, { onDelete: "set null" }),
+
+ // 벤더 정보
+ vendorCode: varchar('vendor_code', { length: 50 }),
+ vendorName: varchar('vendor_name', { length: 200 }).notNull(),
+
+ // 긴급여부
+ isUrgent: boolean('is_urgent').default(false).notNull(),
+
+ // 날짜 필드들
+ requestDate: date('request_date'), // 답변요청일
+ consultationDate: date('consultation_date'), // 의뢰일
+ expectedAnswerDate: date('expected_answer_date'), // 답변예정일
+ legalCompletionDate: date('legal_completion_date'), // 법무완료일
+
+ // 담당자 정보
+ reviewer: varchar('reviewer', { length: 100 }), // 검토요청자
+ legalResponder: varchar('legal_responder', { length: 100 }), // 법무답변자
+
+ // 첨부파일 여부
+ hasAttachment: boolean('has_attachment').default(false).notNull(),
+
+ // 메타데이터
+ createdAt: timestamp('created_at').defaultNow().notNull(),
+ updatedAt: timestamp('updated_at').defaultNow().notNull(),
+});
+
+// 타입 정의
+export type LegalWork = typeof legalWorks.$inferSelect;
+export type NewLegalWork = typeof legalWorks.$inferInsert;
+
+export type LegalWorkCategory = typeof LEGAL_WORK_CATEGORIES[number];
+export type LegalWorkStatus = typeof LEGAL_WORK_STATUSES[number];
+
+
+// 법무 검토 요청 테이블
+export const legalWorkRequests = pgTable('legal_work_requests', {
+ id: serial('id').primaryKey(),
+ legalWorkId: integer('legal_work_id').references(() => legalWorks.id, { onDelete: 'cascade' }).notNull(),
+
+ // 검토부문 (준법문의 or 법무검토)
+ reviewDepartment: varchar('review_department', { length: 50 }).notNull(), // '준법문의' | '법무검토'
+
+ // 문의종류 (법무검토 선택시만)
+ inquiryType: varchar('inquiry_type', { length: 50 }), // '국내계약' | '국내자문' | '해외계약' | '해외자문'
+
+ // 제목
+ title: varchar('title', { length: 500 }).notNull(),
+
+ // 요청내용
+ requestContent: text('request_content').notNull(),
+
+ // ===== 준법문의 관련 필드들 =====
+
+ // 공개여부 (준법문의 선택시)
+ isPublic: boolean('is_public').default(false), // 기본값: 비공개
+
+ // ===== 법무검토 관련 공통 필드들 =====
+
+ // 계약명/프로젝트명 (국내계약/해외계약/해외자문 선택시)
+ contractProjectName: varchar('contract_project_name', { length: 300 }),
+
+ // 계약서 종류 (국내계약/해외계약/해외자문 선택시)
+ contractType: varchar('contract_type', { length: 100 }),
+
+ // 계약금액 (국내계약/해외계약/해외자문 선택시)
+ contractAmount: decimal('contract_amount', { precision: 15, scale: 2 }),
+
+ // ===== 국내계약 전용 필드들 =====
+
+ // 계약상대방 (국내계약 선택시)
+ contractCounterparty: varchar('contract_counterparty', { length: 200 }),
+
+ // 계약상대방 구분 (법인/개인)
+ counterpartyType: varchar('counterparty_type', { length: 20 }), // '법인' | '개인'
+
+ // 계약기간 (국내계약 선택시)
+ contractPeriod: varchar('contract_period', { length: 200 }),
+
+ // ===== 자문 관련 필드들 =====
+
+ // 사실관계 (국내자문/해외자문 선택시)
+ factualRelation: text('factual_relation'),
+
+ // ===== 해외 관련 필드들 =====
+
+ // 프로젝트번호 (해외계약/해외자문 선택시)
+ projectNumber: varchar('project_number', { length: 100 }),
+
+ // 선주/발주처 (해외계약/해외자문 선택시)
+ shipownerOrderer: varchar('shipowner_orderer', { length: 200 }),
+
+ // 준거법 (해외계약/해외자문 선택시)
+ governingLaw: varchar('governing_law', { length: 100 }),
+
+ // 프로젝트종류 (해외계약/해외자문 선택시)
+ projectType: varchar('project_type', { length: 100 }),
+
+ // 메타데이터
+ createdAt: timestamp('created_at').defaultNow().notNull(),
+ updatedAt: timestamp('updated_at').defaultNow().notNull(),
+});
+
+// 법무 회신 테이블
+export const legalWorkResponses = pgTable('legal_work_responses', {
+ id: serial('id').primaryKey(),
+ legalWorkId: integer('legal_work_id').references(() => legalWorks.id, { onDelete: 'cascade' }).notNull(),
+
+ // 답변내용
+ responseContent: text('response_content').notNull(),
+
+ // 답변 관련 담당자들
+ responseReviewer: varchar('response_reviewer', { length: 100 }), // 답변검토자
+ responseConfirmer: varchar('response_confirmer', { length: 100 }), // 답변확인자
+ responseApprover: varchar('response_approver', { length: 100 }), // 승인자
+
+ // 처리 시간들
+ reviewedAt: timestamp('reviewed_at'), // 검토시간
+ confirmedAt: timestamp('confirmed_at'), // 확인시간
+ approvedAt: timestamp('approved_at'), // 승인시간
+
+ // 공개여부
+ isPublic: boolean('is_public').default(false).notNull(),
+
+ // 재검토 관련
+ isReRevision: boolean('is_re_revision').default(false).notNull(), // 재검토 여부
+ parentResponseId: integer('parent_response_id'), // 이전 답변 참조
+
+ // 메타데이터
+ createdAt: timestamp('created_at').defaultNow().notNull(),
+ updatedAt: timestamp('updated_at').defaultNow().notNull(),
+});
+
+// 첨부파일 테이블
+export const legalWorkAttachments = pgTable('legal_work_attachments', {
+ id: serial('id').primaryKey(),
+ legalWorkId: integer('legal_work_id').references(() => legalWorks.id, { onDelete: 'cascade' }).notNull(),
+
+ fileName: varchar('file_name', { length: 255 }).notNull(),
+ originalFileName: varchar('original_file_name', { length: 255 }).notNull(),
+ filePath: varchar('file_path', { length: 500 }).notNull(),
+ fileSize: integer('file_size').notNull(),
+ mimeType: varchar('mime_type', { length: 100 }).notNull(),
+
+ // 자동 생성 파일 여부 (Case1에서 PDF 자동 생성)
+ isAutoGenerated: boolean('is_auto_generated').default(false).notNull(),
+
+ // 첨부파일 타입 (요청시 첨부 vs 답변시 첨부)
+ attachmentType: varchar('attachment_type', { length: 50 }).default('request'), // 'request' | 'response'
+
+ createdAt: timestamp('created_at').defaultNow().notNull(),
+});
+
+
+export type LegalWorkRequest = typeof legalWorkRequests.$inferSelect;
+export type LegalWorkResponse = typeof legalWorkResponses.$inferSelect;
+export type LegalWorkAttachment = typeof legalWorkAttachments.$inferSelect;
+
+// 상수 정의
+export const LEGAL_WORK_CATEGORIES = [
+ 'CP',
+ 'GTC',
+ '기타'
+] as const;
+
+export const LEGAL_WORK_STATUSES = [
+ '신규등록',
+ '검토요청',
+ '담당자배정',
+ '검토중',
+ '답변완료',
+ '재검토요청',
+ '보류',
+ '취소'
+] as const;
+
+export const REVIEW_DEPARTMENTS = [
+ '준법문의',
+ '법무검토'
+] as const;
+
+export const INQUIRY_TYPES = [
+ '국내계약',
+ '국내자문',
+ '해외계약',
+ '해외자문'
+] as const;
+
+export const COUNTERPARTY_TYPES = [
+ '법인',
+ '개인'
+] as const;
+
+export const SOURCE_TYPES = [
+ 'interface', // 22번화면에서 이관
+ 'manual' // 신규생성
+] as const;
+
+export const ATTACHMENT_TYPES = [
+ 'request', // 요청시 첨부
+ 'response' // 답변시 첨부
+] as const;
+
+
+
+export const legalWorksDetailView = pgView("legal_works_detail_view").as((qb) => {
+ return qb
+ .select({
+ // legal_works 기본 필드들
+ id: legalWorks.id,
+ category: legalWorks.category,
+ status: legalWorks.status,
+ vendorId: legalWorks.vendorId,
+ vendorCode: legalWorks.vendorCode,
+ vendorName: legalWorks.vendorName,
+ isUrgent: legalWorks.isUrgent,
+ requestDate: legalWorks.requestDate,
+ consultationDate: legalWorks.consultationDate,
+ expectedAnswerDate: legalWorks.expectedAnswerDate,
+ legalCompletionDate: legalWorks.legalCompletionDate,
+ reviewer: legalWorks.reviewer,
+ legalResponder: legalWorks.legalResponder,
+ hasAttachment: legalWorks.hasAttachment,
+ createdAt: legalWorks.createdAt,
+ updatedAt: legalWorks.updatedAt,
+
+ // legal_work_requests 필드들
+ reviewDepartment: legalWorkRequests.reviewDepartment,
+ inquiryType: legalWorkRequests.inquiryType,
+ title: legalWorkRequests.title,
+ requestContent: legalWorkRequests.requestContent,
+ isPublicRequest: legalWorkRequests.isPublic,
+ contractProjectName: legalWorkRequests.contractProjectName,
+ contractType: legalWorkRequests.contractType,
+ contractAmount: legalWorkRequests.contractAmount,
+
+
+ // 최신 답변 정보 (서브쿼리)
+ responseContent: sql<string | null>`(
+ SELECT response_content
+ FROM legal_work_responses lwr_latest
+ WHERE lwr_latest.legal_work_id = ${legalWorks.id}
+ ORDER BY lwr_latest.created_at DESC
+ LIMIT 1
+ )`.as('response_content'),
+
+ // 첨부파일 개수
+ attachmentCount: sql<number>`(
+ SELECT COUNT(*)::integer
+ FROM legal_work_attachments lwa
+ WHERE lwa.legal_work_id = ${legalWorks.id}
+ )`.as('attachment_count'),
+ })
+ .from(legalWorks)
+ .leftJoin(legalWorkRequests, sql`${legalWorks.id} = ${legalWorkRequests.legalWorkId}`)
+ .leftJoin(vendors, sql`${legalWorks.vendorId} = ${vendors.id}`);
+});
+
+// 타입 추출
+export type LegalWorksDetailView = typeof legalWorksDetailView.$inferSelect;
+