2017-06-10 14:50:00 +08:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace App\Services;
|
|
|
|
|
2019-07-16 03:51:35 +08:00
|
|
|
use App\Contracts\Service;
|
2018-02-21 12:33:09 +08:00
|
|
|
use App\Events\PirepAccepted;
|
2020-02-12 02:56:20 +08:00
|
|
|
use App\Events\PirepCancelled;
|
2018-02-21 12:33:09 +08:00
|
|
|
use App\Events\PirepFiled;
|
2021-03-30 02:53:35 +08:00
|
|
|
use App\Events\PirepPrefiled;
|
2018-02-21 12:33:09 +08:00
|
|
|
use App\Events\PirepRejected;
|
|
|
|
use App\Events\UserStatsChanged;
|
2020-08-18 04:44:31 +08:00
|
|
|
use App\Exceptions\AircraftInvalid;
|
2020-03-23 21:31:35 +08:00
|
|
|
use App\Exceptions\AircraftNotAtAirport;
|
2021-05-14 03:26:53 +08:00
|
|
|
use App\Exceptions\AircraftNotAvailable;
|
2020-03-23 21:31:35 +08:00
|
|
|
use App\Exceptions\AircraftPermissionDenied;
|
2020-08-18 05:06:02 +08:00
|
|
|
use App\Exceptions\AirportNotFound;
|
2019-09-17 01:08:26 +08:00
|
|
|
use App\Exceptions\PirepCancelNotAllowed;
|
2021-05-03 22:00:10 +08:00
|
|
|
use App\Exceptions\PirepError;
|
2020-03-23 21:31:35 +08:00
|
|
|
use App\Exceptions\UserNotAtAirport;
|
2018-01-02 03:48:02 +08:00
|
|
|
use App\Models\Acars;
|
2020-08-18 04:44:31 +08:00
|
|
|
use App\Models\Aircraft;
|
2018-02-21 12:33:09 +08:00
|
|
|
use App\Models\Enums\AcarsType;
|
2021-05-14 03:26:53 +08:00
|
|
|
use App\Models\Enums\AircraftState;
|
2020-03-23 21:31:35 +08:00
|
|
|
use App\Models\Enums\FlightType;
|
2018-02-21 12:33:09 +08:00
|
|
|
use App\Models\Enums\PirepSource;
|
|
|
|
use App\Models\Enums\PirepState;
|
2018-05-31 03:00:20 +08:00
|
|
|
use App\Models\Enums\PirepStatus;
|
2018-01-02 03:48:02 +08:00
|
|
|
use App\Models\Navdata;
|
2017-07-02 10:06:55 +08:00
|
|
|
use App\Models\Pirep;
|
2021-03-03 04:43:34 +08:00
|
|
|
use App\Models\PirepComment;
|
|
|
|
use App\Models\PirepFare;
|
2018-07-13 10:20:10 +08:00
|
|
|
use App\Models\PirepFieldValue;
|
2021-01-21 22:21:39 +08:00
|
|
|
use App\Models\SimBrief;
|
2018-01-02 03:48:02 +08:00
|
|
|
use App\Models\User;
|
2020-08-18 04:44:31 +08:00
|
|
|
use App\Repositories\AircraftRepository;
|
2020-08-18 05:06:02 +08:00
|
|
|
use App\Repositories\AirportRepository;
|
2019-09-17 01:08:26 +08:00
|
|
|
use App\Repositories\PirepRepository;
|
2018-02-21 12:33:09 +08:00
|
|
|
use Carbon\Carbon;
|
|
|
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
2019-08-02 03:23:59 +08:00
|
|
|
use Illuminate\Support\Facades\Log;
|
2017-12-03 14:48:33 +08:00
|
|
|
|
2018-03-20 09:50:40 +08:00
|
|
|
class PirepService extends Service
|
2017-07-04 14:05:37 +08:00
|
|
|
{
|
2020-08-18 04:44:31 +08:00
|
|
|
private $aircraftRepo;
|
2020-08-18 05:06:02 +08:00
|
|
|
private $airportRepo;
|
|
|
|
private $airportSvc;
|
2021-06-04 22:51:59 +08:00
|
|
|
private $fareSvc;
|
2018-08-27 00:40:04 +08:00
|
|
|
private $geoSvc;
|
2019-09-17 01:08:26 +08:00
|
|
|
private $pirepRepo;
|
2021-01-25 19:54:17 +08:00
|
|
|
private $simBriefSvc;
|
2020-08-18 05:06:02 +08:00
|
|
|
private $userSvc;
|
2017-06-10 14:50:00 +08:00
|
|
|
|
|
|
|
/**
|
2020-08-18 05:06:02 +08:00
|
|
|
* @param AirportRepository $airportRepo
|
|
|
|
* @param AirportService $airportSvc
|
2021-06-04 22:51:59 +08:00
|
|
|
* @param AircraftRepository $aircraftRepo
|
|
|
|
* @param FareService $fareSvc
|
|
|
|
* @param GeoService $geoSvc
|
2020-08-18 05:06:02 +08:00
|
|
|
* @param PirepRepository $pirepRepo
|
2021-01-25 19:54:17 +08:00
|
|
|
* @param SimBriefService $simBriefSvc
|
2020-08-18 05:06:02 +08:00
|
|
|
* @param UserService $userSvc
|
2017-06-10 14:50:00 +08:00
|
|
|
*/
|
2017-12-03 14:48:33 +08:00
|
|
|
public function __construct(
|
2020-08-18 05:06:02 +08:00
|
|
|
AirportRepository $airportRepo,
|
|
|
|
AirportService $airportSvc,
|
2020-08-18 04:44:31 +08:00
|
|
|
AircraftRepository $aircraftRepo,
|
2021-06-04 22:51:59 +08:00
|
|
|
FareService $fareSvc,
|
2018-01-02 03:48:02 +08:00
|
|
|
GeoService $geoSvc,
|
2019-09-17 01:08:26 +08:00
|
|
|
PirepRepository $pirepRepo,
|
2021-01-25 19:54:17 +08:00
|
|
|
SimBriefService $simBriefSvc,
|
2020-03-23 21:31:35 +08:00
|
|
|
UserService $userSvc
|
2018-03-20 09:50:40 +08:00
|
|
|
) {
|
2020-08-18 05:06:02 +08:00
|
|
|
$this->airportRepo = $airportRepo;
|
|
|
|
$this->airportSvc = $airportSvc;
|
2020-08-18 04:44:31 +08:00
|
|
|
$this->aircraftRepo = $aircraftRepo;
|
2021-06-04 22:51:59 +08:00
|
|
|
$this->fareSvc = $fareSvc;
|
2018-01-02 03:48:02 +08:00
|
|
|
$this->geoSvc = $geoSvc;
|
2019-09-17 01:08:26 +08:00
|
|
|
$this->pirepRepo = $pirepRepo;
|
2021-01-25 19:54:17 +08:00
|
|
|
$this->simBriefSvc = $simBriefSvc;
|
2021-01-21 22:21:39 +08:00
|
|
|
$this->userSvc = $userSvc;
|
2017-06-10 14:50:00 +08:00
|
|
|
}
|
|
|
|
|
2020-03-23 21:31:35 +08:00
|
|
|
/**
|
|
|
|
* Create a prefiled PIREP
|
|
|
|
*
|
2021-06-04 22:51:59 +08:00
|
|
|
* @param User $user
|
|
|
|
* @param array $attrs
|
|
|
|
* @param PirepFieldValue[] $fields
|
|
|
|
* @param PirepFare[] $fares
|
2020-03-23 21:31:35 +08:00
|
|
|
*
|
2020-08-18 05:06:02 +08:00
|
|
|
* @throws AirportNotFound If one of the departure or arrival airports isn't found locally
|
2020-03-23 21:31:35 +08:00
|
|
|
* @throws \Exception
|
|
|
|
*
|
|
|
|
* @return \App\Models\Pirep
|
|
|
|
*/
|
2021-06-04 22:51:59 +08:00
|
|
|
public function prefile(User $user, array $attrs, array $fields = [], array $fares = []): Pirep
|
2020-03-23 21:31:35 +08:00
|
|
|
{
|
|
|
|
$attrs['user_id'] = $user->id;
|
|
|
|
$attrs['state'] = PirepState::IN_PROGRESS;
|
|
|
|
|
|
|
|
if (!array_key_exists('status', $attrs)) {
|
|
|
|
$attrs['status'] = PirepStatus::INITIATED;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Default to a scheduled passenger flight
|
|
|
|
if (!array_key_exists('flight_type', $attrs)) {
|
|
|
|
$attrs['flight_type'] = FlightType::SCHED_PAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
$pirep = new Pirep($attrs);
|
|
|
|
|
2020-08-18 05:06:02 +08:00
|
|
|
// Check if the airports listed actually exist or not. If they're not in the local DB
|
|
|
|
// throw an error which should bubble up to say that they don't
|
|
|
|
if (setting('general.allow_unadded_airports', false) === true) {
|
|
|
|
$this->airportSvc->lookupAirportIfNotFound($pirep->dpt_airport_id);
|
|
|
|
$this->airportSvc->lookupAirportIfNotFound($pirep->arr_airport_id);
|
|
|
|
} else {
|
|
|
|
$dptApt = $this->airportRepo->findWithoutFail($pirep->dpt_airport_id);
|
|
|
|
if (!$dptApt) {
|
|
|
|
throw new AirportNotFound($pirep->dpt_airport_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
$arrApt = $this->airportRepo->findWithoutFail($pirep->arr_airport_id);
|
|
|
|
if (!$arrApt) {
|
|
|
|
throw new AirportNotFound($pirep->arr_airport_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-23 21:31:35 +08:00
|
|
|
// See if this user is at the current airport
|
|
|
|
/* @noinspection NotOptimalIfConditionsInspection */
|
2021-01-25 20:06:27 +08:00
|
|
|
if (setting('pilots.only_flights_from_current', false)
|
2020-03-23 21:31:35 +08:00
|
|
|
&& $user->curr_airport_id !== $pirep->dpt_airport_id) {
|
|
|
|
throw new UserNotAtAirport($user, $pirep->dpt_airport);
|
|
|
|
}
|
|
|
|
|
|
|
|
// See if this user is allowed to fly this aircraft
|
|
|
|
if (setting('pireps.restrict_aircraft_to_rank', false)
|
|
|
|
&& !$this->userSvc->aircraftAllowed($user, $pirep->aircraft_id)) {
|
|
|
|
throw new AircraftPermissionDenied($user, $pirep->aircraft);
|
|
|
|
}
|
|
|
|
|
2021-05-14 03:26:53 +08:00
|
|
|
// See if this aircraft is valid
|
2020-08-18 04:44:31 +08:00
|
|
|
/** @var Aircraft $aircraft */
|
|
|
|
$aircraft = $this->aircraftRepo->findWithoutFail($pirep->aircraft_id);
|
|
|
|
if ($aircraft === null) {
|
|
|
|
throw new AircraftInvalid($aircraft);
|
|
|
|
}
|
|
|
|
|
2021-05-14 03:26:53 +08:00
|
|
|
// See if this aircraft is available for flight
|
|
|
|
/** @var Aircraft $aircraft */
|
|
|
|
$aircraft = $this->aircraftRepo->where('id', $pirep->aircraft_id)->where('state', AircraftState::PARKED)->first();
|
|
|
|
if ($aircraft === null) {
|
|
|
|
throw new AircraftNotAvailable($pirep->aircraft);
|
|
|
|
}
|
|
|
|
|
2021-06-04 04:17:16 +08:00
|
|
|
// See if this aircraft is being used by another user's active simbrief ofp
|
|
|
|
if (setting('simbrief.block_aircraft', false)) {
|
|
|
|
$sb_aircraft = SimBrief::select('aircraft_id')
|
|
|
|
->where('aircraft_id', $pirep->aircraft_id)
|
|
|
|
->where('user_id', '!=', $pirep->user_id)
|
|
|
|
->whereNotNull('flight_id')
|
|
|
|
->count();
|
|
|
|
if ($sb_aircraft > 0) {
|
|
|
|
throw new AircraftNotAvailable($pirep->aircraft);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-14 03:26:53 +08:00
|
|
|
// See if this aircraft is at the departure airport
|
2020-03-23 21:31:35 +08:00
|
|
|
/* @noinspection NotOptimalIfConditionsInspection */
|
2020-08-18 04:44:31 +08:00
|
|
|
if (setting('pireps.only_aircraft_at_dpt_airport') && $aircraft->airport_id !== $pirep->dpt_airport_id) {
|
2020-03-23 21:31:35 +08:00
|
|
|
throw new AircraftNotAtAirport($pirep->aircraft);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find if there's a duplicate, if so, let's work on that
|
|
|
|
$dupe_pirep = $this->findDuplicate($pirep);
|
|
|
|
if ($dupe_pirep !== false) {
|
|
|
|
$pirep = $dupe_pirep;
|
2021-04-23 22:33:13 +08:00
|
|
|
Log::info('Found duplicate PIREP, id='.$dupe_pirep->id);
|
2020-03-23 21:31:35 +08:00
|
|
|
if ($pirep->cancelled) {
|
|
|
|
throw new \App\Exceptions\PirepCancelled($pirep);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-04 22:51:59 +08:00
|
|
|
$pirep->status = PirepStatus::INITIATED;
|
2020-03-23 21:31:35 +08:00
|
|
|
$pirep->save();
|
2021-06-04 04:17:16 +08:00
|
|
|
$pirep->refresh();
|
|
|
|
|
|
|
|
// Check if there is a simbrief_id, update it to have the pirep_id
|
|
|
|
// Keep the flight_id until the end of flight (pirep file)
|
|
|
|
if (array_key_exists('simbrief_id', $attrs)) {
|
|
|
|
/** @var SimBrief $simbrief */
|
|
|
|
$simbrief = SimBrief::find($attrs['simbrief_id']);
|
|
|
|
if ($simbrief) {
|
|
|
|
$this->simBriefSvc->attachSimbriefToPirep($pirep, $simbrief, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-04 22:51:59 +08:00
|
|
|
$this->updateCustomFields($pirep->id, $fields);
|
|
|
|
$this->fareSvc->saveForPirep($pirep, $fares);
|
|
|
|
|
2021-06-04 04:17:16 +08:00
|
|
|
event(new PirepPrefiled($pirep));
|
2020-03-23 21:31:35 +08:00
|
|
|
|
|
|
|
return $pirep;
|
|
|
|
}
|
|
|
|
|
2019-11-06 00:44:31 +08:00
|
|
|
/**
|
|
|
|
* Create a new PIREP with some given fields
|
|
|
|
*
|
|
|
|
* @param Pirep $pirep
|
|
|
|
* @param array PirepFieldValue[] $field_values
|
|
|
|
*
|
|
|
|
* @return Pirep
|
|
|
|
*/
|
2021-06-04 22:51:59 +08:00
|
|
|
public function create(Pirep $pirep, array $fields = []): Pirep
|
2019-11-06 00:44:31 +08:00
|
|
|
{
|
2021-06-04 22:51:59 +08:00
|
|
|
if (empty($fields)) {
|
|
|
|
$fields = [];
|
2019-11-06 00:44:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check the block times. If a block on (arrival) time isn't
|
|
|
|
// specified, then use the time that it was submitted. It won't
|
|
|
|
// be the most accurate, but that might be OK
|
|
|
|
if (!$pirep->block_on_time) {
|
|
|
|
if ($pirep->submitted_at) {
|
|
|
|
$pirep->block_on_time = $pirep->submitted_at;
|
|
|
|
} else {
|
|
|
|
$pirep->block_on_time = Carbon::now('UTC');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the depart time isn't set, then try to calculate it by
|
|
|
|
// subtracting the flight time from the block_on (arrival) time
|
|
|
|
if (!$pirep->block_off_time && $pirep->flight_time > 0) {
|
|
|
|
$pirep->block_off_time = $pirep->block_on_time->subMinutes($pirep->flight_time);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that there's a submit time
|
|
|
|
if (!$pirep->submitted_at) {
|
|
|
|
$pirep->submitted_at = Carbon::now('UTC');
|
|
|
|
}
|
|
|
|
|
|
|
|
$pirep->status = PirepStatus::ARRIVED;
|
|
|
|
|
|
|
|
// Copy some fields over from Flight if we have it
|
|
|
|
if ($pirep->flight) {
|
|
|
|
$pirep->planned_distance = $pirep->flight->distance;
|
|
|
|
$pirep->planned_flight_time = $pirep->flight->flight_time;
|
|
|
|
}
|
|
|
|
|
|
|
|
$pirep->save();
|
|
|
|
$pirep->refresh();
|
|
|
|
|
2021-06-04 22:51:59 +08:00
|
|
|
$this->updateCustomFields($pirep->id, $fields);
|
|
|
|
|
|
|
|
return $pirep;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param PirepFieldValue[] $fields
|
|
|
|
* @param PirepFare[] $fares
|
|
|
|
*
|
|
|
|
* @throws \Prettus\Validator\Exceptions\ValidatorException
|
|
|
|
* @throws \Exception
|
|
|
|
*/
|
|
|
|
public function update(string $pirep_id, array $attrs, array $fields = [], array $fares = []): Pirep
|
|
|
|
{
|
|
|
|
$pirep = $this->pirepRepo->update($attrs, $pirep_id);
|
|
|
|
$this->updateCustomFields($pirep_id, $fields);
|
|
|
|
$this->fareSvc->saveForPirep($pirep, $fares);
|
2019-11-06 00:44:31 +08:00
|
|
|
|
|
|
|
return $pirep;
|
|
|
|
}
|
|
|
|
|
2021-01-25 19:54:17 +08:00
|
|
|
/**
|
|
|
|
* Finalize a PIREP (meaning it's been filed)
|
|
|
|
*
|
2021-06-04 22:51:59 +08:00
|
|
|
* @param Pirep $pirep
|
|
|
|
* @param array $attrs
|
|
|
|
* @param PirepFieldValue[] $fields
|
|
|
|
* @param PirepFare[] $fares
|
2021-01-25 19:54:17 +08:00
|
|
|
*
|
|
|
|
* @throws \Exception
|
|
|
|
*
|
|
|
|
* @return Pirep
|
|
|
|
*/
|
2021-06-04 22:51:59 +08:00
|
|
|
public function file(Pirep $pirep, array $attrs = [], array $fields = [], array $fares = []): Pirep
|
2021-01-25 19:54:17 +08:00
|
|
|
{
|
2021-06-04 22:51:59 +08:00
|
|
|
if (empty($fields)) {
|
|
|
|
$fields = [];
|
2021-01-25 19:54:17 +08:00
|
|
|
}
|
|
|
|
|
2021-05-03 22:00:10 +08:00
|
|
|
// Check if the PIREP has already been submitted
|
|
|
|
$is_already_submitted = in_array($pirep->state, [
|
|
|
|
PirepState::PENDING,
|
|
|
|
PirepState::ACCEPTED,
|
|
|
|
PirepState::CANCELLED,
|
|
|
|
PirepState::REJECTED,
|
|
|
|
], true);
|
|
|
|
|
|
|
|
if ($is_already_submitted) {
|
|
|
|
throw new PirepError($pirep, 'PIREP has already been submitted');
|
|
|
|
}
|
|
|
|
|
2021-01-25 19:54:17 +08:00
|
|
|
$attrs['state'] = PirepState::PENDING;
|
|
|
|
$attrs['status'] = PirepStatus::ARRIVED;
|
|
|
|
$attrs['submitted_at'] = Carbon::now('UTC');
|
|
|
|
|
|
|
|
$this->pirepRepo->update($attrs, $pirep->id);
|
|
|
|
$pirep->refresh();
|
|
|
|
|
|
|
|
// Check if there is a simbrief_id, change it to be set to the PIREP
|
|
|
|
// at the end of the flight when it's been filed
|
|
|
|
if (array_key_exists('simbrief_id', $attrs)) {
|
|
|
|
/** @var SimBrief $simbrief */
|
|
|
|
$simbrief = SimBrief::find($attrs['simbrief_id']);
|
|
|
|
if ($simbrief) {
|
|
|
|
$this->simBriefSvc->attachSimbriefToPirep($pirep, $simbrief);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check the block times. If a block on (arrival) time isn't
|
|
|
|
// specified, then use the time that it was submitted. It won't
|
|
|
|
// be the most accurate, but that might be OK
|
|
|
|
if (!$pirep->block_on_time) {
|
|
|
|
if ($pirep->submitted_at) {
|
|
|
|
$pirep->block_on_time = $pirep->submitted_at;
|
|
|
|
} else {
|
|
|
|
$pirep->block_on_time = Carbon::now('UTC');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that there's a submit time
|
|
|
|
if (!$pirep->submitted_at) {
|
|
|
|
$pirep->submitted_at = Carbon::now('UTC');
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy some fields over from Flight if we have it
|
|
|
|
if ($pirep->flight) {
|
|
|
|
$pirep->planned_distance = $pirep->flight->distance;
|
|
|
|
$pirep->planned_flight_time = $pirep->flight->flight_time;
|
|
|
|
}
|
|
|
|
|
|
|
|
$pirep->save();
|
|
|
|
$pirep->refresh();
|
|
|
|
|
2021-06-04 22:51:59 +08:00
|
|
|
$this->updateCustomFields($pirep->id, $fields);
|
|
|
|
$this->fareSvc->saveForPirep($pirep, $fares);
|
2021-01-25 19:54:17 +08:00
|
|
|
|
|
|
|
return $pirep;
|
|
|
|
}
|
|
|
|
|
2018-01-03 03:17:22 +08:00
|
|
|
/**
|
|
|
|
* Find if there are duplicates to a given PIREP. Ideally, the passed
|
|
|
|
* in PIREP hasn't been saved or gone through the create() method
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-01-03 03:17:22 +08:00
|
|
|
* @param Pirep $pirep
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-01-03 03:17:22 +08:00
|
|
|
* @return bool|Pirep
|
|
|
|
*/
|
|
|
|
public function findDuplicate(Pirep $pirep)
|
|
|
|
{
|
|
|
|
$minutes = setting('pireps.duplicate_check_time', 10);
|
2021-04-13 21:25:38 +08:00
|
|
|
$time_limit = Carbon::now('UTC')->subMinutes($minutes)->toDateTimeString();
|
2018-01-03 03:17:22 +08:00
|
|
|
|
|
|
|
$where = [
|
2021-04-23 22:33:13 +08:00
|
|
|
'user_id' => $pirep->user_id,
|
|
|
|
'airline_id' => $pirep->airline_id,
|
|
|
|
'flight_number' => $pirep->flight_number,
|
|
|
|
'dpt_airport_id' => $pirep->dpt_airport_id,
|
|
|
|
'arr_airport_id' => $pirep->arr_airport_id,
|
2018-01-03 03:17:22 +08:00
|
|
|
];
|
|
|
|
|
2018-03-16 07:20:07 +08:00
|
|
|
if (filled($pirep->route_code)) {
|
2018-01-03 03:17:22 +08:00
|
|
|
$where['route_code'] = $pirep->route_code;
|
|
|
|
}
|
|
|
|
|
2018-03-16 07:20:07 +08:00
|
|
|
if (filled($pirep->route_leg)) {
|
2018-01-03 03:17:22 +08:00
|
|
|
$where['route_leg'] = $pirep->route_leg;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
$found_pireps = Pirep::where($where)
|
2018-03-16 07:20:07 +08:00
|
|
|
->where('state', '!=', PirepState::CANCELLED)
|
|
|
|
->where('created_at', '>=', $time_limit)
|
|
|
|
->get();
|
2018-01-03 03:17:22 +08:00
|
|
|
|
2018-03-16 07:20:07 +08:00
|
|
|
if ($found_pireps->count() === 0) {
|
2018-01-03 03:17:22 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $found_pireps[0];
|
|
|
|
} catch (ModelNotFoundException $e) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-02 03:48:02 +08:00
|
|
|
/**
|
|
|
|
* Save the route into the ACARS table with AcarsType::ROUTE
|
2018-07-06 03:07:54 +08:00
|
|
|
* This attempts to create the route from the navdata and the route
|
|
|
|
* entered into the PIREP's route field
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-01-02 03:48:02 +08:00
|
|
|
* @param Pirep $pirep
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-02-11 06:10:19 +08:00
|
|
|
* @throws \Exception
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
|
|
|
* @return Pirep
|
2018-01-02 03:48:02 +08:00
|
|
|
*/
|
|
|
|
public function saveRoute(Pirep $pirep): Pirep
|
|
|
|
{
|
2018-08-27 00:40:04 +08:00
|
|
|
// Delete all the existing nav points
|
2018-01-02 03:48:02 +08:00
|
|
|
Acars::where([
|
2018-01-02 23:40:42 +08:00
|
|
|
'pirep_id' => $pirep->id,
|
2018-03-20 09:50:40 +08:00
|
|
|
'type' => AcarsType::ROUTE,
|
2018-01-02 23:40:42 +08:00
|
|
|
])->delete();
|
2018-01-02 03:48:02 +08:00
|
|
|
|
2018-08-27 00:40:04 +08:00
|
|
|
// See if a route exists
|
2018-02-11 06:10:19 +08:00
|
|
|
if (!filled($pirep->route)) {
|
2018-01-02 03:48:02 +08:00
|
|
|
return $pirep;
|
|
|
|
}
|
|
|
|
|
2018-02-11 06:10:19 +08:00
|
|
|
if (!filled($pirep->dpt_airport)) {
|
2018-03-20 09:50:40 +08:00
|
|
|
Log::error('saveRoute: dpt_airport not found: '.$pirep->dpt_airport_id);
|
2018-01-06 04:33:22 +08:00
|
|
|
return $pirep;
|
|
|
|
}
|
|
|
|
|
2018-01-02 05:04:32 +08:00
|
|
|
$route = $this->geoSvc->getCoordsFromRoute(
|
|
|
|
$pirep->dpt_airport_id,
|
|
|
|
$pirep->arr_airport_id,
|
|
|
|
[$pirep->dpt_airport->lat, $pirep->dpt_airport->lon],
|
|
|
|
$pirep->route
|
2018-01-02 03:48:02 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var $point Navdata
|
|
|
|
*/
|
2018-01-02 23:40:42 +08:00
|
|
|
$point_count = 1;
|
2018-01-02 06:01:01 +08:00
|
|
|
foreach ($route as $point) {
|
2018-01-02 03:48:02 +08:00
|
|
|
$acars = new Acars();
|
|
|
|
$acars->pirep_id = $pirep->id;
|
|
|
|
$acars->type = AcarsType::ROUTE;
|
|
|
|
$acars->nav_type = $point->type;
|
2018-01-02 23:40:42 +08:00
|
|
|
$acars->order = $point_count;
|
2018-01-02 03:48:02 +08:00
|
|
|
$acars->name = $point->id;
|
|
|
|
$acars->lat = $point->lat;
|
|
|
|
$acars->lon = $point->lon;
|
|
|
|
|
|
|
|
$acars->save();
|
2018-08-27 00:40:04 +08:00
|
|
|
$point_count++;
|
2018-01-02 03:48:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return $pirep;
|
|
|
|
}
|
|
|
|
|
2018-05-10 23:35:10 +08:00
|
|
|
/**
|
|
|
|
* Submit the PIREP. Figure out its default state
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-05-10 23:35:10 +08:00
|
|
|
* @param Pirep $pirep
|
2018-08-27 02:51:47 +08:00
|
|
|
*
|
2018-08-27 02:50:08 +08:00
|
|
|
* @throws \Exception
|
2018-05-10 23:35:10 +08:00
|
|
|
*/
|
|
|
|
public function submit(Pirep $pirep)
|
|
|
|
{
|
2018-08-27 00:40:04 +08:00
|
|
|
// Figure out what default state should be. Look at the default
|
|
|
|
// behavior from the rank that the pilot is assigned to
|
2018-05-10 23:35:10 +08:00
|
|
|
$default_state = PirepState::PENDING;
|
|
|
|
if ($pirep->source === PirepSource::ACARS) {
|
2019-09-17 01:08:26 +08:00
|
|
|
if ($pirep->user->rank->auto_approve_acars) {
|
2018-05-10 23:35:10 +08:00
|
|
|
$default_state = PirepState::ACCEPTED;
|
|
|
|
}
|
|
|
|
} else {
|
2019-09-17 01:08:26 +08:00
|
|
|
if ($pirep->user->rank->auto_approve_manual) {
|
2018-05-10 23:35:10 +08:00
|
|
|
$default_state = PirepState::ACCEPTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-04 04:17:16 +08:00
|
|
|
// Check if there is a simbrief_id, change it to be set to the PIREP
|
|
|
|
// at the end of the flight when it's been submitted finally.
|
|
|
|
// Prefile, Save (as draft) and File already have this but the Submit button
|
|
|
|
// visible at pireps.show blade uses this function so Simbrief also needs to
|
|
|
|
// checked here too (to remove the flight_id and release the aircraft)
|
|
|
|
if (!empty($pirep->simbrief)) {
|
|
|
|
/** @var SimBrief $simbrief */
|
|
|
|
$simbrief = SimBrief::find($pirep->simbrief->id);
|
|
|
|
if ($simbrief) {
|
|
|
|
$this->simBriefSvc->attachSimbriefToPirep($pirep, $simbrief);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-03 14:48:33 +08:00
|
|
|
Log::info('New PIREP filed', [$pirep]);
|
2017-12-03 00:55:17 +08:00
|
|
|
event(new PirepFiled($pirep));
|
|
|
|
|
2018-08-27 00:40:04 +08:00
|
|
|
// only update the pilot last state if they are accepted
|
2017-12-20 10:19:36 +08:00
|
|
|
if ($default_state === PirepState::ACCEPTED) {
|
2017-12-26 05:19:34 +08:00
|
|
|
$pirep = $this->accept($pirep);
|
2019-08-02 03:23:59 +08:00
|
|
|
} else {
|
|
|
|
$pirep->state = $default_state;
|
2017-08-24 03:19:05 +08:00
|
|
|
}
|
2017-07-04 14:05:37 +08:00
|
|
|
|
2019-08-02 03:23:59 +08:00
|
|
|
$pirep->save();
|
2019-09-17 01:08:26 +08:00
|
|
|
}
|
2019-08-02 03:23:59 +08:00
|
|
|
|
2019-09-17 01:08:26 +08:00
|
|
|
/**
|
|
|
|
* Cancel a PIREP
|
|
|
|
*
|
|
|
|
* @param Pirep $pirep
|
|
|
|
*
|
|
|
|
* @throws \Prettus\Validator\Exceptions\ValidatorException
|
|
|
|
*
|
|
|
|
* @return Pirep
|
|
|
|
*/
|
|
|
|
public function cancel(Pirep $pirep): Pirep
|
|
|
|
{
|
|
|
|
if (in_array($pirep->state, Pirep::$cancel_states, true)) {
|
|
|
|
Log::info('PIREP '.$pirep->id.' can\'t be cancelled, state='.$pirep->state);
|
2018-03-31 11:28:19 +08:00
|
|
|
|
2019-09-17 01:08:26 +08:00
|
|
|
throw new PirepCancelNotAllowed($pirep);
|
2018-03-31 11:28:19 +08:00
|
|
|
}
|
2019-09-17 01:08:26 +08:00
|
|
|
|
|
|
|
$pirep = $this->pirepRepo->update([
|
|
|
|
'state' => PirepState::CANCELLED,
|
|
|
|
'status' => PirepStatus::CANCELLED,
|
|
|
|
], $pirep->id);
|
|
|
|
|
2020-02-12 02:56:20 +08:00
|
|
|
event(new PirepCancelled($pirep));
|
|
|
|
|
2019-09-17 01:08:26 +08:00
|
|
|
return $pirep;
|
2017-07-04 14:05:37 +08:00
|
|
|
}
|
|
|
|
|
2021-03-03 04:43:34 +08:00
|
|
|
/**
|
|
|
|
* Delete the PIREP and all of the associated data. Does a force delete to make sure that we
|
|
|
|
* don't run into problems with foreign keys. Models/tables affected:
|
|
|
|
*
|
|
|
|
* acars
|
|
|
|
* bids
|
|
|
|
* pirep_comments
|
|
|
|
* pirep_fares
|
|
|
|
* pirep_field_values
|
|
|
|
* simbrief
|
|
|
|
*
|
|
|
|
* @param Pirep $pirep
|
|
|
|
*/
|
|
|
|
public function delete(Pirep $pirep): void
|
|
|
|
{
|
2021-06-04 22:51:59 +08:00
|
|
|
$user_id = $pirep->user_id;
|
|
|
|
|
2021-03-03 04:43:34 +08:00
|
|
|
$w = ['pirep_id' => $pirep->id];
|
|
|
|
PirepComment::where($w)->forceDelete();
|
|
|
|
PirepFare::where($w)->forceDelete();
|
|
|
|
PirepFieldValue::where($w)->forceDelete();
|
|
|
|
SimBrief::where($w)->forceDelete();
|
|
|
|
$pirep->forceDelete();
|
2021-06-04 22:51:59 +08:00
|
|
|
|
|
|
|
// Update the user's last PIREP
|
|
|
|
$last_pirep = Pirep::where(['user_id' => $user_id, 'state' => PirepState::ACCEPTED])
|
|
|
|
->latest('submitted_at')
|
|
|
|
->first();
|
|
|
|
|
|
|
|
$user = User::find($user_id);
|
|
|
|
$user->last_pirep_id = !empty($last_pirep) ? $last_pirep->id : null;
|
|
|
|
$user->save();
|
2021-03-03 04:43:34 +08:00
|
|
|
}
|
|
|
|
|
2018-02-07 03:46:23 +08:00
|
|
|
/**
|
|
|
|
* Update any custom PIREP fields
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2021-06-04 22:51:59 +08:00
|
|
|
* @param string $pirep_id
|
|
|
|
* @param PirepFieldValue[] $field_values
|
2018-02-07 03:46:23 +08:00
|
|
|
*/
|
2021-06-04 22:51:59 +08:00
|
|
|
public function updateCustomFields(string $pirep_id, array $field_values): void
|
2018-02-07 03:46:23 +08:00
|
|
|
{
|
2021-06-04 22:51:59 +08:00
|
|
|
if (!$field_values || empty($field_values)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-02-07 03:46:23 +08:00
|
|
|
foreach ($field_values as $fv) {
|
2018-07-13 10:20:10 +08:00
|
|
|
PirepFieldValue::updateOrCreate(
|
2021-06-04 22:51:59 +08:00
|
|
|
['pirep_id' => $pirep_id, 'name' => $fv->name],
|
|
|
|
['value' => $fv->value, 'source' => $fv->source]
|
2018-02-07 03:46:23 +08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-03 14:48:33 +08:00
|
|
|
/**
|
|
|
|
* @param Pirep $pirep
|
2018-03-20 09:50:40 +08:00
|
|
|
* @param int $new_state
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2019-08-02 03:23:59 +08:00
|
|
|
* @throws \Exception
|
|
|
|
*
|
2017-12-03 14:48:33 +08:00
|
|
|
* @return Pirep
|
|
|
|
*/
|
2021-06-04 22:51:59 +08:00
|
|
|
public function changeState(Pirep $pirep, int $new_state): Pirep
|
2017-07-04 14:05:37 +08:00
|
|
|
{
|
2018-03-20 09:50:40 +08:00
|
|
|
Log::info('PIREP '.$pirep->id.' state change from '.$pirep->state.' to '.$new_state);
|
2017-12-03 14:48:33 +08:00
|
|
|
|
2017-12-20 10:19:36 +08:00
|
|
|
if ($pirep->state === $new_state) {
|
2017-07-04 14:05:37 +08:00
|
|
|
return $pirep;
|
|
|
|
}
|
|
|
|
|
2018-08-27 00:40:04 +08:00
|
|
|
/*
|
2017-07-04 14:05:37 +08:00
|
|
|
* Move from a PENDING status into either ACCEPTED or REJECTED
|
|
|
|
*/
|
2017-12-20 10:19:36 +08:00
|
|
|
if ($pirep->state === PirepState::PENDING) {
|
|
|
|
if ($new_state === PirepState::ACCEPTED) {
|
2017-07-04 14:05:37 +08:00
|
|
|
return $this->accept($pirep);
|
2019-05-13 07:05:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($new_state === PirepState::REJECTED) {
|
2017-07-04 14:05:37 +08:00
|
|
|
return $this->reject($pirep);
|
|
|
|
}
|
2019-05-13 07:05:36 +08:00
|
|
|
|
2018-08-27 00:40:04 +08:00
|
|
|
return $pirep;
|
2019-05-13 07:05:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-07-04 14:05:37 +08:00
|
|
|
* Move from a ACCEPTED to REJECTED status
|
|
|
|
*/
|
2019-05-13 07:05:36 +08:00
|
|
|
if ($pirep->state === PirepState::ACCEPTED) {
|
2017-07-04 14:05:37 +08:00
|
|
|
$pirep = $this->reject($pirep);
|
|
|
|
return $pirep;
|
2019-05-13 07:05:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-07-04 14:05:37 +08:00
|
|
|
* Move from REJECTED to ACCEPTED
|
|
|
|
*/
|
2019-05-13 07:05:36 +08:00
|
|
|
if ($pirep->state === PirepState::REJECTED) {
|
2017-07-04 14:05:37 +08:00
|
|
|
$pirep = $this->accept($pirep);
|
|
|
|
return $pirep;
|
|
|
|
}
|
2017-12-20 10:19:36 +08:00
|
|
|
|
|
|
|
return $pirep->refresh();
|
2017-07-04 14:05:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param Pirep $pirep
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-08-27 02:50:08 +08:00
|
|
|
* @throws \Exception
|
2018-08-27 02:51:47 +08:00
|
|
|
*
|
|
|
|
* @return Pirep
|
2017-07-04 14:05:37 +08:00
|
|
|
*/
|
2017-12-14 00:56:26 +08:00
|
|
|
public function accept(Pirep $pirep): Pirep
|
2017-07-04 14:05:37 +08:00
|
|
|
{
|
2018-08-27 00:40:04 +08:00
|
|
|
// moving from a REJECTED state to ACCEPTED, reconcile statuses
|
2017-12-20 10:19:36 +08:00
|
|
|
if ($pirep->state === PirepState::ACCEPTED) {
|
2017-07-04 14:05:37 +08:00
|
|
|
return $pirep;
|
|
|
|
}
|
|
|
|
|
|
|
|
$ft = $pirep->flight_time;
|
2019-09-17 01:08:26 +08:00
|
|
|
$pilot = $pirep->user;
|
2017-07-04 14:05:37 +08:00
|
|
|
|
2020-03-23 21:31:35 +08:00
|
|
|
$this->userSvc->adjustFlightTime($pilot, $ft);
|
|
|
|
$this->userSvc->adjustFlightCount($pilot, +1);
|
|
|
|
$this->userSvc->calculatePilotRank($pilot);
|
2019-09-17 01:08:26 +08:00
|
|
|
$pirep->user->refresh();
|
2017-07-04 14:05:37 +08:00
|
|
|
|
2018-08-27 00:40:04 +08:00
|
|
|
// Change the status
|
2017-12-20 10:19:36 +08:00
|
|
|
$pirep->state = PirepState::ACCEPTED;
|
2017-07-04 14:05:37 +08:00
|
|
|
$pirep->save();
|
2017-08-24 03:19:05 +08:00
|
|
|
$pirep->refresh();
|
2017-07-04 14:05:37 +08:00
|
|
|
|
2018-03-20 09:50:40 +08:00
|
|
|
Log::info('PIREP '.$pirep->id.' state change to ACCEPTED');
|
2017-12-03 14:48:33 +08:00
|
|
|
|
2018-08-27 00:40:04 +08:00
|
|
|
// Update the aircraft
|
2019-08-05 20:27:53 +08:00
|
|
|
$pirep->aircraft->flight_time = $pirep->aircraft->flight_time + $pirep->flight_time;
|
2018-01-11 02:39:13 +08:00
|
|
|
$pirep->aircraft->airport_id = $pirep->arr_airport_id;
|
|
|
|
$pirep->aircraft->landing_time = $pirep->updated_at;
|
2021-02-25 01:22:52 +08:00
|
|
|
$pirep->aircraft->fuel_onboard = $pirep->block_fuel - $pirep->fuel_used;
|
2018-01-11 02:39:13 +08:00
|
|
|
$pirep->aircraft->save();
|
|
|
|
|
2018-03-03 03:12:39 +08:00
|
|
|
$pirep->refresh();
|
|
|
|
|
2018-03-18 01:55:50 +08:00
|
|
|
$this->setPilotState($pilot, $pirep);
|
2017-12-03 00:55:17 +08:00
|
|
|
event(new PirepAccepted($pirep));
|
|
|
|
|
2017-07-04 14:05:37 +08:00
|
|
|
return $pirep;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param Pirep $pirep
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2017-07-04 14:05:37 +08:00
|
|
|
* @return Pirep
|
|
|
|
*/
|
2017-12-14 00:56:26 +08:00
|
|
|
public function reject(Pirep $pirep): Pirep
|
2017-07-04 14:05:37 +08:00
|
|
|
{
|
2018-08-27 00:40:04 +08:00
|
|
|
// If this was previously ACCEPTED, then reconcile the flight hours
|
|
|
|
// that have already been counted, etc
|
2017-12-20 10:19:36 +08:00
|
|
|
if ($pirep->state === PirepState::ACCEPTED) {
|
2019-09-17 01:08:26 +08:00
|
|
|
$user = $pirep->user;
|
2017-07-04 14:05:37 +08:00
|
|
|
$ft = $pirep->flight_time * -1;
|
|
|
|
|
2020-03-23 21:31:35 +08:00
|
|
|
$this->userSvc->adjustFlightTime($user, $ft);
|
|
|
|
$this->userSvc->adjustFlightCount($user, -1);
|
|
|
|
$this->userSvc->calculatePilotRank($user);
|
2019-09-17 01:08:26 +08:00
|
|
|
$pirep->user->refresh();
|
2017-07-04 14:05:37 +08:00
|
|
|
}
|
|
|
|
|
2018-08-27 00:40:04 +08:00
|
|
|
// Change the status
|
2017-12-20 10:19:36 +08:00
|
|
|
$pirep->state = PirepState::REJECTED;
|
2017-07-04 14:05:37 +08:00
|
|
|
$pirep->save();
|
2017-08-24 03:19:05 +08:00
|
|
|
$pirep->refresh();
|
2017-07-04 14:05:37 +08:00
|
|
|
|
2018-01-12 12:00:39 +08:00
|
|
|
$pirep->aircraft->flight_time -= $pirep->flight_time;
|
|
|
|
$pirep->aircraft->save();
|
|
|
|
|
2018-03-20 09:50:40 +08:00
|
|
|
Log::info('PIREP '.$pirep->id.' state change to REJECTED');
|
2017-12-03 14:48:33 +08:00
|
|
|
|
2017-12-03 00:55:17 +08:00
|
|
|
event(new PirepRejected($pirep));
|
|
|
|
|
2017-07-04 14:05:37 +08:00
|
|
|
return $pirep;
|
2017-06-10 14:50:00 +08:00
|
|
|
}
|
2017-07-11 07:54:51 +08:00
|
|
|
|
2017-12-03 14:48:33 +08:00
|
|
|
/**
|
2019-09-17 01:08:26 +08:00
|
|
|
* @param User $pilot
|
2017-12-03 14:48:33 +08:00
|
|
|
* @param Pirep $pirep
|
|
|
|
*/
|
2017-12-26 05:19:34 +08:00
|
|
|
public function setPilotState(User $pilot, Pirep $pirep)
|
2017-12-03 14:48:33 +08:00
|
|
|
{
|
2017-08-24 03:19:05 +08:00
|
|
|
$pilot->refresh();
|
2017-12-03 14:48:33 +08:00
|
|
|
|
2017-12-23 06:55:47 +08:00
|
|
|
$previous_airport = $pilot->curr_airport_id;
|
2017-08-24 03:19:05 +08:00
|
|
|
$pilot->curr_airport_id = $pirep->arr_airport_id;
|
|
|
|
$pilot->last_pirep_id = $pirep->id;
|
|
|
|
$pilot->save();
|
2017-07-11 07:54:51 +08:00
|
|
|
|
2017-12-26 05:19:34 +08:00
|
|
|
$pirep->refresh();
|
|
|
|
|
2017-12-23 06:55:47 +08:00
|
|
|
event(new UserStatsChanged($pilot, 'airport', $previous_airport));
|
2017-07-11 07:54:51 +08:00
|
|
|
}
|
2017-06-10 14:50:00 +08:00
|
|
|
}
|