diff options
Diffstat (limited to 'db/seeds/rfqSeed.ts')
| -rw-r--r-- | db/seeds/rfqSeed.ts | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/db/seeds/rfqSeed.ts b/db/seeds/rfqSeed.ts new file mode 100644 index 00000000..2d37393d --- /dev/null +++ b/db/seeds/rfqSeed.ts @@ -0,0 +1,147 @@ +// 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); + }); +}
\ No newline at end of file |
