- Implemented rescheduleAdminBooking service to allow users to change court and time for confirmed bookings. - Added validation for court availability, maintenance status, and overlapping bookings. - Created reschedule-admin-booking handler to process rescheduling requests and send confirmation emails. - Updated booking email service to include rescheduling notifications. - Enhanced frontend components to support booking rescheduling, including a new dialog for selecting new court and time. - Added tests for rescheduling logic, covering various scenarios including validation errors and successful reschedules. - Updated Prisma schema to log previous court and time for audit purposes.
172 lines
7.3 KiB
Plaintext
172 lines
7.3 KiB
Plaintext
enum DayOfWeek {
|
|
MONDAY
|
|
TUESDAY
|
|
WEDNESDAY
|
|
THURSDAY
|
|
FRIDAY
|
|
SATURDAY
|
|
SUNDAY
|
|
}
|
|
|
|
enum CourtBookingStatus {
|
|
CONFIRMED
|
|
CANCELLED
|
|
COMPLETED
|
|
NOSHOW
|
|
}
|
|
|
|
enum RecurringBookingGroupStatus {
|
|
ACTIVE
|
|
CANCELLED
|
|
}
|
|
|
|
model Sport {
|
|
id String @id @db.Uuid
|
|
name String @unique
|
|
slug String @unique
|
|
isActive Boolean @default(true) @map("is_active")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
courts Court[]
|
|
|
|
@@map("sports")
|
|
}
|
|
|
|
model Court {
|
|
id String @id @db.Uuid
|
|
complexId String @map("complex_id") @db.Uuid
|
|
sportId String @map("sport_id") @db.Uuid
|
|
name String
|
|
slotDurationMinutes Int @map("slot_duration_minutes")
|
|
basePrice Decimal @map("base_price") @db.Decimal(19, 2)
|
|
isUnderMaintenance Boolean @default(false) @map("is_under_maintenance")
|
|
maintenanceReason String? @map("maintenance_reason") @db.VarChar(500)
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
complex Complex @relation(fields: [complexId], references: [id], onDelete: Cascade)
|
|
sport Sport @relation(fields: [sportId], references: [id])
|
|
availabilities CourtAvailability[]
|
|
priceRules CourtPriceRule[]
|
|
bookings CourtBooking[]
|
|
maintenances CourtMaintenance[]
|
|
recurringGroups RecurringBookingGroup[]
|
|
|
|
@@index([complexId])
|
|
@@index([sportId])
|
|
@@map("courts")
|
|
}
|
|
|
|
model CourtMaintenance {
|
|
id String @id @db.Uuid
|
|
courtId String @map("court_id") @db.Uuid
|
|
startDate DateTime @map("start_date") @db.Date
|
|
startTime String? @map("start_time") @db.VarChar(5)
|
|
endTime String? @map("end_time") @db.VarChar(5)
|
|
reason String? @db.VarChar(500)
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
court Court @relation(fields: [courtId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([courtId, startDate])
|
|
@@map("court_maintenances")
|
|
}
|
|
|
|
model CourtAvailability {
|
|
id String @id @db.Uuid
|
|
courtId String @map("court_id") @db.Uuid
|
|
dayOfWeek DayOfWeek @map("day_of_week")
|
|
startTime String @map("start_time") @db.VarChar(5)
|
|
endTime String @map("end_time") @db.VarChar(5)
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
court Court @relation(fields: [courtId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([courtId, dayOfWeek])
|
|
@@map("court_availabilities")
|
|
}
|
|
|
|
model CourtPriceRule {
|
|
id String @id @db.Uuid
|
|
courtId String @map("court_id") @db.Uuid
|
|
dayOfWeek DayOfWeek? @map("day_of_week")
|
|
startTime String? @map("start_time") @db.VarChar(5)
|
|
endTime String? @map("end_time") @db.VarChar(5)
|
|
price Decimal @db.Decimal(19, 2)
|
|
isActive Boolean @default(true) @map("is_active")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
court Court @relation(fields: [courtId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([courtId, isActive])
|
|
@@map("court_price_rules")
|
|
}
|
|
|
|
model CourtBooking {
|
|
id String @id @db.Uuid
|
|
bookingCode String @unique @map("booking_code") @db.VarChar(8)
|
|
courtId String @map("court_id") @db.Uuid
|
|
bookingDate DateTime @map("booking_date") @db.Date
|
|
startTime String @map("start_time") @db.VarChar(5)
|
|
endTime String @map("end_time") @db.VarChar(5)
|
|
customerName String @map("customer_name") @db.VarChar(120)
|
|
customerPhone String @map("customer_phone") @db.VarChar(30)
|
|
customerEmail String @map("customer_email") @db.VarChar(254)
|
|
status CourtBookingStatus @default(CONFIRMED)
|
|
recurringGroupId String? @map("recurring_group_id") @db.Uuid
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
court Court @relation(fields: [courtId], references: [id], onDelete: Cascade)
|
|
recurringGroup RecurringBookingGroup? @relation(fields: [recurringGroupId], references: [id])
|
|
|
|
@@unique([courtId, bookingDate, startTime])
|
|
@@index([courtId, bookingDate])
|
|
@@index([bookingDate])
|
|
@@index([recurringGroupId])
|
|
@@map("court_bookings")
|
|
}
|
|
|
|
model CourtBookingLog {
|
|
id String @id @db.Uuid
|
|
bookingCode String @map("booking_code") @db.VarChar(8)
|
|
courtId String @map("court_id") @db.Uuid
|
|
bookingDate DateTime @map("booking_date") @db.Date
|
|
startTime String @map("start_time") @db.VarChar(5)
|
|
endTime String @map("end_time") @db.VarChar(5)
|
|
previousStatus CourtBookingStatus @map("previous_status")
|
|
newStatus CourtBookingStatus @map("new_status")
|
|
previousCourtId String? @map("previous_court_id") @db.Uuid
|
|
previousStartTime String? @map("previous_start_time") @db.VarChar(5)
|
|
previousEndTime String? @map("previous_end_time") @db.VarChar(5)
|
|
customerName String @map("customer_name") @db.VarChar(120)
|
|
customerPhone String @map("customer_phone") @db.VarChar(30)
|
|
customerEmail String @map("customer_email") @db.VarChar(254)
|
|
changedAt DateTime @default(now()) @map("changed_at")
|
|
|
|
@@map("court_booking_logs")
|
|
@@index([courtId, newStatus])
|
|
}
|
|
|
|
model RecurringBookingGroup {
|
|
id String @id @db.Uuid
|
|
complexId String @map("complex_id") @db.Uuid
|
|
courtId String @map("court_id") @db.Uuid
|
|
startTime String @map("start_time") @db.VarChar(5)
|
|
endTime String @map("end_time") @db.VarChar(5)
|
|
dayOfWeek DayOfWeek @map("day_of_week")
|
|
startDate DateTime @map("start_date") @db.Date
|
|
endDate DateTime? @map("end_date") @db.Date
|
|
status RecurringBookingGroupStatus @default(ACTIVE)
|
|
customerName String @map("customer_name") @db.VarChar(120)
|
|
customerPhone String @map("customer_phone") @db.VarChar(30)
|
|
customerEmail String @map("customer_email") @db.VarChar(254)
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
court Court @relation(fields: [courtId], references: [id], onDelete: Cascade)
|
|
complex Complex @relation(fields: [complexId], references: [id], onDelete: Cascade)
|
|
bookings CourtBooking[]
|
|
|
|
@@index([complexId])
|
|
@@index([courtId])
|
|
@@index([status])
|
|
@@map("recurring_booking_groups")
|
|
}
|