diff options
Diffstat (limited to 'db/schema/legal.ts')
| -rw-r--r-- | db/schema/legal.ts | 276 |
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; + |
