diff options
Diffstat (limited to 'db/schema/pq.ts')
| -rw-r--r-- | db/schema/pq.ts | 236 |
1 files changed, 179 insertions, 57 deletions
diff --git a/db/schema/pq.ts b/db/schema/pq.ts index c5f8c732..580a45b3 100644 --- a/db/schema/pq.ts +++ b/db/schema/pq.ts @@ -1,12 +1,44 @@ import { pgTable, serial, integer, varchar, text, - timestamp, uniqueIndex, pgView + timestamp, uniqueIndex, pgView, boolean, + jsonb, decimal } from "drizzle-orm/pg-core"; import { vendorTypes, vendors } from "./vendors"; import { projects } from "./projects"; import { sql, eq } from "drizzle-orm"; import { users } from "./users"; +// --------------------------------------------------------------------------- +// PQ Lists – 관리자가 생성하는 PQ 목록 정의 (GENERAL / PROJECT / NON_INSPECTION) +// --------------------------------------------------------------------------- + +export const pqLists = pgTable("pq_lists", { + id: serial("id").primaryKey(), + + // 목록 명칭 – "General PQ", "Project PQ – EPC-1234" 등 + name: varchar("name", { length: 255 }).notNull(), + + // GENERAL | PROJECT | NON_INSPECTION + type: varchar("type", { length: 20 }).notNull(), + + // 프로젝트 PQ의 경우 연결될 프로젝트 + projectId: integer("project_id").references(() => projects.id), + + // 삭제 플래그 (실제 데이터는 보존) + isDeleted: boolean("is_deleted").notNull().default(false), + + // 프로젝트 PQ 사용 기한 (선택) + validTo: timestamp("valid_to"), + // 생성자 + createdBy: integer("created_by").references(() => users.id), + // 수정자 + updatedBy: integer("updated_by").references(() => users.id), + createdAt: timestamp("created_at").defaultNow().notNull(), + updatedAt: timestamp("updated_at").defaultNow().notNull(), +}); + +export type PqList = typeof pqLists.$inferSelect; + export const pqCriterias = pgTable("pq_criterias", { id: serial("id").primaryKey(), code: varchar("code", { length: 50 }).notNull(), // 예: "1-1" @@ -16,37 +48,26 @@ export const pqCriterias = pgTable("pq_criterias", { // (선택) "GENERAL", "Quality Management System" 등 큰 분류 groupName: varchar("group_name", { length: 255 }), - createdAt: timestamp("created_at").defaultNow().notNull(), - updatedAt: timestamp("updated_at").defaultNow().notNull(), -}); - -export const pqCriteriasExtension = pgTable("pq_criterias_extension", { - id: serial("id").primaryKey(), + subGroupName: varchar("sub_group_name", { length: 255 }), - // pq_criterias와 연결 (1:1 or 1:N 중 필요에 맞춰 사용) - pqCriteriaId: integer("pq_criteria_id") + // 해당 항목이 속하는 PQ 목록 (General/Project/Non-Inspection) + pqListId: integer("pq_list_id") .notNull() - .references(() => pqCriterias.id, { + .references(() => pqLists.id, { onDelete: "cascade", onUpdate: "cascade", }), - // projects 테이블에 대한 FK - projectId: integer("project_id") + // 협력업체 입력 형식 – TEXT, FILE, EMAIL, PHONE, NUMBER 등 + inputFormat: varchar("input_format", { length: 50 }) .notNull() - .references(() => projects.id, { - onDelete: "cascade", - onUpdate: "cascade", - }), - - // 프로젝트별 PQ 시 필요한 추가 정보 - contractInfo: text("contract_info"), - additionalRequirement: text("additional_requirement"), + .default("TEXT"), createdAt: timestamp("created_at").defaultNow().notNull(), updatedAt: timestamp("updated_at").defaultNow().notNull(), }); + export const vendorCriteriaAttachments = pgTable("vendor_criteria_attachments", { id: serial("id").primaryKey(), vendorCriteriaAnswerId: integer("vendor_criteria_answer_id") @@ -54,6 +75,7 @@ export const vendorCriteriaAttachments = pgTable("vendor_criteria_attachments", .notNull(), fileName: varchar("file_name", { length: 255 }).notNull(), + originalFileName: varchar("original_file_name", { length: 255 }), filePath: varchar("file_path", { length: 1024 }).notNull(), fileType: varchar("file_type", { length: 50 }), fileSize: integer("file_size"), @@ -82,38 +104,6 @@ export type PqCriterias = typeof pqCriterias.$inferSelect // 협력업체와 프로젝트 PQ 요청 연결 테이블 -export const vendorProjectPQs = pgTable("vendor_project_pqs", { - id: serial("id").primaryKey(), - - // vendors 테이블 FK - vendorId: integer("vendor_id") - .notNull() - .references(() => vendors.id, { - onDelete: "cascade", - onUpdate: "cascade", - }), - - // projects 테이블 FK - projectId: integer("project_id") - .notNull() - .references(() => projects.id, { - onDelete: "cascade", - onUpdate: "cascade", - }), - - // 상태: REQUESTED(요청됨), IN_PROGRESS(진행중), SUBMITTED(제출됨), APPROVED(승인됨), REJECTED(거부됨) - status: varchar("status", { length: 20 }).notNull().default("REQUESTED"), - - // 메타데이터 - submittedAt: timestamp("submitted_at"), - approvedAt: timestamp("approved_at"), - rejectedAt: timestamp("rejected_at"), - rejectReason: text("reject_reason"), - - createdAt: timestamp("created_at").defaultNow().notNull(), - updatedAt: timestamp("updated_at").defaultNow().notNull(), -}); - export const vendorPQSubmissions = pgTable("vendor_pq_submissions", { id: serial("id").primaryKey(), @@ -137,9 +127,14 @@ export const vendorPQSubmissions = pgTable("vendor_pq_submissions", { }), // PQ 유형 구분을 명시적으로 - type: varchar("type", { length: 20 }).notNull(), // "GENERAL" or "PROJECT" + type: varchar("type", { length: 20 }).notNull(), // "GENERAL" or "PROJECT" or "NON_INSPECTION" status: varchar("status", { length: 20 }).notNull().default("REQUESTED"), + dueDate: timestamp("due_date"), + agreements: jsonb("agreements").notNull().default({}), // ✅ 체크 항목들을 JSON으로 저장 + + // PQ 대상품목 + pqItems: varchar("pq_items", { length: 1000 }), submittedAt: timestamp("submitted_at"), approvedAt: timestamp("approved_at"), @@ -185,6 +180,8 @@ export const vendorPqCriteriaAnswers = pgTable("vendor_pq_criteria_answers", { }), answer: text("answer"), + shiComment: text("shi_comment"), + vendorReply: text("vendor_reply"), createdAt: timestamp("created_at").defaultNow().notNull(), updatedAt: timestamp("updated_at").defaultNow().notNull(), @@ -259,6 +256,7 @@ export const vendorInvestigations = pgTable("vendor_investigations", { "IN_PROGRESS", // 진행 중 "COMPLETED", // 완료됨 "CANCELED", // 취소됨 + "RESULT_SENT", // 실사결과발송 - 구매담당자가 Vendor측으로 실사결과를 발송한 상태 ], }) .notNull() @@ -268,8 +266,10 @@ export const vendorInvestigations = pgTable("vendor_investigations", { evaluationType: varchar("evaluation_type", { length: 50, enum: [ - "SITE_AUDIT", // 실사의뢰평가 - "QM_SELF_AUDIT", // QM자체평가 + "PURCHASE_SELF_EVAL", // 구매자체평가 - 신규 평가 + "DOCUMENT_EVAL", // 서류평가 - 기존 QM 자체평가 + "PRODUCT_INSPECTION", // 제품검사평가 - 기존 실사의뢰평가 + "SITE_VISIT_EVAL" // 방문실사평가 - 기존 실사의뢰평가 ], }), @@ -277,7 +277,15 @@ export const vendorInvestigations = pgTable("vendor_investigations", { investigationAddress: text("investigation_address"), // 실사 방법 - investigationMethod: varchar("investigation_method", { length: 100 }), + investigationMethod: varchar("investigation_method", { + length: 100, + enum: [ + "PURCHASE_SELF_EVAL", // 구매자체평가 + "DOCUMENT_EVAL", // 서류평가 + "PRODUCT_INSPECTION", // 제품검사평가 + "SITE_VISIT_EVAL" // 방문실사평가 + ], + }), // 실사 일정 시작일 / 종료일 scheduledStartAt: timestamp("scheduled_start_at"), @@ -312,6 +320,9 @@ export const vendorInvestigations = pgTable("vendor_investigations", { // 실사 내용이나 특이사항 investigationNotes: text("investigation_notes"), + // 구매 담당자 추가 의견 (실사 결과 발송 시 사용) + purchaseComment: text("purchase_comment"), + createdAt: timestamp("created_at").defaultNow().notNull(), updatedAt: timestamp("updated_at").defaultNow().notNull(), }); @@ -329,6 +340,7 @@ export const vendorInvestigationAttachments = pgTable( .references(() => vendorInvestigations.id, { onDelete: "cascade" }), fileName: varchar("file_name", { length: 255 }).notNull(), + originalFileName: varchar("original_file_name", { length: 255 }), filePath: varchar("file_path", { length: 1024 }).notNull(), // 권장: 사용자 경험과 기능성을 위해 추가 @@ -436,4 +448,114 @@ export const vendorInvestigationsView = pgView( sql`users AS qm_manager`, eq(vendorInvestigations.qmManagerId, sql`qm_manager.id`) ) -})
\ No newline at end of file +}) + +// 방문실사 요청 테이블 +export const siteVisitRequests = pgTable("site_visit_requests", { + id: serial("id").primaryKey(), + + // 어떤 실사(investigation)에 대한 방문실사 요청인지 + investigationId: integer("investigation_id") + .notNull() + .references(() => vendorInvestigations.id, { onDelete: "cascade" }), + + // 요청자 + requesterId: integer("requester_id") + .references(() => users.id), + + // 실사 기간 (W/D 기준) + inspectionDuration: decimal("inspection_duration", { precision: 4, scale: 1 }), + + // 실사 요청일 (시작일, 종료일) + requestedStartDate: timestamp("requested_start_date"), + requestedEndDate: timestamp("requested_end_date"), + + // SHI 실사참석 예정부문 (JSON으로 저장) + shiAttendees: jsonb("shi_attendees").notNull().default({}), + + // 협력업체 요청정보 및 자료 (JSON으로 저장) + vendorRequests: jsonb("vendor_requests").notNull().default({}), + + // 추가 요청사항 + additionalRequests: text("additional_requests"), + + // 상태 + status: varchar("status", { length: 20 }).notNull().default("REQUESTED"), + + // 메일 발송일 + sentAt: timestamp("sent_at"), + + createdAt: timestamp("created_at").defaultNow().notNull(), + updatedAt: timestamp("updated_at").defaultNow().notNull(), +}); + +// 방문실사 요청 첨부파일 +export const siteVisitRequestAttachments = pgTable("site_visit_request_attachments", { + id: serial("id").primaryKey(), + + siteVisitRequestId: integer("site_visit_request_id") + .notNull() + .references(() => siteVisitRequests.id, { onDelete: "cascade" }), + + // 협력업체가 제출한 첨부파일인 경우 vendor_site_visit_info와 연결 + vendorSiteVisitInfoId: integer("vendor_site_visit_info_id") + .references(() => vendorSiteVisitInfo.id, { onDelete: "cascade" }), + + fileName: varchar("file_name", { length: 255 }).notNull(), + originalFileName: varchar("original_file_name", { length: 255 }), + filePath: varchar("file_path", { length: 1024 }).notNull(), + fileSize: integer("file_size"), + mimeType: varchar("mime_type", { length: 100 }), + + createdAt: timestamp("created_at").defaultNow().notNull(), + updatedAt: timestamp("updated_at").defaultNow().notNull(), +}); + +// 협력업체 방문실사 정보 테이블 +export const vendorSiteVisitInfo = pgTable("vendor_site_visit_info", { + id: serial("id").primaryKey(), + + // 방문실사 요청과 연결 + siteVisitRequestId: integer("site_visit_request_id") + .notNull() + .references(() => siteVisitRequests.id, { onDelete: "cascade" }), + + // 공장 정보 + factoryName: varchar("factory_name", { length: 255 }).notNull(), + factoryLocation: varchar("factory_location", { length: 255 }).notNull(), + factoryAddress: text("factory_address").notNull(), + + // 담당자 정보 + factoryPicName: varchar("factory_pic_name", { length: 255 }).notNull(), + factoryPicPhone: varchar("factory_pic_phone", { length: 50 }).notNull(), + factoryPicEmail: varchar("factory_pic_email", { length: 255 }).notNull(), + + // 방문 정보 + factoryDirections: text("factory_directions"), + accessProcedure: text("access_procedure"), + + + + // 첨부파일 여부 + hasAttachments: boolean("has_attachments").notNull().default(false), + + // 기타 정보 + otherInfo: text("other_info"), + + // 제출 정보 + submittedAt: timestamp("submitted_at").defaultNow().notNull(), + submittedBy: integer("submitted_by") + .notNull() + .references(() => users.id), + + createdAt: timestamp("created_at").defaultNow().notNull(), + updatedAt: timestamp("updated_at").defaultNow().notNull(), +}); + +// 타입 정의 +export type SiteVisitRequest = typeof siteVisitRequests.$inferSelect; +export type NewSiteVisitRequest = typeof siteVisitRequests.$inferInsert; +export type SiteVisitRequestAttachment = typeof siteVisitRequestAttachments.$inferSelect; +export type NewSiteVisitRequestAttachment = typeof siteVisitRequestAttachments.$inferInsert; +export type VendorSiteVisitInfo = typeof vendorSiteVisitInfo.$inferSelect; +export type NewVendorSiteVisitInfo = typeof vendorSiteVisitInfo.$inferInsert;
\ No newline at end of file |
