import { PrismaClient } from "@prisma/client"; const prisma = new PrismaClient(); async function main() { console.log("Seeding CRM deals + revenue attribution..."); const brands = await prisma.brand.findMany(); if (brands.length === 0) { console.log("No brands. Run main seed first."); return; } for (const brand of brands) { // Clear existing await prisma.revenueAttribution.deleteMany({ where: { brandId: brand.id } }); await prisma.crmDeal.deleteMany({ where: { brandId: brand.id } }); // Get some conversions to link const conversions = await prisma.conversionEvent.findMany({ where: { brandId: brand.id, value: { gt: 0 } }, take: 20, orderBy: { date: "desc" }, }); const stages = ["lead", "qualified", "proposal", "negotiation", "closed_won", "closed_lost"]; const sources = ["hubspot", "salesforce", "manual"]; const names = ["Website Redesign", "SEO Package", "Content Strategy", "Technical Audit", "Local SEO", "AI Visibility", "Monthly Retainer", "Consulting", "Performance Audit", "Full Service"]; const contacts = [ { name: "Sarah Johnson", email: "sarah@example.com" }, { name: "Mike Chen", email: "mike@company.co" }, { name: "Emily Davis", email: "emily@startup.io" }, { name: "James Wilson", email: "james@agency.com" }, { name: "Lisa Park", email: "lisa@enterprise.com" }, ]; const deals: Array<{ id: string; value: number; channel: string; page: string; type: string; date: Date }> = []; for (let i = 0; i < 15; i++) { const daysAgo = Math.floor(Math.random() * 60); const date = new Date(); date.setDate(date.getDate() - daysAgo); const stage = stages[Math.floor(Math.random() * stages.length)]; const status = stage === "closed_won" ? "won" : stage === "closed_lost" ? "lost" : "open"; const value = Math.round((500 + Math.random() * 9500) / 100) * 100; const contact = contacts[i % contacts.length]; const conv = conversions[i % conversions.length] || null; const deal = await prisma.crmDeal.create({ data: { brandId: brand.id, externalId: `ext_${brand.id}_${i}`, source: sources[Math.floor(Math.random() * sources.length)], contactName: contact.name, contactEmail: contact.email, dealName: `${names[i % names.length]} — ${contact.name}`, value, stage, status, closeDate: status !== "open" ? date : null, conversionId: conv?.id || null, createdAt: date, }, }); deals.push({ id: deal.id, value, channel: conv?.channel || ["organic", "direct", "social"][Math.floor(Math.random() * 3)], page: conv?.landingPage || ["/", "/pricing", "/features", "/contact"][Math.floor(Math.random() * 4)], type: conv?.type || ["form", "phone", "order"][Math.floor(Math.random() * 3)], date, }); } console.log(` CRM: 15 deals for ${brand.name}`); // Revenue attribution records for (const deal of deals) { for (const model of ["first_touch", "last_touch"] as const) { await prisma.revenueAttribution.create({ data: { brandId: brand.id, attributionModel: model, channel: deal.channel, landingPage: deal.page, conversionType: deal.type, revenue: deal.value, creditPct: 100, date: deal.date, dealId: deal.id, }, }); } } console.log(` Attribution: ${deals.length * 2} records (first + last touch) for ${brand.name}`); } console.log("CRM + attribution seeding complete!"); } main() .catch((e) => { console.error(e); process.exit(1); }) .finally(() => prisma.$disconnect());