From 011ddc650249310fbad2495f5d6a8b965765fe2c Mon Sep 17 00:00:00 2001 From: Nabeel Shahzad Date: Fri, 6 Mar 2020 11:07:36 -0500 Subject: [PATCH] Add fixed pilot pay for a flight #487 --- ...020_03_06_141152_flights_add_pilot_pay.php | 32 +++++ app/Models/Flight.php | 3 + app/Services/Finance/PirepFinanceService.php | 22 ++- app/Services/ImportExport/FlightImporter.php | 1 + .../views/admin/flights/fields.blade.php | 130 ++++++++++-------- tests/FinanceTest.php | 42 ++++++ tests/data/flights.csv | 8 +- tests/data/flights_empty_fields.csv | 4 +- 8 files changed, 172 insertions(+), 70 deletions(-) create mode 100644 app/Database/migrations/2020_03_06_141152_flights_add_pilot_pay.php 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 000000000..ebce9e0b8 --- /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 0f4530f95..da0a2ea31 100644 --- a/app/Models/Flight.php +++ b/app/Models/Flight.php @@ -28,6 +28,7 @@ * @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 e79f0b28b..d8e6f99cd 100644 --- a/app/Services/Finance/PirepFinanceService.php +++ b/app/Services/Finance/PirepFinanceService.php @@ -374,11 +374,18 @@ public function payGroundHandlingForPirep(Pirep $pirep): void 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 @@ public function getPilotPayRateForPirep(Pirep $pirep) */ 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 c76d2793e..7c9653eb5 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 870cbca3f..985d9555e 100644 --- a/resources/views/admin/flights/fields.blade.php +++ b/resources/views/admin/flights/fields.blade.php @@ -67,6 +67,49 @@ class="required">*
+ {{ 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('load_factor', 'Load Factor:') }} + {{ Form::text('load_factor', null, ['class' => 'form-control']) }} +

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

+ @component('admin.components.info') + Value between 1 and 100. See + docs. + Leave blank to use the default value. + @endcomponent +
+ +
+ {{ Form::label('load_factor_variance', 'Load Factor Variance:') }} + {{ Form::text('load_factor_variance', null, ['class' => 'form-control']) }} +

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

+ @component('admin.components.info') + How much the load factor can vary per flight (+ or -). Leave blank to + use the default value. + @endcomponent +
+
+ + + + + +
+
+
+
+  Route +
+
+
+
{{ Form::label('dpt_airport_id', 'Departure Airport:') }} * {{ Form::select('dpt_airport_id', $airports, null , [ @@ -77,7 +120,7 @@ class="required">*
-
+
{{ Form::label('arr_airport_id', 'Arrival Airport:') }} * {{ Form::select('arr_airport_id', $airports, null , [ @@ -87,37 +130,30 @@ class="required">*

{{ $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') }}

-
- - - {{-- NEXT ROW --}} -
- {{ Form::label('load_factor', 'Load Factor:') }} - {{ Form::text('load_factor', null, ['class' => 'form-control']) }} -

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

- @component('admin.components.info') - Value between 1 and 100. See - docs. - Leave blank to use the default value. - @endcomponent -
- -
- {{ Form::label('load_factor_variance', 'Load Factor Variance:') }} - {{ Form::text('load_factor_variance', null, ['class' => 'form-control']) }} -

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

- @component('admin.components.info') - How much the load factor can vary per flight (+ or -). Leave blank to - use the default value. - @endcomponent + {{ Form::label('level', 'Flight Level:') }} + {{ Form::text('level', null, ['class' => 'form-control']) }} +

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

@@ -132,6 +168,7 @@ class="required">*
+
@@ -140,7 +177,6 @@ class="required">*
-
{{ Form::label('start_date', 'Start Date') }} optional @@ -207,47 +243,21 @@ class="required">*
-
-
-
-
-  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 68e52518e..3db0fff1a 100644 --- a/tests/FinanceTest.php +++ b/tests/FinanceTest.php @@ -90,6 +90,7 @@ public function createFullPirep() '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 @@ public function testGetPirepPilotPay() $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 397c11c8f..0474a0f9c 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 ac33faf55..3e2b4a18d 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?,