Files
booking_backend/booking/models.py
2026-04-10 20:51:43 -05:00

105 lines
4.1 KiB
Python

from django.conf import settings
from django.db import models
from django.db.models import Q
class AvailabilitySlot(models.Model):
equipment_item = models.ForeignKey(
"equipment.EquipmentItem",
on_delete=models.CASCADE,
null=True,
blank=True,
related_name="availability_slots",
)
adventure_offering = models.ForeignKey(
"adventrues.AdventureOffering",
on_delete=models.CASCADE,
null=True,
blank=True,
related_name="availability_slots",
)
starts_at = models.DateTimeField()
ends_at = models.DateTimeField()
is_available = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
constraints = [
models.CheckConstraint(
condition=Q(equipment_item__isnull=False, adventure_offering__isnull=True)
| Q(equipment_item__isnull=True, adventure_offering__isnull=False),
name="availability_slot_exactly_one_target",
),
models.CheckConstraint(condition=Q(ends_at__gt=models.F("starts_at")), name="availability_slot_valid_range"),
]
ordering = ("starts_at",)
def __str__(self) -> str:
target = self.equipment_item or self.adventure_offering
return f"{target} | {self.starts_at} - {self.ends_at}"
class Booking(models.Model):
class Status(models.TextChoices):
REQUESTED = "requested", "Requested"
APPROVED = "approved", "Approved"
DECLINED = "declined", "Declined"
CANCELLED = "cancelled", "Cancelled"
CONFIRMED = "confirmed", "Confirmed"
customer = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="bookings", limit_choices_to={"is_customer": True}
)
vendor = models.ForeignKey("accounts.VendorProfile", on_delete=models.CASCADE, related_name="bookings")
equipment_item = models.ForeignKey(
"equipment.EquipmentItem", on_delete=models.SET_NULL, null=True, blank=True, related_name="bookings"
)
adventure_offering = models.ForeignKey(
"adventrues.AdventureOffering", on_delete=models.SET_NULL, null=True, blank=True, related_name="bookings"
)
starts_at = models.DateTimeField()
ends_at = models.DateTimeField()
status = models.CharField(max_length=16, choices=Status.choices, default=Status.REQUESTED)
total_price = models.DecimalField(max_digits=10, decimal_places=2, default=0)
customer_notes = models.TextField(blank=True)
vendor_notes = models.TextField(blank=True)
listing_click = models.ForeignKey(
"marketing.ListingClick",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="bookings",
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
constraints = [
models.CheckConstraint(
condition=Q(equipment_item__isnull=False, adventure_offering__isnull=True)
| Q(equipment_item__isnull=True, adventure_offering__isnull=False),
name="booking_exactly_one_target",
),
models.CheckConstraint(condition=Q(ends_at__gt=models.F("starts_at")), name="booking_valid_range"),
]
ordering = ("-created_at",)
def __str__(self) -> str:
return f"Booking #{self.id} ({self.status})"
class BookingEventLog(models.Model):
booking = models.ForeignKey(Booking, on_delete=models.CASCADE, related_name="events")
from_status = models.CharField(max_length=16, choices=Booking.Status.choices, blank=True)
to_status = models.CharField(max_length=16, choices=Booking.Status.choices)
note = models.TextField(blank=True)
actor = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ("-created_at",)
def __str__(self) -> str:
return f"Booking {self.booking_id}: {self.from_status} -> {self.to_status}"