summaryrefslogtreecommitdiff
path: root/db
diff options
context:
space:
mode:
authorkiman Kim <94714426+rlaks5757@users.noreply.github.com>2025-03-28 13:59:09 +0900
committerGitHub <noreply@github.com>2025-03-28 13:59:09 +0900
commit53e136b022c0b8d6afee7bbf743bdcec49dd4e95 (patch)
treea7cb3cfcae4291b0b76dd497ad596dbb6a328950 /db
parentf839e58817340f09720e477ad610d41994a2cd8c (diff)
parent2bcbef17fadb6799cca97bf612c87fc558dd19ca (diff)
Merge pull request #4 from DTS-Development/feature/kiman
Report Batch, Report Temp Sample Download
Diffstat (limited to 'db')
-rw-r--r--db/migrations/0097_poa_initial_setup.sql95
-rw-r--r--db/schema/contract.ts104
-rw-r--r--db/schema/vendorData.ts321
-rw-r--r--db/seeds_2/poaSeed.ts109
4 files changed, 181 insertions, 448 deletions
diff --git a/db/migrations/0097_poa_initial_setup.sql b/db/migrations/0097_poa_initial_setup.sql
deleted file mode 100644
index fae3f4d1..00000000
--- a/db/migrations/0097_poa_initial_setup.sql
+++ /dev/null
@@ -1,95 +0,0 @@
--- Drop existing tables and views
-DROP VIEW IF EXISTS change_orders_detail_view;
-DROP TABLE IF EXISTS change_order_items CASCADE;
-DROP TABLE IF EXISTS change_orders CASCADE;
-DROP VIEW IF EXISTS poa_detail_view;
-DROP TABLE IF EXISTS poa CASCADE;
-
--- Create POA table
-CREATE TABLE poa (
- id SERIAL PRIMARY KEY,
- contract_no VARCHAR(100) NOT NULL,
- original_contract_no VARCHAR(100) NOT NULL,
- project_id INTEGER NOT NULL,
- vendor_id INTEGER NOT NULL,
- original_contract_name VARCHAR(255) NOT NULL,
- original_status VARCHAR(50) NOT NULL,
- delivery_terms TEXT,
- delivery_date DATE,
- delivery_location VARCHAR(255),
- currency VARCHAR(10),
- total_amount NUMERIC(12,2),
- discount NUMERIC(12,2),
- tax NUMERIC(12,2),
- shipping_fee NUMERIC(12,2),
- net_total NUMERIC(12,2),
- change_reason TEXT,
- approval_status VARCHAR(50) DEFAULT 'PENDING',
- created_at TIMESTAMP NOT NULL DEFAULT NOW(),
- updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
- CONSTRAINT poa_original_contract_no_contracts_contract_no_fk
- FOREIGN KEY (original_contract_no)
- REFERENCES contracts(contract_no)
- ON DELETE CASCADE,
- CONSTRAINT poa_project_id_projects_id_fk
- FOREIGN KEY (project_id)
- REFERENCES projects(id)
- ON DELETE CASCADE,
- CONSTRAINT poa_vendor_id_vendors_id_fk
- FOREIGN KEY (vendor_id)
- REFERENCES vendors(id)
- ON DELETE CASCADE
-);
-
--- Create POA detail view
-CREATE VIEW poa_detail_view AS
-SELECT
- -- POA primary information
- poa.id,
- poa.contract_no,
- poa.change_reason,
- poa.approval_status,
-
- -- Original PO information
- poa.original_contract_no,
- poa.original_contract_name,
- poa.original_status,
- c.start_date as original_start_date,
- c.end_date as original_end_date,
-
- -- Project information
- poa.project_id,
- p.code as project_code,
- p.name as project_name,
-
- -- Vendor information
- poa.vendor_id,
- v.vendor_name,
-
- -- Changed delivery details
- poa.delivery_terms,
- poa.delivery_date,
- poa.delivery_location,
-
- -- Changed financial information
- poa.currency,
- poa.total_amount,
- poa.discount,
- poa.tax,
- poa.shipping_fee,
- poa.net_total,
-
- -- Timestamps
- poa.created_at,
- poa.updated_at,
-
- -- Electronic signature status
- EXISTS (
- SELECT 1
- FROM contract_envelopes
- WHERE contract_envelopes.contract_id = poa.id
- ) as has_signature
-FROM poa
-LEFT JOIN contracts c ON poa.original_contract_no = c.contract_no
-LEFT JOIN projects p ON poa.project_id = p.id
-LEFT JOIN vendors v ON poa.vendor_id = v.id; \ No newline at end of file
diff --git a/db/schema/contract.ts b/db/schema/contract.ts
index c14921bb..10721b4d 100644
--- a/db/schema/contract.ts
+++ b/db/schema/contract.ts
@@ -257,106 +257,4 @@ export const contractsDetailView = pgView("contracts_detail_view").as((qb) => {
});
// Type inference for the view
-export type ContractDetail = typeof contractsDetailView.$inferSelect;
-
-
-
-
-// ============ poa (Purchase Order Amendment) ============
-export const poa = pgTable("poa", {
- // 주 키
- id: integer("id").primaryKey().generatedAlwaysAsIdentity(),
-
- // Form code는 원본과 동일하게 유지
- contractNo: varchar("contract_no", { length: 100 }).notNull(),
-
- // 원본 PO 참조
- originalContractNo: varchar("original_contract_no", { length: 100 })
- .notNull()
- .references(() => contracts.contractNo, { onDelete: "cascade" }),
-
- // 원본 계약 정보
- projectId: integer("project_id")
- .notNull()
- .references(() => projects.id, { onDelete: "cascade" }),
- vendorId: integer("vendor_id")
- .notNull()
- .references(() => vendors.id, { onDelete: "cascade" }),
- originalContractName: varchar("original_contract_name", { length: 255 }).notNull(),
- originalStatus: varchar("original_status", { length: 50 }).notNull(),
-
- // 변경된 납품 조건
- deliveryTerms: text("delivery_terms"), // 변경된 납품 조건
- deliveryDate: date("delivery_date"), // 변경된 납품 기한
- deliveryLocation: varchar("delivery_location", { length: 255 }), // 변경된 납품 장소
-
- // 변경된 가격/금액 관련
- currency: varchar("currency", { length: 10 }), // 변경된 통화
- totalAmount: numeric("total_amount", { precision: 12, scale: 2 }), // 변경된 총 금액
- discount: numeric("discount", { precision: 12, scale: 2 }), // 변경된 할인
- tax: numeric("tax", { precision: 12, scale: 2 }), // 변경된 세금
- shippingFee: numeric("shipping_fee", { precision: 12, scale: 2 }), // 변경된 배송비
- netTotal: numeric("net_total", { precision: 12, scale: 2 }), // 변경된 순 총액
-
- // 변경 사유
- changeReason: text("change_reason"),
-
- // 승인 상태
- approvalStatus: varchar("approval_status", { length: 50 }).default("PENDING"),
-
- // 생성/수정 시각
- createdAt: timestamp("created_at").defaultNow().notNull(),
- updatedAt: timestamp("updated_at").defaultNow().notNull(),
-})
-
-// 타입 추론
-export type POA = typeof poa.$inferSelect
-
-// ============ poa_detail_view ============
-export const poaDetailView = pgView("poa_detail_view").as((qb) => {
- return qb
- .select({
- // POA primary information
- id: poa.id,
- contractNo: poa.contractNo,
- projectId: contracts.projectId,
- vendorId: contracts.vendorId,
- changeReason: poa.changeReason,
- approvalStatus: poa.approvalStatus,
-
- // Original PO information
- originalContractName: sql<string>`${contracts.contractName}`.as('original_contract_name'),
- originalStatus: sql<string>`${contracts.status}`.as('original_status'),
- originalStartDate: sql<Date>`${contracts.startDate}`.as('original_start_date'),
- originalEndDate: sql<Date>`${contracts.endDate}`.as('original_end_date'),
-
- // Changed delivery details
- deliveryTerms: poa.deliveryTerms,
- deliveryDate: poa.deliveryDate,
- deliveryLocation: poa.deliveryLocation,
-
- // Changed financial information
- currency: poa.currency,
- totalAmount: poa.totalAmount,
- discount: poa.discount,
- tax: poa.tax,
- shippingFee: poa.shippingFee,
- netTotal: poa.netTotal,
-
- // Timestamps
- createdAt: poa.createdAt,
- updatedAt: poa.updatedAt,
-
- // Electronic signature status
- hasSignature: sql<boolean>`EXISTS (
- SELECT 1
- FROM ${contractEnvelopes}
- WHERE ${contractEnvelopes.contractId} = ${poa.id}
- )`.as('has_signature'),
- })
- .from(poa)
- .leftJoin(contracts, eq(poa.contractNo, contracts.contractNo))
-});
-
-// Type inference for the view
-export type POADetail = typeof poaDetailView.$inferSelect; \ No newline at end of file
+export type ContractDetail = typeof contractsDetailView.$inferSelect; \ No newline at end of file
diff --git a/db/schema/vendorData.ts b/db/schema/vendorData.ts
index 92a92c8e..01a10b7e 100644
--- a/db/schema/vendorData.ts
+++ b/db/schema/vendorData.ts
@@ -3,32 +3,41 @@ import {
text,
varchar,
timestamp,
- integer, numeric, date, unique, serial, jsonb, uniqueIndex
-} from "drizzle-orm/pg-core"
-import { contractItems } from "./contract"
-
-export const forms = pgTable("forms", {
- id: integer("id").primaryKey().generatedAlwaysAsIdentity(),
- contractItemId: integer("contract_item_id")
+ integer,
+ numeric,
+ date,
+ unique,
+ serial,
+ jsonb,
+ uniqueIndex,
+ } from "drizzle-orm/pg-core";
+ import { contractItems } from "./contract";
+
+ export const forms = pgTable(
+ "forms",
+ {
+ id: integer("id").primaryKey().generatedAlwaysAsIdentity(),
+ contractItemId: integer("contract_item_id")
.notNull()
.references(() => contractItems.id, { onDelete: "cascade" }),
- formCode: varchar("form_code", { length: 100 }).notNull(),
- formName: varchar("form_name", { length: 255 }).notNull(),
- // tagType: varchar("tag_type", { length: 50 }).notNull(),
- // class: varchar("class", { length: 100 }).notNull(),
- createdAt: timestamp("created_at").defaultNow().notNull(),
- updatedAt: timestamp("updated_at").defaultNow().notNull(),
-}, (table) => {
- return {
+ formCode: varchar("form_code", { length: 100 }).notNull(),
+ formName: varchar("form_name", { length: 255 }).notNull(),
+ // tagType: varchar("tag_type", { length: 50 }).notNull(),
+ // class: varchar("class", { length: 100 }).notNull(),
+ createdAt: timestamp("created_at").defaultNow().notNull(),
+ updatedAt: timestamp("updated_at").defaultNow().notNull(),
+ },
+ (table) => {
+ return {
// contractItemId와 formCode의 조합을 유니크하게 설정
- contractItemFormCodeUnique: uniqueIndex("contract_item_form_code_unique").on(
- table.contractItemId,
- table.formCode
- ),
+ contractItemFormCodeUnique: uniqueIndex(
+ "contract_item_form_code_unique"
+ ).on(table.contractItemId, table.formCode),
+ };
}
-})
-
-export const rfqAttachments = pgTable("form_templates", {
+ );
+
+ export const rfqAttachments = pgTable("form_templates", {
id: serial("id").primaryKey(),
formId: integer("form_id").references(() => forms.id),
fileName: varchar("file_name", { length: 255 }).notNull(),
@@ -36,175 +45,204 @@ export const rfqAttachments = pgTable("form_templates", {
createdAt: timestamp("created_at").defaultNow().notNull(),
udpatedAt: timestamp("updated_at").defaultNow().notNull(),
+ });
-});
-
-
-export const formMetas = pgTable("form_metas", {
+ export const formMetas = pgTable("form_metas", {
id: serial("id").primaryKey(),
formCode: varchar("form_code", { length: 50 }).notNull(),
formName: varchar("form_name", { length: 255 }).notNull(),
columns: jsonb("columns").notNull(),
- createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
- updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull(),
-})
-
-export const formEntries = pgTable("form_entries", {
+ createdAt: timestamp("created_at", { withTimezone: true })
+ .defaultNow()
+ .notNull(),
+ updatedAt: timestamp("updated_at", { withTimezone: true })
+ .defaultNow()
+ .notNull(),
+ });
+
+ export const formEntries = pgTable("form_entries", {
id: serial("id").primaryKey(),
formCode: varchar("form_code", { length: 50 }).notNull(),
data: jsonb("data").notNull(),
contractItemId: integer("contract_item_id")
- .notNull()
- .references(() => contractItems.id, { onDelete: "cascade" }),
- createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
- updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull(),
-})
-
-
-// ============ tags (각 계약 아이템에 대한 Tag) ============
-// "어느 계약의 어느 아이템에 대한 태그"임을 나타내려면 contract_items를 참조
-export const tags = pgTable("tags", {
+ .notNull()
+ .references(() => contractItems.id, { onDelete: "cascade" }),
+ createdAt: timestamp("created_at", { withTimezone: true })
+ .defaultNow()
+ .notNull(),
+ updatedAt: timestamp("updated_at", { withTimezone: true })
+ .defaultNow()
+ .notNull(),
+ });
+
+ // ============ tags (각 계약 아이템에 대한 Tag) ============
+ // "어느 계약의 어느 아이템에 대한 태그"임을 나타내려면 contract_items를 참조
+ export const tags = pgTable("tags", {
id: integer("id").primaryKey().generatedAlwaysAsIdentity(),
-
+
// 이 Tag가 속한 "계약 내 아이템" (즉 contract_items.id)
contractItemId: integer("contract_item_id")
- .notNull()
- .references(() => contractItems.id, { onDelete: "cascade" }),
-
- formId: integer("form_id")
- .references(() => forms.id, { onDelete: "set null" }),
-
+ .notNull()
+ .references(() => contractItems.id, { onDelete: "cascade" }),
+
+ formId: integer("form_id").references(() => forms.id, {
+ onDelete: "set null",
+ }),
+
tagNo: varchar("tag_no", { length: 100 }).notNull(),
tagType: varchar("tag_type", { length: 50 }).notNull(),
class: varchar("class", { length: 100 }).notNull(),
description: text("description"),
-
+
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
-})
-
-export type Tag = typeof tags.$inferSelect
-export type Form = typeof forms.$inferSelect
-export type NewTag = typeof tags.$inferInsert
-
-export const tagTypes = pgTable("tag_types", {
+ });
+
+ export type Tag = typeof tags.$inferSelect;
+ export type Form = typeof forms.$inferSelect;
+ export type NewTag = typeof tags.$inferInsert;
+
+ export const tagTypes = pgTable("tag_types", {
code: varchar("code", { length: 50 }).primaryKey(),
description: text("description").notNull(),
-
- createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
- updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull(),
-})
-
-export const tagSubfields = pgTable("tag_subfields", {
- id: serial("id").primaryKey(),
-
- // 외래키: tagTypeCode -> tagTypes.code
- tagTypeCode: varchar("tag_type_code", { length: 50 })
+
+ createdAt: timestamp("created_at", { withTimezone: true })
+ .defaultNow()
+ .notNull(),
+ updatedAt: timestamp("updated_at", { withTimezone: true })
+ .defaultNow()
+ .notNull(),
+ });
+
+ export const tagSubfields = pgTable(
+ "tag_subfields",
+ {
+ id: serial("id").primaryKey(),
+
+ // 외래키: tagTypeCode -> tagTypes.code
+ tagTypeCode: varchar("tag_type_code", { length: 50 })
.notNull()
.references(() => tagTypes.code, { onDelete: "cascade" }),
-
- /**
- * 나머지 필드
- */
- // tagTypeDescription: -> 이제 불필요. tagTypes.description로 join
- attributesId: varchar("attributes_id", { length: 50 }).notNull(),
- attributesDescription: text("attributes_description").notNull(),
-
- expression: text("expression"),
- delimiter: varchar("delimiter", { length: 10 }),
-
- sortOrder: integer("sort_order").default(0).notNull(),
-
- createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
- updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull(),
-}, (table) => {
- return {
+
+ /**
+ * 나머지 필드
+ */
+ // tagTypeDescription: -> 이제 불필요. tagTypes.description로 join
+ attributesId: varchar("attributes_id", { length: 50 }).notNull(),
+ attributesDescription: text("attributes_description").notNull(),
+
+ expression: text("expression"),
+ delimiter: varchar("delimiter", { length: 10 }),
+
+ sortOrder: integer("sort_order").default(0).notNull(),
+
+ createdAt: timestamp("created_at", { withTimezone: true })
+ .defaultNow()
+ .notNull(),
+ updatedAt: timestamp("updated_at", { withTimezone: true })
+ .defaultNow()
+ .notNull(),
+ },
+ (table) => {
+ return {
uniqTagTypeAttribute: unique("uniq_tag_type_attribute").on(
- table.tagTypeCode,
- table.attributesId
+ table.tagTypeCode,
+ table.attributesId
),
- };
-});
-
-export const tagSubfieldOptions = pgTable("tag_subfield_options", {
+ };
+ }
+ );
+
+ export const tagSubfieldOptions = pgTable("tag_subfield_options", {
id: serial("id").primaryKey(),
-
+
// 어떤 subfield에 속하는 옵션인지
attributesId: varchar("attributes_id", { length: 50 })
- .notNull()
- .references(() => tagSubfields.attributesId, { onDelete: "cascade" }),
-
+ .notNull()
+ .references(() => tagSubfields.attributesId, { onDelete: "cascade" }),
+
/**
* 실제 코드 (예: "PM", "AA", "VB", "VAR", "01", "02" ...)
*/
code: varchar("code", { length: 50 }).notNull(),
-
+
/**
* 사용자에게 보여줄 레이블 (예: "Pump", "Pneumatic Motor", "Ball Valve", ...)
*/
label: text("label").notNull(),
-
+
/**
* 생성/수정 시각 (선택)
*/
- createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
- updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull(),
-})
-
-export const tagClasses = pgTable("tag_classes", {
+ createdAt: timestamp("created_at", { withTimezone: true })
+ .defaultNow()
+ .notNull(),
+ updatedAt: timestamp("updated_at", { withTimezone: true })
+ .defaultNow()
+ .notNull(),
+ });
+
+ export const tagClasses = pgTable("tag_classes", {
id: integer("id").primaryKey().generatedAlwaysAsIdentity(),
-
+
// 기존 code/label
code: varchar("code", { length: 100 }).notNull(),
label: text("label").notNull(),
-
+
// 새 필드: tagTypeCode -> references tagTypes.code
tagTypeCode: varchar("tag_type_code", { length: 50 })
- .notNull()
- .references(() => tagTypes.code, { onDelete: "cascade" }),
-
+ .notNull()
+ .references(() => tagTypes.code, { onDelete: "cascade" }),
+
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
-})
-
-export const tagTypeClassFormMappings = pgTable("tag_type_class_form_mappings", {
- id: serial("id").primaryKey(),
-
- tagTypeLabel: varchar("tag_type_label", { length: 255 }).notNull(),
- classLabel: varchar("class_label", { length: 255 }).notNull(),
-
- formCode: varchar("form_code", { length: 50 }).notNull(),
- formName: varchar("form_name", { length: 255 }).notNull(),
-
- createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
- updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull(),
-})
-
-export type TagTypeClassFormMappings = typeof tagTypeClassFormMappings.$inferSelect
-export type TagSubfields = typeof tagSubfields.$inferSelect
-export type TagSubfieldOption = typeof tagSubfieldOptions.$inferSelect
-export type TagClasses = typeof tagClasses.$inferSelect
-
-
-export const viewTagSubfields = pgTable("view_tag_subfields", {
+ });
+
+ export const tagTypeClassFormMappings = pgTable(
+ "tag_type_class_form_mappings",
+ {
+ id: serial("id").primaryKey(),
+
+ tagTypeLabel: varchar("tag_type_label", { length: 255 }).notNull(),
+ classLabel: varchar("class_label", { length: 255 }).notNull(),
+
+ formCode: varchar("form_code", { length: 50 }).notNull(),
+ formName: varchar("form_name", { length: 255 }).notNull(),
+
+ createdAt: timestamp("created_at", { withTimezone: true })
+ .defaultNow()
+ .notNull(),
+ updatedAt: timestamp("updated_at", { withTimezone: true })
+ .defaultNow()
+ .notNull(),
+ }
+ );
+
+ export type TagTypeClassFormMappings =
+ typeof tagTypeClassFormMappings.$inferSelect;
+ export type TagSubfields = typeof tagSubfields.$inferSelect;
+ export type TagSubfieldOption = typeof tagSubfieldOptions.$inferSelect;
+ export type TagClasses = typeof tagClasses.$inferSelect;
+
+ export const viewTagSubfields = pgTable("view_tag_subfields", {
id: integer("id").primaryKey(),
-
+
tagTypeCode: varchar("tag_type_code", { length: 50 }).notNull(),
tagTypeDescription: text("tag_type_description"),
attributesId: varchar("attributes_id", { length: 50 }).notNull(),
attributesDescription: text("attributes_description").notNull(),
-
+
expression: text("expression"),
delimiter: varchar("delimiter", { length: 10 }),
sortOrder: integer("sort_order").default(0).notNull(),
-
+
createdAt: timestamp("created_at", { withTimezone: true }),
updatedAt: timestamp("updated_at", { withTimezone: true }),
-})
-
-export type ViewTagSubfields = typeof viewTagSubfields.$inferSelect
-
-export const vendorDataReportTemps = pgTable("vendor_data_report_temps", {
+ });
+
+ export type ViewTagSubfields = typeof viewTagSubfields.$inferSelect;
+
+ export const vendorDataReportTemps = pgTable("vendor_data_report_temps", {
id: serial("id").primaryKey(),
contractItemId: integer("contract_item_id")
.notNull()
@@ -215,11 +253,12 @@ export const vendorDataReportTemps = pgTable("vendor_data_report_temps", {
fileName: varchar("file_name", { length: 255 }).notNull(),
filePath: varchar("file_path", { length: 1024 }).notNull(),
createdAt: timestamp("created_at", { withTimezone: true })
- .defaultNow()
- .notNull(),
- updatedAt: timestamp("updated_at", { withTimezone: true })
- .defaultNow()
- .notNull(),
+ .defaultNow()
+ .notNull(),
+ updatedAt: timestamp("updated_at", { withTimezone: true })
+ .defaultNow()
+ .notNull(),
});
- export type VendorDataReportTemps = typeof vendorDataReportTemps.$inferSelect; \ No newline at end of file
+ export type VendorDataReportTemps = typeof vendorDataReportTemps.$inferSelect;
+
diff --git a/db/seeds_2/poaSeed.ts b/db/seeds_2/poaSeed.ts
deleted file mode 100644
index d93cde14..00000000
--- a/db/seeds_2/poaSeed.ts
+++ /dev/null
@@ -1,109 +0,0 @@
-import { faker } from "@faker-js/faker"
-import db from "../db"
-import { contracts, poa } from "../schema/contract"
-import { sql } from "drizzle-orm"
-
-export async function seedPOA({ count = 10 } = {}) {
- try {
- console.log(`📝 Inserting POA ${count}`)
-
- // 기존 POA 데이터 삭제 및 ID 시퀀스 초기화
- await db.delete(poa)
- await db.execute(sql`ALTER SEQUENCE poa_id_seq RESTART WITH 1;`)
- console.log("✅ 기존 POA 데이터 삭제 및 ID 초기화 완료")
-
- // 조선업 맥락에 맞는 예시 문구들
- const deliveryTermsExamples = [
- "FOB 부산항",
- "CIF 상하이항",
- "DAP 울산조선소",
- "DDP 거제 옥포조선소",
- ]
- const deliveryLocations = [
- "부산 영도조선소",
- "울산 본사 도크 #3",
- "거제 옥포조선소 해양공장",
- "목포신항 부두",
- ]
- const changeReasonExamples = [
- "납품 일정 조정 필요",
- "자재 사양 변경",
- "선박 설계 변경에 따른 수정",
- "추가 부품 요청",
- "납품 장소 변경",
- "계약 조건 재협상"
- ]
-
- // 1. 기존 계약(PO) 목록 가져오기
- const existingContracts = await db.select().from(contracts)
- console.log(`Found ${existingContracts.length} existing contracts`)
-
- if (existingContracts.length === 0) {
- throw new Error("계약(PO) 데이터가 없습니다. 먼저 계약 데이터를 생성해주세요.")
- }
-
- // 2. POA 생성
- for (let i = 0; i < count; i++) {
- try {
- // 랜덤으로 원본 계약 선택
- const originalContract = faker.helpers.arrayElement(existingContracts)
- console.log(`Selected original contract: ${originalContract.contractNo}`)
-
- // POA 생성
- const totalAmount = faker.number.float({ min: 5000000, max: 500000000 })
- const discount = faker.helpers.maybe(() => faker.number.float({ min: 0, max: 500000 }), { probability: 0.3 })
- const tax = faker.helpers.maybe(() => faker.number.float({ min: 0, max: 1000000 }), { probability: 0.8 })
- const shippingFee = faker.helpers.maybe(() => faker.number.float({ min: 0, max: 300000 }), { probability: 0.5 })
- const netTotal = totalAmount - (discount || 0) + (tax || 0) + (shippingFee || 0)
-
- const poaData = {
- // Form code는 원본과 동일하게 유지
- contractNo: originalContract.contractNo,
- originalContractNo: originalContract.contractNo,
- projectId: originalContract.projectId,
- vendorId: originalContract.vendorId,
- originalContractName: originalContract.contractName,
- originalStatus: originalContract.status,
-
- // 변경 가능한 정보들
- deliveryTerms: faker.helpers.arrayElement(deliveryTermsExamples),
- deliveryDate: faker.helpers.maybe(() => faker.date.future().toISOString(), { probability: 0.7 }),
- deliveryLocation: faker.helpers.arrayElement(deliveryLocations),
- currency: "KRW",
- totalAmount: totalAmount.toString(),
- discount: discount?.toString(),
- tax: tax?.toString(),
- shippingFee: shippingFee?.toString(),
- netTotal: netTotal.toString(),
- changeReason: faker.helpers.arrayElement(changeReasonExamples),
- approvalStatus: faker.helpers.arrayElement(["PENDING", "APPROVED", "REJECTED"]),
- createdAt: new Date(),
- updatedAt: new Date(),
- }
-
- console.log("POA data:", poaData)
-
- await db.insert(poa).values(poaData)
- console.log(`Created POA for contract: ${originalContract.contractNo}`)
- } catch (error) {
- console.error(`Error creating POA ${i + 1}:`, error)
- throw error
- }
- }
-
- console.log(`✅ Successfully added ${count} new POAs`)
- } catch (error) {
- console.error("Error in seedPOA:", error)
- throw error
- }
-}
-
-// 실행
-if (require.main === module) {
- seedPOA({ count: 5 })
- .then(() => process.exit(0))
- .catch((error) => {
- console.error(error)
- process.exit(1)
- })
-} \ No newline at end of file