summaryrefslogtreecommitdiff
path: root/db/schema
diff options
context:
space:
mode:
Diffstat (limited to 'db/schema')
-rw-r--r--db/schema/index.ts1
-rw-r--r--db/schema/techSales.ts152
-rw-r--r--db/schema/techVendors.ts6
3 files changed, 79 insertions, 80 deletions
diff --git a/db/schema/index.ts b/db/schema/index.ts
index 9ed0c59e..d3dbdf6d 100644
--- a/db/schema/index.ts
+++ b/db/schema/index.ts
@@ -17,6 +17,7 @@ export * from './setting';
export * from './techSales';
export * from './ocr';
export * from './bRfq';
+export * from './techVendors';
// MDG SOAP 수신용
// export * from './MDG/modelMaster'
diff --git a/db/schema/techSales.ts b/db/schema/techSales.ts
index 082ab592..334bf6bb 100644
--- a/db/schema/techSales.ts
+++ b/db/schema/techSales.ts
@@ -34,13 +34,12 @@ import {
integer,
numeric,
date,
- jsonb,
} from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";
import { biddingProjects } from "./projects";
import { users } from "./users";
-import { itemShipbuilding } from "./items";
-import { vendors } from "./vendors";
+import { itemOffshoreHull, itemOffshoreTop, itemShipbuilding } from "./items";
+import { techVendors } from "./techVendors";
// ===== 기술영업 상태 관리 상수 및 타입 =====
@@ -60,7 +59,6 @@ export const TECH_SALES_QUOTATION_STATUSES = {
DRAFT: "Draft",
SUBMITTED: "Submitted",
REVISED: "Revised",
- REJECTED: "Rejected",
ACCEPTED: "Accepted",
} as const;
@@ -86,12 +84,6 @@ export const TECH_SALES_QUOTATION_STATUS_CONFIG = {
description: "수정된 견적서",
color: "text-purple-600",
},
- [TECH_SALES_QUOTATION_STATUSES.REJECTED]: {
- label: "반려됨",
- variant: "destructive" as const,
- description: "반려된 견적서",
- color: "text-red-600",
- },
[TECH_SALES_QUOTATION_STATUSES.ACCEPTED]: {
label: "승인됨",
variant: "success" as const,
@@ -102,19 +94,22 @@ export const TECH_SALES_QUOTATION_STATUS_CONFIG = {
// ===== 스키마 정의 =====
-// 기술영업 RFQ 테이블
+// 기술영업 RFQ 테이블 - 아이템 관계를 1:N으로 변경
export const techSalesRfqs = pgTable("tech_sales_rfqs", {
id: serial("id").primaryKey(),
rfqCode: varchar("rfq_code", { length: 50 }).unique(), // ex) "RFQ-2025-001"
- // item에서 기술영업에서 사용하는 추가 정보는 itemShipbuilding 테이블에 저장되어 있다.
- itemShipbuildingId: integer("item_shipbuilding_id")
- .notNull()
- .references(() => itemShipbuilding.id, { onDelete: "cascade" }),
+ // 아이템 직접 참조 제거 - tech_sales_rfq_items 테이블로 분리
+ // itemShipbuildingId: integer("item_shipbuilding_id")
+ // .notNull()
+ // .references(() => itemShipbuilding.id, { onDelete: "cascade" }),
// 프로젝트 참조 ID
biddingProjectId: integer("bidding_project_id").references(() => biddingProjects.id, { onDelete: "set null" }),
+ // RFQ 설명 (새로 추가)
+ description: text("description"),
+ remark: text("remark"),
// 기술영업에서 벤더에게 제공할 정보로, 모든 벤더에게 동일하게 제공함.
materialCode: varchar("material_code", { length: 255 }),
@@ -126,12 +121,10 @@ export const techSalesRfqs = pgTable("tech_sales_rfqs", {
.$type<TechSalesRfqStatus>()
.default(TECH_SALES_RFQ_STATUSES.RFQ_CREATED)
.notNull(),
-
- // rfq 밀봉 기능은, 기술영업에서 사용하지 않겠다고 함.
-
+
//picCode: 발주자 코드
picCode: varchar("pic_code", { length: 50 }),
- remark: text("remark"),
+
// WHO
sentBy: integer("sent_by").references(() => users.id, {
@@ -150,48 +143,37 @@ export const techSalesRfqs = pgTable("tech_sales_rfqs", {
// 삼성중공업이 RFQ를 취소한 경우
cancelReason: text("cancel_reason"),
+ // RFQ 타입 구분 (조선/해양top/해양hull)
+ rfqType: varchar("rfq_type", { length: 20 })
+ .$type<"SHIP" | "TOP" | "HULL">()
+ .default("SHIP")
+ .notNull(),
+});
- // 프로젝트 정보 스냅샷 (프로젝트 관련 모든 정보)
- // 기존 개별 컬럼 방식에서 jsonb로 마이그레이션 시:
- // 1. 기존 RFQ 데이터는 pspid 등의 개별 컬럼 값을 기반으로 jsonb 형태로 변환하여 마이그레이션
- // 2. 새로운 RFQ 생성 시에는 biddingProjects와 projectSeries 테이블에서 정보를 조회하여 스냅샷으로 저장
- projectSnapshot: jsonb("project_snapshot").$type<{
- pspid: string; // 견적프로젝트번호
- projNm?: string; // 견적프로젝트명
- sector?: string; // 부문(S / M)
- projMsrm?: number; // 척수
- kunnr?: string; // 선주코드
- kunnrNm?: string; // 선주명
- cls1?: string; // 선급코드
- cls1Nm?: string; // 선급명
- ptype?: string; // 선종코드
- ptypeNm?: string; // 선종명
- pmodelCd?: string; // 선형코드
- pmodelNm?: string; // 선형명
- pmodelSz?: string; // 선형크기
- pmodelUom?: string; // 선형단위
- txt04?: string; // 견적상태코드
- txt30?: string; // 견적상태명
- estmPm?: string; // 견적대표PM 성명
- pspCreatedAt?: Date | string; // 원래 생성 일자
- pspUpdatedAt?: Date | string; // 원래 업데이트 일자
- }>(),
+// 기술영업 RFQ 아이템 테이블 (1:N 관계)
+export const techSalesRfqItems = pgTable("tech_sales_rfq_items", {
+ id: serial("id").primaryKey(),
+ rfqId: integer("rfq_id")
+ .notNull()
+ .references(() => techSalesRfqs.id, { onDelete: "cascade" }),
- // 프로젝트 시리즈 정보 스냅샷
- // 시리즈 정보는 배열 형태로 저장되며, 프로젝트의 모든 시리즈 정보를 포함
- // RFQ 생성 시점의 시리즈 정보를 스냅샷으로 보존함으로써 후속 변경에 영향을 받지 않음
- seriesSnapshot: jsonb("series_snapshot").$type<Array<{
- pspid: string; // 견적프로젝트번호
- sersNo: string; // 시리즈번호
- scDt?: string; // Steel Cutting Date
- klDt?: string; // Keel Laying Date
- lcDt?: string; // Launching Date
- dlDt?: string; // Delivery Date
- dockNo?: string; // 도크코드
- dockNm?: string; // 도크명
- projNo?: string; // SN공사번호(계약후)
- post1?: string; // SN공사명(계약후)
- }>>(),
+ // 아이템 타입별 참조
+ itemShipbuildingId: integer("item_shipbuilding_id")
+ .references(() => itemShipbuilding.id, { onDelete: "cascade" }),
+ // 해양 관련 아이템들
+ itemOffshoreTopId: integer("item_offshore_top_id")
+ .references(() => itemOffshoreTop.id, { onDelete: "cascade" }),
+ itemOffshoreHullId: integer("item_offshore_hull_id")
+ .references(() => itemOffshoreHull.id, { onDelete: "cascade" }),
+
+ // 아이템 타입
+ itemType: varchar("item_type", { length: 20 })
+ .$type<"SHIP" | "TOP" | "HULL">()
+ .notNull(),
+
+ // 생성 정보
+ createdAt: timestamp("created_at").defaultNow().notNull(),
+ updatedAt: timestamp("updated_at").defaultNow().notNull(),
});
// 기술영업 첨부파일 테이블 (RFQ 에 첨부되는 것임)
@@ -227,7 +209,7 @@ export const techSalesVendorQuotations = pgTable(
.references(() => techSalesRfqs.id, { onDelete: "cascade" }),
vendorId: integer("vendor_id")
.notNull()
- .references(() => vendors.id, { onDelete: "set null" }),
+ .references(() => techVendors.id, { onDelete: "set null" }),
// === [시작]견적 응답 정보 ===
quotationCode: varchar("quotation_code", { length: 50 }),
@@ -266,7 +248,7 @@ export const techSalesRfqComments = pgTable(
rfqId: integer("rfq_id")
.notNull()
.references(() => techSalesRfqs.id, { onDelete: "cascade" }),
- vendorId: integer("vendor_id").references(() => vendors.id, {
+ vendorId: integer("vendor_id").references(() => techVendors.id, {
onDelete: "set null",
}),
userId: integer("user_id").references(() => users.id, {
@@ -311,7 +293,7 @@ export const techSalesRfqCommentAttachments = pgTable("tech_sales_rfq_comment_at
uploadedBy: integer("uploaded_by").references(() => users.id, {
onDelete: "set null",
}),
- vendorId: integer("vendor_id").references(() => vendors.id, {
+ vendorId: integer("vendor_id").references(() => techVendors.id, {
onDelete: "set null",
}),
uploadedAt: timestamp("uploaded_at").defaultNow().notNull(),
@@ -324,12 +306,6 @@ export type TechSalesVendorQuotations =
// Relations 정의
export const techSalesRfqsRelations = relations(techSalesRfqs, ({ one, many }) => ({
- // 조선 아이템 관계
- itemShipbuilding: one(itemShipbuilding, {
- fields: [techSalesRfqs.itemShipbuildingId],
- references: [itemShipbuilding.id],
- }),
-
// 프로젝트 관계
biddingProject: one(biddingProjects, {
fields: [techSalesRfqs.biddingProjectId],
@@ -354,11 +330,39 @@ export const techSalesRfqsRelations = relations(techSalesRfqs, ({ one, many }) =
}),
// 하위 관계들
+ rfqItems: many(techSalesRfqItems), // 새로 추가된 1:N 관계
vendorQuotations: many(techSalesVendorQuotations),
attachments: many(techSalesAttachments),
comments: many(techSalesRfqComments),
}));
+// 새로운 RFQ Items 관계
+export const techSalesRfqItemsRelations = relations(techSalesRfqItems, ({ one }) => ({
+ // 상위 RFQ 관계
+ rfq: one(techSalesRfqs, {
+ fields: [techSalesRfqItems.rfqId],
+ references: [techSalesRfqs.id],
+ }),
+
+ // 조선 아이템 관계
+ itemShipbuilding: one(itemShipbuilding, {
+ fields: [techSalesRfqItems.itemShipbuildingId],
+ references: [itemShipbuilding.id],
+ }),
+
+ // 해양 Hull 아이템 관계
+ itemOffshoreHull: one(itemOffshoreHull, {
+ fields: [techSalesRfqItems.itemOffshoreHullId],
+ references: [itemOffshoreHull.id],
+ }),
+
+ // 해양 Top 아이템 관계
+ itemOffshoreTop: one(itemOffshoreTop, {
+ fields: [techSalesRfqItems.itemOffshoreTopId],
+ references: [itemOffshoreTop.id],
+ }),
+}));
+
export const techSalesVendorQuotationsRelations = relations(techSalesVendorQuotations, ({ one, many }) => ({
// 상위 RFQ 관계
rfq: one(techSalesRfqs, {
@@ -367,9 +371,9 @@ export const techSalesVendorQuotationsRelations = relations(techSalesVendorQuota
}),
// 벤더 관계
- vendor: one(vendors, {
+ vendor: one(techVendors, {
fields: [techSalesVendorQuotations.vendorId],
- references: [vendors.id],
+ references: [techVendors.id],
}),
// 사용자 관계
@@ -411,9 +415,9 @@ export const techSalesRfqCommentsRelations = relations(techSalesRfqComments, ({
}),
// 벤더 관계
- vendor: one(vendors, {
+ vendor: one(techVendors, {
fields: [techSalesRfqComments.vendorId],
- references: [vendors.id],
+ references: [techVendors.id],
}),
// 사용자 관계
@@ -466,8 +470,8 @@ export const techSalesRfqCommentAttachmentsRelations = relations(techSalesRfqCom
}),
// 벤더 관계
- vendor: one(vendors, {
+ vendor: one(techVendors, {
fields: [techSalesRfqCommentAttachments.vendorId],
- references: [vendors.id],
+ references: [techVendors.id],
}),
})); \ No newline at end of file
diff --git a/db/schema/techVendors.ts b/db/schema/techVendors.ts
index dcf73611..9cb15ad8 100644
--- a/db/schema/techVendors.ts
+++ b/db/schema/techVendors.ts
@@ -38,11 +38,6 @@ export const techVendors = pgTable("tech_vendors", {
representativeEmail: varchar("representative_email", { length: 255 }),
representativePhone: varchar("representative_phone", { length: 50 }),
representativeBirth: varchar("representative_birth", { length: 20 }),
-
- // 사업자등록번호
- corporateRegistrationNumber: varchar("corporate_registration_number", {
- length: 100,
- }),
items: text("items"),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
@@ -121,7 +116,6 @@ export const techVendorDetailView = pgView("tech_vendor_detail_view").as((qb) =>
representativeEmail: techVendors.representativeEmail,
representativePhone: techVendors.representativePhone,
representativeBirth: techVendors.representativeBirth,
- corporateRegistrationNumber: techVendors.corporateRegistrationNumber,
createdAt: techVendors.createdAt,
updatedAt: techVendors.updatedAt,