Spaces:
Runtime error
Runtime error
| from django.db import models | |
| from django.core.exceptions import ValidationError | |
| class Experience(models.Model): | |
| title = models.CharField(max_length=200) | |
| tagline = models.CharField(max_length=200) | |
| description = models.TextField() | |
| duration = models.CharField(max_length=50) | |
| people = models.CharField(max_length=50) | |
| min_participants = models.PositiveIntegerField(null=True, blank=True) | |
| max_participants = models.PositiveIntegerField(null=True, blank=True) | |
| price = models.IntegerField() | |
| image = models.JSONField(default=list, blank=True) | |
| is_active = models.BooleanField(default=True) | |
| def __str__(self): | |
| return self.title | |
| class ExperienceSlot(models.Model): | |
| experience = models.ForeignKey( | |
| Experience, | |
| on_delete=models.CASCADE, | |
| related_name="slots" | |
| ) | |
| date = models.DateField() | |
| start_time = models.TimeField() | |
| end_time = models.TimeField() | |
| total_slots = models.PositiveIntegerField() | |
| booked_slots = models.PositiveIntegerField(default=0) | |
| is_active = models.BooleanField(default=True) | |
| def clean(self): | |
| if self.start_time >= self.end_time: | |
| raise ValidationError("Start time must be before end time.") | |
| if self.booked_slots > self.total_slots: | |
| raise ValidationError("Booked slots cannot exceed total slots.") | |
| exp = self.experience | |
| if exp.min_participants and exp.max_participants: | |
| if exp.min_participants > exp.max_participants: | |
| raise ValidationError( | |
| "Experience min participants cannot exceed max participants." | |
| ) | |
| def save(self, *args, **kwargs): | |
| self.full_clean() | |
| super().save(*args, **kwargs) | |
| def __str__(self): | |
| return f"{self.experience.title} | {self.date} {self.start_time}-{self.end_time}" | |
| class Meta: | |
| ordering = ["date", "start_time"] | |
| class Booking(models.Model): | |
| STATUS_CHOICES = ( | |
| ("pending", "Pending"), | |
| ("confirmed", "Confirmed"), | |
| ("cancelled", "Cancelled"), | |
| ("failed", "Failed"), | |
| ) | |
| experience = models.ForeignKey( | |
| Experience, | |
| on_delete=models.CASCADE, | |
| related_name="bookings" | |
| ) | |
| slot = models.ForeignKey( | |
| ExperienceSlot, | |
| on_delete=models.PROTECT, | |
| related_name="bookings", | |
| null=True, | |
| blank=True, | |
| ) | |
| full_name = models.CharField(max_length=100) | |
| phone = models.CharField(max_length=15) | |
| email = models.EmailField() | |
| booking_date = models.DateField() | |
| number_of_people = models.PositiveIntegerField() | |
| status = models.CharField( | |
| max_length=20, | |
| choices=STATUS_CHOICES, | |
| default="pending" | |
| ) | |
| payment_amount = models.PositiveIntegerField() | |
| # 🔗 LINK TO ORDERS APP | |
| payment_order = models.OneToOneField( | |
| "orders.PaymentOrder", | |
| on_delete=models.SET_NULL, | |
| null=True, | |
| blank=True, | |
| related_name="experience_booking" | |
| ) | |
| created_at = models.DateTimeField(auto_now_add=True) | |
| def __str__(self): | |
| return f"{self.full_name} - {self.experience.title}" | |
| class StudioBooking(models.Model): | |
| full_name = models.CharField(max_length=100) | |
| phone = models.CharField(max_length=15) | |
| email = models.EmailField() | |
| visit_date = models.DateField() | |
| time_slot = models.CharField(max_length=50) | |
| created_at = models.DateTimeField(auto_now_add=True) | |
| def __str__(self): | |
| return f"{self.full_name} - {self.visit_date} ({self.time_slot})" | |
| class UpcomingEvent(models.Model): | |
| title = models.CharField(max_length=200) | |
| date = models.CharField(max_length=50) # simple string for now | |
| location = models.CharField(max_length=200) | |
| description = models.TextField() | |
| badge = models.CharField(max_length=50, default="✨ Upcoming") | |
| def __str__(self): | |
| return self.title | |
| class Workshop(models.Model): | |
| WORKSHOP_TYPE_CHOICES = [ | |
| ("group", "Group"), | |
| ("private", "Private"), | |
| ("experience", "Experience"), | |
| ] | |
| LEVEL_CHOICES = [ | |
| ("beginner", "Beginner"), | |
| ("intermediate", "Intermediate"), | |
| ("advanced", "Advanced"), | |
| ] | |
| EXPERIENCE_TYPE_CHOICES = [ | |
| ("couples_date", "Couple’s Date"), | |
| ("birthday_party", "Birthday Party"), | |
| ("corporate", "Corporate"), | |
| ("masterclass", "Masterclass"), | |
| ] | |
| name = models.CharField(max_length=200) | |
| type = models.CharField(max_length=20, choices=WORKSHOP_TYPE_CHOICES) | |
| level = models.CharField(max_length=20, choices=LEVEL_CHOICES) | |
| experience_type = models.CharField( | |
| max_length=30, | |
| choices=EXPERIENCE_TYPE_CHOICES, | |
| blank=True, | |
| null=True | |
| ) | |
| description = models.TextField() | |
| long_description = models.TextField() | |
| images = models.JSONField(default=list) | |
| duration = models.CharField(max_length=50) | |
| min_participants = models.PositiveIntegerField() | |
| max_participants = models.PositiveIntegerField() | |
| price = models.PositiveIntegerField() | |
| price_per_person = models.BooleanField(default=True) | |
| includes = models.JSONField(default=list) | |
| requirements = models.JSONField(blank=True, null=True) | |
| provided_materials = models.JSONField(default=list) | |
| location = models.CharField(max_length=200) | |
| instructor = models.CharField(max_length=100) | |
| take_home = models.CharField(max_length=200) | |
| certificate = models.BooleanField(default=False) | |
| lunch_included = models.BooleanField(default=False) | |
| featured = models.BooleanField(default=False) | |
| is_active = models.BooleanField(default=True) | |
| def __str__(self): | |
| return self.name | |
| class WorkshopSlot(models.Model): | |
| workshop = models.ForeignKey( | |
| Workshop, | |
| on_delete=models.CASCADE, | |
| related_name="slots" | |
| ) | |
| date = models.DateField() | |
| start_time = models.TimeField() | |
| end_time = models.TimeField() | |
| available_spots = models.PositiveIntegerField() | |
| is_available = models.BooleanField(default=True) | |
| def __str__(self): | |
| return f"{self.workshop.name} | {self.date} {self.start_time}" | |
| class WorkshopRegistration(models.Model): | |
| STATUS_CHOICES = ( | |
| ("pending", "Pending"), | |
| ("confirmed", "Confirmed"), | |
| ("failed", "Failed"), | |
| ) | |
| workshop = models.ForeignKey( | |
| Workshop, | |
| on_delete=models.CASCADE, | |
| related_name="registrations" | |
| ) | |
| slot = models.ForeignKey( | |
| WorkshopSlot, | |
| on_delete=models.PROTECT, | |
| related_name="registrations" | |
| ) | |
| name = models.CharField(max_length=100) | |
| email = models.EmailField() | |
| phone = models.CharField(max_length=15) | |
| number_of_participants = models.PositiveIntegerField() | |
| special_requests = models.TextField(blank=True, null=True) | |
| gst_number = models.CharField(max_length=50, blank=True, null=True) | |
| status = models.CharField( | |
| max_length=20, | |
| choices=STATUS_CHOICES, | |
| default="pending" | |
| ) | |
| # 🔗 LINK TO ORDERS APP | |
| payment_order = models.OneToOneField( | |
| "orders.PaymentOrder", | |
| on_delete=models.SET_NULL, | |
| null=True, | |
| blank=True, | |
| related_name="workshop_registration" | |
| ) | |
| created_at = models.DateTimeField(auto_now_add=True) | |
| def __str__(self): | |
| return f"{self.name} - {self.workshop.name}" |