- Organization: Cabo Pickleball Club, Mazatlan timezone - Single site: Corridor Courts, Cabo San Lucas - 6 outdoor courts at 300 MXN/person - Admin: ivan@horuxfin.com - 5 membership plans: Day Pass, 10-Day, 10-Morning, Monthly, Family - Pickleball products replacing padel items Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
394 lines
13 KiB
TypeScript
394 lines
13 KiB
TypeScript
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: 'Cabo Pickleball Club',
|
|
slug: 'cabo-pickleball-club',
|
|
settings: {
|
|
currency: 'MXN',
|
|
timezone: 'America/Mazatlan',
|
|
language: 'en',
|
|
},
|
|
},
|
|
});
|
|
|
|
console.log(` Created organization: ${organization.name}`);
|
|
console.log('');
|
|
|
|
// =============================================================================
|
|
// SITES
|
|
// =============================================================================
|
|
console.log('Creating site...');
|
|
|
|
const sitesData = [
|
|
{
|
|
name: 'Corridor Courts',
|
|
slug: 'corridor-courts',
|
|
address: 'Corridor area, Cabo San Lucas, BCS',
|
|
phone: '+52-624-151-5455',
|
|
email: 'topdogcabo@yahoo.com',
|
|
timezone: 'America/Mazatlan',
|
|
openTime: '07:00',
|
|
closeTime: '22: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 (6 outdoor courts)
|
|
// =============================================================================
|
|
console.log('Creating courts...');
|
|
|
|
const courts: { id: string; name: string; siteId: string }[] = [];
|
|
|
|
for (let i = 1; i <= 6; i++) {
|
|
const created = await prisma.court.create({
|
|
data: {
|
|
siteId: sites[0].id,
|
|
name: `Court ${i}`,
|
|
type: CourtType.OUTDOOR,
|
|
status: CourtStatus.AVAILABLE,
|
|
pricePerHour: 300,
|
|
description: 'Outdoor court with night lighting',
|
|
features: ['Night lighting', 'Court dividers'],
|
|
displayOrder: i,
|
|
},
|
|
});
|
|
courts.push(created);
|
|
console.log(` Created court: ${created.name}`);
|
|
}
|
|
|
|
console.log('');
|
|
|
|
// =============================================================================
|
|
// ADMIN USER (SUPER_ADMIN)
|
|
// =============================================================================
|
|
console.log('Creating admin user...');
|
|
|
|
const hashedPassword = await bcrypt.hash('Aasi940812', 10);
|
|
|
|
const adminUser = await prisma.user.create({
|
|
data: {
|
|
organizationId: organization.id,
|
|
email: 'ivan@horuxfin.com',
|
|
password: hashedPassword,
|
|
firstName: 'Ivan',
|
|
lastName: 'Admin',
|
|
role: UserRole.SUPER_ADMIN,
|
|
phone: '+52 55 9999 0000',
|
|
siteIds: sites.map(s => s.id),
|
|
},
|
|
});
|
|
|
|
console.log(` Created super admin: ${adminUser.email}`);
|
|
|
|
console.log('');
|
|
|
|
// =============================================================================
|
|
// PRODUCT CATEGORIES
|
|
// =============================================================================
|
|
console.log('Creating product categories...');
|
|
|
|
const categoriesData = [
|
|
{ name: 'Drinks', description: 'Beverages and refreshments', displayOrder: 1 },
|
|
{ name: 'Snacks', description: 'Snacks and light food', displayOrder: 2 },
|
|
{ name: 'Equipment', description: 'Pickleball equipment and accessories', displayOrder: 3 },
|
|
{ name: 'Rental', description: 'Rental items', 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
|
|
// =============================================================================
|
|
console.log('Creating products...');
|
|
|
|
const drinksCategory = categories.find(c => c.name === 'Drinks');
|
|
const snacksCategory = categories.find(c => c.name === 'Snacks');
|
|
const equipmentCategory = categories.find(c => c.name === 'Equipment');
|
|
const rentalCategory = categories.find(c => c.name === 'Rental');
|
|
|
|
const productsData = [
|
|
{ name: 'Water', description: 'Natural water 600ml', price: 20, costPrice: 8, stock: 100, categoryId: drinksCategory?.id, sku: 'DRK-001' },
|
|
{ name: 'Gatorade', description: 'Sports drink 500ml', price: 35, costPrice: 18, stock: 50, categoryId: drinksCategory?.id, sku: 'DRK-002' },
|
|
{ name: 'Beer', description: 'Craft beer 355ml', price: 45, costPrice: 22, stock: 48, categoryId: drinksCategory?.id, sku: 'DRK-003' },
|
|
{ name: 'Chips', description: 'Potato chips 45g', price: 25, costPrice: 12, stock: 30, categoryId: snacksCategory?.id, sku: 'SNK-001' },
|
|
{ name: 'Energy Bar', description: 'Protein bar 50g', price: 30, costPrice: 15, stock: 25, categoryId: snacksCategory?.id, sku: 'SNK-002' },
|
|
{ name: 'Pickleballs', description: 'Franklin X-40 Outdoor (3 pack)', price: 180, costPrice: 90, stock: 20, categoryId: equipmentCategory?.id, sku: 'EQP-001' },
|
|
{ name: 'Paddle Grip', description: 'Replacement grip', price: 50, costPrice: 25, stock: 40, categoryId: equipmentCategory?.id, sku: 'EQP-002' },
|
|
{ name: 'Paddle Rental', description: 'Pickleball paddle rental (per session)', price: 100, costPrice: 0, stock: 10, categoryId: rentalCategory?.id, sku: 'RNT-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: 'Day Pass',
|
|
description: 'Single day access to all courts',
|
|
price: 300,
|
|
durationMonths: 1,
|
|
courtHours: 0,
|
|
discountPercent: 0,
|
|
benefits: ['Full day access', 'All courts', 'Night play included'],
|
|
},
|
|
{
|
|
name: '10-Day Pass',
|
|
description: '10 visits, any time of day',
|
|
price: 2500,
|
|
durationMonths: 3,
|
|
courtHours: 10,
|
|
discountPercent: 15,
|
|
benefits: ['10 day passes', 'Valid any time', 'Save vs single day pass'],
|
|
},
|
|
{
|
|
name: '10-Morning Pass',
|
|
description: '10 morning sessions (7am-12pm)',
|
|
price: 2000,
|
|
durationMonths: 3,
|
|
courtHours: 10,
|
|
discountPercent: 10,
|
|
benefits: ['10 morning passes', '7:00 AM - 12:00 PM only', 'Best value for morning players'],
|
|
},
|
|
{
|
|
name: 'Monthly Individual',
|
|
description: 'Unlimited monthly access for one player',
|
|
price: 4000,
|
|
durationMonths: 1,
|
|
courtHours: 30,
|
|
discountPercent: 25,
|
|
benefits: ['Unlimited court access', 'Priority booking', 'All time slots'],
|
|
},
|
|
{
|
|
name: 'Monthly Family',
|
|
description: 'Unlimited monthly access for up to 4 family members',
|
|
price: 6500,
|
|
durationMonths: 1,
|
|
courtHours: 60,
|
|
discountPercent: 30,
|
|
benefits: ['Up to 4 family members', 'Unlimited court access', 'Priority booking', 'All time slots'],
|
|
},
|
|
];
|
|
|
|
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}`);
|
|
}
|
|
|
|
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 Monthly Individual)
|
|
// =============================================================================
|
|
console.log('Creating sample membership...');
|
|
|
|
const monthlyPlan = membershipPlans.find(p => p.name === 'Monthly Individual');
|
|
const mariaClient = clients.find(c => c.firstName === 'Maria');
|
|
|
|
if (monthlyPlan && mariaClient) {
|
|
const startDate = new Date();
|
|
const endDate = new Date();
|
|
endDate.setMonth(endDate.getMonth() + 1);
|
|
|
|
const membership = await prisma.membership.create({
|
|
data: {
|
|
planId: monthlyPlan.id,
|
|
clientId: mariaClient.id,
|
|
startDate,
|
|
endDate,
|
|
status: MembershipStatus.ACTIVE,
|
|
remainingHours: monthlyPlan.courtHours,
|
|
autoRenew: true,
|
|
},
|
|
});
|
|
|
|
console.log(` Created Monthly Individual 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} Site`);
|
|
console.log(` - ${courts.length} Courts`);
|
|
console.log(` - 1 Admin user`);
|
|
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(' Admin: ivan@horuxfin.com / Aasi940812');
|
|
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);
|
|
});
|