Coverage for src/api/models.py: 98%
42 statements
« prev ^ index » next coverage.py v7.11.1, created at 2025-11-08 10:41 +0000
« prev ^ index » next coverage.py v7.11.1, created at 2025-11-08 10:41 +0000
1from django.conf import settings
2from django.db import models
3from django.utils import timezone
5class ParkingLot(models.Model):
6 name = models.CharField(max_length=100)
7 city = models.CharField(max_length=100)
8 street = models.CharField(max_length=150)
9 building = models.CharField(max_length=20, blank=True)
11 def __str__(self):
12 return f"{self.name} ({self.city}, {self.street} {self.building or ''})"
14class Spot(models.Model):
15 number = models.CharField(max_length=10)
16 lot = models.ForeignKey(ParkingLot, related_name="spots", on_delete=models.CASCADE)
17 is_ev = models.BooleanField(default=False)
18 is_disabled = models.BooleanField(default=False)
20 created_by = models.ForeignKey(
21 settings.AUTH_USER_MODEL,
22 null=True,
23 blank=True,
24 on_delete=models.SET_NULL,
25 related_name="created_spots"
26 )
28 class Meta:
29 unique_together = ("lot", "number")
31 def __str__(self):
32 return f"{self.lot.name} #{self.number}"
34class Booking(models.Model):
35 user = models.ForeignKey(
36 settings.AUTH_USER_MODEL,
37 on_delete=models.SET_NULL,
38 null=True,
39 blank=True,
40 )
41 spot = models.ForeignKey(Spot, on_delete=models.PROTECT, related_name="bookings")
42 start_at = models.DateTimeField()
43 end_at = models.DateTimeField()
44 status = models.CharField(max_length=16, default="confirmed")
45 created_at = models.DateTimeField(auto_now_add=True)
46 cancellation_reason = models.CharField(max_length=255, blank=True, default="")
47 payment_intent_id = models.CharField(max_length=100, blank=True)
48 def check_cancellable_error(self) -> str | None:
49 if self.status == 'cancelled':
50 return 'Booking is already cancelled.'
52 if self.end_at <= timezone.now():
53 return 'Booking time has already completed and cannot be cancelled.'
55 return None
57 class Meta:
58 indexes = [
59 models.Index(fields=["spot", "start_at", "end_at", "status"])
60 ]
62class OperatorProfile(models.Model):
63 user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='operator_profile')
64 lot = models.ForeignKey(ParkingLot, on_delete=models.SET_NULL, null=True, related_name='operators')
66 def __str__(self):
67 return f"Operator {self.user.username} for {self.lot.name if self.lot else 'N/A'}"