39291-vm/core/models.py
Flatlogic Bot 46ee143ab1 1.1
2026-04-01 16:28:08 +00:00

73 lines
2.9 KiB
Python

from decimal import Decimal
from django.core.exceptions import ValidationError
from django.db import models
from django.urls import reverse
from django.utils import timezone
class Trip(models.Model):
class TripType(models.TextChoices):
BUSINESS = "business", "Business"
PERSONAL = "personal", "Personal"
COMMUTING = "commuting", "Commuting"
REPAIR = "repair", "Repair / Maintenance"
class DistanceSource(models.TextChoices):
ODOMETER = "odometer", "Odometer"
MAP = "map", "Google Maps"
date = models.DateField()
start_time = models.TimeField()
end_time = models.TimeField()
start_location = models.CharField(max_length=255)
end_location = models.CharField(max_length=255)
business_purpose = models.TextField()
trip_type = models.CharField(max_length=20, choices=TripType.choices)
start_odometer = models.DecimalField(max_digits=10, decimal_places=1, null=True, blank=True)
end_odometer = models.DecimalField(max_digits=10, decimal_places=1, null=True, blank=True)
distance_miles = models.DecimalField(max_digits=8, decimal_places=1, null=True, blank=True)
distance_source = models.CharField(max_length=20, choices=DistanceSource.choices, default=DistanceSource.MAP)
notes = models.TextField(blank=True)
created_at = models.DateTimeField(default=timezone.now)
updated_at = models.DateTimeField(default=timezone.now)
class Meta:
ordering = ["-date", "-start_time", "-created_at"]
def __str__(self):
return f"{self.date:%Y-%m-%d} · {self.start_location}{self.end_location}"
def get_absolute_url(self):
return reverse("trip_detail", args=[self.pk])
@property
def miles_display(self):
return self.distance_miles or Decimal("0.0")
def clean(self):
errors = {}
if self.end_time and self.start_time and self.end_time < self.start_time:
errors["end_time"] = "End time must be after the start time."
if self.start_odometer is not None and self.end_odometer is not None:
if self.end_odometer < self.start_odometer:
errors["end_odometer"] = "Ending odometer must be greater than or equal to starting odometer."
else:
self.distance_miles = self.end_odometer - self.start_odometer
self.distance_source = self.DistanceSource.ODOMETER
elif self.distance_miles is not None:
if self.distance_miles < 0:
errors["distance_miles"] = "Distance must be zero or greater."
else:
self.distance_source = self.DistanceSource.MAP
else:
errors["distance_miles"] = "Add odometer readings or calculate mileage from Google Maps."
if errors:
raise ValidationError(errors)
def save(self, *args, **kwargs):
self.full_clean()
super().save(*args, **kwargs)