Major refactor WIP

This commit is contained in:
2026-04-03 11:13:44 -04:00
parent dee58e0aae
commit 7b2de645db
25 changed files with 5841 additions and 7760 deletions
+38
View File
@@ -6,6 +6,9 @@ from app.models.arrival import Arrival, ArrivalStatus
from app.schemas.arrival import ArrivalCreate, ArrivalUpdate, ArrivalStatusUpdate
from app.models.journal import EntityType
from app.crud.crud_journal import journal
from app.crud.crud_movement import movement as movement_crud
from app.schemas.movement import MovementCreate
from app.models.movement import MovementType
class CRUDArrival:
@@ -155,6 +158,41 @@ class CRUDArrival:
db.commit()
db.refresh(db_obj)
# Create movement record if applicable
if status == ArrivalStatus.LANDED and db_obj.landed_dt:
movement_data = MovementCreate(
movement_type=MovementType.LANDING,
aircraft_registration=db_obj.registration,
aircraft_type=db_obj.type,
callsign=db_obj.callsign,
timestamp=db_obj.landed_dt,
entity_type="ARRIVAL",
entity_id=arrival_id,
from_location=db_obj.in_from,
created_by=user,
ip_address=user_ip
)
movement_crud.create(db, movement_data)
# Promote any PENDING departure linked to this arrival to BOOKED_OUT
from app.models.departure import Departure as DepartureModel, DepartureStatus as DepStatus
pending_dep = db.query(DepartureModel).filter(
DepartureModel.arrival_id == arrival_id,
DepartureModel.status == DepStatus.PENDING
).first()
if pending_dep:
pending_dep.status = DepStatus.BOOKED_OUT
db.add(pending_dep)
db.commit()
journal.log_change(
db,
EntityType.ARRIVAL,
arrival_id,
f"Linked departure #{pending_dep.id} promoted to BOOKED_OUT on landing",
user,
user_ip
)
# Log status change in journal
journal.log_change(
db,
+38
View File
@@ -6,6 +6,11 @@ from app.models.circuit import Circuit
from app.schemas.circuit import CircuitCreate, CircuitUpdate
from app.models.journal import EntityType
from app.crud.crud_journal import journal
from app.crud.crud_movement import movement as movement_crud
from app.schemas.movement import MovementCreate
from app.models.movement import MovementType
from app.crud.crud_local_flight import local_flight as crud_local_flight
from app.crud.crud_arrival import arrival as crud_arrival
class CRUDCircuit:
@@ -56,6 +61,39 @@ class CRUDCircuit:
user_ip
)
# Create TOUCH_AND_GO movement
if obj_in.local_flight_id:
flight = crud_local_flight.get(db, obj_in.local_flight_id)
if flight:
movement_data = MovementCreate(
movement_type=MovementType.TOUCH_AND_GO,
aircraft_registration=flight.registration,
aircraft_type=flight.type,
callsign=flight.callsign,
timestamp=obj_in.circuit_timestamp,
entity_type="LOCAL_FLIGHT",
entity_id=obj_in.local_flight_id,
created_by=user,
ip_address=user_ip
)
movement_crud.create(db, movement_data)
elif obj_in.arrival_id:
arrival = crud_arrival.get(db, obj_in.arrival_id)
if arrival:
movement_data = MovementCreate(
movement_type=MovementType.TOUCH_AND_GO,
aircraft_registration=arrival.registration,
aircraft_type=arrival.type,
callsign=arrival.callsign,
timestamp=obj_in.circuit_timestamp,
entity_type="ARRIVAL",
entity_id=obj_in.arrival_id,
from_location=arrival.in_from,
created_by=user,
ip_address=user_ip
)
movement_crud.create(db, movement_data)
return db_obj
def update(self, db: Session, db_obj: Circuit, obj_in: CircuitUpdate, user: str = "system", user_ip: Optional[str] = None) -> Circuit:
+30 -2
View File
@@ -6,6 +6,9 @@ from app.models.departure import Departure, DepartureStatus
from app.schemas.departure import DepartureCreate, DepartureUpdate, DepartureStatusUpdate
from app.models.journal import EntityType
from app.crud.crud_journal import journal
from app.crud.crud_movement import movement as movement_crud
from app.schemas.movement import MovementCreate
from app.models.movement import MovementType
class CRUDDeparture:
@@ -57,9 +60,18 @@ class CRUDDeparture:
if submitted_via == SubmissionSource.ADMIN:
initial_status = DepartureStatus.GROUND
contact_dt = func.now() # Set contact_dt to creation time for admin submissions
obj_data = obj_in.dict()
arrival_id = obj_data.pop('arrival_id', None)
# If arrival_id is provided this is a PPR-linked departure — stay PENDING until arrival lands
if arrival_id is not None:
initial_status = DepartureStatus.PENDING
contact_dt = None
db_obj = Departure(
**obj_in.dict(),
**obj_data,
arrival_id=arrival_id,
created_by=created_by,
status=initial_status,
contact_dt=contact_dt,
@@ -149,6 +161,22 @@ class CRUDDeparture:
db.commit()
db.refresh(db_obj)
# Create movement record if applicable
if db_obj.takeoff_dt and status == DepartureStatus.LOCAL:
movement_data = MovementCreate(
movement_type=MovementType.TAKEOFF,
aircraft_registration=db_obj.registration,
aircraft_type=db_obj.type,
callsign=db_obj.callsign,
timestamp=db_obj.takeoff_dt,
entity_type="DEPARTURE",
entity_id=departure_id,
to_location=db_obj.out_to,
created_by=user,
ip_address=user_ip
)
movement_crud.create(db, movement_data)
# Log status change in journal
journal.log_change(
db,
+36 -3
View File
@@ -7,6 +7,9 @@ from app.schemas.local_flight import LocalFlightCreate, LocalFlightUpdate, Local
from app.models.journal import EntityType
from app.models.circuit import Circuit
from app.crud.crud_journal import journal
from app.crud.crud_movement import movement as movement_crud
from app.schemas.movement import MovementCreate
from app.models.movement import MovementType
class CRUDLocalFlight:
@@ -186,9 +189,7 @@ class CRUDLocalFlight:
db_obj.contact_dt = current_time
elif status == LocalFlightStatus.DEPARTED:
db_obj.departed_dt = current_time
elif status == LocalFlightStatus.LOCAL:
db_obj.takeoff_dt = current_time
elif status == LocalFlightStatus.LANDED:
elif status == LocalFlightStatus.LANDED and not db_obj.landed_dt:
db_obj.landed_dt = current_time
# Count circuits from the circuits table and populate the circuits column
circuit_count = db.query(func.count(Circuit.id)).filter(
@@ -196,10 +197,42 @@ class CRUDLocalFlight:
).scalar()
db_obj.circuits = circuit_count
# Takeoff: happens once when transitioning away from GROUND
if old_status == LocalFlightStatus.GROUND and status in (LocalFlightStatus.DEPARTED, LocalFlightStatus.LOCAL, LocalFlightStatus.CIRCUIT) and not db_obj.takeoff_dt:
db_obj.takeoff_dt = current_time
db.add(db_obj)
db.commit()
db.refresh(db_obj)
# Create movement record if applicable
if db_obj.takeoff_dt and old_status == LocalFlightStatus.GROUND and status in (LocalFlightStatus.DEPARTED, LocalFlightStatus.LOCAL, LocalFlightStatus.CIRCUIT):
movement_data = MovementCreate(
movement_type=MovementType.TAKEOFF,
aircraft_registration=db_obj.registration,
aircraft_type=db_obj.type,
callsign=db_obj.callsign,
timestamp=db_obj.takeoff_dt,
entity_type="LOCAL_FLIGHT",
entity_id=flight_id,
created_by=user,
ip_address=user_ip
)
movement_crud.create(db, movement_data)
if db_obj.landed_dt and status == LocalFlightStatus.LANDED:
movement_data = MovementCreate(
movement_type=MovementType.LANDING,
aircraft_registration=db_obj.registration,
aircraft_type=db_obj.type,
callsign=db_obj.callsign,
timestamp=db_obj.landed_dt,
entity_type="LOCAL_FLIGHT",
entity_id=flight_id,
created_by=user,
ip_address=user_ip
)
movement_crud.create(db, movement_data)
# Log status change in journal
journal.log_change(
db,
+61
View File
@@ -0,0 +1,61 @@
from typing import List, Optional
from sqlalchemy.orm import Session
from sqlalchemy import and_, func
from datetime import date, datetime
from app.models.movement import Movement, MovementType
from app.schemas.movement import MovementCreate
class CRUDMovement:
def get(self, db: Session, movement_id: int) -> Optional[Movement]:
return db.query(Movement).filter(Movement.id == movement_id).first()
def get_multi(
self,
db: Session,
skip: int = 0,
limit: int = 100,
movement_type: Optional[MovementType] = None,
aircraft_registration: Optional[str] = None,
date_from: Optional[date] = None,
date_to: Optional[date] = None,
entity_type: Optional[str] = None
) -> List[Movement]:
query = db.query(Movement)
if movement_type:
query = query.filter(Movement.movement_type == movement_type)
if aircraft_registration:
query = query.filter(Movement.aircraft_registration.ilike(f"%{aircraft_registration}%"))
if date_from:
query = query.filter(func.date(Movement.timestamp) >= date_from)
if date_to:
query = query.filter(func.date(Movement.timestamp) <= date_to)
if entity_type:
query = query.filter(Movement.entity_type == entity_type)
return query.order_by(Movement.timestamp.desc()).offset(skip).limit(limit).all()
def create(self, db: Session, obj_in: MovementCreate) -> Movement:
db_obj = Movement(**obj_in.dict())
db.add(db_obj)
db.commit()
db.refresh(db_obj)
return db_obj
def get_movements_by_entity(self, db: Session, entity_type: str, entity_id: int) -> List[Movement]:
return db.query(Movement).filter(
and_(Movement.entity_type == entity_type, Movement.entity_id == entity_id)
).order_by(Movement.timestamp).all()
def get_daily_movements(self, db: Session, target_date: date) -> List[Movement]:
return db.query(Movement).filter(
func.date(Movement.timestamp) == target_date
).order_by(Movement.timestamp).all()
movement = CRUDMovement()
+18
View File
@@ -6,6 +6,9 @@ from app.models.overflight import Overflight, OverflightStatus
from app.schemas.overflight import OverflightCreate, OverflightUpdate, OverflightStatusUpdate
from app.models.journal import EntityType
from app.crud.crud_journal import journal
from app.crud.crud_movement import movement as movement_crud
from app.schemas.movement import MovementCreate
from app.models.movement import MovementType
class CRUDOverflight:
@@ -57,6 +60,21 @@ class CRUDOverflight:
db.commit()
db.refresh(db_obj)
# Create OVERFLIGHT movement if call_dt is set
if db_obj.call_dt:
movement_data = MovementCreate(
movement_type=MovementType.OVERFLIGHT,
aircraft_registration=db_obj.registration,
aircraft_type=db_obj.type,
timestamp=db_obj.call_dt,
entity_type="OVERFLIGHT",
entity_id=db_obj.id,
from_location=db_obj.departure_airfield,
to_location=db_obj.destination_airfield,
created_by=created_by
)
movement_crud.create(db, movement_data)
# Log creation in journal
journal.log_change(
db,