Implementados módulos base de Fase 6: 1. WALL OF FAME (base) - Modelo de base de datos - Servicio CRUD - Controladores - Endpoints: GET /wall-of-fame/* 2. ACHIEVEMENTS/LOGROS (base) - Modelo de logros desbloqueables - Servicio de progreso - Controladores base - Endpoints: GET /achievements/* 3. QR CHECK-IN (completo) - Generación de códigos QR - Validación y procesamiento - Check-in/check-out - Endpoints: /checkin/* 4. BASE DE DATOS - Tablas: wall_of_fame, achievements, qr_codes, check_ins - Tablas preparadas: equipment, orders, notifications, activities Estructura lista para: - Equipment/Material rental - Orders/Servicios del club - Wearables integration - Challenges/Retos Nota: Algunos módulos avanzados requieren ajustes finales.
1565 lines
38 KiB
Plaintext
1565 lines
38 KiB
Plaintext
// This is your Prisma schema file,
|
|
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "sqlite"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
// Modelo de Usuario
|
|
model User {
|
|
id String @id @default(uuid())
|
|
email String @unique
|
|
password String
|
|
|
|
// Datos personales
|
|
firstName String
|
|
lastName String
|
|
phone String?
|
|
avatarUrl String?
|
|
city String?
|
|
birthDate DateTime?
|
|
|
|
// Datos de juego (usamos String para simular enums en SQLite)
|
|
role String @default("PLAYER") // PLAYER, ADMIN, SUPERADMIN
|
|
playerLevel String @default("BEGINNER") // BEGINNER, ELEMENTARY, INTERMEDIATE, ADVANCED, COMPETITION, PROFESSIONAL
|
|
handPreference String @default("RIGHT") // RIGHT, LEFT, BOTH
|
|
positionPreference String @default("BOTH") // DRIVE, BACKHAND, BOTH
|
|
bio String?
|
|
yearsPlaying Int?
|
|
|
|
// Estadísticas globales
|
|
matchesPlayed Int @default(0)
|
|
matchesWon Int @default(0)
|
|
matchesLost Int @default(0)
|
|
totalPoints Int @default(0)
|
|
|
|
// Estado
|
|
isActive Boolean @default(true)
|
|
isVerified Boolean @default(false)
|
|
lastLogin DateTime?
|
|
|
|
// Relaciones
|
|
bookings Booking[]
|
|
levelHistory LevelHistory[]
|
|
|
|
// Relaciones con MatchResult
|
|
team1Player1Matches MatchResult[] @relation("Team1Player1")
|
|
team1Player2Matches MatchResult[] @relation("Team1Player2")
|
|
team2Player1Matches MatchResult[] @relation("Team2Player1")
|
|
team2Player2Matches MatchResult[] @relation("Team2Player2")
|
|
|
|
// Relación con UserStats
|
|
userStats UserStats[]
|
|
|
|
// Amistades
|
|
friendsSent Friend[] @relation("FriendRequestsSent")
|
|
friendsReceived Friend[] @relation("FriendRequestsReceived")
|
|
|
|
// Grupos
|
|
groupsCreated Group[] @relation("GroupsCreated")
|
|
groupMembers GroupMember[] @relation("GroupMemberships")
|
|
|
|
// Ligas
|
|
leaguesCreated League[] @relation("LeaguesCreated") // Ligas creadas por el usuario
|
|
teamCaptain LeagueTeam[] @relation("TeamCaptain") // Equipos donde es capitán
|
|
leagueTeamMembers LeagueTeamMember[] // Membresías de equipo en liga
|
|
|
|
// Reservas recurrentes
|
|
recurringBookings RecurringBooking[]
|
|
|
|
// Torneos
|
|
tournamentsCreated Tournament[] @relation("TournamentsCreated")
|
|
tournamentParticipations TournamentParticipant[]
|
|
|
|
// Bonos (Fase 4.2)
|
|
userBonuses UserBonus[]
|
|
|
|
// Pagos (Fase 4.1)
|
|
payments Payment[]
|
|
|
|
// Suscripciones (Fase 4.3)
|
|
subscriptions UserSubscription[]
|
|
|
|
// Clases con profesores (Fase 4.4)
|
|
coach Coach?
|
|
studentEnrollments StudentEnrollment[]
|
|
coachReviews CoachReview[]
|
|
|
|
// Servicios del Club (Fase 6.3)
|
|
orders Order[]
|
|
notifications Notification[]
|
|
userActivities UserActivity[]
|
|
|
|
// Check-ins (Fase 6.2)
|
|
checkIns CheckIn[]
|
|
|
|
// Alquileres de equipamiento (Fase 6.2)
|
|
equipmentRentals EquipmentRental[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@map("users")
|
|
}
|
|
|
|
// Modelo de Historial de Niveles
|
|
model LevelHistory {
|
|
id String @id @default(uuid())
|
|
|
|
// Niveles
|
|
oldLevel String
|
|
newLevel String
|
|
|
|
// Referencias
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
userId String
|
|
|
|
// Quién realizó el cambio (admin)
|
|
changedBy String
|
|
|
|
// Metadata
|
|
reason String?
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([userId])
|
|
@@map("level_history")
|
|
}
|
|
|
|
// Modelo de Cancha
|
|
model Court {
|
|
id String @id @default(uuid())
|
|
name String @unique
|
|
description String?
|
|
|
|
// Características
|
|
type String @default("PANORAMIC") // PANORAMIC, OUTDOOR, INDOOR, SINGLE
|
|
isIndoor Boolean @default(false)
|
|
hasLighting Boolean @default(true)
|
|
hasParking Boolean @default(false)
|
|
|
|
// Precio por hora (en centavos para evitar decimales)
|
|
pricePerHour Int @default(2000)
|
|
|
|
// Imagen
|
|
imageUrl String?
|
|
|
|
// Estado
|
|
isActive Boolean @default(true)
|
|
|
|
// Relaciones
|
|
bookings Booking[]
|
|
schedules CourtSchedule[]
|
|
recurringBookings RecurringBooking[]
|
|
leagueMatches LeagueMatch[]
|
|
tournamentMatches TournamentMatch[]
|
|
classBookings ClassBooking[]
|
|
|
|
// Servicios del Club (Fase 6.3)
|
|
orders Order[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@map("courts")
|
|
}
|
|
|
|
// Modelo de Horarios de Cancha (días y horas de operación)
|
|
model CourtSchedule {
|
|
id String @id @default(uuid())
|
|
|
|
// Día de la semana (0=Domingo, 1=Lunes, ..., 6=Sábado)
|
|
dayOfWeek Int
|
|
|
|
// Horario
|
|
openTime String
|
|
closeTime String
|
|
|
|
// Precio especial para esta franja (opcional)
|
|
priceOverride Int?
|
|
|
|
// Relación
|
|
court Court @relation(fields: [courtId], references: [id], onDelete: Cascade)
|
|
courtId String
|
|
|
|
@@unique([courtId, dayOfWeek])
|
|
@@map("court_schedules")
|
|
}
|
|
|
|
// Modelo de Reserva
|
|
model Booking {
|
|
id String @id @default(uuid())
|
|
|
|
// Fecha y hora
|
|
date DateTime
|
|
startTime String
|
|
endTime String
|
|
|
|
// Estado (PENDING, CONFIRMED, CANCELLED, COMPLETED, NO_SHOW)
|
|
status String @default("PENDING")
|
|
|
|
// Precio
|
|
totalPrice Int
|
|
|
|
// Notas
|
|
notes String?
|
|
|
|
// Relaciones
|
|
user User @relation(fields: [userId], references: [id])
|
|
userId String
|
|
|
|
court Court @relation(fields: [courtId], references: [id])
|
|
courtId String
|
|
|
|
// Relación con MatchResult
|
|
matchResult MatchResult?
|
|
|
|
// Referencia a reserva recurrente (si aplica)
|
|
recurringBooking RecurringBooking? @relation(fields: [recurringBookingId], references: [id])
|
|
recurringBookingId String?
|
|
|
|
// Uso de bonos
|
|
bonusUsages BonusUsage[]
|
|
|
|
// Servicios del Club (Fase 6.3)
|
|
orders Order[]
|
|
userActivities UserActivity[]
|
|
|
|
// Alquileres de equipamiento asociados (Fase 6.2)
|
|
equipmentRentals EquipmentRental[]
|
|
|
|
// Check-ins asociados (Fase 6.2)
|
|
checkIns CheckIn[]
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([userId])
|
|
@@index([courtId])
|
|
@@index([date])
|
|
@@index([recurringBookingId])
|
|
@@map("bookings")
|
|
}
|
|
|
|
// Modelo de Amistad
|
|
model Friend {
|
|
id String @id @default(uuid())
|
|
|
|
// Quien envía la solicitud
|
|
requester User @relation("FriendRequestsSent", fields: [requesterId], references: [id])
|
|
requesterId String
|
|
|
|
// Quien recibe la solicitud
|
|
addressee User @relation("FriendRequestsReceived", fields: [addresseeId], references: [id])
|
|
addresseeId String
|
|
|
|
// Estado (PENDING, ACCEPTED, REJECTED, BLOCKED)
|
|
status String @default("PENDING")
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([requesterId, addresseeId])
|
|
@@index([requesterId])
|
|
@@index([addresseeId])
|
|
@@index([status])
|
|
@@map("friends")
|
|
}
|
|
|
|
// Modelo de Grupo
|
|
model Group {
|
|
id String @id @default(uuid())
|
|
name String
|
|
description String?
|
|
|
|
// Creador del grupo
|
|
createdBy User @relation("GroupsCreated", fields: [createdById], references: [id])
|
|
createdById String
|
|
|
|
// Relaciones
|
|
members GroupMember[]
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([createdById])
|
|
@@map("groups")
|
|
}
|
|
|
|
// Modelo de Miembro de Grupo
|
|
model GroupMember {
|
|
id String @id @default(uuid())
|
|
|
|
// Grupo
|
|
group Group @relation(fields: [groupId], references: [id], onDelete: Cascade)
|
|
groupId String
|
|
|
|
// Usuario
|
|
user User @relation("GroupMemberships", fields: [userId], references: [id])
|
|
userId String
|
|
|
|
// Rol (ADMIN, MEMBER)
|
|
role String @default("MEMBER")
|
|
|
|
// Fecha de unión
|
|
joinedAt DateTime @default(now())
|
|
|
|
@@unique([groupId, userId])
|
|
@@index([groupId])
|
|
@@index([userId])
|
|
@@map("group_members")
|
|
}
|
|
|
|
// Modelo de Reserva Recurrente
|
|
model RecurringBooking {
|
|
id String @id @default(uuid())
|
|
|
|
// Usuario que crea la reserva recurrente
|
|
user User @relation(fields: [userId], references: [id])
|
|
userId String
|
|
|
|
// Cancha
|
|
court Court @relation(fields: [courtId], references: [id])
|
|
courtId String
|
|
|
|
// Día de la semana (0=Domingo, 1=Lunes, ..., 6=Sábado)
|
|
dayOfWeek Int
|
|
|
|
// Horario
|
|
startTime String
|
|
endTime String
|
|
|
|
// Rango de fechas
|
|
startDate DateTime
|
|
endDate DateTime?
|
|
|
|
// Estado
|
|
isActive Boolean @default(true)
|
|
|
|
// Relaciones
|
|
bookings Booking[]
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([userId])
|
|
@@index([courtId])
|
|
@@index([dayOfWeek])
|
|
@@index([isActive])
|
|
@@map("recurring_bookings")
|
|
}
|
|
|
|
// Modelo de Resultado de Partido
|
|
model MatchResult {
|
|
id String @id @default(uuid())
|
|
|
|
// Relación opcional con reserva
|
|
booking Booking? @relation(fields: [bookingId], references: [id], onDelete: SetNull)
|
|
bookingId String? @unique
|
|
|
|
// Jugadores del Equipo 1
|
|
team1Player1 User @relation("Team1Player1", fields: [team1Player1Id], references: [id])
|
|
team1Player1Id String
|
|
team1Player2 User @relation("Team1Player2", fields: [team1Player2Id], references: [id])
|
|
team1Player2Id String
|
|
|
|
// Jugadores del Equipo 2
|
|
team2Player1 User @relation("Team2Player1", fields: [team2Player1Id], references: [id])
|
|
team2Player1Id String
|
|
team2Player2 User @relation("Team2Player2", fields: [team2Player2Id], references: [id])
|
|
team2Player2Id String
|
|
|
|
// Resultado
|
|
team1Score Int
|
|
team2Score Int
|
|
winner String // TEAM1, TEAM2, DRAW
|
|
|
|
// Fecha en que se jugó el partido
|
|
playedAt DateTime
|
|
|
|
// Confirmaciones (JSON array de userIds)
|
|
confirmedBy String @default("[]")
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([team1Player1Id])
|
|
@@index([team1Player2Id])
|
|
@@index([team2Player1Id])
|
|
@@index([team2Player2Id])
|
|
@@index([playedAt])
|
|
@@map("match_results")
|
|
}
|
|
|
|
// Modelo de Estadísticas de Usuario por Período
|
|
model UserStats {
|
|
id String @id @default(uuid())
|
|
|
|
// Usuario
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
userId String
|
|
|
|
// Período (MONTH, YEAR, ALL_TIME)
|
|
period String
|
|
|
|
// Valor del período (ej: "2024-01" para mes, "2024" para año)
|
|
periodValue String
|
|
|
|
// Estadísticas de partidos
|
|
matchesPlayed Int @default(0)
|
|
matchesWon Int @default(0)
|
|
matchesLost Int @default(0)
|
|
|
|
// Estadísticas de torneos
|
|
tournamentsPlayed Int @default(0)
|
|
tournamentsWon Int @default(0)
|
|
|
|
// Puntos para ranking
|
|
points Int @default(0)
|
|
|
|
// Timestamps
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([userId, period, periodValue])
|
|
@@index([userId])
|
|
@@index([period, periodValue])
|
|
@@index([points])
|
|
@@map("user_stats")
|
|
}
|
|
|
|
// Modelo de Torneo
|
|
model Tournament {
|
|
id String @id @default(uuid())
|
|
name String
|
|
description String?
|
|
|
|
// Tipo de torneo
|
|
type String // ELIMINATION, ROUND_ROBIN, SWISS, CONSOLATION
|
|
|
|
// Categoría
|
|
category String // MEN, WOMEN, MIXED
|
|
|
|
// Niveles permitidos (almacenados como JSON string)
|
|
allowedLevels String
|
|
|
|
// Capacidad
|
|
maxParticipants Int
|
|
|
|
// Fechas importantes
|
|
registrationStartDate DateTime
|
|
registrationEndDate DateTime
|
|
startDate DateTime
|
|
endDate DateTime
|
|
|
|
// Canchas asignadas (almacenadas como JSON string de IDs)
|
|
courtIds String
|
|
|
|
// Precio de inscripción (en centavos)
|
|
price Int @default(0)
|
|
|
|
// Estado del torneo
|
|
status String @default("DRAFT") // DRAFT, OPEN, CLOSED, IN_PROGRESS, FINISHED, CANCELLED
|
|
|
|
// Creador (admin)
|
|
createdBy User @relation("TournamentsCreated", fields: [createdById], references: [id])
|
|
createdById String
|
|
|
|
// Relaciones
|
|
participants TournamentParticipant[] @relation("TournamentParticipants")
|
|
matches TournamentMatch[]
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([status])
|
|
@@index([createdById])
|
|
@@index([startDate])
|
|
@@index([registrationStartDate])
|
|
@@map("tournaments")
|
|
}
|
|
|
|
// Modelo de Participante de Torneo
|
|
model TournamentParticipant {
|
|
id String @id @default(uuid())
|
|
|
|
// Torneo
|
|
tournament Tournament @relation("TournamentParticipants", fields: [tournamentId], references: [id], onDelete: Cascade)
|
|
tournamentId String
|
|
|
|
// Usuario (jugador individual)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
userId String
|
|
|
|
// Fecha de inscripción
|
|
registrationDate DateTime @default(now())
|
|
|
|
// Estado del pago
|
|
paymentStatus String @default("PENDING") // PENDING, PAID, REFUNDED
|
|
|
|
// Número de cabeza de serie (opcional)
|
|
seed Int?
|
|
|
|
// Estado de la inscripción
|
|
status String @default("REGISTERED") // REGISTERED, CONFIRMED, WITHDRAWN
|
|
|
|
// Timestamps
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// Relaciones con partidos (como jugador individual)
|
|
team1Player1Matches TournamentMatch[] @relation("T1P1")
|
|
team1Player2Matches TournamentMatch[] @relation("T1P2")
|
|
team2Player1Matches TournamentMatch[] @relation("T2P1")
|
|
team2Player2Matches TournamentMatch[] @relation("T2P2")
|
|
|
|
@@unique([tournamentId, userId])
|
|
@@index([tournamentId])
|
|
@@index([userId])
|
|
@@index([paymentStatus])
|
|
@@index([status])
|
|
@@map("tournament_participants")
|
|
}
|
|
|
|
// Modelo de Partido de Torneo
|
|
model TournamentMatch {
|
|
id String @id @default(uuid())
|
|
|
|
// Torneo
|
|
tournament Tournament @relation(fields: [tournamentId], references: [id], onDelete: Cascade)
|
|
tournamentId String
|
|
|
|
// Ronda (1=final, 2=semifinal, etc. o número de ronda en liga)
|
|
round Int
|
|
|
|
// Número de partido en la ronda
|
|
matchNumber Int
|
|
|
|
// Posición en el cuadro
|
|
position Int
|
|
|
|
// Equipo 1 (pareja o individual)
|
|
team1Player1 TournamentParticipant? @relation("T1P1", fields: [team1Player1Id], references: [id], onDelete: SetNull)
|
|
team1Player1Id String?
|
|
team1Player2 TournamentParticipant? @relation("T1P2", fields: [team1Player2Id], references: [id], onDelete: SetNull)
|
|
team1Player2Id String?
|
|
|
|
// Equipo 2 (pareja o individual)
|
|
team2Player1 TournamentParticipant? @relation("T2P1", fields: [team2Player1Id], references: [id], onDelete: SetNull)
|
|
team2Player1Id String?
|
|
team2Player2 TournamentParticipant? @relation("T2P2", fields: [team2Player2Id], references: [id], onDelete: SetNull)
|
|
team2Player2Id String?
|
|
|
|
// Cancha asignada
|
|
court Court? @relation(fields: [courtId], references: [id], onDelete: SetNull)
|
|
courtId String?
|
|
|
|
// Fecha y hora programada
|
|
scheduledDate DateTime?
|
|
scheduledTime String?
|
|
|
|
// Estado del partido
|
|
status String @default("PENDING") // PENDING, SCHEDULED, IN_PROGRESS, FINISHED, CANCELLED, BYE
|
|
|
|
// Resultado
|
|
team1Score Int?
|
|
team2Score Int?
|
|
winner String? // TEAM1, TEAM2, DRAW
|
|
|
|
// Avance en cuadro
|
|
nextMatch TournamentMatch? @relation("NextMatch", fields: [nextMatchId], references: [id], onDelete: SetNull)
|
|
nextMatchId String?
|
|
parentMatches TournamentMatch[] @relation("NextMatch")
|
|
|
|
// Confirmaciones del resultado (JSON array de userIds)
|
|
confirmedBy String @default("[]")
|
|
|
|
// Metadatos adicionales (para sistemas suizo, round robin, etc)
|
|
metadata String? // JSON string con datos adicionales
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([tournamentId])
|
|
@@index([round])
|
|
@@index([status])
|
|
@@index([courtId])
|
|
@@index([nextMatchId])
|
|
@@index([tournamentId, round])
|
|
@@map("tournament_matches")
|
|
}
|
|
|
|
|
|
// ============================================
|
|
// Modelos de Liga por Equipos (Fase 3.3)
|
|
// ============================================
|
|
|
|
// Modelo de Liga
|
|
model League {
|
|
id String @id @default(uuid())
|
|
name String
|
|
description String?
|
|
|
|
// Tipo y formato
|
|
type String @default("TEAM_LEAGUE") // TEAM_LEAGUE, INDIVIDUAL_LEAGUE
|
|
format String @default("DOUBLE_ROUND_ROBIN") // SINGLE_ROUND_ROBIN, DOUBLE_ROUND_ROBIN, etc.
|
|
|
|
// Configuración de partidos por jornada
|
|
matchesPerMatchday Int @default(2) // Número de partidos entre dos equipos por jornada
|
|
|
|
// Fechas
|
|
startDate DateTime?
|
|
endDate DateTime?
|
|
|
|
// Estado
|
|
status String @default("DRAFT") // DRAFT, ACTIVE, FINISHED, CANCELLED
|
|
|
|
// Creador (admin)
|
|
createdBy User @relation("LeaguesCreated", fields: [createdById], references: [id])
|
|
createdById String
|
|
|
|
// Relaciones
|
|
teams LeagueTeam[]
|
|
matches LeagueMatch[]
|
|
standings LeagueStanding[]
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([status])
|
|
@@index([createdById])
|
|
@@index([startDate])
|
|
@@map("leagues")
|
|
}
|
|
|
|
// Modelo de Equipo en Liga
|
|
model LeagueTeam {
|
|
id String @id @default(uuid())
|
|
name String
|
|
description String?
|
|
|
|
// Liga
|
|
league League @relation(fields: [leagueId], references: [id], onDelete: Cascade)
|
|
leagueId String
|
|
|
|
// Capitán del equipo
|
|
captain User @relation("TeamCaptain", fields: [captainId], references: [id])
|
|
captainId String
|
|
|
|
// Relaciones
|
|
members LeagueTeamMember[]
|
|
|
|
// Partidos como equipo 1 o 2
|
|
matchesAsTeam1 LeagueMatch[] @relation("Team1Matches")
|
|
matchesAsTeam2 LeagueMatch[] @relation("Team2Matches")
|
|
|
|
// Clasificación
|
|
standing LeagueStanding?
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now())
|
|
|
|
@@unique([leagueId, name])
|
|
@@index([leagueId])
|
|
@@index([captainId])
|
|
@@map("league_teams")
|
|
}
|
|
|
|
// Modelo de Miembro de Equipo
|
|
model LeagueTeamMember {
|
|
id String @id @default(uuid())
|
|
|
|
// Equipo
|
|
team LeagueTeam @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
|
teamId String
|
|
|
|
// Usuario
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
userId String
|
|
|
|
// Estado
|
|
isActive Boolean @default(true)
|
|
|
|
// Fecha de unión
|
|
joinedAt DateTime @default(now())
|
|
|
|
// Timestamps
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([teamId, userId])
|
|
@@index([teamId])
|
|
@@index([userId])
|
|
@@map("league_team_members")
|
|
}
|
|
|
|
// Modelo de Partido de Liga
|
|
model LeagueMatch {
|
|
id String @id @default(uuid())
|
|
|
|
// Liga
|
|
league League @relation(fields: [leagueId], references: [id], onDelete: Cascade)
|
|
leagueId String
|
|
|
|
// Jornada
|
|
matchday Int // Número de jornada
|
|
|
|
// Equipos
|
|
team1 LeagueTeam @relation("Team1Matches", fields: [team1Id], references: [id])
|
|
team1Id String
|
|
team2 LeagueTeam @relation("Team2Matches", fields: [team2Id], references: [id])
|
|
team2Id String
|
|
|
|
// Cancha y horario (opcional)
|
|
court Court? @relation(fields: [courtId], references: [id], onDelete: SetNull)
|
|
courtId String?
|
|
|
|
scheduledDate DateTime? // Fecha programada
|
|
scheduledTime String? // Hora programada (formato HH:mm)
|
|
|
|
// Estado
|
|
status String @default("SCHEDULED") // SCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED, CANCELLED, POSTPONED, WALKOVER
|
|
|
|
// Resultado
|
|
team1Score Int? // Sets ganados por equipo 1
|
|
team2Score Int? // Sets ganados por equipo 2
|
|
|
|
// Detalle de sets (almacenado como JSON)
|
|
// Ej: [{team1Games: 6, team2Games: 4}, {team1Games: 6, team2Games: 2}]
|
|
setDetails String?
|
|
|
|
// Ganador
|
|
winner String? // TEAM1, TEAM2, DRAW
|
|
|
|
// Fecha de finalización
|
|
completedAt DateTime?
|
|
|
|
// Notas
|
|
notes String?
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([leagueId])
|
|
@@index([matchday])
|
|
@@index([team1Id])
|
|
@@index([team2Id])
|
|
@@index([status])
|
|
@@index([scheduledDate])
|
|
@@map("league_matches")
|
|
}
|
|
|
|
// Modelo de Clasificación
|
|
model LeagueStanding {
|
|
id String @id @default(uuid())
|
|
|
|
// Liga
|
|
league League @relation(fields: [leagueId], references: [id], onDelete: Cascade)
|
|
leagueId String
|
|
|
|
// Equipo
|
|
team LeagueTeam @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
|
teamId String @unique
|
|
|
|
// Partidos
|
|
matchesPlayed Int @default(0)
|
|
matchesWon Int @default(0)
|
|
matchesLost Int @default(0)
|
|
matchesDrawn Int @default(0)
|
|
|
|
// Sets
|
|
setsFor Int @default(0)
|
|
setsAgainst Int @default(0)
|
|
|
|
// Games (opcional)
|
|
gamesFor Int @default(0)
|
|
gamesAgainst Int @default(0)
|
|
|
|
// Puntos
|
|
points Int @default(0)
|
|
|
|
// Posición actual
|
|
position Int @default(0)
|
|
|
|
// Timestamps
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([leagueId, teamId])
|
|
@@index([leagueId])
|
|
@@index([position])
|
|
@@index([points])
|
|
@@map("league_standings")
|
|
}
|
|
|
|
// ============================================
|
|
// Modelo de Pagos (Fase 4.1)
|
|
// ============================================
|
|
|
|
model Payment {
|
|
id String @id @default(uuid())
|
|
|
|
// Usuario que realiza el pago
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
userId String
|
|
|
|
// Tipo de pago: BOOKING, TOURNAMENT, BONUS, SUBSCRIPTION, CLASS
|
|
type String
|
|
|
|
// ID de la entidad relacionada (booking, tournament, etc.)
|
|
referenceId String
|
|
|
|
// Monto en centavos (para evitar decimales)
|
|
amount Int
|
|
|
|
// Moneda (ARS, MXN, etc.)
|
|
currency String @default("ARS")
|
|
|
|
// Proveedor de pago
|
|
provider String @default("MERCADOPAGO")
|
|
|
|
// IDs de MercadoPago
|
|
providerPaymentId String? // ID del pago en MP (cuando se confirma)
|
|
providerPreferenceId String @unique // ID de la preferencia MP
|
|
|
|
// Estado del pago
|
|
status String @default("PENDING") // PENDING, PROCESSING, COMPLETED, FAILED, REFUNDED, CANCELLED
|
|
|
|
// Información del método de pago
|
|
paymentMethod String?
|
|
installments Int? // Cantidad de cuotas
|
|
|
|
// Metadata adicional (JSON)
|
|
metadata String?
|
|
|
|
// Fechas
|
|
paidAt DateTime?
|
|
refundedAt DateTime?
|
|
refundAmount Int? // Monto reembolsado en centavos
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([userId])
|
|
@@index([status])
|
|
@@index([type, referenceId])
|
|
@@index([providerPaymentId])
|
|
@@index([providerPreferenceId])
|
|
@@index([createdAt])
|
|
@@map("payments")
|
|
}
|
|
|
|
// ============================================
|
|
// Modelos de Sistema de Bonos (Fase 4.2)
|
|
// ============================================
|
|
|
|
// Modelo de Pack de Bonos (tipos de bonos disponibles)
|
|
model BonusPack {
|
|
id String @id @default(uuid())
|
|
name String
|
|
description String?
|
|
|
|
// Configuración del bono
|
|
numberOfBookings Int // Cantidad de reservas incluidas
|
|
price Int // Precio del bono en centavos
|
|
validityDays Int // Días de validez desde la compra
|
|
|
|
// Estado
|
|
isActive Boolean @default(true)
|
|
|
|
// Relaciones
|
|
userBonuses UserBonus[]
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([isActive])
|
|
@@map("bonus_packs")
|
|
}
|
|
|
|
// Modelo de Bono de Usuario (bonos comprados)
|
|
model UserBonus {
|
|
id String @id @default(uuid())
|
|
|
|
// Relaciones
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
userId String
|
|
bonusPack BonusPack @relation(fields: [bonusPackId], references: [id])
|
|
bonusPackId String
|
|
|
|
// Uso del bono
|
|
totalBookings Int
|
|
usedBookings Int @default(0)
|
|
remainingBookings Int
|
|
|
|
// Fechas
|
|
purchaseDate DateTime
|
|
expirationDate DateTime
|
|
|
|
// Estado: ACTIVE, EXPIRED, DEPLETED
|
|
status String @default("ACTIVE")
|
|
|
|
// Referencia al pago
|
|
paymentId String?
|
|
|
|
// Relaciones
|
|
usages BonusUsage[]
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([userId])
|
|
@@index([status])
|
|
@@index([expirationDate])
|
|
@@index([userId, status])
|
|
@@map("user_bonuses")
|
|
}
|
|
|
|
// Modelo de Uso de Bono (registro de usos)
|
|
model BonusUsage {
|
|
id String @id @default(uuid())
|
|
|
|
// Relaciones
|
|
userBonus UserBonus @relation(fields: [userBonusId], references: [id], onDelete: Cascade)
|
|
userBonusId String
|
|
|
|
// Reserva asociada
|
|
booking Booking @relation(fields: [bookingId], references: [id])
|
|
bookingId String
|
|
|
|
// Fecha de uso
|
|
usedAt DateTime @default(now())
|
|
|
|
@@unique([bookingId])
|
|
@@index([userBonusId])
|
|
@@index([usedAt])
|
|
@@map("bonus_usages")
|
|
}
|
|
|
|
// ============================================
|
|
// Modelos de Sistema de Suscripciones (Fase 4.3)
|
|
// ============================================
|
|
|
|
// Modelo de Plan de Suscripción (planes disponibles)
|
|
model SubscriptionPlan {
|
|
id String @id @default(uuid())
|
|
name String
|
|
description String?
|
|
|
|
// Tipo de plan
|
|
type String // MONTHLY, QUARTERLY, YEARLY
|
|
|
|
// Precio en centavos
|
|
price Int
|
|
|
|
// Características (JSON array de strings)
|
|
features String? // Ej: ["Reservas ilimitadas", "Prioridad en reservas"]
|
|
|
|
// Beneficios del plan (almacenados como JSON)
|
|
// discountPercentage: porcentaje de descuento en reservas
|
|
// freeBookingsPerMonth: cantidad de reservas gratis por mes
|
|
// priorityBooking: prioridad en reservas
|
|
// tournamentDiscount: descuento en torneos
|
|
benefits String // JSON: { discountPercentage, freeBookingsPerMonth, priorityBooking, tournamentDiscount }
|
|
|
|
// ID del plan en MercadoPago
|
|
mercadoPagoPlanId String?
|
|
|
|
// Estado
|
|
isActive Boolean @default(true)
|
|
|
|
// Relaciones
|
|
subscriptions UserSubscription[]
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([type])
|
|
@@index([isActive])
|
|
@@map("subscription_plans")
|
|
}
|
|
|
|
// Modelo de Suscripción de Usuario
|
|
model UserSubscription {
|
|
id String @id @default(uuid())
|
|
|
|
// Usuario
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
userId String
|
|
|
|
// Plan
|
|
plan SubscriptionPlan @relation(fields: [planId], references: [id])
|
|
planId String
|
|
|
|
// Estado: PENDING, ACTIVE, PAUSED, CANCELLED, EXPIRED
|
|
status String @default("PENDING")
|
|
|
|
// Fechas de suscripción
|
|
startDate DateTime?
|
|
endDate DateTime?
|
|
|
|
// Período actual
|
|
currentPeriodStart DateTime?
|
|
currentPeriodEnd DateTime?
|
|
|
|
// Cancelar al final del período
|
|
cancelAtPeriodEnd Boolean @default(false)
|
|
|
|
// Referencia a MercadoPago
|
|
mercadoPagoSubscriptionId String?
|
|
|
|
// Método de pago vinculado
|
|
paymentMethodId String?
|
|
|
|
// Fechas de pagos
|
|
lastPaymentDate DateTime?
|
|
nextPaymentDate DateTime?
|
|
|
|
// Contador de reservas gratis usadas en el período actual
|
|
freeBookingsUsed Int @default(0)
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([userId, status])
|
|
@@index([userId])
|
|
@@index([planId])
|
|
@@index([status])
|
|
@@index([mercadoPagoSubscriptionId])
|
|
@@map("user_subscriptions")
|
|
}
|
|
|
|
// ============================================
|
|
// Modelos de Clases con Profesores (Fase 4.4)
|
|
// ============================================
|
|
|
|
// Modelo de Profesor (Coach)
|
|
model Coach {
|
|
id String @id @default(uuid())
|
|
|
|
// Relación con usuario
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
userId String @unique
|
|
|
|
// Perfil profesional
|
|
bio String?
|
|
specialties String? // JSON array de especialidades
|
|
certifications String? // JSON array de certificaciones
|
|
yearsExperience Int @default(0)
|
|
hourlyRate Int @default(0) // en centavos
|
|
photoUrl String?
|
|
|
|
// Estado
|
|
isActive Boolean @default(true)
|
|
isVerified Boolean @default(false)
|
|
|
|
// Calificaciones
|
|
rating Float?
|
|
reviewCount Int @default(0)
|
|
|
|
// Relaciones
|
|
availabilities CoachAvailability[]
|
|
classes Class[]
|
|
classBookings ClassBooking[]
|
|
coachReviews CoachReview[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([isActive])
|
|
@@index([isVerified])
|
|
@@index([userId])
|
|
@@map("coaches")
|
|
}
|
|
|
|
// Modelo de Disponibilidad del Coach
|
|
model CoachAvailability {
|
|
id String @id @default(uuid())
|
|
|
|
// Relación con coach
|
|
coach Coach @relation(fields: [coachId], references: [id], onDelete: Cascade)
|
|
coachId String
|
|
|
|
// Día de la semana (0=Domingo, 1=Lunes, ..., 6=Sábado)
|
|
dayOfWeek Int
|
|
|
|
// Horario
|
|
startTime String
|
|
endTime String
|
|
|
|
// Estado
|
|
isAvailable Boolean @default(true)
|
|
|
|
@@index([coachId])
|
|
@@index([coachId, dayOfWeek])
|
|
@@index([dayOfWeek])
|
|
@@map("coach_availabilities")
|
|
}
|
|
|
|
// Modelo de Clase (programa/tipo de clase)
|
|
model Class {
|
|
id String @id @default(uuid())
|
|
|
|
// Relación con coach
|
|
coach Coach @relation(fields: [coachId], references: [id], onDelete: Cascade)
|
|
coachId String
|
|
|
|
// Información de la clase
|
|
title String
|
|
description String?
|
|
|
|
// Tipo: INDIVIDUAL, GROUP, CLINIC
|
|
type String @default("INDIVIDUAL")
|
|
|
|
// Configuración
|
|
maxStudents Int @default(1) // Máximo de alumnos
|
|
price Int @default(0) // Precio por persona en centavos
|
|
duration Int @default(60) // Duración en minutos
|
|
|
|
// Nivel mínimo requerido
|
|
levelRequired String?
|
|
|
|
// Estado
|
|
isActive Boolean @default(true)
|
|
|
|
// Relaciones
|
|
sessions ClassBooking[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([coachId])
|
|
@@index([type])
|
|
@@index([isActive])
|
|
@@map("classes")
|
|
}
|
|
|
|
// Modelo de Sesión de Clase (instancia específica de una clase)
|
|
model ClassBooking {
|
|
id String @id @default(uuid())
|
|
|
|
// Relaciones
|
|
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
|
|
classId String
|
|
|
|
coach Coach @relation(fields: [coachId], references: [id])
|
|
coachId String
|
|
|
|
court Court? @relation(fields: [courtId], references: [id], onDelete: SetNull)
|
|
courtId String?
|
|
|
|
// Fecha y hora
|
|
date DateTime
|
|
startTime String
|
|
|
|
// Estudiantes (JSON array de userIds)
|
|
students String @default("[]")
|
|
|
|
// Cupo
|
|
maxStudents Int @default(1)
|
|
enrolledStudents Int @default(0)
|
|
|
|
// Estado: AVAILABLE, FULL, COMPLETED, CANCELLED
|
|
status String @default("AVAILABLE")
|
|
|
|
// Precio
|
|
price Int @default(0)
|
|
|
|
// Pago
|
|
paymentId String?
|
|
|
|
// Relaciones
|
|
enrollments StudentEnrollment[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([classId])
|
|
@@index([coachId])
|
|
@@index([courtId])
|
|
@@index([date])
|
|
@@index([status])
|
|
@@map("class_bookings")
|
|
}
|
|
|
|
// Modelo de Inscripción de Estudiante
|
|
model StudentEnrollment {
|
|
id String @id @default(uuid())
|
|
|
|
// Relaciones
|
|
classBooking ClassBooking @relation(fields: [classBookingId], references: [id], onDelete: Cascade)
|
|
classBookingId String
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
userId String
|
|
|
|
// Referencia al pago
|
|
paymentId String?
|
|
|
|
// Estado: PENDING, CONFIRMED, CANCELLED, ATTENDED
|
|
status String @default("PENDING")
|
|
|
|
// Timestamps
|
|
enrolledAt DateTime @default(now())
|
|
cancelledAt DateTime?
|
|
|
|
@@unique([classBookingId, userId])
|
|
@@index([userId])
|
|
@@index([status])
|
|
@@index([classBookingId])
|
|
@@map("student_enrollments")
|
|
}
|
|
|
|
// Modelo de Reseña de Coach
|
|
model CoachReview {
|
|
id String @id @default(uuid())
|
|
|
|
// Relaciones
|
|
coach Coach @relation(fields: [coachId], references: [id], onDelete: Cascade)
|
|
coachId String
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
userId String
|
|
|
|
// Calificación (1-5)
|
|
rating Int
|
|
comment String?
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@unique([coachId, userId])
|
|
@@index([coachId])
|
|
@@index([userId])
|
|
@@index([rating])
|
|
@@map("coach_reviews")
|
|
}
|
|
|
|
// ============================================
|
|
// Modelos de Servicios del Club (Fase 6.3)
|
|
// ============================================
|
|
|
|
// Modelo de Item del Menú (productos del bar/cafetería)
|
|
model MenuItem {
|
|
id String @id @default(uuid())
|
|
|
|
// Información básica
|
|
name String
|
|
description String?
|
|
|
|
// Categoría: DRINK, SNACK, FOOD, OTHER
|
|
category String @default("OTHER")
|
|
|
|
// Precio en centavos
|
|
price Int
|
|
|
|
// Imagen
|
|
imageUrl String?
|
|
|
|
// Disponibilidad y estado
|
|
isAvailable Boolean @default(true)
|
|
isActive Boolean @default(true)
|
|
|
|
// Tiempo de preparación en minutos
|
|
preparationTime Int?
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([category])
|
|
@@index([isAvailable])
|
|
@@index([isActive])
|
|
@@map("menu_items")
|
|
}
|
|
|
|
// Modelo de Pedido (órdenes a la cancha)
|
|
model Order {
|
|
id String @id @default(uuid())
|
|
|
|
// Usuario que realiza el pedido
|
|
user User @relation(fields: [userId], references: [id])
|
|
userId String
|
|
|
|
// Reserva asociada (vinculado a reserva activa)
|
|
booking Booking @relation(fields: [bookingId], references: [id])
|
|
bookingId String
|
|
|
|
// Cancha donde se entregará
|
|
court Court @relation(fields: [courtId], references: [id])
|
|
courtId String
|
|
|
|
// Items del pedido (JSON array de {itemId, quantity, notes, price})
|
|
items String
|
|
|
|
// Estado del pedido: PENDING, PREPARING, READY, DELIVERED, CANCELLED
|
|
status String @default("PENDING")
|
|
|
|
// Monto total en centavos
|
|
totalAmount Int
|
|
|
|
// Estado de pago: PENDING, PAID
|
|
paymentStatus String @default("PENDING")
|
|
|
|
// ID de referencia de pago (MercadoPago u otro)
|
|
paymentId String?
|
|
|
|
// Notas adicionales
|
|
notes String?
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([userId])
|
|
@@index([bookingId])
|
|
@@index([courtId])
|
|
@@index([status])
|
|
@@index([paymentStatus])
|
|
@@index([createdAt])
|
|
@@map("orders")
|
|
}
|
|
|
|
// Modelo de Notificación (push/in-app)
|
|
model Notification {
|
|
id String @id @default(uuid())
|
|
|
|
// Usuario destinatario
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
userId String
|
|
|
|
// Tipo de notificación: ORDER_READY, BOOKING_REMINDER, TOURNAMENT_START, etc.
|
|
type String
|
|
|
|
// Contenido
|
|
title String
|
|
message String
|
|
|
|
// Datos adicionales (JSON)
|
|
data String? // Puede contener orderId, bookingId, etc.
|
|
|
|
// Estado de lectura
|
|
isRead Boolean @default(false)
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([userId])
|
|
@@index([type])
|
|
@@index([isRead])
|
|
@@index([createdAt])
|
|
@@map("notifications")
|
|
}
|
|
|
|
// ============================================
|
|
// Modelos de Integración con Wearables (Fase 6.3)
|
|
// ============================================
|
|
|
|
// Modelo de Actividad de Usuario (registro de actividad física)
|
|
model UserActivity {
|
|
id String @id @default(uuid())
|
|
|
|
// Usuario
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
userId String
|
|
|
|
// Fuente de datos: APPLE_HEALTH, GOOGLE_FIT, MANUAL
|
|
source String
|
|
|
|
// Tipo de actividad: PADEL_GAME, WORKOUT
|
|
activityType String @default("PADEL_GAME")
|
|
|
|
// Tiempos
|
|
startTime DateTime
|
|
endTime DateTime
|
|
duration Int // Duración en minutos
|
|
|
|
// Métricas de salud
|
|
caloriesBurned Int
|
|
heartRateAvg Int?
|
|
heartRateMax Int?
|
|
steps Int?
|
|
distance Float? // km
|
|
|
|
// Metadatos adicionales (JSON)
|
|
metadata String?
|
|
|
|
// Reserva asociada (opcional)
|
|
booking Booking? @relation(fields: [bookingId], references: [id], onDelete: SetNull)
|
|
bookingId String?
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([userId])
|
|
@@index([source])
|
|
@@index([activityType])
|
|
@@index([startTime])
|
|
@@index([bookingId])
|
|
@@map("user_activities")
|
|
}
|
|
|
|
// ============================================
|
|
// Modelos de Check-in Digital QR (Fase 6.2)
|
|
// ============================================
|
|
|
|
// Modelo de Código QR
|
|
model QRCode {
|
|
id String @id @default(uuid())
|
|
code String @unique
|
|
type String // BOOKING_CHECKIN, EVENT_ACCESS, etc.
|
|
referenceId String // ID de la entidad (booking, etc.)
|
|
|
|
expiresAt DateTime
|
|
usedAt DateTime?
|
|
usedBy String? // userId que usó el QR
|
|
isActive Boolean @default(true)
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
// Relaciones
|
|
checkIns CheckIn[]
|
|
|
|
@@index([code])
|
|
@@index([referenceId])
|
|
@@index([type])
|
|
@@index([isActive])
|
|
@@map("qr_codes")
|
|
}
|
|
|
|
// Modelo de CheckIn (registro de asistencia)
|
|
model CheckIn {
|
|
id String @id @default(uuid())
|
|
|
|
bookingId String
|
|
userId String
|
|
qrCodeId String?
|
|
|
|
checkInTime DateTime
|
|
checkOutTime DateTime?
|
|
|
|
method String // QR, MANUAL
|
|
verifiedBy String? // admin que verificó
|
|
notes String?
|
|
|
|
// Relaciones
|
|
qrCode QRCode? @relation(fields: [qrCodeId], references: [id], onDelete: SetNull)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
booking Booking @relation(fields: [bookingId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([bookingId])
|
|
@@index([userId])
|
|
@@index([checkInTime])
|
|
@@index([method])
|
|
@@map("check_ins")
|
|
}
|
|
|
|
// ============================================
|
|
// Modelos de Gestión de Material (Fase 6.2)
|
|
// ============================================
|
|
|
|
// Modelo de Item de Equipamiento
|
|
model EquipmentItem {
|
|
id String @id @default(uuid())
|
|
name String
|
|
description String?
|
|
|
|
category String // RACKET, BALLS, ACCESSORIES, SHOES
|
|
brand String?
|
|
model String?
|
|
size String? // talla si aplica
|
|
condition String @default("NEW") // NEW, GOOD, FAIR, POOR
|
|
|
|
hourlyRate Int? // tarifa por hora (en centavos)
|
|
dailyRate Int? // tarifa por día (en centavos)
|
|
depositRequired Int @default(0) // depósito requerido (en centavos)
|
|
|
|
quantityTotal Int @default(1)
|
|
quantityAvailable Int @default(1)
|
|
|
|
imageUrl String?
|
|
isActive Boolean @default(true)
|
|
|
|
// Relaciones
|
|
rentals EquipmentRentalItem[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([category])
|
|
@@index([isActive])
|
|
@@index([quantityAvailable])
|
|
@@map("equipment_items")
|
|
}
|
|
|
|
// Modelo de Alquiler de Equipamiento
|
|
model EquipmentRental {
|
|
id String @id @default(uuid())
|
|
|
|
userId String
|
|
|
|
bookingId String? // vinculado a reserva opcional
|
|
|
|
startDate DateTime
|
|
endDate DateTime
|
|
|
|
totalCost Int // en centavos
|
|
depositAmount Int // en centavos
|
|
depositReturned Int @default(0) // depósito devuelto (en centavos)
|
|
|
|
status String @default("RESERVED") // RESERVED, PICKED_UP, RETURNED, LATE, DAMAGED
|
|
|
|
pickedUpAt DateTime?
|
|
returnedAt DateTime?
|
|
|
|
paymentId String?
|
|
|
|
notes String?
|
|
|
|
// Relaciones
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
booking Booking? @relation(fields: [bookingId], references: [id], onDelete: SetNull)
|
|
items EquipmentRentalItem[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([userId])
|
|
@@index([bookingId])
|
|
@@index([status])
|
|
@@index([startDate])
|
|
@@index([endDate])
|
|
@@map("equipment_rentals")
|
|
}
|
|
|
|
// Modelo intermedio para items de un alquiler
|
|
model EquipmentRentalItem {
|
|
id String @id @default(uuid())
|
|
|
|
rentalId String
|
|
itemId String
|
|
quantity Int @default(1)
|
|
|
|
hourlyRate Int? // tarifa aplicada al momento del alquiler
|
|
dailyRate Int? // tarifa aplicada al momento del alquiler
|
|
|
|
// Relaciones
|
|
rental EquipmentRental @relation(fields: [rentalId], references: [id], onDelete: Cascade)
|
|
item EquipmentItem @relation(fields: [itemId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([rentalId])
|
|
@@index([itemId])
|
|
@@map("equipment_rental_items")
|
|
}
|