import db from "@/db/db" import { contracts, contractItems } from "@/db/schema/contract" // 실제 경로 import { vendors } from "@/db/schema/vendors" // 실제 경로 import { items } from "@/db/schema/items" // 실제 경로 import { projects } from "@/db/schema/projects" // 실제 경로 import { faker } from "@faker-js/faker" import { eq } from "drizzle-orm" async function main() { console.log("Seeding contracts / contract_items...") // (옵션) 기존 데이터 삭제 await db.delete(contractItems) await db.delete(contracts) // 1) 기존 vendor, item, project 목록 조회 const allVendors = await db.select().from(vendors) const allItems = await db.select().from(items) const allProjects = await db.select().from(projects) if (allVendors.length === 0 || allItems.length === 0 || allProjects.length === 0) { console.log("Vendors / Items / Projects 테이블 중 하나가 비어있습니다. 먼저 해당 테이블을 seed 해주세요.") process.exit(1) } // -- 조선업 맥락에 맞는 예시 문구들 -- const shipyardProjectNamesKR = [ "벌크선 선체 건조", "컨테이너선 엔진 오버홀", "해양 플랜트 모듈 제작", "LNG 운반선 화물창 시공", "FPSO 개조 작업", "밸러스트 수 처리장치 설치", "VLCC 프로펠러 교체", "드릴십 탑사이드 모듈 제작", ] const paymentTermsExamples = [ "선금 30%, 중도금 20%, 잔금 50% (인도 후 60일)", "LC 결제 (신용장 발행 후 30일)", "전액 선결제", "계약금 10%, 선박 명명식 시 40%, 인도 시 50%", ] const deliveryTermsExamples = [ "FOB 부산항", "CIF 상하이항", "DAP 울산조선소", "DDP 거제 옥포조선소", ] const deliveryLocations = [ "부산 영도조선소", "울산 본사 도크 #3", "거제 옥포조선소 해양공장", "목포신항 부두", ] // (여기서는 30개) 계약 생성 const NUM_CONTRACTS = 30 for (let i = 0; i < NUM_CONTRACTS; i++) { // 무작위 협력업체, 프로젝트 선택 const randomVendor = faker.helpers.arrayElement(allVendors) const randomProject = faker.helpers.arrayElement(allProjects) // 예: C-1234 const contractNo = `C-${faker.number.int({ min: 1000, max: 9999 })}` // 예: "조선 프로젝트: 벌크선 선체 건조 - (프로젝트명)" const randomShipyardName = faker.helpers.arrayElement(shipyardProjectNamesKR) const contractName = `조선 프로젝트: ${randomShipyardName} - ${randomProject.name}` // 상태 const randomStatus = faker.helpers.arrayElement([ "ACTIVE", "FINISHED", "CANCELED", "ON_HOLD", ]) // 날짜 const startDate = faker.helpers.maybe(() => faker.date.past({ years: 1 }), { probability: 0.7, }) const endDate = faker.helpers.maybe(() => faker.date.future({ years: 0.5 }), { probability: 0.5, }) // PO에 추가된 필드들에 대해 랜덤 할당 const paymentTerms = faker.helpers.arrayElement(paymentTermsExamples) const deliveryTerms = faker.helpers.arrayElement(deliveryTermsExamples) const deliveryDate = faker.date.future({ years: 1 }) const deliveryLocation = faker.helpers.arrayElement(deliveryLocations) // 가격 관련 (단순 랜덤) const totalAmount = faker.number.float({ min: 5000000, max: 500000000 }) const discount = faker.number.float({ min: 0, max: 500000}) const tax = faker.number.float({ min: 0, max: 1000000 }) const shippingFee = faker.number.float({ min: 0, max: 300000}) const netTotal = totalAmount - discount + tax + shippingFee // 부분 납품/결제 가능 여부 const partialShippingAllowed = faker.datatype.boolean() const partialPaymentAllowed = faker.datatype.boolean() // remarks, version const remarks = faker.helpers.maybe(() => faker.lorem.sentence(), { probability: 0.4, }) const version = 1 // 혹은 faker.number.int({ min: 1, max: 5 }) // DB에 insert const [insertedContract] = await db .insert(contracts) .values({ projectId: randomProject.id, vendorId: randomVendor.id, contractNo, contractName, status: randomStatus, startDate: startDate ?? null, endDate: endDate ?? null, paymentTerms, deliveryTerms, deliveryDate, deliveryLocation, currency: faker.helpers.arrayElement(["KRW", "USD"]), totalAmount, discount, tax, shippingFee, netTotal, partialShippingAllowed, partialPaymentAllowed, remarks: remarks ?? null, version, }) .returning({ id: contracts.id }) const contractId = insertedContract.id console.log(`Inserted Contract #${contractId}: ${contractNo}`) // 3) 각 계약에 대해 2~5개 contract_items const numItems = faker.number.int({ min: 2, max: 5 }) const usedItemIds = new Set() for (let j = 0; j < numItems; j++) { // 중복되지 않게 아이템 추출 let randomItem do { randomItem = faker.helpers.arrayElement(allItems) } while (usedItemIds.has(randomItem.id)) usedItemIds.add(randomItem.id) const quantity = faker.number.int({ min: 1, max: 100 }) // unitPrice: 1천원 ~ 50만원 범위 (소수점 2자리) const unitPrice = faker.number.float({ min: 1000, max: 500000 }) // 세율, 세금, 합계 계산 (예시) const taxRate = faker.helpers.arrayElement([0, 0.05, 0.1]) const taxAmount = parseFloat((unitPrice * quantity * taxRate).toFixed(2)) const totalLineAmount = parseFloat((unitPrice * quantity + taxAmount).toFixed(2)) const description = faker.commerce.productName() // 간단히 예시 const remark = faker.helpers.maybe(() => faker.lorem.sentence(), { probability: 0.3 }) const [insertedContractItem] = await db .insert(contractItems) .values({ contractId, itemId: randomItem.id, description, quantity, unitPrice, taxRate, taxAmount, totalLineAmount, remark: remark ?? null, }) .returning({ id: contractItems.id }) console.log( ` -> Inserted ContractItem #${insertedContractItem.id} (itemId=${randomItem.id})` ) } } console.log("Seeding completed.") process.exit(0) } main().catch((err) => { console.error(err) process.exit(1) })