diff --git a/app/Database/migrations/2020_03_06_141152_flights_add_pilot_pay.php b/app/Database/migrations/2020_03_06_141152_flights_add_pilot_pay.php new file mode 100644 index 00000000..ebce9e0b --- /dev/null +++ b/app/Database/migrations/2020_03_06_141152_flights_add_pilot_pay.php @@ -0,0 +1,32 @@ +decimal('pilot_pay') + ->nullable() + ->after('route'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('flights', function (Blueprint $table) { + $table->dropColumn('pilot_pay'); + }); + } +} diff --git a/app/Models/Flight.php b/app/Models/Flight.php index 0f4530f9..da0a2ea3 100644 --- a/app/Models/Flight.php +++ b/app/Models/Flight.php @@ -28,6 +28,7 @@ use Illuminate\Support\Collection; * @property int level * @property float load_factor * @property float load_factor_variance + * @property float pilot_pay * @property Airport dpt_airport * @property Airport arr_airport * @property Airport alt_airport @@ -69,6 +70,7 @@ class Flight extends Model 'flight_type', 'load_factor', 'load_factor_variance', + 'pilot_pay', 'route', 'notes', 'start_date', @@ -88,6 +90,7 @@ class Flight extends Model 'end_date' => 'date', 'load_factor' => 'double', 'load_factor_variance' => 'double', + 'pilot_pay' => 'float', 'has_bid' => 'boolean', 'route_leg' => 'integer', 'active' => 'boolean', diff --git a/app/Services/Finance/PirepFinanceService.php b/app/Services/Finance/PirepFinanceService.php index e79f0b28..d8e6f99c 100644 --- a/app/Services/Finance/PirepFinanceService.php +++ b/app/Services/Finance/PirepFinanceService.php @@ -374,11 +374,18 @@ class PirepFinanceService extends Service public function payPilotForPirep(Pirep $pirep): void { $pilot_pay = $this->getPilotPay($pirep); - $pilot_pay_rate = $this->getPilotPayRateForPirep($pirep); - $memo = 'Pilot Payment @ '.$pilot_pay_rate; - Log::info('Finance: PIREP: '.$pirep->id - .'; pilot pay: '.$pilot_pay_rate.', total: '.$pilot_pay); + if ($pirep->flight && !empty($pirep->flight->pilot_pay)) { + $memo = 'Pilot fixed payment for flight: '.$pirep->flight->pilot_pay; + Log::info('Finance: PIREP: '.$pirep->id + .'; pilot pay: fixed for flight='.$pirep->flight->pilot_pay.', total: '.$pilot_pay); + } else { + $pilot_pay_rate = $this->getPilotPayRateForPirep($pirep); + $memo = 'Pilot Payment @ '.$pilot_pay_rate; + + Log::info('Finance: PIREP: '.$pirep->id + .'; pilot pay: '.$pilot_pay_rate.', total: '.$pilot_pay); + } $this->financeSvc->debitFromJournal( $pirep->airline->journal, @@ -530,6 +537,13 @@ class PirepFinanceService extends Service */ public function getPilotPay(Pirep $pirep) { + // If there is a fixed price for this flight, return that amount + $flight = $pirep->flight; + if ($flight && !empty($flight->pilot_pay)) { + return new Money(Money::convertToSubunit($flight->pilot_pay)); + } + + // Divided by 60 to get the rate per minute $pilot_rate = $this->getPilotPayRateForPirep($pirep) / 60; $payment = round($pirep->flight_time * $pilot_rate, 2); diff --git a/app/Services/ImportExport/FlightImporter.php b/app/Services/ImportExport/FlightImporter.php index c76d2793..7c9653eb 100644 --- a/app/Services/ImportExport/FlightImporter.php +++ b/app/Services/ImportExport/FlightImporter.php @@ -41,6 +41,7 @@ class FlightImporter extends ImportExport 'flight_type' => 'required|alpha', 'load_factor' => 'nullable', 'load_factor_variance' => 'nullable', + 'pilot_pay' => 'nullable', 'route' => 'nullable', 'notes' => 'nullable', 'active' => 'nullable|boolean', diff --git a/resources/views/admin/flights/fields.blade.php b/resources/views/admin/flights/fields.blade.php index 870cbca3..985d9555 100644 --- a/resources/views/admin/flights/fields.blade.php +++ b/resources/views/admin/flights/fields.blade.php @@ -67,38 +67,14 @@
- {{ Form::label('dpt_airport_id', 'Departure Airport:') }} * - {{ Form::select('dpt_airport_id', $airports, null , [ - 'id' => 'dpt_airport_id', - 'class' => 'form-control select2' - ]) }} -

{{ $errors->first('dpt_airport_id') }}

+ {{ Form::label('pilot_pay', 'Pilot Pay:') }} + {{ Form::text('pilot_pay', null, ['class' => 'form-control']) }} +

{{ $errors->first('pilot_pay') }}

+ @component('admin.components.info') + Fill this in to pay a pilot a fixed amount for this flight. + @endcomponent
- -
- {{ Form::label('arr_airport_id', 'Arrival Airport:') }} * - {{ Form::select('arr_airport_id', $airports, null , [ - 'id' => 'arr_airport_id', - 'class' => 'form-control select2 select2' - ]) }} -

{{ $errors->first('arr_airport_id') }}

-
- - -
- {{ Form::label('alt_airport_id', 'Alt Airport:') }} - {{ Form::select('alt_airport_id', $alt_airports, null , ['class' => 'form-control select2']) }} -

{{ $errors->first('alt_airport_id') }}

-
-
- - - {{-- NEXT ROW --}} - -
{{ Form::label('load_factor', 'Load Factor:') }} {{ Form::text('load_factor', null, ['class' => 'form-control']) }} @@ -119,6 +95,66 @@ use the default value. @endcomponent
+
+ + + + + +
+
+
+
+  Route +
+
+
+
+ {{ Form::label('dpt_airport_id', 'Departure Airport:') }} * + {{ Form::select('dpt_airport_id', $airports, null , [ + 'id' => 'dpt_airport_id', + 'class' => 'form-control select2' + ]) }} +

{{ $errors->first('dpt_airport_id') }}

+
+ + +
+ {{ Form::label('arr_airport_id', 'Arrival Airport:') }} * + {{ Form::select('arr_airport_id', $airports, null , [ + 'id' => 'arr_airport_id', + 'class' => 'form-control select2 select2' + ]) }} +

{{ $errors->first('arr_airport_id') }}

+
+ +
+
+ +
+ {{ Form::label('route', 'Route:') }} + {{ Form::textarea('route', null, [ + 'class' => 'form-control input-text', + 'style' => 'padding: 10px', + ]) }} +

{{ $errors->first('route') }}

+
+
+
+ +
+ {{ Form::label('alt_airport_id', 'Alt Airport:') }} + {{ Form::select('alt_airport_id', $alt_airports, null , ['class' => 'form-control select2']) }} +

{{ $errors->first('alt_airport_id') }}

+
+ +
+ {{ Form::label('level', 'Flight Level:') }} + {{ Form::text('level', null, ['class' => 'form-control']) }} +

{{ $errors->first('level') }}

+
{{ Form::label('distance', 'Distance:') }} in nautical miles @@ -132,6 +168,7 @@
+
@@ -140,7 +177,6 @@
-
{{ Form::label('start_date', 'Start Date') }} optional @@ -207,47 +243,21 @@
-
-
-
-
-  Route -
-
- -
- {{ Form::textarea('route', null, [ - 'class' => 'form-control input-text', - 'style' => 'padding: 10px', - ]) }} -

{{ $errors->first('route') }}

-
-
- -
-
- {{ Form::label('level', 'Flight Level:') }} - {{ Form::text('level', null, ['class' => 'form-control']) }} -

{{ $errors->first('level') }}

-
-
-
-
-
-
 Remarks
-
-
- {{ Form::textarea('notes', null, [ - 'class' => 'form-control input-text', - 'style' => 'padding: 10px', - ]) }} -

{{ $errors->first('notes') }}

+
+
+
+ {{ Form::textarea('notes', null, [ + 'class' => 'form-control input-text', + 'style' => 'padding: 10px', + ]) }} +

{{ $errors->first('notes') }}

+
diff --git a/tests/FinanceTest.php b/tests/FinanceTest.php index 68e52518..3db0fff1 100644 --- a/tests/FinanceTest.php +++ b/tests/FinanceTest.php @@ -90,6 +90,7 @@ class FinanceTest extends TestCase 'user_id' => $user->id, 'airline_id' => $user->airline_id, 'aircraft_id' => $subfleet['aircraft']->random(), + 'flight_id' => $flight->id, 'source' => PirepSource::ACARS, 'flight_time' => 120, 'block_fuel' => 10, @@ -495,6 +496,47 @@ class FinanceTest extends TestCase $this->assertEquals($payment->getValue(), 150); } + public function testGetPirepPilotPayWithFixedPrice() + { + $acars_pay_rate = 100; + + $subfleet = $this->createSubfleetWithAircraft(2); + $rank = $this->createRank(10, [$subfleet['subfleet']->id]); + $this->fleetSvc->addSubfleetToRank($subfleet['subfleet'], $rank, [ + 'acars_pay' => $acars_pay_rate, + ]); + + $this->user = factory(App\Models\User::class)->create([ + 'rank_id' => $rank->id, + ]); + + $flight = factory(App\Models\Flight::class)->create([ + 'airline_id' => $this->user->airline_id, + 'pilot_pay' => 1000, + ]); + + $pirep_acars = factory(App\Models\Pirep::class)->create([ + 'user_id' => $this->user->id, + 'aircraft_id' => $subfleet['aircraft']->random(), + 'source' => PirepSource::ACARS, + 'flight_id' => $flight->id, + 'flight_time' => 60, + ]); + + $payment = $this->financeSvc->getPilotPay($pirep_acars); + $this->assertEquals(1000, $payment->getValue()); + + $pirep_acars = factory(App\Models\Pirep::class)->create([ + 'user_id' => $this->user->id, + 'aircraft_id' => $subfleet['aircraft']->random(), + 'source' => PirepSource::ACARS, + 'flight_time' => 90, + ]); + + $payment = $this->financeSvc->getPilotPay($pirep_acars); + $this->assertEquals($payment->getValue(), 150); + } + /** * @throws \Prettus\Validator\Exceptions\ValidatorException */ diff --git a/tests/data/flights.csv b/tests/data/flights.csv index 397c11c8..0474a0f9 100644 --- a/tests/data/flights.csv +++ b/tests/data/flights.csv @@ -1,4 +1,4 @@ -airline,flight_number,route_code,route_leg,dpt_airport,arr_airport,alt_airport,days,dpt_time,arr_time,level,distance,flight_time,flight_type,load_factor, load_factor_variance,route,notes,active,subfleets,fares,fields -VMS,1972,,,KAUS,KJFK,KLGA,15,0810 CST,1235 EST,350,1477,207,J,85,0, ILEXY2 ZENZI LFK ELD J29 MEM Q29 JHW J70 STENT J70 MAGIO J70 LVZ LENDY6,"Just a flight",1,A32X,Y?price=300&cost=100&capacity=130;F?price=600&cost=400;B?,Departure Gate=4;Arrival Gate=C41 -" ",1972,,,KAUS,KJFK,KLGA,15,0810 CST,1235 EST,350,1477,207,J,100,10, ILEXY2 ZENZI LFK ELD J29 MEM Q29 JHW J70 STENT J70 MAGIO J70 LVZ LENDY6,"Just a flight",1,A32X,Y?price=300&cost=100&capacity=130;F?price=600&cost=400;B?,Departure Gate=4;Arrival Gate=C41 -VMS,113,,,KJFK,KAUS,KDFW,15,0810 EST,1035 CST,350,,207,J,70,2,,"Empty distance",1,A32X,Y?price=300&cost=100&capacity=130;F?price=600&cost=400;B?,Departure Gate=C41;Arrival Gate=2 +airline,flight_number,route_code,route_leg,dpt_airport,arr_airport,alt_airport,days,dpt_time,arr_time,level,distance,flight_time,flight_type,load_factor, load_factor_variance,pilot_pay,route,notes,active,subfleets,fares,fields +VMS,1972,,,KAUS,KJFK,KLGA,15,0810 CST,1235 EST,350,1477,207,J,85,0,100, ILEXY2 ZENZI LFK ELD J29 MEM Q29 JHW J70 STENT J70 MAGIO J70 LVZ LENDY6,"Just a flight",1,A32X,Y?price=300&cost=100&capacity=130;F?price=600&cost=400;B?,Departure Gate=4;Arrival Gate=C41 +" ",1972,,,KAUS,KJFK,KLGA,15,0810 CST,1235 EST,350,1477,207,J,100,10, ,ILEXY2 ZENZI LFK ELD J29 MEM Q29 JHW J70 STENT J70 MAGIO J70 LVZ LENDY6,"Just a flight",1,A32X,Y?price=300&cost=100&capacity=130;F?price=600&cost=400;B?,Departure Gate=4;Arrival Gate=C41 +VMS,113,,,KJFK,KAUS,KDFW,15,0810 EST,1035 CST,350,,207,J,70,2,,,"Empty distance",1,A32X,Y?price=300&cost=100&capacity=130;F?price=600&cost=400;B?,Departure Gate=C41;Arrival Gate=2 diff --git a/tests/data/flights_empty_fields.csv b/tests/data/flights_empty_fields.csv index ac33faf5..3e2b4a18 100644 --- a/tests/data/flights_empty_fields.csv +++ b/tests/data/flights_empty_fields.csv @@ -1,2 +1,2 @@ -airline,flight_number,route_code,route_leg,dpt_airport,arr_airport,alt_airport,days,dpt_time,arr_time,level,distance,flight_time,flight_type,load_factor, load_factor_variance,route,notes,active,subfleets,fares,fields -VMS,1972,,,KAUS,KJFK,KLGA,15,0810 CST,1235 EST,350,1477,207,J,,,ILEXY2 ZENZI LFK ELD J29 MEM Q29 JHW J70 STENT J70 MAGIO J70 LVZ LENDY6,"Just a flight",1,A32X,Y?price=300&cost=100&capacity=130;F?price=600&cost=400;B?, +airline,flight_number,route_code,route_leg,dpt_airport,arr_airport,alt_airport,days,dpt_time,arr_time,level,distance,flight_time,flight_type,load_factor, load_factor_variance,pilot_pay,route,notes,active,subfleets,fares,fields +VMS,1972,,,KAUS,KJFK,KLGA,15,0810 CST,1235 EST,350,1477,207,J,,,,ILEXY2 ZENZI LFK ELD J29 MEM Q29 JHW J70 STENT J70 MAGIO J70 LVZ LENDY6,"Just a flight",1,A32X,Y?price=300&cost=100&capacity=130;F?price=600&cost=400;B?,