import { PrismaClient, User, Court, Booking, Payment, CourtSchedule, Prisma } from '@prisma/client'; import { hashPassword } from '../../src/utils/password'; import { UserRole, CourtType, BookingStatus, PaymentStatus } from '../../src/utils/constants'; import { getPrismaClient } from './testDb'; // Type for overrides export type Overrides = Partial; // Prisma client let prisma: PrismaClient; function getClient(): PrismaClient { if (!prisma) { prisma = getPrismaClient(); } return prisma; } /** * User Factory */ export interface CreateUserInput { email?: string; password?: string; firstName?: string; lastName?: string; phone?: string; role?: string; playerLevel?: string; handPreference?: string; positionPreference?: string; isActive?: boolean; avatarUrl?: string; city?: string; bio?: string; } export async function createUser(overrides: CreateUserInput = {}): Promise { const client = getClient(); const defaultPassword = 'Password123!'; const hashedPassword = await hashPassword(overrides.password || defaultPassword); const userData: Prisma.UserCreateInput = { email: overrides.email || `user_${Date.now()}_${Math.random().toString(36).substring(2, 9)}@test.com`, password: hashedPassword, firstName: overrides.firstName || 'Test', lastName: overrides.lastName || 'User', phone: overrides.phone || '+1234567890', role: overrides.role || UserRole.PLAYER, playerLevel: overrides.playerLevel || 'BEGINNER', handPreference: overrides.handPreference || 'RIGHT', positionPreference: overrides.positionPreference || 'BOTH', isActive: overrides.isActive ?? true, avatarUrl: overrides.avatarUrl, city: overrides.city, bio: overrides.bio, }; return client.user.create({ data: userData }); } /** * Create an admin user */ export async function createAdminUser(overrides: CreateUserInput = {}): Promise { return createUser({ ...overrides, role: UserRole.ADMIN, }); } /** * Create a superadmin user */ export async function createSuperAdminUser(overrides: CreateUserInput = {}): Promise { return createUser({ ...overrides, role: UserRole.SUPERADMIN, }); } /** * Court Factory */ export interface CreateCourtInput { name?: string; description?: string; type?: string; isIndoor?: boolean; hasLighting?: boolean; hasParking?: boolean; pricePerHour?: number; imageUrl?: string; isActive?: boolean; } export async function createCourt(overrides: CreateCourtInput = {}): Promise { const client = getClient(); const courtData: Prisma.CourtCreateInput = { name: overrides.name || `Court ${Date.now()}_${Math.random().toString(36).substring(2, 9)}`, description: overrides.description || 'A test court', type: overrides.type || CourtType.PANORAMIC, isIndoor: overrides.isIndoor ?? false, hasLighting: overrides.hasLighting ?? true, hasParking: overrides.hasParking ?? false, pricePerHour: overrides.pricePerHour ?? 2000, imageUrl: overrides.imageUrl, isActive: overrides.isActive ?? true, }; return client.court.create({ data: courtData }); } /** * Create court with default schedules */ export async function createCourtWithSchedules(overrides: CreateCourtInput = {}): Promise { const client = getClient(); const court = await createCourt(overrides); // Create schedules for all days (0-6) const schedules: Prisma.CourtScheduleCreateManyInput[] = []; for (let day = 0; day <= 6; day++) { schedules.push({ courtId: court.id, dayOfWeek: day, openTime: '08:00', closeTime: '23:00', }); } await client.courtSchedule.createMany({ data: schedules }); return client.court.findUnique({ where: { id: court.id }, include: { schedules: true }, }) as Promise; } /** * Booking Factory */ export interface CreateBookingInput { userId?: string; courtId?: string; date?: Date; startTime?: string; endTime?: string; status?: string; totalPrice?: number; notes?: string; } export async function createBooking(overrides: CreateBookingInput = {}): Promise { const client = getClient(); // Create user if not provided let userId = overrides.userId; if (!userId) { const user = await createUser(); userId = user.id; } // Create court if not provided let courtId = overrides.courtId; if (!courtId) { const court = await createCourt(); courtId = court.id; } // Default to tomorrow const tomorrow = new Date(); tomorrow.setDate(tomorrow.getDate() + 1); tomorrow.setHours(0, 0, 0, 0); const bookingData: Prisma.BookingCreateInput = { user: { connect: { id: userId } }, court: { connect: { id: courtId } }, date: overrides.date || tomorrow, startTime: overrides.startTime || '10:00', endTime: overrides.endTime || '11:00', status: overrides.status || BookingStatus.PENDING, totalPrice: overrides.totalPrice ?? 2000, notes: overrides.notes, }; return client.booking.create({ data: bookingData }); } /** * Create a confirmed booking */ export async function createConfirmedBooking(overrides: CreateBookingInput = {}): Promise { return createBooking({ ...overrides, status: BookingStatus.CONFIRMED, }); } /** * Create a cancelled booking */ export async function createCancelledBooking(overrides: CreateBookingInput = {}): Promise { return createBooking({ ...overrides, status: BookingStatus.CANCELLED, }); } /** * Payment Factory */ export interface CreatePaymentInput { userId?: string; type?: string; referenceId?: string; amount?: number; currency?: string; status?: string; providerPreferenceId?: string; providerPaymentId?: string; paymentMethod?: string; installments?: number; metadata?: string; paidAt?: Date; } export async function createPayment(overrides: CreatePaymentInput = {}): Promise { const client = getClient(); // Create user if not provided let userId = overrides.userId; if (!userId) { const user = await createUser(); userId = user.id; } const paymentData: Prisma.PaymentCreateInput = { user: { connect: { id: userId } }, type: overrides.type || 'BOOKING', referenceId: overrides.referenceId || 'test-reference-id', amount: overrides.amount ?? 2000, currency: overrides.currency || 'ARS', status: overrides.status || PaymentStatus.PENDING, providerPreferenceId: overrides.providerPreferenceId || `pref_${Date.now()}`, providerPaymentId: overrides.providerPaymentId, paymentMethod: overrides.paymentMethod, installments: overrides.installments, metadata: overrides.metadata, paidAt: overrides.paidAt, }; return client.payment.create({ data: paymentData }); } /** * Create a completed payment */ export async function createCompletedPayment(overrides: CreatePaymentInput = {}): Promise { return createPayment({ ...overrides, status: PaymentStatus.COMPLETED, paidAt: new Date(), }); } /** * Bulk create multiple entities */ export async function createManyUsers(count: number, overrides: CreateUserInput = {}): Promise { const users: User[] = []; for (let i = 0; i < count; i++) { users.push(await createUser({ ...overrides, email: `user_${i}_${Date.now()}@test.com`, })); } return users; } export async function createManyCourts(count: number, overrides: CreateCourtInput = {}): Promise { const courts: Court[] = []; for (let i = 0; i < count; i++) { courts.push(await createCourt({ ...overrides, name: `Court ${i}_${Date.now()}`, })); } return courts; } export async function createManyBookings(count: number, overrides: CreateBookingInput = {}): Promise { const bookings: Booking[] = []; for (let i = 0; i < count; i++) { const date = new Date(); date.setDate(date.getDate() + i + 1); date.setHours(0, 0, 0, 0); bookings.push(await createBooking({ ...overrides, date, })); } return bookings; }