M54: harden operations and demo resilience
This commit is contained in:
@@ -27,6 +27,7 @@ from app.schemas import (
|
||||
VehiclePageOut,
|
||||
)
|
||||
from app.services.audit import record_audit_event
|
||||
from app.services.data_quality import open_odometer_regression_issue
|
||||
|
||||
router = APIRouter(prefix="/api/v1/vehicles", tags=["vehicles"])
|
||||
|
||||
@@ -143,7 +144,7 @@ def list_vehicles(
|
||||
def get_vehicle(
|
||||
public_ref: str,
|
||||
db: Session = Depends(get_db),
|
||||
_user: CurrentUser = Depends(get_current_user),
|
||||
user: CurrentUser = Depends(get_current_user),
|
||||
) -> VehicleDetailOut:
|
||||
vehicle = db.scalar(select(Vehicle).where(Vehicle.public_ref == public_ref))
|
||||
if vehicle is None:
|
||||
@@ -163,11 +164,21 @@ def get_vehicle(
|
||||
.where(MaintenanceRecord.vehicle_id == vehicle.id)
|
||||
.order_by(MaintenanceRecord.occurred_at.desc())
|
||||
).all()
|
||||
issues = db.scalars(
|
||||
select(DataQualityIssue)
|
||||
.where(DataQualityIssue.entity_type == "vehicle", DataQualityIssue.entity_id == vehicle.id)
|
||||
.order_by(DataQualityIssue.detected_at.desc())
|
||||
).all()
|
||||
# Detailed data-quality evidence is an operations-manager surface. Employees still
|
||||
# get the operational vehicle record they need, but never receive hidden evidence in
|
||||
# the payload merely because the frontend omits the Quality tab.
|
||||
issues = (
|
||||
db.scalars(
|
||||
select(DataQualityIssue)
|
||||
.where(
|
||||
DataQualityIssue.entity_type == "vehicle",
|
||||
DataQualityIssue.entity_id == vehicle.id,
|
||||
)
|
||||
.order_by(DataQualityIssue.detected_at.desc())
|
||||
).all()
|
||||
if user.role == "operations_manager"
|
||||
else []
|
||||
)
|
||||
|
||||
booking_by_id = {b.id: b.public_ref for b in bookings}
|
||||
next_booking = next(
|
||||
@@ -276,6 +287,12 @@ def create_maintenance_record(
|
||||
vehicle = db.scalar(select(Vehicle).where(Vehicle.public_ref == public_ref).with_for_update())
|
||||
if vehicle is None:
|
||||
raise HTTPException(status_code=404, detail="Vehicle not found")
|
||||
correlation_id = uuid.uuid4()
|
||||
before_vehicle = {
|
||||
"operational_status": vehicle.operational_status,
|
||||
"odometer_km": vehicle.odometer_km,
|
||||
"next_service_km": vehicle.next_service_km,
|
||||
}
|
||||
record = MaintenanceRecord(
|
||||
public_ref=f"MAINT-{uuid.uuid4().hex[:8].upper()}",
|
||||
vehicle_id=vehicle.id,
|
||||
@@ -285,6 +302,17 @@ def create_maintenance_record(
|
||||
summary=body.summary.strip(),
|
||||
)
|
||||
db.add(record)
|
||||
open_odometer_regression_issue(
|
||||
db,
|
||||
vehicle=vehicle,
|
||||
reading_ref=record.public_ref,
|
||||
reading_km=body.odometer_km,
|
||||
canonical_km=vehicle.odometer_km,
|
||||
source_type="maintenance",
|
||||
related_refs=[record.public_ref],
|
||||
actor_label=user.display_name,
|
||||
correlation_id=correlation_id,
|
||||
)
|
||||
vehicle.odometer_km = max(vehicle.odometer_km, body.odometer_km)
|
||||
if body.next_service_km is not None:
|
||||
if body.next_service_km < vehicle.odometer_km:
|
||||
@@ -301,7 +329,14 @@ def create_maintenance_record(
|
||||
action="maintenance_record_created",
|
||||
entity_type="vehicle",
|
||||
entity_id=vehicle.id,
|
||||
after={"maintenance_ref": record.public_ref, "status": vehicle.operational_status},
|
||||
correlation_id=correlation_id,
|
||||
before=before_vehicle,
|
||||
after={
|
||||
"maintenance_ref": record.public_ref,
|
||||
"operational_status": vehicle.operational_status,
|
||||
"odometer_km": vehicle.odometer_km,
|
||||
"next_service_km": vehicle.next_service_km,
|
||||
},
|
||||
)
|
||||
db.commit()
|
||||
return MaintenanceOut(
|
||||
|
||||
Reference in New Issue
Block a user