utc(); $oneHourAgo = $now->copy()->subHours(1); $userFlights = UserFlight::whereBetween('arrival_date', [ $oneHourAgo->toDateTimeString(), $now->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}"); continue; } $airlineCode = strtoupper($matches[1]); $flightNumber = $matches[2]; $arrivalDate = $flight->arrival_date->setTimezone($flight->arrivalAirport->timezone); $year = $arrivalDate->year; $month = $arrivalDate->month; $day = $arrivalDate->day; $url = "https://www.flightstats.com/v2/api-next/flight-tracker/{$airlineCode}/{$flightNumber}/{$year}/{$month}/{$day}"; $response = Http::get($url); if (!$response->successful()) { $this->warn("Failed to fetch data for {$flight->flight_number}: HTTP {$response->status()}"); continue; } $data = $response->json(); $flightData = $data['data'] ?? []; if (empty($flightData)) { $this->warn("No flight data returned for {$airlineCode}{$flightNumber}"); continue; } $tailNumber = $flightData['positional']['flexTrack']['tailNumber'] ?? null; $estimatedDepartureUtc = $flightData['schedule']['estimatedActualDepartureUTC'] ?? null; $estimatedArrivalUtc = $flightData['schedule']['estimatedActualArrivalUTC'] ?? null; $equipmentCode = $flightData['additionalFlightInfo']['equipment']['iata'] ?? null; $apiDepartureIata = $data['data']['departureAirport']['iata'] ?? null; $apiArrivalIata = $data['data']['arrivalAirport']['iata'] ?? null; if ($apiDepartureIata !== $flight->departureAirport->iata_code || $apiArrivalIata !== $flight->arrivalAirport->iata_code) { $this->warn("Airport mismatch for {$airlineCode}{$flightNumber} — API: {$apiDepartureIata}→{$apiArrivalIata}, expected: {$flight->departureAirport->iata_code}→{$flight->arrivalAirport->iata_code}"); continue; } $updates = []; if ($tailNumber && $tailNumber !== $flight->aircraft_registration) { $updates['aircraft_registration'] = $tailNumber; } if ($estimatedDepartureUtc && Carbon::parse($estimatedDepartureUtc)->ne($flight->departure_date)) { $updates['departure_date'] = Carbon::parse($estimatedDepartureUtc); } if ($estimatedArrivalUtc && Carbon::parse($estimatedArrivalUtc)->ne($flight->arrival_date)) { $updates['arrival_date'] = Carbon::parse($estimatedArrivalUtc); } if (!empty($updates)) { $flight->update($updates); $this->info("Updated flight {$airlineCode}{$flightNumber}: " . implode(', ', array_keys($updates))); } $this->info("Flight {$airlineCode}{$flightNumber} — Tail: {$tailNumber}, Equipment: {$equipmentCode}"); $this->info("Departure: {$estimatedDepartureUtc} | Arrival: {$estimatedArrivalUtc}"); } } }