#406 Refactor bids (#432)

* Add flight_id column to pireps table

* Refactor PIREPs and bids closes 406

* Formatting
This commit is contained in:
Nabeel S
2019-11-05 11:44:31 -05:00
committed by GitHub
parent db087d0ccb
commit f5183babf6
35 changed files with 967 additions and 798 deletions

View File

@@ -1,5 +1,8 @@
<?php
use App\Models\Enums\PirepSource;
use App\Models\Enums\PirepState;
use App\Models\Enums\PirepStatus;
use Carbon\Carbon;
use Faker\Generator as Faker;
@@ -7,10 +10,15 @@ use Faker\Generator as Faker;
* Create a new PIREP
*/
$factory->define(App\Models\Pirep::class, function (Faker $faker) {
$airline = factory(App\Models\Airline::class)->create();
$flight = factory(App\Models\Flight::class)->create([
'airline_id' => $airline->id,
]);
return [
'id' => $faker->unique()->numberBetween(10, 10000000),
'airline_id' => function () {
return factory(App\Models\Airline::class)->create()->id;
'airline_id' => function () use ($airline) {
return $airline->id;
},
'user_id' => function () {
return factory(App\Models\User::class)->create()->id;
@@ -18,18 +26,19 @@ $factory->define(App\Models\Pirep::class, function (Faker $faker) {
'aircraft_id' => function () {
return factory(App\Models\Aircraft::class)->create()->id;
},
'flight_number' => function (array $pirep) {
return factory(App\Models\Flight::class)->create([
'airline_id' => $pirep['airline_id'],
])->flight_number;
'flight_id' => function () use ($flight) {
return $flight->id;
},
'flight_number' => function () use ($flight) {
return $flight->flight_number;
},
'route_code' => null,
'route_leg' => null,
'dpt_airport_id' => function () {
return factory(App\Models\Airport::class)->create()->id;
'dpt_airport_id' => function () use ($flight) {
return $flight->dpt_airport_id;
},
'arr_airport_id' => function () {
return factory(App\Models\Airport::class)->create()->id;
'arr_airport_id' => function () use ($flight) {
return $flight->arr_airport_id;
},
'level' => $faker->numberBetween(20, 400),
'distance' => $faker->randomFloat(2, 0, 6000),
@@ -48,7 +57,7 @@ $factory->define(App\Models\Pirep::class, function (Faker $faker) {
'route' => $faker->text(200),
'notes' => $faker->text(200),
'source' => $faker->randomElement([PirepSource::MANUAL, PirepSource::ACARS]),
'source_name' => 'Test Factory',
'source_name' => 'TestFactory',
'state' => PirepState::PENDING,
'status' => PirepStatus::SCHEDULED,
'submitted_at' => Carbon::now('UTC')->toDateTimeString(),

View File

@@ -1,6 +1,7 @@
<?php
use App\Contracts\Migration;
use App\Contracts\Model;
use App\Models\Enums\FlightType;
use Illuminate\Database\Schema\Blueprint;
@@ -14,7 +15,7 @@ class CreateFlightTables extends Migration
public function up()
{
Schema::create('flights', function (Blueprint $table) {
$table->string('id', \App\Contracts\Model::ID_MAX_LENGTH);
$table->string('id', Model::ID_MAX_LENGTH);
$table->unsignedInteger('airline_id');
$table->unsignedInteger('flight_number');
$table->string('route_code', 5)->nullable();
@@ -47,7 +48,7 @@ class CreateFlightTables extends Migration
});
Schema::create('flight_fare', function (Blueprint $table) {
$table->string('flight_id', \App\Contracts\Model::ID_MAX_LENGTH);
$table->string('flight_id', Model::ID_MAX_LENGTH);
$table->unsignedInteger('fare_id');
$table->string('price', 10)->nullable();
$table->string('cost', 10)->nullable();
@@ -71,7 +72,7 @@ class CreateFlightTables extends Migration
*/
Schema::create('flight_field_values', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('flight_id', \App\Contracts\Model::ID_MAX_LENGTH);
$table->string('flight_id', Model::ID_MAX_LENGTH);
$table->string('name', 50);
$table->string('slug', 50)->nullable();
$table->text('value');
@@ -83,7 +84,7 @@ class CreateFlightTables extends Migration
Schema::create('flight_subfleet', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('subfleet_id');
$table->string('flight_id', \App\Contracts\Model::ID_MAX_LENGTH);
$table->string('flight_id', Model::ID_MAX_LENGTH);
$table->index(['subfleet_id', 'flight_id']);
$table->index(['flight_id', 'subfleet_id']);

View File

@@ -1,6 +1,7 @@
<?php
use App\Contracts\Migration;
use App\Contracts\Model;
use App\Models\Enums\FlightType;
use App\Models\Enums\PirepState;
use App\Models\Enums\PirepStatus;
@@ -16,7 +17,7 @@ class CreatePirepTables extends Migration
public function up()
{
Schema::create('pireps', function (Blueprint $table) {
$table->string('id', \App\Contracts\Model::ID_MAX_LENGTH);
$table->string('id', Model::ID_MAX_LENGTH);
$table->unsignedInteger('user_id');
$table->unsignedInteger('airline_id');
$table->unsignedInteger('aircraft_id')->nullable();
@@ -57,7 +58,7 @@ class CreatePirepTables extends Migration
Schema::create('pirep_comments', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('pirep_id', \App\Contracts\Model::ID_MAX_LENGTH);
$table->string('pirep_id', Model::ID_MAX_LENGTH);
$table->unsignedInteger('user_id');
$table->text('comment');
$table->timestamps();
@@ -65,7 +66,7 @@ class CreatePirepTables extends Migration
Schema::create('pirep_fares', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('pirep_id', \App\Contracts\Model::ID_MAX_LENGTH);
$table->string('pirep_id', Model::ID_MAX_LENGTH);
$table->unsignedInteger('fare_id');
$table->unsignedInteger('count')->nullable()->default(0);
@@ -81,7 +82,7 @@ class CreatePirepTables extends Migration
Schema::create('pirep_field_values', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('pirep_id', \App\Contracts\Model::ID_MAX_LENGTH);
$table->string('pirep_id', Model::ID_MAX_LENGTH);
$table->string('name', 50);
$table->string('slug', 50)->nullable();
$table->string('value')->nullable();

View File

@@ -1,6 +1,7 @@
<?php
use App\Contracts\Migration;
use App\Contracts\Model;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
@@ -16,7 +17,7 @@ class CreateBidsTable extends Migration
Schema::create('bids', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('user_id');
$table->string('flight_id', \App\Contracts\Model::ID_MAX_LENGTH);
$table->string('flight_id', Model::ID_MAX_LENGTH);
$table->timestamps();
$table->index('user_id');

View File

@@ -0,0 +1,31 @@
<?php
use App\Contracts\Model;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class PirepsAddFlightId extends Migration
{
/**
* Add a `flight_id` column to the PIREPs table
*/
public function up()
{
Schema::table('pireps', function (Blueprint $table) {
$table->string('flight_id', Model::ID_MAX_LENGTH)->nullable()->after('aircraft_id');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('pireps', function (Blueprint $table) {
$table->dropColumn('flight_id');
});
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace App\Exceptions;
use App\Models\User;
class UserBidLimit extends HttpException
{
private $user;
public function __construct(User $user)
{
$this->user = $user;
parent::__construct(
409,
'User '.$user->ident.' has the maximum number of bids'
);
}
/**
* Return the RFC 7807 error type (without the URL root)
*/
public function getErrorType(): string
{
return 'user-bid-limit';
}
/**
* Get the detailed error string
*/
public function getErrorDetails(): string
{
return $this->getMessage();
}
/**
* Return an array with the error details, merged with the RFC7807 response
*/
public function getErrorMetadata(): array
{
return [
'user_id' => $this->user->id,
];
}
}

View File

@@ -8,8 +8,8 @@ use App\Http\Resources\Navdata as NavdataResource;
use App\Repositories\Criteria\WhereCriteria;
use App\Repositories\FlightRepository;
use App\Services\FlightService;
use Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Prettus\Repository\Criteria\RequestCriteria;
use Prettus\Repository\Exceptions\RepositoryException;
@@ -44,6 +44,9 @@ class FlightController extends Controller
*/
public function index(Request $request)
{
/**
* @var $user \App\Models\User
*/
$user = Auth::user();
$where = [
@@ -52,7 +55,7 @@ class FlightController extends Controller
];
if (setting('pilots.restrict_to_company')) {
$where['airline_id'] = Auth::user()->airline_id;
$where['airline_id'] = $user->airline_id;
}
if (setting('pilots.only_flights_from_current', false)) {
$where['dpt_airport_id'] = $user->curr_airport_id;

View File

@@ -20,6 +20,7 @@ use App\Http\Resources\PirepComment as PirepCommentResource;
use App\Http\Resources\PirepFieldCollection;
use App\Models\Acars;
use App\Models\Enums\AcarsType;
use App\Models\Enums\FlightType;
use App\Models\Enums\PirepFieldSource;
use App\Models\Enums\PirepSource;
use App\Models\Enums\PirepState;
@@ -93,6 +94,10 @@ class PirepController extends Controller
$attrs['created_at'] = Carbon::createFromTimeString($attrs['created_at']);
}
if (array_key_exists('updated_at', $attrs)) {
$attrs['updated_at'] = Carbon::createFromTimeString($attrs['updated_at']);
}
return $attrs;
}
@@ -186,6 +191,9 @@ class PirepController extends Controller
{
Log::info('PIREP Prefile, user '.Auth::id(), $request->post());
/**
* @var $user \App\Models\User
*/
$user = Auth::user();
$attrs = $this->parsePirep($request);
@@ -228,7 +236,7 @@ class PirepController extends Controller
// Default to a scheduled passenger flight
if (!array_key_exists('flight_type', $attrs)) {
$attrs['flight_type'] = 'J';
$attrs['flight_type'] = FlightType::SCHED_PAX;
}
$pirep->save();

View File

@@ -13,18 +13,17 @@ use App\Repositories\Criteria\WhereCriteria;
use App\Repositories\FlightRepository;
use App\Repositories\PirepRepository;
use App\Repositories\UserRepository;
use App\Services\BidService;
use App\Services\FlightService;
use App\Services\UserService;
use Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Prettus\Repository\Criteria\RequestCriteria;
use Prettus\Repository\Exceptions\RepositoryException;
/**
* Class UserController
*/
class UserController extends Controller
{
private $bidSvc;
private $flightRepo;
private $flightSvc;
private $pirepRepo;
@@ -32,8 +31,7 @@ class UserController extends Controller
private $userSvc;
/**
* UserController constructor.
*
* @param BidService $bidSvc
* @param FlightRepository $flightRepo
* @param FlightService $flightSvc
* @param PirepRepository $pirepRepo
@@ -41,12 +39,14 @@ class UserController extends Controller
* @param UserService $userSvc
*/
public function __construct(
BidService $bidSvc,
FlightRepository $flightRepo,
FlightService $flightSvc,
PirepRepository $pirepRepo,
UserRepository $userRepo,
UserService $userSvc
) {
$this->bidSvc = $bidSvc;
$this->flightRepo = $flightRepo;
$this->flightSvc = $flightSvc;
$this->pirepRepo = $pirepRepo;
@@ -61,11 +61,11 @@ class UserController extends Controller
*/
protected function getUserId(Request $request)
{
if ($request->id === null) {
if ($request->get('id') === null) {
return Auth::user()->id;
}
return $request->id;
return $request->get('id');
}
/**
@@ -110,7 +110,7 @@ class UserController extends Controller
if ($request->isMethod('PUT') || $request->isMethod('POST')) {
$flight_id = $request->input('flight_id');
$flight = $this->flightRepo->find($flight_id);
$bid = $this->flightSvc->addBid($flight, $user);
$bid = $this->bidSvc->addBid($flight, $user);
return new BidResource($bid);
}
@@ -124,11 +124,11 @@ class UserController extends Controller
}
$flight = $this->flightRepo->find($flight_id);
$this->flightSvc->removeBid($flight, $user);
$this->bidSvc->removeBid($flight, $user);
}
// Return the flights they currently have bids on
$bids = Bid::where(['user_id' => $user->id])->get();
$bids = $this->bidSvc->findBidsForUser($user);
return BidResource::collection($bids);
}

View File

@@ -14,6 +14,7 @@ use App\Repositories\AircraftRepository;
use App\Repositories\AirlineRepository;
use App\Repositories\AirportRepository;
use App\Repositories\Criteria\WhereCriteria;
use App\Repositories\FlightRepository;
use App\Repositories\PirepFieldRepository;
use App\Repositories\PirepRepository;
use App\Services\FareService;
@@ -35,6 +36,7 @@ class PirepController extends Controller
private $aircraftRepo;
private $airlineRepo;
private $fareSvc;
private $flightRepo;
private $geoSvc;
private $pirepRepo;
private $airportRepo;
@@ -43,12 +45,11 @@ class PirepController extends Controller
private $userSvc;
/**
* PirepController constructor.
*
* @param AircraftRepository $aircraftRepo
* @param AirlineRepository $airlineRepo
* @param AirportRepository $airportRepo
* @param FareService $fareSvc
* @param FlightRepository $flightRepo
* @param GeoService $geoSvc
* @param PirepRepository $pirepRepo
* @param PirepFieldRepository $pirepFieldRepo
@@ -60,6 +61,7 @@ class PirepController extends Controller
AirlineRepository $airlineRepo,
AirportRepository $airportRepo,
FareService $fareSvc,
FlightRepository $flightRepo,
GeoService $geoSvc,
PirepRepository $pirepRepo,
PirepFieldRepository $pirepFieldRepo,
@@ -73,6 +75,7 @@ class PirepController extends Controller
$this->pirepFieldRepo = $pirepFieldRepo;
$this->fareSvc = $fareSvc;
$this->flightRepo = $flightRepo;
$this->geoSvc = $geoSvc;
$this->pirepSvc = $pirepSvc;
$this->userSvc = $userSvc;
@@ -231,12 +234,24 @@ class PirepController extends Controller
/**
* Create a new flight report
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function create()
public function create(Request $request)
{
$pirep = null;
// See if request has a ?flight_id, so we can pre-populate the fields from the flight
// Makes filing easier, but we can also more easily find a bid and close it
if ($request->has('flight_id')) {
$flight = $this->flightRepo->find($request->get('flight_id'));
$pirep = Pirep::fromFlight($flight);
}
return view('pireps.create', [
'aircraft' => null,
'pirep' => $pirep,
'read_only' => false,
'airline_list' => $this->airlineRepo->selectBoxList(true),
'aircraft_list' => $this->aircraftList(true),

View File

@@ -4,9 +4,6 @@ namespace App\Http\Requests\Acars;
use App\Contracts\FormRequest;
/**
* Class CommentRequest
*/
class CommentRequest extends FormRequest
{
public function rules(): array

View File

@@ -4,25 +4,17 @@ namespace App\Http\Requests\Acars;
use App\Contracts\FormRequest;
use App\Models\Pirep;
use Auth;
use Illuminate\Support\Facades\Auth;
/**
* Class EventRequest
*/
class EventRequest extends FormRequest
{
/**
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException
*
* @return bool
*/
public function authorize()
public function authorize(): bool
{
$pirep = Pirep::findOrFail($this->route('pirep_id'), ['user_id']);
return $pirep->user_id === Auth::id();
}
public function rules()
public function rules(): array
{
$rules = [
'events' => 'required|array',

View File

@@ -9,10 +9,7 @@ use App\Contracts\FormRequest;
*/
class FieldsRequest extends FormRequest
{
/**
* @return array
*/
public function rules()
public function rules(): array
{
return [
'fields' => 'required|array',

View File

@@ -4,26 +4,22 @@ namespace App\Http\Requests\Acars;
use App\Contracts\FormRequest;
use App\Models\Pirep;
use Auth;
use Illuminate\Support\Facades\Auth;
/**
* Class FileRequest
*/
class FileRequest extends FormRequest
{
public function authorize()
public function authorize(): bool
{
$pirep = Pirep::findOrFail($this->route('pirep_id'), ['user_id']);
return $pirep->user_id === Auth::id();
}
public function rules()
public function rules(): array
{
$rules = [
'distance' => 'required|numeric',
'flight_time' => 'required|integer',
'fuel_used' => 'required|numeric',
'distance' => 'required|numeric',
'flight_time' => 'required|integer',
'fuel_used' => 'required|numeric',
'block_time' => 'nullable|integer',
'airline_id' => 'nullable|exists:airlines,id',
'aircraft_id' => 'nullable|exists:aircraft,id',

View File

@@ -4,20 +4,17 @@ namespace App\Http\Requests\Acars;
use App\Contracts\FormRequest;
use App\Models\Pirep;
use Auth;
use Illuminate\Support\Facades\Auth;
/**
* Class LogRequest
*/
class LogRequest extends FormRequest
{
public function authorize()
public function authorize(): bool
{
$pirep = Pirep::findOrFail($this->route('pirep_id'), ['user_id']);
return $pirep->user_id === Auth::id();
}
public function rules()
public function rules(): array
{
$rules = [
'logs' => 'required|array',

View File

@@ -4,36 +4,20 @@ namespace App\Http\Requests\Acars;
use App\Contracts\FormRequest;
use App\Models\Pirep;
use Auth;
use Illuminate\Support\Facades\Auth;
/**
* Class PositionRequest
*/
class PositionRequest extends FormRequest
{
/**
* @return bool
* Is the user allowed to do this?
*/
public function authorize()
public function authorize(): bool
{
$pirep = Pirep::findOrFail($this->route('pirep_id'), ['user_id']);
return $pirep->user_id === Auth::id();
}
/**
* @return array
*/
/*public function sanitize()
{
return [
'positions.*.sim_time' => Acars::$sanitize['sim_time'],
];
}*/
/**
* @return array
*/
public function rules()
public function rules(): array
{
$rules = [
'positions' => 'required|array',

View File

@@ -4,32 +4,18 @@ namespace App\Http\Requests\Acars;
use App\Contracts\FormRequest;
/**
* Class PrefileRequest
*/
class PrefileRequest extends FormRequest
{
/**
* @return array|void
*/
/*public function sanitize()
{
return Pirep::$sanitize;
}*/
/**
* @return array
*/
public function rules()
public function rules(): array
{
$rules = [
'airline_id' => 'required|exists:airlines,id',
'aircraft_id' => 'required|exists:aircraft,id',
'flight_number' => 'required',
'dpt_airport_id' => 'required',
'arr_airport_id' => 'required',
'source_name' => 'required',
'airline_id' => 'required|exists:airlines,id',
'aircraft_id' => 'required|exists:aircraft,id',
'flight_number' => 'required',
'dpt_airport_id' => 'required',
'arr_airport_id' => 'required',
'flight_id' => 'nullable',
'source_name' => 'required',
'alt_airport_id' => 'nullable',
'status' => 'nullable',
'level' => 'nullable|numeric',

View File

@@ -4,20 +4,17 @@ namespace App\Http\Requests\Acars;
use App\Contracts\FormRequest;
use App\Models\Pirep;
use Auth;
use Illuminate\Support\Facades\Auth;
/**
* Class RouteRequest
*/
class RouteRequest extends FormRequest
{
public function authorize()
public function authorize(): bool
{
$pirep = Pirep::findOrFail($this->route('pirep_id'), ['user_id']);
return $pirep->user_id === Auth::id();
}
public function rules()
public function rules(): array
{
$rules = [
'route' => 'required|array',

View File

@@ -4,20 +4,17 @@ namespace App\Http\Requests\Acars;
use App\Contracts\FormRequest;
use App\Models\Pirep;
use Auth;
use Illuminate\Support\Facades\Auth;
/**
* Class UpdateRequest
*/
class UpdateRequest extends FormRequest
{
public function authorize()
public function authorize(): bool
{
$pirep = Pirep::findOrFail($this->route('pirep_id'), ['user_id']);
return $pirep->user_id === Auth::id();
}
public function rules()
public function rules(): array
{
$rules = [
'airline_id' => 'nullable|exists:airlines,id',

View File

@@ -4,7 +4,7 @@ namespace App\Listeners;
use App\Contracts\Listener;
use App\Events\PirepAccepted;
use App\Services\PirepService;
use App\Services\BidService;
use Illuminate\Contracts\Events\Dispatcher;
/**
@@ -12,17 +12,11 @@ use Illuminate\Contracts\Events\Dispatcher;
*/
class BidEvents extends Listener
{
private $pirepSvc;
private $bidSvc;
/**
* FinanceEvents constructor.
*
* @param PirepService $pirepSvc
*/
public function __construct(
PirepService $pirepSvc
) {
$this->pirepSvc = $pirepSvc;
public function __construct(BidService $bidSvc)
{
$this->bidSvc = $bidSvc;
}
/**
@@ -44,10 +38,9 @@ class BidEvents extends Listener
* @throws \UnexpectedValueException
* @throws \InvalidArgumentException
* @throws \Exception
* @throws \Prettus\Validator\Exceptions\ValidatorException
*/
public function onPirepAccept(PirepAccepted $event): void
{
$this->pirepSvc->removeBid($event->pirep);
$this->bidSvc->removeBidForPirep($event->pirep);
}
}

View File

@@ -22,7 +22,10 @@ use Illuminate\Support\Collection;
* @property Collection fares
* @property Collection subfleets
* @property int days
* @property int distance
* @property int flight_time
* @property string route
* @property int level
* @property Airport dpt_airport
* @property Airport arr_airport
* @property Airport alt_airport

View File

@@ -150,6 +150,28 @@ class Pirep extends Model
PirepState::DELETED,
];
/**
* Create a new PIREP model from a given flight. Pre-populates the fields
*
* @param \App\Models\Flight $flight
*
* @return \App\Models\Pirep
*/
public static function fromFlight(Flight $flight)
{
return new self([
'flight_id' => $flight->id,
'airline_id' => $flight->airline_id,
'flight_number' => $flight->flight_number,
'route_code' => $flight->route_code,
'route_leg' => $flight->route_leg,
'dpt_airport_id' => $flight->dpt_airport_id,
'arr_airport_id' => $flight->arr_airport_id,
'route' => $flight->route,
'level' => $flight->level,
]);
}
/**
* Get the flight ident, e.,g JBU1900
*
@@ -277,10 +299,16 @@ class Pirep extends Model
/**
* Look up the flight, based on the PIREP flight info
*
* @param mixed $value
*
* @return Flight|null
*/
public function getFlightAttribute(): ?Flight
/*public function getFlightAttribute(): ?Flight
{
if (!empty($this->flight_id)) {
return Flight::find($this->flight_id);
}
$where = [
'airline_id' => $this->airline_id,
'flight_number' => $this->flight_number,
@@ -296,7 +324,7 @@ class Pirep extends Model
}
return Flight::where($where)->first();
}
}*/
/**
* Set the amount of fuel used
@@ -412,6 +440,11 @@ class Pirep extends Model
return $this->belongsTo(Airline::class, 'airline_id');
}
public function flight()
{
return $this->belongsTo(Flight::class, 'flight_id');
}
public function arr_airport()
{
return $this->belongsTo(Airport::class, 'arr_airport_id');

View File

@@ -12,6 +12,7 @@ use Laratrust\Traits\LaratrustUserTrait;
/**
* @property int id
* @property int pilot_id
* @property int airline_id
* @property string name
* @property string email
* @property string password

145
app/Services/BidService.php Normal file
View File

@@ -0,0 +1,145 @@
<?php
namespace App\Services;
use App\Contracts\Service;
use App\Exceptions\BidExistsForFlight;
use App\Exceptions\UserBidLimit;
use App\Models\Bid;
use App\Models\Flight;
use App\Models\Pirep;
use App\Models\User;
use Illuminate\Support\Facades\Log;
class BidService extends Service
{
/**
* Find all of the bids for a given user
*
* @param \App\Models\User $user
*
* @return mixed
*/
public function findBidsForUser(User $user)
{
$bids = Bid::where(['user_id' => $user->id])->get();
return $bids;
}
/**
* Allow a user to bid on a flight. Check settings and all that good stuff
*
* @param Flight $flight
* @param User $user
*
* @throws \App\Exceptions\BidExistsForFlight
*
* @return mixed
*/
public function addBid(Flight $flight, User $user)
{
// Get all of the bids for this user. See if they're allowed to have multiple
// bids
$bid_count = Bid::where(['user_id' => $user->id])->count();
if ($bid_count > 0 && setting('bids.allow_multiple_bids') === false) {
throw new UserBidLimit($user);
}
// Get all of the bids for this flight
$bids = Bid::where(['flight_id' => $flight->id])->get();
if ($bids->count() > 0) {
// Does the flight have a bid set?
if ($flight->has_bid === false) {
$flight->has_bid = true;
$flight->save();
}
// Check all the bids for one of this user
foreach ($bids as $bid) {
if ($bid->user_id === $user->id) {
Log::info('Bid exists, user='.$user->ident.', flight='.$flight->id);
return $bid;
}
}
// Check if the flight should be blocked off
if (setting('bids.disable_flight_on_bid') === true) {
throw new BidExistsForFlight($flight);
}
if (setting('bids.allow_multiple_bids') === false) {
throw new BidExistsForFlight($flight);
}
} else {
/* @noinspection NestedPositiveIfStatementsInspection */
if ($flight->has_bid === true) {
Log::info('Bid exists, flight='.$flight->id.'; no entry in bids table, cleaning up');
}
}
$bid = Bid::firstOrCreate([
'user_id' => $user->id,
'flight_id' => $flight->id,
]);
$flight->has_bid = true;
$flight->save();
return $bid;
}
/**
* Remove a bid from a given flight
*
* @param Flight $flight
* @param User $user
*/
public function removeBid(Flight $flight, User $user)
{
$bids = Bid::where([
'flight_id' => $flight->id,
'user_id' => $user->id,
])->get();
foreach ($bids as $bid) {
$bid->forceDelete();
}
// Only flip the flag if there are no bids left for this flight
$bid_count = Bid::where(['flight_id' => $flight->id])->count();
if ($bid_count === 0) {
$flight->has_bid = false;
$flight->save();
}
}
/**
* If the setting is enabled, remove the bid
*
* @param Pirep $pirep
*
* @throws \Exception
*/
public function removeBidForPirep(Pirep $pirep)
{
if (!setting('pireps.remove_bid_on_accept')) {
return;
}
$flight = $pirep->flight;
if (!$flight) {
return;
}
$bid = Bid::where([
'user_id' => $pirep->user->id,
'flight_id' => $flight->id,
]);
if ($bid) {
Log::info('Bid for user: '.$pirep->user->ident.' on flight '.$flight->ident);
$bid->delete();
}
}
}

View File

@@ -3,17 +3,14 @@
namespace App\Services;
use App\Contracts\Service;
use App\Exceptions\BidExistsForFlight;
use App\Exceptions\DuplicateFlight;
use App\Models\Bid;
use App\Models\Enums\Days;
use App\Models\Flight;
use App\Models\FlightFieldValue;
use App\Models\User;
use App\Repositories\FlightRepository;
use App\Repositories\NavdataRepository;
use App\Support\Units\Time;
use Illuminate\Support\Facades\Log;
class FlightService extends Service
{
@@ -123,24 +120,6 @@ class FlightService extends Service
return $fields;
}
/**
* Filter out any flights according to different settings
*
* @param $user
*
* @return FlightRepository
*/
public function filterFlights($user)
{
$where = [];
if (setting('pilots.only_flights_from_current', false)) {
$where['dpt_airport_id'] = $user->curr_airport_id;
}
return $this->flightRepo
->whereOrder($where, 'flight_number', 'asc');
}
/**
* Filter out subfleets to only include aircraft that a user has access to
*
@@ -276,91 +255,4 @@ class FlightService extends Service
return collect($return_points);
}
/**
* Allow a user to bid on a flight. Check settings and all that good stuff
*
* @param Flight $flight
* @param User $user
*
*@throws \App\Exceptions\BidExistsForFlight
*
* @return mixed
*/
public function addBid(Flight $flight, User $user)
{
// Get all of the bids for this user. See if they're allowed to have multiple
// bids
$bids = Bid::where('user_id', $user->id)->get();
if ($bids->count() > 0 && setting('bids.allow_multiple_bids') === false) {
throw new BidExistsForFlight('User "'.$user->ident.'" already has bids, skipping');
}
// Get all of the bids for this flight
$bids = Bid::where('flight_id', $flight->id)->get();
if ($bids->count() > 0) {
// Does the flight have a bid set?
if ($flight->has_bid === false) {
$flight->has_bid = true;
$flight->save();
}
// Check all the bids for one of this user
foreach ($bids as $bid) {
if ($bid->user_id === $user->id) {
Log::info('Bid exists, user='.$user->ident.', flight='.$flight->id);
return $bid;
}
}
// Check if the flight should be blocked off
if (setting('bids.disable_flight_on_bid') === true) {
throw new BidExistsForFlight($flight);
}
if (setting('bids.allow_multiple_bids') === false) {
throw new BidExistsForFlight($flight);
}
} else {
/* @noinspection NestedPositiveIfStatementsInspection */
if ($flight->has_bid === true) {
Log::info('Bid exists, flight='.$flight->id.'; no entry in bids table, cleaning up');
}
}
$bid = Bid::firstOrCreate([
'user_id' => $user->id,
'flight_id' => $flight->id,
]);
$flight->has_bid = true;
$flight->save();
return $bid;
}
/**
* Remove a bid from a given flight
*
* @param Flight $flight
* @param User $user
*/
public function removeBid(Flight $flight, User $user)
{
$bids = Bid::where([
'flight_id' => $flight->id,
'user_id' => $user->id,
])->get();
foreach ($bids as $bid) {
$bid->forceDelete();
}
// Only flip the flag if there are no bids left for this flight
$bids = Bid::where('flight_id', $flight->id)->get();
if ($bids->count() === 0) {
$flight->has_bid = false;
$flight->save();
}
}
}

View File

@@ -9,7 +9,6 @@ use App\Events\PirepRejected;
use App\Events\UserStatsChanged;
use App\Exceptions\PirepCancelNotAllowed;
use App\Models\Acars;
use App\Models\Bid;
use App\Models\Enums\AcarsType;
use App\Models\Enums\PirepSource;
use App\Models\Enums\PirepState;
@@ -20,12 +19,10 @@ use App\Models\PirepFieldValue;
use App\Models\User;
use App\Repositories\PirepRepository;
use Carbon\Carbon;
use function count;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Log;
/**
* Class PirepService
*/
class PirepService extends Service
{
private $geoSvc;
@@ -33,8 +30,6 @@ class PirepService extends Service
private $pirepRepo;
/**
* PirepService constructor.
*
* @param GeoService $geoSvc
* @param PirepRepository $pirepRepo
* @param UserService $pilotSvc
@@ -49,6 +44,60 @@ class PirepService extends Service
$this->pirepRepo = $pirepRepo;
}
/**
* Create a new PIREP with some given fields
*
* @param Pirep $pirep
* @param array PirepFieldValue[] $field_values
*
* @return Pirep
*/
public function create(Pirep $pirep, array $field_values = []): Pirep
{
if (empty($field_values)) {
$field_values = [];
}
// 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();
if (count($field_values) > 0) {
$this->updateCustomFields($pirep->id, $field_values);
}
return $pirep;
}
/**
* Find if there are duplicates to a given PIREP. Ideally, the passed
* in PIREP hasn't been saved or gone through the create() method
@@ -149,54 +198,6 @@ class PirepService extends Service
return $pirep;
}
/**
* Create a new PIREP with some given fields
*
* @param Pirep $pirep
* @param array PirepFieldValue[] $field_values
*
* @return Pirep
*/
public function create(Pirep $pirep, array $field_values = []): Pirep
{
if (empty($field_values)) {
$field_values = [];
}
// 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;
$pirep->save();
$pirep->refresh();
if (\count($field_values) > 0) {
$this->updateCustomFields($pirep->id, $field_values);
}
return $pirep;
}
/**
* Submit the PIREP. Figure out its default state
*
@@ -421,33 +422,4 @@ class PirepService extends Service
event(new UserStatsChanged($pilot, 'airport', $previous_airport));
}
/**
* If the setting is enabled, remove the bid
*
* @param Pirep $pirep
*
* @throws \Exception
*/
public function removeBid(Pirep $pirep)
{
if (!setting('pireps.remove_bid_on_accept')) {
return;
}
$flight = $pirep->flight;
if (!$flight) {
return;
}
$bid = Bid::where([
'user_id' => $pirep->user->id,
'flight_id' => $flight->id,
]);
if ($bid) {
Log::info('Bid for user: '.$pirep->user->ident.' on flight '.$flight->ident);
$bid->delete();
}
}
}

View File

@@ -7,6 +7,7 @@ return [
'submitpirep' => 'Submit PIREP',
'fileflightreport' => 'File New Report',
'filenewpirep' => 'File New PIREP',
'newpirep' => 'New PIREP',
'pilotreport' => 'Pilot Report|Pilot Reports',
'arrived' => 'Arrived',
'source' => 'Source',

View File

@@ -7,6 +7,7 @@ return [
'submitpirep' => 'Enviar PIREP',
'fileflightreport' => 'Archivo informe de vuelo',
'filenewpirep' => 'Archivo nuevo PIREP',
'newpirep' => 'Nuevo PIREP',
'pilotreport' => 'Informe de piloto|Informes de piloto',
'arrived' => 'Llegó',
'source' => 'Origen',

View File

@@ -2,6 +2,7 @@
return [
'filenewpirep' => 'Inserici Nuovo PIREP',
'newpirep' => 'Nuovo PIREP',
'pilotreport' => 'Rapporto Pilota|Rapporti Pilota',
'arrived' => 'Arrivato',
'source' => 'Fonte',

View File

@@ -23,8 +23,7 @@
x-id="{{ $flight->id }}"
x-saved-class="btn-info"
type="button"
title="@lang('flights.addremovebid')"
>
title="@lang('flights.addremovebid')">
<i class="fas fa-map-marker"></i>
</button>
@endif
@@ -64,6 +63,14 @@
@endif
</div>
</div>
<div class="row">
<div class="col-sm-12 text-right">
<a href="{{ route('frontend.pireps.create') }}?flight_id={{ $flight->id }}"
class="btn btn-sm btn-info">
{{ __('pireps.newpirep') }}
</a>
</div>
</div>
</div>
</div>

View File

@@ -2,17 +2,22 @@
@section('title', __('pireps.fileflightreport'))
@section('content')
<div class="row">
<div class="col-md-12">
<h2>@lang('pireps.newflightreport')</h2>
@include('flash::message')
{{ Form::open(['route' => 'frontend.pireps.store']) }}
<div class="row">
<div class="col-md-12">
<h2>@lang('pireps.newflightreport')</h2>
@include('flash::message')
@if(!empty($pirep))
wee
{{ Form::model($pirep, ['route' => 'frontend.pireps.store']) }}
@else
{{ Form::open(['route' => 'frontend.pireps.store']) }}
@endif
@include('pireps.fields')
@include('pireps.fields')
{{ Form::close() }}
</div>
{{ Form::close() }}
</div>
</div>
@endsection
@include('pireps.scripts')

View File

@@ -9,323 +9,326 @@ flight reports that have been filed. You've been warned!
--}}
@if(!empty($pirep) && $pirep->read_only)
<div class="row">
<div class="col-sm-12">
@component('components.info')
@lang('pireps.fieldsreadonly')
@endcomponent
</div>
<div class="row">
<div class="col-sm-12">
@component('components.info')
@lang('pireps.fieldsreadonly')
@endcomponent
</div>
</div>
@endif
<div class="row">
<div class="col-8">
<div class="form-container">
<h6><i class="fas fa-info-circle"></i>
&nbsp;@lang('pireps.flightinformations')
</h6>
<div class="form-container-body">
<div class="row">
<div class="col-sm-4">
{{ Form::label('airline_id', __('common.airline')) }}
@if(!empty($pirep) && $pirep->read_only)
<p>{{ $pirep->airline->name }}</p>
{{ Form::hidden('airline_id') }}
@else
<div class="input-group input-group form-group">
{{ Form::select('airline_id', $airline_list, null, [
'class' => 'custom-select select2',
'style' => 'width: 100%',
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
</div>
<p class="text-danger">{{ $errors->first('airline_id') }}</p>
@endif
</div>
<div class="col-sm-4">
{{ Form::label('flight_number', __('pireps.flightident')) }}
@if(!empty($pirep) && $pirep->read_only)
<p>{{ $pirep->ident }}
{{ Form::hidden('flight_number') }}
{{ Form::hidden('flight_code') }}
{{ Form::hidden('flight_leg') }}
</p>
@else
<div class="input-group input-group-sm mb3">
{{ Form::text('flight_number', null, [
'placeholder' => __('flights.flightnumber'),
'class' => 'form-control',
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
&nbsp;
{{ Form::text('route_code', null, [
'placeholder' => __('pireps.codeoptional'),
'class' => 'form-control',
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
&nbsp;
{{ Form::text('route_leg', null, [
'placeholder' => __('pireps.legoptional'),
'class' => 'form-control',
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
</div>
<p class="text-danger">{{ $errors->first('flight_number') }}</p>
<p class="text-danger">{{ $errors->first('route_code') }}</p>
<p class="text-danger">{{ $errors->first('route_leg') }}</p>
@endif
</div>
<div class="col-lg-4">
{{ Form::label('flight_type', __('flights.flighttype')) }}
@if(!empty($pirep) && $pirep->read_only)
<p>{{ \App\Models\Enums\FlightType::label($pirep->flight_type) }}</p>
{{ Form::hidden('flight_type') }}
@else
<div class="form-group">
{{ Form::select('flight_type',
\App\Models\Enums\FlightType::select(), null, [
'class' => 'custom-select select2',
'style' => 'width: 100%',
'readonly' => (!empty($pirep) && $pirep->read_only),
])
}}
</div>
<p class="text-danger">{{ $errors->first('flight_type') }}</p>
@endif
</div>
</div>
<div class="row">
<div class="col-3">
{{ Form::label('hours', __('flights.flighttime')) }}
@if(!empty($pirep) && $pirep->read_only)
<p>
{{ $pirep->hours.' '.trans_choice('common.hour', $pirep->hours) }}, {{ $pirep->minutes.' '.trans_choice('common.minute', $pirep->minutes) }}
{{ Form::hidden('hours') }}
{{ Form::hidden('minutes') }}
</p>
@else
<div class="input-group input-group-sm" style="max-width: 400px;">
{{ Form::number('hours', null, [
'class' => 'form-control',
'placeholder' => trans_choice('common.hour', 2),
'min' => '0',
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
{{ Form::number('minutes', null, [
'class' => 'form-control',
'placeholder' => trans_choice('common.minute', 2),
'min' => 0,
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
</div>
<p class="text-danger">{{ $errors->first('hours') }}</p>
<p class="text-danger">{{ $errors->first('minutes') }}</p>
@endif
</div>
</div>
</div>
<div class="col-8">
<div class="form-container">
<h6><i class="fas fa-info-circle"></i>
&nbsp;@lang('pireps.flightinformations')
</h6>
<div class="form-container-body">
<div class="row">
<div class="col-sm-4">
{{ Form::label('airline_id', __('common.airline')) }}
@if(!empty($pirep) && $pirep->read_only)
<p>{{ $pirep->airline->name }}</p>
{{ Form::hidden('airline_id') }}
@else
<div class="input-group input-group form-group">
{{ Form::select('airline_id', $airline_list, null, [
'class' => 'custom-select select2',
'style' => 'width: 100%',
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
</div>
<p class="text-danger">{{ $errors->first('airline_id') }}</p>
@endif
</div>
<div class="col-sm-4">
{{ Form::label('flight_number', __('pireps.flightident')) }}
@if(!empty($pirep) && $pirep->read_only)
<p>{{ $pirep->ident }}
{{ Form::hidden('flight_number') }}
{{ Form::hidden('flight_code') }}
{{ Form::hidden('flight_leg') }}
</p>
@else
<div class="input-group input-group-sm mb3">
{{ Form::text('flight_number', null, [
'placeholder' => __('flights.flightnumber'),
'class' => 'form-control',
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
&nbsp;
{{ Form::text('route_code', null, [
'placeholder' => __('pireps.codeoptional'),
'class' => 'form-control',
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
&nbsp;
{{ Form::text('route_leg', null, [
'placeholder' => __('pireps.legoptional'),
'class' => 'form-control',
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
</div>
<p class="text-danger">{{ $errors->first('flight_number') }}</p>
<p class="text-danger">{{ $errors->first('route_code') }}</p>
<p class="text-danger">{{ $errors->first('route_leg') }}</p>
@endif
</div>
<div class="col-lg-4">
{{ Form::label('flight_type', __('flights.flighttype')) }}
@if(!empty($pirep) && $pirep->read_only)
<p>{{ \App\Models\Enums\FlightType::label($pirep->flight_type) }}</p>
{{ Form::hidden('flight_type') }}
@else
<div class="form-group">
{{ Form::select('flight_type',
\App\Models\Enums\FlightType::select(), null, [
'class' => 'custom-select select2',
'style' => 'width: 100%',
'readonly' => (!empty($pirep) && $pirep->read_only),
])
}}
</div>
<p class="text-danger">{{ $errors->first('flight_type') }}</p>
@endif
</div>
</div>
<div class="row">
<div class="col-3">
{{ Form::label('hours', __('flights.flighttime')) }}
@if(!empty($pirep) && $pirep->read_only)
<p>
{{ $pirep->hours.' '.trans_choice('common.hour', $pirep->hours) }}
, {{ $pirep->minutes.' '.trans_choice('common.minute', $pirep->minutes) }}
{{ Form::hidden('hours') }}
{{ Form::hidden('minutes') }}
</p>
@else
<div class="input-group input-group-sm" style="max-width: 400px;">
{{ Form::number('hours', null, [
'class' => 'form-control',
'placeholder' => trans_choice('common.hour', 2),
'min' => '0',
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
<div class="form-container">
<h6><i class="fas fa-globe"></i>
&nbsp;@lang('pireps.deparrinformations')
</h6>
<div class="form-container-body">
<div class="row">
<div class="col-6">
{{ Form::label('dpt_airport_id', __('airports.departure')) }}
@if(!empty($pirep) && $pirep->read_only)
{{ $pirep->dpt_airport->name }}
(<a href="{{route('frontend.airports.show', [
{{ Form::number('minutes', null, [
'class' => 'form-control',
'placeholder' => trans_choice('common.minute', 2),
'min' => 0,
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
</div>
<p class="text-danger">{{ $errors->first('hours') }}</p>
<p class="text-danger">{{ $errors->first('minutes') }}</p>
@endif
</div>
</div>
</div>
</div>
<div class="form-container">
<h6><i class="fas fa-globe"></i>
&nbsp;@lang('pireps.deparrinformations')
</h6>
<div class="form-container-body">
<div class="row">
<div class="col-6">
{{ Form::label('dpt_airport_id', __('airports.departure')) }}
@if(!empty($pirep) && $pirep->read_only)
{{ $pirep->dpt_airport->name }}
(<a href="{{route('frontend.airports.show', [
'id' => $pirep->dpt_airport->icao
])}}">{{$pirep->dpt_airport->icao}}</a>)
{{ Form::hidden('dpt_airport_id') }}
@else
<div class="form-group">
{{ Form::select('dpt_airport_id', $airport_list, null, [
'class' => 'custom-select select2',
'style' => 'width: 100%',
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
</div>
<p class="text-danger">{{ $errors->first('dpt_airport_id') }}</p>
@endif
</div>
{{ Form::hidden('dpt_airport_id') }}
@else
<div class="form-group">
{{ Form::select('dpt_airport_id', $airport_list, null, [
'class' => 'custom-select select2',
'style' => 'width: 100%',
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
</div>
<p class="text-danger">{{ $errors->first('dpt_airport_id') }}</p>
@endif
</div>
<div class="col-6">
{{ Form::label('arr_airport_id', __('airports.arrival')) }}
@if(!empty($pirep) && $pirep->read_only)
{{ $pirep->arr_airport->name }}
(<a href="{{route('frontend.airports.show', [
<div class="col-6">
{{ Form::label('arr_airport_id', __('airports.arrival')) }}
@if(!empty($pirep) && $pirep->read_only)
{{ $pirep->arr_airport->name }}
(<a href="{{route('frontend.airports.show', [
'id' => $pirep->arr_airport->icao
])}}">{{$pirep->arr_airport->icao}}</a>)
{{ Form::hidden('arr_airport_id') }}
@else
<div class="input-group input-group-sm form-group">
{{ Form::select('arr_airport_id', $airport_list, null, [
'class' => 'custom-select select2',
'style' => 'width: 100%',
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
</div>
<p class="text-danger">{{ $errors->first('arr_airport_id') }}</p>
@endif
</div>
</div>
</div>
</div>
<div class="form-container">
<h6><i class="fab fa-avianex"></i>
&nbsp;@lang('pireps.aircraftinformations')
</h6>
<div class="form-container-body">
<div class="row">
<div class="col-4">
{{ Form::label('aircraft_id', __('common.aircraft')) }}
@if(!empty($pirep) && $pirep->read_only)
<p>{{ $pirep->aircraft->name }}</p>
{{ Form::hidden('aircraft_id') }}
@else
<div class="input-group input-group-sm form-group">
{{-- You probably don't want to change this ID if you want the fare select to work --}}
{{ Form::select('aircraft_id', $aircraft_list, null, [
'id' => 'aircraft_select',
'class' => 'custom-select select2',
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
</div>
<p class="text-danger">{{ $errors->first('aircraft_id') }}</p>
@endif
</div>
<div class="col-4">
{{ Form::label('block_fuel', __('pireps.block_fuel')) }} ({{config('phpvms.internal_units.fuel')}})
@if(!empty($pirep) && $pirep->read_only)
<p>{{ $pirep->block_fuel }}</p>
@else
<div class="input-group input-group-sm form-group">
{{ Form::number('block_fuel', null, [
'class' => 'form-control',
'min' => '0',
'step' => '0.01',
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
</div>
<p class="text-danger">{{ $errors->first('block_fuel') }}</p>
@endif
</div>
<div class="col-4">
{{ Form::label('fuel_used', __('pireps.fuel_used')) }} ({{config('phpvms.internal_units.fuel')}})
@if(!empty($pirep) && $pirep->read_only)
<p>{{ $pirep->fuel_used }}</p>
@else
<div class="input-group input-group-sm form-group">
{{ Form::number('fuel_used', null, [
'class' => 'form-control',
'min' => '0',
'step' => '0.01',
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
</div>
<p class="text-danger">{{ $errors->first('fuel_used') }}</p>
@endif
</div>
</div>
</div>
</div>
<div id="fares_container" class="form-container">
@include('pireps.fares')
</div>
<div class="form-container">
<h6><i class="far fa-comments"></i>
&nbsp;@lang('flights.route')
</h6>
<div class="form-container-body">
<div class="row">
<div class="col">
<div class="input-group input-group-sm form-group">
{{ Form::textarea('route', null, [
'class' => 'form-control',
'placeholder' => __('flights.route'),
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
<p class="text-danger">{{ $errors->first('route') }}</p>
</div>
</div>
</div>
</div>
</div>
<div class="form-container">
<h6><i class="far fa-comments"></i>
&nbsp;{{ trans_choice('common.remark', 2) }}
</h6>
<div class="form-container-body">
<div class="row">
<div class="col">
<div class="input-group input-group-sm form-group">
{{ Form::textarea('notes', null, ['class' => 'form-control', 'placeholder' => trans_choice('common.note', 2)]) }}
<p class="text-danger">{{ $errors->first('notes') }}</p>
</div>
</div>
</div>
</div>
{{ Form::hidden('arr_airport_id') }}
@else
<div class="input-group input-group-sm form-group">
{{ Form::select('arr_airport_id', $airport_list, null, [
'class' => 'custom-select select2',
'style' => 'width: 100%',
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
</div>
<p class="text-danger">{{ $errors->first('arr_airport_id') }}</p>
@endif
</div>
</div>
</div>
</div>
{{--
Write out the custom fields, and label if they're required
--}}
<div class="col-4">
<div class="form-container">
<h6><i class="fab fa-wpforms"></i>
&nbsp;{{ trans_choice('common.field', 2) }}
</h6>
<div class="form-container-body">
@if(isset($pirep) && $pirep->fields)
@each('pireps.custom_fields', $pirep->fields, 'field')
@else
@each('pireps.custom_fields', $pirep_fields, 'field')
@endif
</div>
<div class="form-container">
<h6><i class="fab fa-avianex"></i>
&nbsp;@lang('pireps.aircraftinformations')
</h6>
<div class="form-container-body">
<div class="row">
<div class="col-4">
{{ Form::label('aircraft_id', __('common.aircraft')) }}
@if(!empty($pirep) && $pirep->read_only)
<p>{{ $pirep->aircraft->name }}</p>
{{ Form::hidden('aircraft_id') }}
@else
<div class="input-group input-group-sm form-group">
{{-- You probably don't want to change this ID if you want the fare select to work --}}
{{ Form::select('aircraft_id', $aircraft_list, null, [
'id' => 'aircraft_select',
'class' => 'custom-select select2',
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
</div>
<p class="text-danger">{{ $errors->first('aircraft_id') }}</p>
@endif
</div>
<div class="col-4">
{{ Form::label('block_fuel', __('pireps.block_fuel')) }} ({{config('phpvms.internal_units.fuel')}})
@if(!empty($pirep) && $pirep->read_only)
<p>{{ $pirep->block_fuel }}</p>
@else
<div class="input-group input-group-sm form-group">
{{ Form::number('block_fuel', null, [
'class' => 'form-control',
'min' => '0',
'step' => '0.01',
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
</div>
<p class="text-danger">{{ $errors->first('block_fuel') }}</p>
@endif
</div>
<div class="col-4">
{{ Form::label('fuel_used', __('pireps.fuel_used')) }} ({{config('phpvms.internal_units.fuel')}})
@if(!empty($pirep) && $pirep->read_only)
<p>{{ $pirep->fuel_used }}</p>
@else
<div class="input-group input-group-sm form-group">
{{ Form::number('fuel_used', null, [
'class' => 'form-control',
'min' => '0',
'step' => '0.01',
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
</div>
<p class="text-danger">{{ $errors->first('fuel_used') }}</p>
@endif
</div>
</div>
</div>
</div>
<div id="fares_container" class="form-container">
@include('pireps.fares')
</div>
<div class="form-container">
<h6><i class="far fa-comments"></i>
&nbsp;@lang('flights.route')
</h6>
<div class="form-container-body">
<div class="row">
<div class="col">
<div class="input-group input-group-sm form-group">
{{ Form::textarea('route', null, [
'class' => 'form-control',
'placeholder' => __('flights.route'),
'readonly' => (!empty($pirep) && $pirep->read_only),
]) }}
<p class="text-danger">{{ $errors->first('route') }}</p>
</div>
</div>
</div>
</div>
</div>
<div class="form-container">
<h6><i class="far fa-comments"></i>
&nbsp;{{ trans_choice('common.remark', 2) }}
</h6>
<div class="form-container-body">
<div class="row">
<div class="col">
<div class="input-group input-group-sm form-group">
{{ Form::textarea('notes', null, ['class' => 'form-control', 'placeholder' => trans_choice('common.note', 2)]) }}
<p class="text-danger">{{ $errors->first('notes') }}</p>
</div>
</div>
</div>
</div>
</div>
</div>
{{--
Write out the custom fields, and label if they're required
--}}
<div class="col-4">
<div class="form-container">
<h6><i class="fab fa-wpforms"></i>
&nbsp;{{ trans_choice('common.field', 2) }}
</h6>
<div class="form-container-body">
@if(isset($pirep) && $pirep->fields)
@each('pireps.custom_fields', $pirep->fields, 'field')
@else
@each('pireps.custom_fields', $pirep_fields, 'field')
@endif
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="float-right">
<div class="form-group">
<div class="col-sm-12">
<div class="float-right">
<div class="form-group">
@if(isset($pirep) && !$pirep->read_only)
{{ Form::button(__('pireps.deletepirep'), [
'name' => 'submit',
'value' => 'Delete',
'class' => 'btn btn-warning',
'type' => 'submit'])
}}
@endif
{{ Form::hidden('flight_id') }}
{{ Form::button(__('pireps.savepirep'), [
'name' => 'submit',
'value' => 'Save',
'class' => 'btn btn-info',
'type' => 'submit'])
}}
@if(isset($pirep) && !$pirep->read_only)
{{ Form::button(__('pireps.deletepirep'), [
'name' => 'submit',
'value' => 'Delete',
'class' => 'btn btn-warning',
'type' => 'submit'])
}}
@endif
@if(!isset($pirep) || (filled($pirep) && !$pirep->read_only))
{{ Form::button(__('pireps.submitpirep'), [
'name' => 'submit',
'value' => 'Submit',
'class' => 'btn btn-success',
'type' => 'submit'])
}}
@endif
</div>
</div>
{{ Form::button(__('pireps.savepirep'), [
'name' => 'submit',
'value' => 'Save',
'class' => 'btn btn-info',
'type' => 'submit'])
}}
@if(!isset($pirep) || (filled($pirep) && !$pirep->read_only))
{{ Form::button(__('pireps.submitpirep'), [
'name' => 'submit',
'value' => 'Submit',
'class' => 'btn btn-success',
'type' => 'submit'])
}}
@endif
</div>
</div>
</div>
</div>

212
tests/BidTest.php Normal file
View File

@@ -0,0 +1,212 @@
<?php
use App\Models\Bid;
use App\Models\Flight;
use App\Models\User;
use App\Repositories\SettingRepository;
use App\Services\BidService;
use App\Services\FlightService;
class BidTest extends TestCase
{
protected $bidSvc;
protected $flightSvc;
protected $settingsRepo;
public function setUp(): void
{
parent::setUp();
$this->addData('base');
$this->bidSvc = app(BidService::class);
$this->flightSvc = app(FlightService::class);
$this->settingsRepo = app(SettingRepository::class);
}
public function addFlight($user)
{
$flight = factory(App\Models\Flight::class)->create([
'airline_id' => $user->airline_id,
]);
$flight->subfleets()->syncWithoutDetaching([
factory(App\Models\Subfleet::class)->create([
'airline_id' => $user->airline_id,
])->id,
]);
return $flight;
}
/**
* Add/remove a bid, test the API, etc
*
* @throws \App\Services\Exception
*/
public function testBids()
{
$this->settingsRepo->store('bids.allow_multiple_bids', true);
$this->settingsRepo->store('bids.disable_flight_on_bid', false);
$user = factory(User::class)->create();
$user2 = factory(User::class)->create();
$headers = $this->headers($user);
$flight = $this->addFlight($user);
$bid = $this->bidSvc->addBid($flight, $user);
$this->assertEquals($user->id, $bid->user_id);
$this->assertEquals($flight->id, $bid->flight_id);
$this->assertTrue($flight->has_bid);
// Refresh
$flight = Flight::find($flight->id);
$this->assertTrue($flight->has_bid);
// Check the table and make sure the entry is there
$bid_retrieved = $this->bidSvc->addBid($flight, $user);
$this->assertEquals($bid->id, $bid_retrieved->id);
$user->refresh();
$bids = $user->bids;
$this->assertEquals(1, $bids->count());
// Query the API and see that the user has the bids
// And pull the flight details for the user/bids
$req = $this->get('/api/user', $headers);
$req->assertStatus(200);
$body = $req->json()['data'];
$this->assertCount(1, $body['bids']);
$this->assertEquals($flight->id, $body['bids'][0]['flight_id']);
$req = $this->get('/api/users/'.$user->id.'/bids', $headers);
$body = $req->json()['data'];
$req->assertStatus(200);
$this->assertEquals($flight->id, $body[0]['flight_id']);
// have a second user bid on it
$bid_user2 = $this->bidSvc->addBid($flight, $user2);
$this->assertNotNull($bid_user2);
$this->assertNotEquals($bid_retrieved->id, $bid_user2->id);
// Now remove the flight and check API
$this->bidSvc->removeBid($flight, $user);
$flight = Flight::find($flight->id);
// user2 still has a bid on it
$this->assertTrue($flight->has_bid);
// Remove it from 2nd user
$this->bidSvc->removeBid($flight, $user2);
$flight->refresh();
$this->assertFalse($flight->has_bid);
$user->refresh();
$bids = $user->bids()->get();
$this->assertTrue($bids->isEmpty());
$req = $this->get('/api/user', $headers);
$req->assertStatus(200);
$body = $req->json()['data'];
$this->assertEquals($user->id, $body['id']);
$this->assertCount(0, $body['bids']);
$req = $this->get('/api/users/'.$user->id.'/bids', $headers);
$req->assertStatus(200);
$body = $req->json()['data'];
$this->assertCount(0, $body);
}
public function testMultipleBidsSingleFlight()
{
$this->settingsRepo->store('bids.disable_flight_on_bid', true);
$user1 = factory(User::class)->create();
$user2 = factory(User::class)->create([
'airline_id' => $user1->airline_id,
]);
$flight = $this->addFlight($user1);
// Put bid on the flight to block it off
$this->bidSvc->addBid($flight, $user1);
// Try adding again, should throw an exception
$this->expectException(\App\Exceptions\BidExistsForFlight::class);
$this->bidSvc->addBid($flight, $user2);
}
/**
* Add a flight bid VIA the API
*/
public function testAddBidApi()
{
$this->user = factory(User::class)->create();
$user2 = factory(User::class)->create();
$flight = $this->addFlight($this->user);
$uri = '/api/user/bids';
$data = ['flight_id' => $flight->id];
$body = $this->put($uri, $data);
$body = $body->json('data');
$this->assertEquals($body['flight_id'], $flight->id);
// Now try to have the second user bid on it
// Should return a 409 error
$response = $this->put($uri, $data, [], $user2);
$response->assertStatus(409);
// Try now deleting the bid from the user
$response = $this->delete($uri, $data);
$body = $response->json('data');
$this->assertCount(0, $body);
}
/**
* Delete a flight and make sure all the bids are gone
*/
public function testDeleteFlightWithBids()
{
$user = factory(User::class)->create();
$headers = $this->headers($user);
$flight = $this->addFlight($user);
$bid = $this->bidSvc->addBid($flight, $user);
$this->assertEquals($user->id, $bid->user_id);
$this->assertEquals($flight->id, $bid->flight_id);
$this->assertTrue($flight->has_bid);
$this->flightSvc->deleteFlight($flight);
$empty_flight = Flight::find($flight->id);
$this->assertNull($empty_flight);
// Make sure no bids exist
$user_bids_count = Bid::where(['flight_id' => $flight->id])->count();
$this->assertEquals(0, $user_bids_count);
// Query the API and see that the user has the bids
// And pull the flight details for the user/bids
$req = $this->get('/api/user', $headers);
$req->assertStatus(200);
$body = $req->json()['data'];
$this->assertEquals($user->id, $body['id']);
$this->assertCount(0, $body['bids']);
$req = $this->get('/api/users/'.$user->id.'/bids', $headers);
$req->assertStatus(200);
$body = $req->json()['data'];
$this->assertCount(0, $body);
}
}

View File

@@ -1,6 +1,5 @@
<?php
use App\Models\Bid;
use App\Models\Enums\Days;
use App\Models\Flight;
use App\Models\User;
@@ -401,177 +400,18 @@ class FlightTest extends TestCase
$this->assertCount(1, $found);
}
/**
* Add/remove a bid, test the API, etc
*
* @throws \App\Services\Exception
*/
public function testBids()
{
$this->settingsRepo->store('bids.allow_multiple_bids', true);
$this->settingsRepo->store('bids.disable_flight_on_bid', false);
$user = factory(User::class)->create();
$user2 = factory(User::class)->create();
$headers = $this->headers($user);
$flight = $this->addFlight($user);
$bid = $this->flightSvc->addBid($flight, $user);
$this->assertEquals($user->id, $bid->user_id);
$this->assertEquals($flight->id, $bid->flight_id);
$this->assertTrue($flight->has_bid);
// Refresh
$flight = Flight::find($flight->id);
$this->assertTrue($flight->has_bid);
// Check the table and make sure the entry is there
$bid_retrieved = $this->flightSvc->addBid($flight, $user);
$this->assertEquals($bid->id, $bid_retrieved->id);
$user->refresh();
$bids = $user->bids;
$this->assertEquals(1, $bids->count());
// Query the API and see that the user has the bids
// And pull the flight details for the user/bids
$req = $this->get('/api/user', $headers);
$req->assertStatus(200);
$body = $req->json()['data'];
$this->assertCount(1, $body['bids']);
$this->assertEquals($flight->id, $body['bids'][0]['flight_id']);
$req = $this->get('/api/users/'.$user->id.'/bids', $headers);
$body = $req->json()['data'];
$req->assertStatus(200);
$this->assertEquals($flight->id, $body[0]['flight_id']);
// have a second user bid on it
$bid_user2 = $this->flightSvc->addBid($flight, $user2);
$this->assertNotNull($bid_user2);
$this->assertNotEquals($bid_retrieved->id, $bid_user2->id);
// Now remove the flight and check API
$this->flightSvc->removeBid($flight, $user);
$flight = Flight::find($flight->id);
// user2 still has a bid on it
$this->assertTrue($flight->has_bid);
// Remove it from 2nd user
$this->flightSvc->removeBid($flight, $user2);
$flight->refresh();
$this->assertFalse($flight->has_bid);
$user->refresh();
$bids = $user->bids()->get();
$this->assertTrue($bids->isEmpty());
$req = $this->get('/api/user', $headers);
$req->assertStatus(200);
$body = $req->json()['data'];
$this->assertEquals($user->id, $body['id']);
$this->assertCount(0, $body['bids']);
$req = $this->get('/api/users/'.$user->id.'/bids', $headers);
$req->assertStatus(200);
$body = $req->json()['data'];
$this->assertCount(0, $body);
}
public function testMultipleBidsSingleFlight()
{
$this->settingsRepo->store('bids.disable_flight_on_bid', true);
$user1 = factory(User::class)->create();
$user2 = factory(User::class)->create([
'airline_id' => $user1->airline_id,
]);
$flight = $this->addFlight($user1);
// Put bid on the flight to block it off
$this->flightSvc->addBid($flight, $user1);
// Try adding again, should throw an exception
$this->expectException(\App\Exceptions\BidExistsForFlight::class);
$this->flightSvc->addBid($flight, $user2);
}
/**
* Add a flight bid VIA the API
*/
public function testAddBidApi()
{
$this->user = factory(User::class)->create();
$user2 = factory(User::class)->create();
$flight = $this->addFlight($this->user);
$uri = '/api/user/bids';
$data = ['flight_id' => $flight->id];
$body = $this->put($uri, $data);
$body = $body->json('data');
$this->assertEquals($body['flight_id'], $flight->id);
// Now try to have the second user bid on it
// Should return a 409 error
$response = $this->put($uri, $data, [], $user2);
$response->assertStatus(409);
// Try now deleting the bid from the user
$response = $this->delete($uri, $data);
$body = $response->json('data');
$this->assertCount(0, $body);
}
/**
* Delete a flight and make sure all the bids are gone
*/
public function testDeleteFlight()
{
$user = factory(User::class)->create();
$headers = $this->headers($user);
$flight = $this->addFlight($user);
$bid = $this->flightSvc->addBid($flight, $user);
$this->assertEquals($user->id, $bid->user_id);
$this->assertEquals($flight->id, $bid->flight_id);
$this->assertTrue($flight->has_bid);
$this->flightSvc->deleteFlight($flight);
$empty_flight = Flight::find($flight->id);
$this->assertNull($empty_flight);
// Make sure no bids exist
$user_bids = Bid::where('flight_id', $flight->id)->get();
//$this->assertEquals(0, $user_bid->count());
// Query the API and see that the user has the bids
// And pull the flight details for the user/bids
$req = $this->get('/api/user', $headers);
$req->assertStatus(200);
$body = $req->json()['data'];
$this->assertEquals($user->id, $body['id']);
$this->assertCount(0, $body['bids']);
$req = $this->get('/api/users/'.$user->id.'/bids', $headers);
$req->assertStatus(200);
$body = $req->json()['data'];
$this->assertCount(0, $body);
}
public function testAirportDistance()

View File

@@ -7,6 +7,7 @@ use App\Models\Enums\PirepState;
use App\Models\Pirep;
use App\Models\User;
use App\Repositories\SettingRepository;
use App\Services\BidService;
use App\Services\FlightService;
use App\Services\PirepService;
use Carbon\Carbon;
@@ -358,6 +359,7 @@ class PIREPTest extends TestCase
*/
public function testPirepBidRemoved()
{
$bidSvc = app(BidService::class);
$flightSvc = app(FlightService::class);
$this->settingsRepo->store('pireps.remove_bid_on_accept', true);
@@ -370,11 +372,12 @@ class PIREPTest extends TestCase
'route_leg' => null,
]);
$flightSvc->addBid($flight, $user);
$bidSvc->addBid($flight, $user);
$pirep = factory(App\Models\Pirep::class)->create([
'user_id' => $user->id,
'airline_id' => $flight->airline_id,
'flight_id' => $flight->id,
'flight_number' => $flight->flight_number,
]);