import { PrismaClient, UserRole, CourtType, CourtStatus, MembershipStatus } from '@prisma/client'; import bcrypt from 'bcryptjs'; const prisma = new PrismaClient(); async function main() { console.log('Starting seed...'); console.log(''); // ============================================================================= // CLEANUP - Delete existing data in correct order // ============================================================================= console.log('Cleaning up existing data...'); await prisma.payment.deleteMany(); await prisma.saleItem.deleteMany(); await prisma.sale.deleteMany(); await prisma.cashRegister.deleteMany(); await prisma.match.deleteMany(); await prisma.tournamentInscription.deleteMany(); await prisma.tournament.deleteMany(); await prisma.booking.deleteMany(); await prisma.membership.deleteMany(); await prisma.membershipPlan.deleteMany(); await prisma.product.deleteMany(); await prisma.productCategory.deleteMany(); await prisma.client.deleteMany(); await prisma.user.deleteMany(); await prisma.court.deleteMany(); await prisma.site.deleteMany(); await prisma.organization.deleteMany(); console.log('Cleanup complete.'); console.log(''); // ============================================================================= // ORGANIZATION // ============================================================================= console.log('Creating organization...'); const organization = await prisma.organization.create({ data: { name: 'Padel Pro Demo', slug: 'padel-pro-demo', settings: { currency: 'MXN', timezone: 'America/Mexico_City', language: 'es', }, }, }); console.log(` Created organization: ${organization.name}`); console.log(''); // ============================================================================= // SITES // ============================================================================= console.log('Creating sites...'); const sitesData = [ { name: 'Sede Norte', slug: 'sede-norte', address: 'Av. Universidad 1000, Col. Del Valle', phone: '+52 55 1234 5678', email: 'norte@padelpro.com', timezone: 'America/Mexico_City', openTime: '07:00', closeTime: '23:00', }, { name: 'Sede Sur', slug: 'sede-sur', address: 'Av. Insurgentes 2000, Col. Roma', phone: '+52 55 2345 6789', email: 'sur@padelpro.com', timezone: 'America/Mexico_City', openTime: '08:00', closeTime: '22:00', }, { name: 'Sede Centro', slug: 'sede-centro', address: 'Calle Reforma 500, Centro Historico', phone: '+52 55 3456 7890', email: 'centro@padelpro.com', timezone: 'America/Mexico_City', openTime: '06:00', closeTime: '24:00', }, ]; const sites = await Promise.all( sitesData.map(async (siteData) => { const site = await prisma.site.create({ data: { organizationId: organization.id, ...siteData, }, }); console.log(` Created site: ${site.name}`); return site; }) ); console.log(''); // ============================================================================= // COURTS (2 per site) // ============================================================================= console.log('Creating courts...'); const courts: { id: string; name: string; siteId: string }[] = []; for (const site of sites) { const courtData = [ { name: 'Cancha 1', type: CourtType.INDOOR, status: CourtStatus.AVAILABLE, pricePerHour: 350, description: 'Cancha techada con iluminacion LED', features: ['Iluminacion LED', 'Techada', 'Cristal panoramico'], displayOrder: 1, }, { name: 'Cancha 2', type: CourtType.INDOOR, status: CourtStatus.AVAILABLE, pricePerHour: 450, description: 'Cancha premium con aire acondicionado', features: ['Iluminacion LED', 'Techada', 'Aire acondicionado', 'Cristal panoramico', 'Premium'], displayOrder: 2, }, ]; for (const court of courtData) { const created = await prisma.court.create({ data: { siteId: site.id, ...court, }, }); courts.push(created); console.log(` Created court: ${site.name} - ${created.name}`); } } console.log(''); // ============================================================================= // ADMIN USER (SUPER_ADMIN) // ============================================================================= console.log('Creating admin users...'); const hashedPassword = await bcrypt.hash('admin123', 10); const adminUser = await prisma.user.create({ data: { organizationId: organization.id, email: 'admin@padelpro.com', password: hashedPassword, firstName: 'Administrador', lastName: 'Sistema', role: UserRole.SUPER_ADMIN, phone: '+52 55 9999 0000', siteIds: sites.map(s => s.id), }, }); console.log(` Created super admin: ${adminUser.email}`); // ============================================================================= // SITE ADMINS (one per site) // ============================================================================= const siteAdminsData = [ { email: 'norte@padelpro.com', firstName: 'Carlos', lastName: 'Rodriguez', site: sites[0] }, { email: 'sur@padelpro.com', firstName: 'Maria', lastName: 'Gonzalez', site: sites[1] }, { email: 'centro@padelpro.com', firstName: 'Luis', lastName: 'Hernandez', site: sites[2] }, ]; for (const adminData of siteAdminsData) { const siteAdmin = await prisma.user.create({ data: { organizationId: organization.id, email: adminData.email, password: hashedPassword, firstName: adminData.firstName, lastName: adminData.lastName, role: UserRole.SITE_ADMIN, siteIds: [adminData.site.id], }, }); // Connect user to site await prisma.site.update({ where: { id: adminData.site.id }, data: { users: { connect: { id: siteAdmin.id }, }, }, }); console.log(` Created site admin: ${siteAdmin.email} (${adminData.site.name})`); } console.log(''); // ============================================================================= // PRODUCT CATEGORIES // ============================================================================= console.log('Creating product categories...'); const categoriesData = [ { name: 'Bebidas', description: 'Bebidas y refrescos', displayOrder: 1 }, { name: 'Snacks', description: 'Botanas y snacks', displayOrder: 2 }, { name: 'Equipamiento', description: 'Equipo y accesorios de padel', displayOrder: 3 }, { name: 'Alquiler', description: 'Articulos en renta', displayOrder: 4 }, ]; const categories: { id: string; name: string }[] = []; for (const catData of categoriesData) { const category = await prisma.productCategory.create({ data: { organizationId: organization.id, ...catData, }, }); categories.push(category); console.log(` Created category: ${category.name}`); } console.log(''); // ============================================================================= // PRODUCTS (for organization, shown in Sede Norte initially) // ============================================================================= console.log('Creating products...'); const bebidasCategory = categories.find(c => c.name === 'Bebidas'); const snacksCategory = categories.find(c => c.name === 'Snacks'); const equipamientoCategory = categories.find(c => c.name === 'Equipamiento'); const alquilerCategory = categories.find(c => c.name === 'Alquiler'); const productsData = [ // Bebidas { name: 'Agua', description: 'Agua natural 600ml', price: 20, costPrice: 8, stock: 100, categoryId: bebidasCategory?.id, sku: 'BEB-001' }, { name: 'Gatorade', description: 'Bebida deportiva 500ml', price: 35, costPrice: 18, stock: 50, categoryId: bebidasCategory?.id, sku: 'BEB-002' }, { name: 'Cerveza', description: 'Cerveza artesanal 355ml', price: 45, costPrice: 22, stock: 48, categoryId: bebidasCategory?.id, sku: 'BEB-003' }, // Snacks { name: 'Papas', description: 'Papas fritas 45g', price: 25, costPrice: 12, stock: 30, categoryId: snacksCategory?.id, sku: 'SNK-001' }, { name: 'Barra energetica', description: 'Barra de proteina 50g', price: 30, costPrice: 15, stock: 25, categoryId: snacksCategory?.id, sku: 'SNK-002' }, // Equipamiento { name: 'Pelotas HEAD', description: 'Tubo de 3 pelotas HEAD Pro', price: 180, costPrice: 90, stock: 20, categoryId: equipamientoCategory?.id, sku: 'EQP-001' }, { name: 'Grip', description: 'Overgrip Wilson Pro', price: 50, costPrice: 25, stock: 40, categoryId: equipamientoCategory?.id, sku: 'EQP-002' }, // Alquiler { name: 'Raqueta alquiler', description: 'Raqueta de padel (por hora)', price: 100, costPrice: 0, stock: 10, categoryId: alquilerCategory?.id, sku: 'ALQ-001', trackStock: false }, ]; for (const productData of productsData) { const product = await prisma.product.create({ data: { organizationId: organization.id, ...productData, }, }); console.log(` Created product: ${product.name} - $${product.price}`); } console.log(''); // ============================================================================= // MEMBERSHIP PLANS // ============================================================================= console.log('Creating membership plans...'); const membershipPlansData = [ { name: 'Basico', description: 'Plan basico mensual con beneficios esenciales', price: 499, durationMonths: 1, courtHours: 2, discountPercent: 10, benefits: ['2 horas gratis de cancha al mes', '10% descuento en reservas', '5% descuento en tienda'], }, { name: 'Premium', description: 'Plan premium con mayores beneficios', price: 899, durationMonths: 1, courtHours: 5, discountPercent: 20, benefits: ['5 horas gratis de cancha al mes', '20% descuento en reservas', '10% descuento en tienda', 'Acceso prioritario a torneos'], }, { name: 'VIP', description: 'Plan VIP con todos los beneficios', price: 1499, durationMonths: 1, courtHours: 10, discountPercent: 30, benefits: ['10 horas gratis de cancha al mes', '30% descuento en reservas', '15% descuento en tienda', 'Acceso prioritario a torneos', 'Invitados con descuento', 'Casillero incluido'], }, ]; const membershipPlans: { id: string; name: string; courtHours: number | null }[] = []; for (const planData of membershipPlansData) { const plan = await prisma.membershipPlan.create({ data: { organizationId: organization.id, ...planData, }, }); membershipPlans.push(plan); console.log(` Created membership plan: ${plan.name} - $${plan.price}/mes`); } console.log(''); // ============================================================================= // SAMPLE CLIENTS // ============================================================================= console.log('Creating sample clients...'); const clientsData = [ { firstName: 'Juan', lastName: 'Perez', email: 'juan.perez@email.com', phone: '+52 55 1111 2222', level: 'Intermedio', preferredHand: 'Derecha', }, { firstName: 'Maria', lastName: 'Garcia', email: 'maria.garcia@email.com', phone: '+52 55 2222 3333', level: 'Avanzado', preferredHand: 'Derecha', }, { firstName: 'Carlos', lastName: 'Lopez', email: 'carlos.lopez@email.com', phone: '+52 55 3333 4444', level: 'Principiante', preferredHand: 'Izquierda', }, { firstName: 'Ana', lastName: 'Martinez', email: 'ana.martinez@email.com', phone: '+52 55 4444 5555', level: 'Intermedio', preferredHand: 'Derecha', }, { firstName: 'Roberto', lastName: 'Sanchez', email: 'roberto.sanchez@email.com', phone: '+52 55 5555 6666', level: 'Avanzado', preferredHand: 'Derecha', }, ]; const clients: { id: string; firstName: string; lastName: string }[] = []; for (const clientData of clientsData) { const client = await prisma.client.create({ data: { organizationId: organization.id, ...clientData, }, }); clients.push(client); console.log(` Created client: ${client.firstName} ${client.lastName}`); } console.log(''); // ============================================================================= // MEMBERSHIP FOR ONE CLIENT (Maria Garcia with Premium) // ============================================================================= console.log('Creating sample membership...'); const premiumPlan = membershipPlans.find(p => p.name === 'Premium'); const mariaClient = clients.find(c => c.firstName === 'Maria'); if (premiumPlan && mariaClient) { const startDate = new Date(); const endDate = new Date(); endDate.setMonth(endDate.getMonth() + 1); const membership = await prisma.membership.create({ data: { planId: premiumPlan.id, clientId: mariaClient.id, startDate, endDate, status: MembershipStatus.ACTIVE, remainingHours: premiumPlan.courtHours, autoRenew: true, }, }); console.log(` Created Premium membership for ${mariaClient.firstName} ${mariaClient.lastName}`); } console.log(''); // ============================================================================= // SUMMARY // ============================================================================= console.log('='.repeat(60)); console.log('Seed completed successfully!'); console.log('='.repeat(60)); console.log(''); console.log('Summary:'); console.log(` - 1 Organization: ${organization.name}`); console.log(` - ${sites.length} Sites`); console.log(` - ${courts.length} Courts (${courts.length / sites.length} per site)`); console.log(` - 4 Users (1 super admin + 3 site admins)`); console.log(` - ${categories.length} Product Categories`); console.log(` - ${productsData.length} Products`); console.log(` - ${membershipPlans.length} Membership Plans`); console.log(` - ${clients.length} Sample Clients`); console.log(` - 1 Active Membership`); console.log(''); console.log('Login credentials:'); console.log(' Super Admin: admin@padelpro.com / admin123'); console.log(' Site Admins: norte@padelpro.com, sur@padelpro.com, centro@padelpro.com / admin123'); console.log(''); } main() .then(async () => { await prisma.$disconnect(); }) .catch(async (e) => { console.error(''); console.error('Error during seed:'); console.error(e); await prisma.$disconnect(); process.exit(1); });