// db/seed/rfqSeed.ts import { faker } from "@faker-js/faker"; import db from "@/db/db" import { eq, inArray } 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"; export async function seedRfqData() { // 1) 기존 데이터 삭제 (참조 순서 유의) await db.delete(rfqEvaluations); await db.delete(rfqComments); await db.delete(rfqAttachments); await db.delete(vendorQuotes); await db.delete(rfqVendors); await db.delete(rfqItems); await db.delete(rfqs); // (협력업체 목록이 이미 존재한다고 가정) // 혹은 필요한 경우 vendors도 시드할 수 있음 const existingVendors = await db.select().from(vendors); if (existingVendors.length === 0) { console.log("No vendors found. Please seed vendors first."); return; } // 2) N개의 RFQ 생성 const rfqCount = 5; const rfqIds: number[] = []; for (let i = 0; i < rfqCount; i++) { const newRfqData = { rfqCode: `RFQ-${faker.string.alpha({ length: 4 }).toUpperCase()}-${faker.number.int({ min: 100, max: 999, })}`, projectCode: `PRJ-${faker.number.int({ min: 1000, max: 9999 })}`, projectName: faker.company.name(), dueDate: faker.date.future(), // 임의 미래 날짜 status: faker.helpers.arrayElement(["DRAFT", "PUBLISHED", "EVALUATION", "AWARDED"]), createdBy: faker.number.int({ min: 1, max: 10 }), }; const [insertedRfq] = await db.insert(rfqs).values(newRfqData).returning(); rfqIds.push(insertedRfq.id); } // 3) For each RFQ, create items, vendors, quotes, attachments, comments, evaluations for (const rfqId of rfqIds) { // 3-1) RFQ Items const itemCount = faker.number.int({ min: 1, max: 3 }); const rfqItemIds: number[] = []; for (let j = 0; j < itemCount; j++) { const newItem = { rfqId, itemCode: `ITEM-${faker.string.alphanumeric({ length: 5 }).toUpperCase()}`, itemName: faker.commerce.productName(), description: faker.commerce.productDescription(), quantity: faker.number.float({ min: 1, max: 20, fractionDigits: 2 }), uom: faker.helpers.arrayElement(["EA", "KG", "BOX"]), }; const [insertedItem] = await db.insert(rfqItems).values(newItem).returning(); rfqItemIds.push(insertedItem.id); } // 3-2) RFQ Vendors // - 랜덤으로 2~3개 협력업체를 pick const pickedVendors = faker.helpers.arrayElements(existingVendors, faker.number.int({ min: 2, max: 3 })); for (const ven of pickedVendors) { const newRfqVendor = { rfqId, vendorId: ven.id, status: faker.helpers.arrayElement(["INVITED", "ACCEPTED", "REJECTED", "QUOTED"]), }; const [insertedRfqVendor] = await db.insert(rfqVendors).values(newRfqVendor).returning(); // 3-3) 임의로 협력업체 Quotes 생성 (50% 확률) if (faker.datatype.boolean()) { const newQuote = { rfqId, vendorId: ven.id, totalAmount: faker.number.float({ min: 1000, max: 50000, fractionDigits: 2 }), currency: faker.helpers.arrayElement(["USD", "EUR", "KRW"]), leadTime: `${faker.number.int({ min: 10, max: 40 })} days`, notes: faker.lorem.sentence(), }; await db.insert(vendorQuotes).values(newQuote); } } // 3-4) Attachments (랜덤 0~2개) const attachCount = faker.number.int({ min: 0, max: 2 }); for (let a = 0; a < attachCount; a++) { const newAttach = { rfqId, vendorId: null, // or pick some vendorId fileName: faker.system.fileName(), filePath: faker.system.filePath(), // evaluationId: null, }; await db.insert(rfqAttachments).values(newAttach); } // 3-5) Comments (랜덤 1~2개) const commentCount = faker.number.int({ min: 1, max: 2 }); for (let c = 0; c < commentCount; c++) { const newComment = { rfqId, vendorId: null, commentText: faker.lorem.sentence(), commentedBy: faker.number.int({ min: 1, max: 10 }), // evaluationId: null, }; await db.insert(rfqComments).values(newComment); } // 3-6) Evaluations (랜덤 0~1개) if (faker.datatype.boolean()) { const newEval = { rfqId, vendorId: faker.helpers.arrayElement(pickedVendors).id, evalType: faker.helpers.arrayElement(["TBE", "CBE"]), result: faker.helpers.arrayElement(["PASS", "FAIL", "ACCEPTABLE"]), notes: faker.lorem.sentences(2), }; await db.insert(rfqEvaluations).values(newEval); } } console.log(`✅ Seeded ${rfqIds.length} RFQs (with items, vendors, quotes, attachments, comments, evaluations).`); } if (require.main === module) { seedRfqData() .then(() => { console.log("RFQ seeding complete!"); process.exit(0); }) .catch((err) => { console.error("RFQ seeding failed:", err); process.exit(1); }); }