Save user flights

This commit is contained in:
2026-04-05 15:06:27 +10:00
parent bf34c20d85
commit 8a1581641b
9 changed files with 305 additions and 64 deletions
+98 -61
View File
@@ -5,38 +5,17 @@ namespace App\Http\Controllers;
use App\Models\Aircraft;
use App\Models\Airline;
use App\Models\Airport;
use App\Models\FlightClass;
use App\Models\FlightReason;
use App\Models\ImportedFlight;
use App\Models\SeatType;
use App\Models\UserFlight;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class FlightImportController extends Controller
{
const array FLIGHT_CLASSES = [
0 => 'Please Select',
1 => 'Economy',
2 => 'Business',
3 => 'First',
4 => 'Premium Economy',
5 => 'Private',
];
const array SEAT_TYPES = [
0 => 'Please Select',
1 => 'Window',
2 => 'Middle',
3 => 'Aisle',
];
const array FLIGHT_REASONS = [
0 => 'Please Select',
1 => 'Pleasure',
2 => 'Business',
3 => 'Crew',
4 => 'Other',
];
private function formatTime(?string $time): string
{
if (!$time) return '00:00';
@@ -45,6 +24,15 @@ class FlightImportController extends Controller
return str_pad($hours, 2, '0', STR_PAD_LEFT) . ':' . $minutes;
}
private function selectOptions($model): array
{
return $model::orderBy('id')
->get(['id', 'name'])
->map(fn($item) => ['value' => $item->id, 'title' => $item->name])
->values()
->toArray();
}
public function getPossibleAircraft(string $aircraftQuery) {
preg_match('/\((\w+)\)/', $aircraftQuery, $matches);
$designator = $matches[1] ?? null;
@@ -153,19 +141,10 @@ class FlightImportController extends Controller
return [
'flight_classes' => collect(self::FLIGHT_CLASSES)->map(fn($title, $value) => [
'value' => $value,
'title' => $title,
])->values(),
'flight_reasons' => collect(self::FLIGHT_REASONS)->map(fn($title, $value) => [
'value' => $value,
'title' => $title,
])->values(),
'seat_types' => collect(self::SEAT_TYPES)->map(fn($title, $value) => [
'value' => $value,
'title' => $title,
])->values(),
'imported_flight_id' => $flightToReconcile->id,
'flight_classes' => $this->selectOptions(FlightClass::class),
'flight_reasons' => $this->selectOptions(FlightReason::class),
'seat_types' => $this->selectOptions(SeatType::class),
'flight_number' => $flightToReconcile->flight_number ?? '',
'date' => $date ?? '',
'dep_time' => $this->formatTime($flightToReconcile->dep_time),
@@ -184,32 +163,90 @@ class FlightImportController extends Controller
];
}
public function save(Request $request){
public function save(Request $request)
{
$validated = $request->validate([
'date' => 'required|date',
'flight_number' => 'required|string',
'from_id' => 'required|integer|exists:airports,id',
'to_id' => 'required|integer|exists:airports,id',
'dep_time' => 'nullable|date_format:H:i',
'arr_time' => 'nullable|date_format:H:i',
'duration' => 'required|date_format:H:i',
'airline_id' => 'nullable|integer|exists:airlines,id',
'aircraft_id' => 'nullable|integer|exists:aircraft,id',
'registration' => 'nullable|string',
'seat_number' => 'nullable|string',
'seat_type_id' => 'nullable|integer',
'flight_class_id' => 'nullable|integer',
'flight_reason_id' => 'nullable|integer',
'note' => 'nullable|string',
],[
'from_id.required' => 'Please select a departure airport.',
'to_id.required' => 'Please select an arrival airport.',
'dep_time.date_format' => 'Departure time must be in HH:MM format, i.e: 01:25',
'arr_time.date_format' => 'Arrival time must be in HH:MM format, i.e: 12:25',
'duration.date_format' => 'Must be in HH:MM format, e.g: 03:37',
'duration.required' => 'A duration is required to be able to accurately calculate the arrival date',
'date' => 'required|date',
'imported_flight_id' => 'required|exists:imported_flights,id',
'flight_number' => 'required|string',
'from_id' => 'required|integer|exists:airports,id',
'to_id' => 'required|integer|exists:airports,id',
'dep_time' => 'nullable|date_format:H:i',
'arr_time' => 'nullable|date_format:H:i',
'duration' => 'required|date_format:H:i',
'airline_id' => 'nullable|integer|exists:airlines,id',
'aircraft_id' => 'nullable|integer|exists:aircraft,id',
'registration' => 'nullable|string',
'seat_number' => 'nullable|string',
'seat_type_id' => 'nullable|integer|exists:seat_types,id',
'flight_class_id' => 'nullable|integer|exists:flight_classes,id',
'flight_reason_id' => 'nullable|integer|exists:flight_reasons,id',
'note' => 'nullable|string',
], [
'imported_flight_id.required' => 'The flight you are trying to reconcile needs to be reimported or refreshed.',
'from_id.required' => 'Please select a departure airport.',
'to_id.required' => 'Please select an arrival airport.',
'dep_time.date_format' => 'Departure time must be in HH:MM format, i.e: 01:25',
'arr_time.date_format' => 'Arrival time must be in HH:MM format, i.e: 12:25',
'duration.date_format' => 'Must be in HH:MM format, e.g: 03:37',
'duration.required' => 'A duration is required to be able to accurately calculate the arrival date',
]);
$user = Auth::user();
$departureAirport = Airport::find($validated['from_id']);
$arrivalAirport = Airport::find($validated['to_id']);
// Parse departure in local airport timezone, then convert to UTC
$depTime = $validated['dep_time'] ?? '00:00';
$departure = Carbon::createFromFormat(
'Y-m-d H:i',
$validated['date'] . ' ' . $depTime,
$departureAirport->timezone
)->utc();
// Calculate duration-based arrival in UTC
[$durationHours, $durationMinutes] = explode(':', $validated['duration']);
$durationArrival = $departure->copy()
->addHours((int) $durationHours)
->addMinutes((int) $durationMinutes);
// If arrival time provided, parse it in arrival airport timezone and convert to UTC
if (!empty($validated['arr_time'])) {
$arrival = Carbon::createFromFormat(
'Y-m-d H:i',
$validated['date'] . ' ' . $validated['arr_time'],
$arrivalAirport->timezone
)->utc();
// If arrival is not after departure, fall back to duration-based arrival
if ($arrival->lte($departure)) {
$arrival = $durationArrival;
}
} else {
$arrival = $durationArrival;
}
UserFlight::create([
'user_id' => $user->id,
'departure_date' => $departure,
'arrival_date' => $arrival,
'flight_number' => $validated['flight_number'],
'departure_airport_id' => $validated['from_id'],
'arrival_airport_id' => $validated['to_id'],
'airline_id' => $validated['airline_id'] ?? null,
'aircraft_id' => $validated['aircraft_id'] ?? null,
'aircraft_registration' => $validated['registration'] ?? null,
'seat_number' => $validated['seat_number'] ?? null,
'seat_type_id' => $validated['seat_type_id'] ?? null,
'flight_class_id' => $validated['flight_class_id'] ?? null,
'flight_reason_id' => $validated['flight_reason_id'] ?? null,
'note' => $validated['note'] ?? null,
]);
ImportedFlight::destroy($validated['imported_flight_id']);
return redirect()->route('reconcile');
}