added more flight logic

This commit is contained in:
2025-09-30 18:26:14 -05:00
parent 12bedaf6a8
commit 9493fffff5
3 changed files with 58 additions and 11 deletions

View File

@@ -0,0 +1,23 @@
# Generated by Django 5.2.6 on 2025-09-30 23:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('simulator', '0002_equipment_base_location'),
]
operations = [
migrations.AddField(
model_name='equipment',
name='air_time_hours',
field=models.DecimalField(decimal_places=2, default=0, help_text='Total air time in hours', max_digits=10),
),
migrations.AddField(
model_name='equipment',
name='cycles',
field=models.PositiveIntegerField(default=0, help_text='Total number of flight cycles (takeoff/landing pairs)'),
),
]

View File

@@ -26,6 +26,15 @@ class Equipment(models.Model):
null=True, null=True,
blank=True, blank=True,
) )
cycles = models.PositiveIntegerField(
default=0, help_text="Total number of flight cycles (takeoff/landing pairs)"
)
air_time_hours = models.DecimalField(
max_digits=10,
decimal_places=2,
default=0,
help_text="Total air time in hours",
)
def __str__(self): def __str__(self):
return f"{self.registration} ({self.model})" return f"{self.registration} ({self.model})"
@@ -38,7 +47,6 @@ class Equipment(models.Model):
now = timezone.now() now = timezone.now()
# Get the most recent flight relative to now
last_flight = ( last_flight = (
self.flights.filter(departure_time__lte=now) self.flights.filter(departure_time__lte=now)
.order_by("-departure_time") .order_by("-departure_time")
@@ -46,10 +54,8 @@ class Equipment(models.Model):
) )
if last_flight: if last_flight:
# Check if plane is currently in flight
if last_flight.departure_time <= now < last_flight.arrival_time: if last_flight.departure_time <= now < last_flight.arrival_time:
return "In-Flight" return "In-Flight"
# Plane has arrived at destination
elif last_flight.arrival_time <= now: elif last_flight.arrival_time <= now:
return last_flight.destination return last_flight.destination

View File

@@ -7,6 +7,7 @@ from simulator.utils import haversine_nm
from datetime import timedelta from datetime import timedelta
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.utils import timezone from django.utils import timezone
from decimal import Decimal
class Flight(models.Model): class Flight(models.Model):
@@ -49,7 +50,7 @@ class Flight(models.Model):
@property @property
def duration(self) -> timedelta: def duration(self) -> timedelta:
speed = self.equipment.model.cruise_speed_kt # knots = nm/hr speed = self.equipment.model.cruise_speed_kt
hours = self.distance_nm / speed hours = self.distance_nm / speed
return timedelta(hours=hours) return timedelta(hours=hours)
@@ -58,15 +59,23 @@ class Flight(models.Model):
return self.departure_time + self.duration return self.departure_time + self.duration
def clean(self): def clean(self):
# Validate flight distance is within aircraft range # Validate origin and destination are different
if self.origin == self.destination:
raise ValidationError("Origin and destination airports cannot be the same.")
# Validate carrier owns the equipment
if self.equipment.owner != self.carrier:
raise ValidationError(
f"{self.equipment} is owned by {self.equipment.owner}, "
f"not {self.carrier}. Cannot assign equipment to this flight."
)
if self.distance_nm > self.equipment.model.range_nm: if self.distance_nm > self.equipment.model.range_nm:
raise ValidationError( raise ValidationError(
f"Flight distance ({self.distance_nm:.0f} nm) exceeds {self.equipment.model} " f"Flight distance ({self.distance_nm:.0f} nm) exceeds {self.equipment.model} "
f"maximum range ({self.equipment.model.range_nm} nm)." f"maximum range ({self.equipment.model.range_nm} nm)."
) )
# Validate equipment is at the origin airport
# Get the last flight before this one chronologically
previous_flight = ( previous_flight = (
Flight.objects.filter( Flight.objects.filter(
equipment=self.equipment, departure_time__lt=self.departure_time equipment=self.equipment, departure_time__lt=self.departure_time
@@ -77,7 +86,6 @@ class Flight(models.Model):
) )
if previous_flight: if previous_flight:
# Equipment must be at the destination of the previous flight
if previous_flight.destination != self.origin: if previous_flight.destination != self.origin:
raise ValidationError( raise ValidationError(
f"{self.equipment} will be at {previous_flight.destination.icao} " f"{self.equipment} will be at {previous_flight.destination.icao} "
@@ -85,14 +93,12 @@ class Flight(models.Model):
f"Cannot depart from {self.origin.icao}." f"Cannot depart from {self.origin.icao}."
) )
# Ensure enough time between arrival and next departure (at least arrival happens before departure)
if previous_flight.arrival_time > self.departure_time: if previous_flight.arrival_time > self.departure_time:
raise ValidationError( raise ValidationError(
f"{self.equipment} arrives at {self.origin.icao} at {previous_flight.arrival_time}. " f"{self.equipment} arrives at {self.origin.icao} at {previous_flight.arrival_time}. "
f"Cannot depart before arrival." f"Cannot depart before arrival."
) )
else: else:
# No previous flights, equipment must be at base location
if ( if (
self.equipment.base_location self.equipment.base_location
and self.equipment.base_location != self.origin and self.equipment.base_location != self.origin
@@ -102,7 +108,6 @@ class Flight(models.Model):
f"First flight must depart from base location, not {self.origin.icao}." f"First flight must depart from base location, not {self.origin.icao}."
) )
# Calculate arrival time for this flight
arrival = self.arrival_time arrival = self.arrival_time
@property @property
@@ -114,3 +119,16 @@ class Flight(models.Model):
return "In-Flight" return "In-Flight"
else: else:
return "Arrived" return "Arrived"
def save(self, *args, **kwargs):
"""Override save to update equipment cycles and air time when flight completes."""
is_new = self.pk is None
super().save(*args, **kwargs)
if not is_new and self.status == "Arrived":
if not hasattr(self, "_stats_updated"):
flight_hours = Decimal(str(self.duration.total_seconds() / 3600))
self.equipment.cycles += 1
self.equipment.air_time_hours += flight_hours
self.equipment.save(update_fields=["cycles", "air_time_hours"])
self._stats_updated = True