$flight->user_id, 'title' => "Auto update failed for {$flight->flight_number}", 'body' => "There was an error fetching flight data for {$flight->flight_number}. Please manually check the aircraft type, registration and departure/arrival times.", 'url' => '/flights/' . $flight->id . '/edit' ]); $flight->update(['auto_update' => false]); } /** * Execute the console command. */ public function handle(): void { $now = now()->utc(); $userFlights = UserFlight::where('arrival_date', '<=', $now->copy()->subHour()->toDateTimeString()) ->where('auto_update', true) ->whereNotNull('flight_number') ->get(); $this->info("Found {$userFlights->count()} flights."); foreach ($userFlights as $flight) { preg_match('/^([A-Z]{2,3})(\d+)$/i', $flight->flight_number, $matches); if (empty($matches)) { $this->warn("Could not parse flight number: {$flight->flight_number}"); $this->notifyDataError($flight); continue; } $airlineCode = strtoupper($matches[1]); $flightNumber = $matches[2]; $arrivalDate = $flight->arrival_date->setTimezone($flight->arrivalAirport->timezone); $data = $this->flightStats->fetchFlightData($airlineCode, $flightNumber, $arrivalDate); if (!$data) { $this->warn("No flight data returned for {$airlineCode}{$flightNumber}"); $this->notifyDataError($flight); continue; } if ($data->departure_iata !== $flight->departureAirport->iata_code || $data->arrival_iata !== $flight->arrivalAirport->iata_code) { $this->warn("Airport mismatch for {$airlineCode}{$flightNumber} — API: {$data->departure_iata}→{$data->arrival_iata}, expected: {$flight->departureAirport->iata_code}→{$flight->arrivalAirport->iata_code}"); $this->notifyDataError($flight); continue; } $updates = []; if ($data->aircraft_registration && $data->aircraft_registration !== $flight->aircraft_registration) { $updates['aircraft_registration'] = $data->aircraft_registration; } if ($data->estimated_departure_utc?->ne($flight->departure_date)) { $updates['departure_date'] = $data->estimated_departure_utc; } if ($data->estimated_arrival_utc?->ne($flight->arrival_date)) { $updates['arrival_date'] = $data->estimated_arrival_utc; } if ($data->equipment_iata) { $currentAircraft = $flight->aircraft; if ($currentAircraft?->iata_code !== $data->equipment_iata) { $match = $this->flightStats->guessAircraftFromIata($data->equipment_iata); if ($match) { $updates['aircraft_id'] = $match->id; } else { Log::info("No aircraft match for IATA code {$data->equipment_iata} on flight {$airlineCode}{$flightNumber}"); } } } if (!empty($updates)) { $flight->update($updates); $this->info("Updated flight {$airlineCode}{$flightNumber}: " . implode(', ', array_keys($updates))); $changeDescriptions = []; if (isset($updates['aircraft_registration'])) { $changeDescriptions[] = "Registration updated to {$updates['aircraft_registration']}"; } if (isset($updates['departure_date'])) { $changeDescriptions[] = "Departure updated to {$updates['departure_date']}"; } if (isset($updates['arrival_date'])) { $changeDescriptions[] = "Arrival updated to {$updates['arrival_date']}"; } if (isset($updates['aircraft_id'])) { $aircraft = Aircraft::find($updates['aircraft_id']); $changeDescriptions[] = "Aircraft type updated to {$aircraft->display_name_short}"; } Notification::create([ 'user_id' => $flight->user_id, 'title' => "Flight {$airlineCode}{$flightNumber} updated", 'body' => implode("\n", $changeDescriptions), 'url' => '/u/'. $flight->user->name . '/flight/'. $flight->id, ]); } else { $this->info("No changes for {$airlineCode}{$flightNumber}"); Notification::create([ 'user_id' => $flight->user_id, 'title' => "Flight {$airlineCode}{$flightNumber} updated — no changes", 'body' => "Your flight was completed and no updates were made to aircraft, registration, or departure/arrival times.", 'url' => '/u/'. $flight->user->name . '/flight/'. $flight->id, ]); } $flight->update(['auto_update' => false]); } } }