From 0f82aca4798b79322b37b463ccda4f4a8aed07e9 Mon Sep 17 00:00:00 2001 From: MANFahrer-GF Date: Sun, 31 May 2026 20:51:14 +0200 Subject: [PATCH] Fix PirepStats(): scope PAX/CGO totals to the selected airline/aircraft MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PirepStats() reported VA-wide PAX and Cargo figures on every airline- and aircraft-detail page. The fare totals used a whereNotIn() blacklist built only from the *non-accepted* pireps of the current scope, so it excluded just those few rows and still summed every other airline's/aircraft's fares. Replace it with a single JOIN grouped by fare type. The airline/aircraft scope lives in the JOIN's WHERE, so the figures are correctly scoped and nothing is materialised into a PHP id array — this also removes the MySQL ~65k WHERE IN limit that the original count() < 65500 guard worked around, so the guard is dropped. Soft-deleted pireps are excluded explicitly since join() bypasses the Pirep SoftDeletes scope. Co-Authored-By: Claude Opus 4.8 --- Services/DB_StatServices.php | 49 +++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/Services/DB_StatServices.php b/Services/DB_StatServices.php index 3292246..d0e7c00 100644 --- a/Services/DB_StatServices.php +++ b/Services/DB_StatServices.php @@ -401,20 +401,41 @@ public function PirepStats($airline_id = null, $aircraft_id = null) } // Count carried PAX and CGO for fancy stats - $allpireps = Pirep::where('state', '!=', PirepState::ACCEPTED)->when(isset($airline_id), function ($query) use ($airline_id) { - $query->where('airline_id', $airline_id); - })->when(isset($aircraft_id), function ($query) use ($aircraft_id) { - $query->where('aircraft_id', $aircraft_id); - })->pluck('id')->toArray(); - - if (count($allpireps) < 65500) { - $pax_amount = PirepFare::where('type', FareType::PASSENGER)->whereNotIn('pirep_id', $allpireps)->sum('count'); - $pax_avg = PirepFare::where('type', FareType::PASSENGER)->whereNotIn('pirep_id', $allpireps)->avg('count'); - $cgo_amount = PirepFare::where('type', FareType::CARGO)->whereNotIn('pirep_id', $allpireps)->sum('count'); - $cgo_avg = PirepFare::where('type', FareType::CARGO)->whereNotIn('pirep_id', $allpireps)->avg('count'); - } else { - $pax_amount = 0; - $cgo_amount = 0; + // Aggregate the fares of the ACCEPTED pireps in scope (airline/aircraft) + // in a single grouped JOIN. The scope lives in the JOIN's WHERE, so nothing + // is materialised into a PHP id array: this keeps the figures correctly + // scoped (per airline/aircraft, or whole-VA when both are null) AND avoids + // the MySQL ~65k items "WHERE ... IN" limit for VAs with very large pirep + // counts, which is why the previous count() guard is no longer needed. + // Bare column names `count`/`type` are unambiguous because the pireps table + // has neither (it uses `flight_type`), so no table prefix is required. + // Soft-deleted pireps are excluded explicitly because join() bypasses the + // Pirep model's SoftDeletes global scope. + $fareRows = PirepFare::query() + ->join('pireps', 'pireps.id', '=', 'pirep_fares.pirep_id') + ->whereNull('pireps.deleted_at') + ->where('pireps.state', PirepState::ACCEPTED) + ->when(isset($airline_id), function ($query) use ($airline_id) { + $query->where('pireps.airline_id', $airline_id); + }) + ->when(isset($aircraft_id), function ($query) use ($aircraft_id) { + $query->where('pireps.aircraft_id', $aircraft_id); + }) + ->groupBy('pirep_fares.type') + ->get(['pirep_fares.type', DB::raw('SUM(count) as total'), DB::raw('AVG(count) as average')]); + + $pax_amount = 0; + $pax_avg = 0; + $cgo_amount = 0; + $cgo_avg = 0; + foreach ($fareRows as $row) { + if ((int) $row->type === FareType::PASSENGER) { + $pax_amount = $row->total; + $pax_avg = $row->average; + } elseif ((int) $row->type === FareType::CARGO) { + $cgo_amount = $row->total; + $cgo_avg = $row->average; + } } if ($pax_amount > 0) {