Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fixed pilot pay for a flight #487 #622

Merged
merged 1 commit into from
Mar 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class FlightsAddPilotPay extends Migration
{
/**
* Add a `pilot_pay` column for a fixed amount to pay to a pilot for a flight
*/
public function up()
{
Schema::table('flights', function (Blueprint $table) {
$table->decimal('pilot_pay')
->nullable()
->after('route');
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('flights', function (Blueprint $table) {
$table->dropColumn('pilot_pay');
});
}
}
3 changes: 3 additions & 0 deletions app/Models/Flight.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -69,6 +70,7 @@ class Flight extends Model
'flight_type',
'load_factor',
'load_factor_variance',
'pilot_pay',
'route',
'notes',
'start_date',
Expand All @@ -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',
Expand Down
22 changes: 18 additions & 4 deletions app/Services/Finance/PirepFinanceService.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions app/Services/ImportExport/FlightImporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
130 changes: 70 additions & 60 deletions resources/views/admin/flights/fields.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,49 @@ class="required">*</span>

<div class="row">
<div class="form-group col-sm-4">
{{ Form::label('pilot_pay', 'Pilot Pay:') }}
{{ Form::text('pilot_pay', null, ['class' => 'form-control']) }}
<p class="text-danger">{{ $errors->first('pilot_pay') }}</p>
@component('admin.components.info')
Fill this in to pay a pilot a fixed amount for this flight.
@endcomponent
</div>

<div class="form-group col-sm-4">
{{ Form::label('load_factor', 'Load Factor:') }}
{{ Form::text('load_factor', null, ['class' => 'form-control']) }}
<p class="text-danger">{{ $errors->first('load_factor') }}</p>
@component('admin.components.info')
Value between 1 and 100. See
<a href="{{ docs_link('load_factor') }}" target="_blank">docs</a>.
Leave blank to use the default value.
@endcomponent
</div>

<div class="form-group col-sm-4">
{{ Form::label('load_factor_variance', 'Load Factor Variance:') }}
{{ Form::text('load_factor_variance', null, ['class' => 'form-control']) }}
<p class="text-danger">{{ $errors->first('load_factor_variance') }}</p>
@component('admin.components.info')
How much the load factor can vary per flight (+ or -). Leave blank to
use the default value.
@endcomponent
</div>
</div>
</div>
</div>
</div>
</div>

<div class="row">
<div class="col-lg-12">
<div class="form-container">
<h6><i class="fas fa-map"></i>
&nbsp;Route
</h6>
<div class="form-container-body">
<div class="row">
<div class="form-group col-sm-6">
{{ Form::label('dpt_airport_id', 'Departure Airport:') }}&nbsp;<span
class="required">*</span>
{{ Form::select('dpt_airport_id', $airports, null , [
Expand All @@ -77,7 +120,7 @@ class="required">*</span>
</div>

<!-- Arr Airport Id Field -->
<div class="form-group col-sm-4">
<div class="form-group col-sm-6">
{{ Form::label('arr_airport_id', 'Arrival Airport:') }}&nbsp;<span
class="required">*</span>
{{ Form::select('arr_airport_id', $airports, null , [
Expand All @@ -87,37 +130,30 @@ class="required">*</span>
<p class="text-danger">{{ $errors->first('arr_airport_id') }}</p>
</div>

</div>
<div class="row">
<!-- Route Field -->
<div class="form-group col-sm-12">
{{ Form::label('route', 'Route:') }}
{{ Form::textarea('route', null, [
'class' => 'form-control input-text',
'style' => 'padding: 10px',
]) }}
<p class="text-danger">{{ $errors->first('route') }}</p>
</div>
</div>
<div class="row">
<!-- Alt Airport Id Field -->
<div class="form-group col-sm-4">
{{ Form::label('alt_airport_id', 'Alt Airport:') }}
{{ Form::select('alt_airport_id', $alt_airports, null , ['class' => 'form-control select2']) }}
<p class="text-danger">{{ $errors->first('alt_airport_id') }}</p>
</div>
</div>


{{-- NEXT ROW --}}

<div class="row">
<div class="form-group col-sm-4">
{{ Form::label('load_factor', 'Load Factor:') }}
{{ Form::text('load_factor', null, ['class' => 'form-control']) }}
<p class="text-danger">{{ $errors->first('load_factor') }}</p>
@component('admin.components.info')
Value between 1 and 100. See
<a href="{{ docs_link('load_factor') }}" target="_blank">docs</a>.
Leave blank to use the default value.
@endcomponent
</div>

<div class="form-group col-sm-4">
{{ Form::label('load_factor_variance', 'Load Factor Variance:') }}
{{ Form::text('load_factor_variance', null, ['class' => 'form-control']) }}
<p class="text-danger">{{ $errors->first('load_factor_variance') }}</p>
@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']) }}
<p class="text-danger">{{ $errors->first('level') }}</p>
</div>

<div class="form-group col-sm-4">
Expand All @@ -132,6 +168,7 @@ class="required">*</span>
</div>
</div>


<div class="row">
<div class="col-12">
<div class="form-container">
Expand All @@ -140,7 +177,6 @@ class="required">*</span>
</h6>
<div class="form-container-body">
<div class="row">

<div class="col-sm-4">
{{ Form::label('start_date', 'Start Date') }}
<span class="description small">optional</span>
Expand Down Expand Up @@ -207,47 +243,21 @@ class="required">*</span>
</div>
</div>

<div class="row">
<div class="col-lg-12">
<div class="form-container">
<h6><i class="fas fa-map"></i>
&nbsp;Route
</h6>
<div class="form-container-body row">
<!-- Route Field -->
<div class="form-group col-sm-12">
{{ Form::textarea('route', null, [
'class' => 'form-control input-text',
'style' => 'padding: 10px',
]) }}
<p class="text-danger">{{ $errors->first('route') }}</p>
</div>
</div>

<div class="form-container-body row">
<div class="form-group col-sm-4">
{{ Form::label('level', 'Flight Level:') }}
{{ Form::text('level', null, ['class' => 'form-control']) }}
<p class="text-danger">{{ $errors->first('level') }}</p>
</div>
</div>
</div>
</div>
</div>

<div class="row">
<div class="col-lg-12">
<div class="form-container">
<h6><i class="fas fa-sticky-note"></i>
&nbsp;Remarks
</h6>
<div class="form-container-body row">
<div class="form-group col-sm-12">
{{ Form::textarea('notes', null, [
'class' => 'form-control input-text',
'style' => 'padding: 10px',
]) }}
<p class="text-danger">{{ $errors->first('notes') }}</p>
<div class="form-container-body">
<div class="row">
<div class="form-group col-sm-12">
{{ Form::textarea('notes', null, [
'class' => 'form-control input-text',
'style' => 'padding: 10px',
]) }}
<p class="text-danger">{{ $errors->first('notes') }}</p>
</div>
</div>
</div>
</div>
Expand Down
42 changes: 42 additions & 0 deletions tests/FinanceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
*/
Expand Down
8 changes: 4 additions & 4 deletions tests/data/flights.csv
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions tests/data/flights_empty_fields.csv
Original file line number Diff line number Diff line change
@@ -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?,