summaryrefslogtreecommitdiff
path: root/db/seeds_2/rfqSeed.ts
diff options
context:
space:
mode:
Diffstat (limited to 'db/seeds_2/rfqSeed.ts')
-rw-r--r--db/seeds_2/rfqSeed.ts148
1 files changed, 148 insertions, 0 deletions
diff --git a/db/seeds_2/rfqSeed.ts b/db/seeds_2/rfqSeed.ts
new file mode 100644
index 00000000..f2cde1b2
--- /dev/null
+++ b/db/seeds_2/rfqSeed.ts
@@ -0,0 +1,148 @@
+// db/seed/rfqSeed.ts
+import { faker } from "@faker-js/faker";
+import db from "@/db/db"
+import { eq, inArray, desc } from "drizzle-orm";
+
+// 스키마 import
+import {
+ rfqs, rfqItems, rfqVendors, vendorQuotes, rfqAttachments, rfqComments, rfqEvaluations,
+ Rfq, RfqItem, RfqVendor, VendorQuote, RfqAttach, RfqComment, RfqEvaluation
+} from "../schema/rfq";
+import { vendors } from "../schema/vendors";
+import { users } from "../schema/users";
+import { items } from "../schema/items";
+
+async function generateRfq(index: number, allUsers: any[], allVendors: any[], allItems: any[]) {
+ const year = faker.number.int({ min: 2022, max: 2024 });
+ const sequence = String(index + 1).padStart(3, "0");
+ const rfqCode = `RFQ-${year}-${sequence}`;
+
+ // 상태별 비율 설정
+ const statusDistribution = {
+ DRAFT: 0.3, // 30%
+ PUBLISHED: 0.3, // 30%
+ EVALUATION: 0.2, // 20%
+ AWARDED: 0.2 // 20%
+ };
+
+ // 랜덤 상태 결정
+ const rand = Math.random();
+ let status: "DRAFT" | "PUBLISHED" | "EVALUATION" | "AWARDED";
+ if (rand < statusDistribution.DRAFT) status = "DRAFT";
+ else if (rand < statusDistribution.DRAFT + statusDistribution.PUBLISHED) status = "PUBLISHED";
+ else if (rand < statusDistribution.DRAFT + statusDistribution.PUBLISHED + statusDistribution.EVALUATION) status = "EVALUATION";
+ else status = "AWARDED";
+
+ // RFQ 생성
+ const [rfq] = await db.insert(rfqs).values({
+ rfqCode,
+ description: faker.commerce.productDescription(),
+ projectCode: `PRJ-${faker.string.alphanumeric(6).toUpperCase()}`,
+ projectName: faker.company.catchPhrase(),
+ dueDate: faker.date.future(),
+ status,
+ createdBy: faker.helpers.arrayElement(allUsers).id,
+ }).returning();
+
+ // 3-10개의 items 추가
+ const itemCount = faker.number.int({ min: 3, max: 10 });
+ const selectedItems = faker.helpers.arrayElements(allItems, itemCount);
+ for (const item of selectedItems) {
+ await db.insert(rfqItems).values({
+ rfqId: rfq.id,
+ itemCode: item.itemCode,
+ description: faker.commerce.productDescription(),
+ quantity: faker.number.float({ min: 1, max: 1000, fractionDigits: 2 }),
+ uom: faker.helpers.arrayElement(["EA", "KG", "M", "L", "SET"]),
+ });
+ }
+
+ // 2-5개의 vendors 초대
+ const vendorCount = faker.number.int({ min: 2, max: 5 });
+ const selectedVendors = faker.helpers.arrayElements(allVendors, vendorCount);
+ for (const vendor of selectedVendors) {
+ await db.insert(rfqVendors).values({
+ rfqId: rfq.id,
+ vendorId: vendor.id,
+ status: faker.helpers.arrayElement(["INVITED", "ACCEPTED", "REJECTED", "QUOTED"]),
+ });
+
+ // 50% 확률로 quote 생성
+ if (Math.random() > 0.5) {
+ await db.insert(vendorQuotes).values({
+ rfqId: rfq.id,
+ vendorId: vendor.id,
+ totalAmount: faker.number.float({ min: 1000, max: 1000000, fractionDigits: 2 }),
+ currency: faker.helpers.arrayElement(["USD", "EUR", "KRW"]),
+ leadTime: `${faker.number.int({ min: 1, max: 52 })} weeks`,
+ notes: faker.lorem.paragraph(),
+ });
+ }
+
+ // 30% 확률로 attachment 추가
+ if (Math.random() > 0.7) {
+ await db.insert(rfqAttachments).values({
+ rfqId: rfq.id,
+ vendorId: vendor.id,
+ fileName: `${faker.system.fileName()}.pdf`,
+ filePath: `/uploads/rfq/${rfq.id}/${faker.system.fileName()}.pdf`,
+ });
+ }
+
+ // 40% 확률로 comment 추가
+ if (Math.random() > 0.6) {
+ await db.insert(rfqComments).values({
+ rfqId: rfq.id,
+ vendorId: vendor.id,
+ commentText: faker.lorem.paragraph(),
+ commentedBy: faker.helpers.arrayElement(allUsers).id,
+ });
+ }
+
+ // EVALUATION 또는 AWARDED 상태인 경우 평가 데이터 추가
+ if (status === "EVALUATION" || status === "AWARDED") {
+ await db.insert(rfqEvaluations).values({
+ rfqId: rfq.id,
+ vendorId: vendor.id,
+ evalType: faker.helpers.arrayElement(["TBE", "CBE"]),
+ result: faker.helpers.arrayElement(["PASS", "FAIL", "ACCEPTABLE"]),
+ notes: faker.lorem.paragraph(),
+ });
+ }
+ }
+
+ return rfq;
+}
+
+export async function seedRfqData(input: { count: number }) {
+ try {
+ const allUsers = await db.select().from(users);
+ const allVendors = await db.select().from(vendors);
+ const allItems = await db.select().from(items);
+
+ // 현재 가장 큰 RFQ 코드 찾기
+ const [lastRfq] = await db.select()
+ .from(rfqs)
+ .orderBy(desc(rfqs.rfqCode))
+ .limit(1);
+
+ // RFQ-YYYY-ddd 형식에서 마지막 번호 추출
+ const startIndex = lastRfq?.rfqCode
+ ? parseInt(lastRfq.rfqCode.split('-')[2])
+ : 0;
+
+ console.log("📝 Generating RFQ data...", { lastRfqCode: lastRfq?.rfqCode, startIndex });
+
+ const generatedRfqs = [];
+ for (let i = 0; i < input.count; i++) {
+ const rfq = await generateRfq(startIndex + i, allUsers, allVendors, allItems);
+ generatedRfqs.push(rfq);
+ }
+
+ console.log(`✅ Successfully generated ${generatedRfqs.length} new RFQs with related data`);
+ return generatedRfqs;
+ } catch (err) {
+ console.error("Failed to seed RFQ data:", err);
+ throw err;
+ }
+} \ No newline at end of file