2018-02-25 05:38:25 +08:00
|
|
|
<?php
|
|
|
|
|
2018-03-06 12:49:42 +08:00
|
|
|
namespace App\Services\Finance;
|
2018-02-25 05:38:25 +08:00
|
|
|
|
2019-07-16 03:44:31 +08:00
|
|
|
use App\Contracts\Service;
|
2019-07-16 03:51:35 +08:00
|
|
|
use App\Events\Expenses as ExpensesEvent;
|
2020-02-12 23:40:52 +08:00
|
|
|
use App\Models\Aircraft;
|
|
|
|
use App\Models\Airport;
|
2018-03-02 06:20:13 +08:00
|
|
|
use App\Models\Enums\ExpenseType;
|
2020-03-07 04:10:03 +08:00
|
|
|
use App\Models\Enums\FareType;
|
2018-02-28 04:29:45 +08:00
|
|
|
use App\Models\Enums\PirepSource;
|
2018-03-02 06:20:13 +08:00
|
|
|
use App\Models\Expense;
|
2018-02-28 04:29:45 +08:00
|
|
|
use App\Models\Pirep;
|
2020-02-12 23:40:52 +08:00
|
|
|
use App\Models\Subfleet;
|
2018-03-02 06:20:13 +08:00
|
|
|
use App\Repositories\ExpenseRepository;
|
|
|
|
use App\Repositories\JournalRepository;
|
2018-03-06 12:49:42 +08:00
|
|
|
use App\Services\FareService;
|
2019-11-27 22:19:20 +08:00
|
|
|
use App\Services\FinanceService;
|
2018-02-28 06:16:40 +08:00
|
|
|
use App\Support\Math;
|
2018-03-01 03:34:49 +08:00
|
|
|
use App\Support\Money;
|
2019-07-23 20:41:20 +08:00
|
|
|
use Illuminate\Support\Facades\Log;
|
2018-02-28 04:29:45 +08:00
|
|
|
|
2018-03-20 09:50:40 +08:00
|
|
|
class PirepFinanceService extends Service
|
2018-02-25 05:38:25 +08:00
|
|
|
{
|
2018-08-27 00:40:04 +08:00
|
|
|
private $expenseRepo;
|
|
|
|
private $fareSvc;
|
2019-11-27 22:19:20 +08:00
|
|
|
private $financeSvc;
|
2018-08-27 00:40:04 +08:00
|
|
|
private $journalRepo;
|
2018-02-25 05:38:25 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* FinanceService constructor.
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-03-02 06:20:13 +08:00
|
|
|
* @param ExpenseRepository $expenseRepo
|
2018-03-20 09:50:40 +08:00
|
|
|
* @param FareService $fareSvc
|
2018-03-02 06:20:13 +08:00
|
|
|
* @param JournalRepository $journalRepo
|
2019-11-27 22:19:20 +08:00
|
|
|
* @param FinanceService $financeSvc
|
2018-02-25 05:38:25 +08:00
|
|
|
*/
|
|
|
|
public function __construct(
|
2018-03-02 06:20:13 +08:00
|
|
|
ExpenseRepository $expenseRepo,
|
2018-02-25 05:38:25 +08:00
|
|
|
FareService $fareSvc,
|
2019-11-27 22:19:20 +08:00
|
|
|
FinanceService $financeSvc,
|
2018-08-27 02:50:08 +08:00
|
|
|
JournalRepository $journalRepo
|
2018-08-27 00:40:04 +08:00
|
|
|
) {
|
2018-03-02 06:20:13 +08:00
|
|
|
$this->expenseRepo = $expenseRepo;
|
2018-02-25 05:38:25 +08:00
|
|
|
$this->fareSvc = $fareSvc;
|
2018-03-02 06:20:13 +08:00
|
|
|
$this->journalRepo = $journalRepo;
|
2019-11-27 22:19:20 +08:00
|
|
|
$this->financeSvc = $financeSvc;
|
2018-03-02 06:20:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process all of the finances for a pilot report. This is called
|
|
|
|
* from a listener (FinanceEvents)
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-03-02 06:20:13 +08:00
|
|
|
* @param Pirep $pirep
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-03-02 06:20:13 +08:00
|
|
|
* @throws \UnexpectedValueException
|
|
|
|
* @throws \InvalidArgumentException
|
|
|
|
* @throws \Prettus\Validator\Exceptions\ValidatorException
|
|
|
|
* @throws \Exception
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
|
|
|
* @return mixed
|
2018-03-02 06:20:13 +08:00
|
|
|
*/
|
|
|
|
public function processFinancesForPirep(Pirep $pirep)
|
|
|
|
{
|
2018-03-20 09:50:40 +08:00
|
|
|
if (!$pirep->airline->journal) {
|
2020-04-26 23:55:20 +08:00
|
|
|
$pirep->airline->journal = $pirep->airline->initJournal(setting('units.currency', 'USD'));
|
2018-03-02 06:20:13 +08:00
|
|
|
}
|
|
|
|
|
2018-03-03 03:12:39 +08:00
|
|
|
if (!$pirep->user->journal) {
|
2020-04-26 23:55:20 +08:00
|
|
|
$pirep->user->journal = $pirep->user->initJournal(setting('units.currency', 'USD'));
|
2018-03-03 03:12:39 +08:00
|
|
|
}
|
|
|
|
|
2018-08-27 00:40:04 +08:00
|
|
|
// Clean out the expenses first
|
2018-03-06 02:21:38 +08:00
|
|
|
$this->deleteFinancesForPirep($pirep);
|
|
|
|
|
2018-03-30 03:55:25 +08:00
|
|
|
Log::info('Finance: Starting PIREP pay for '.$pirep->id);
|
|
|
|
|
2018-08-27 00:40:04 +08:00
|
|
|
// Now start and pay from scratch
|
2019-07-23 20:41:20 +08:00
|
|
|
$this->payFuelCosts($pirep);
|
2018-03-03 03:12:39 +08:00
|
|
|
$this->payFaresForPirep($pirep);
|
2018-03-30 02:42:16 +08:00
|
|
|
$this->payExpensesForSubfleet($pirep);
|
2018-03-03 03:12:39 +08:00
|
|
|
$this->payExpensesForPirep($pirep);
|
2020-05-27 06:41:25 +08:00
|
|
|
$this->payAirportExpensesForPirep($pirep);
|
2018-03-06 12:49:42 +08:00
|
|
|
$this->payExpensesEventsForPirep($pirep);
|
2018-03-03 03:12:39 +08:00
|
|
|
$this->payGroundHandlingForPirep($pirep);
|
|
|
|
$this->payPilotForPirep($pirep);
|
|
|
|
|
|
|
|
$pirep->airline->journal->refresh();
|
|
|
|
$pirep->user->journal->refresh();
|
|
|
|
|
2018-03-18 11:20:08 +08:00
|
|
|
// Recalculate balances...
|
|
|
|
$this->journalRepo->recalculateBalance($pirep->airline->journal);
|
|
|
|
$this->journalRepo->recalculateBalance($pirep->user->journal);
|
|
|
|
|
2018-03-03 03:12:39 +08:00
|
|
|
return $pirep;
|
|
|
|
}
|
2018-03-02 06:20:13 +08:00
|
|
|
|
2018-03-03 07:29:11 +08:00
|
|
|
/**
|
|
|
|
* @param Pirep $pirep
|
|
|
|
*/
|
2018-03-30 03:55:25 +08:00
|
|
|
public function deleteFinancesForPirep(Pirep $pirep): void
|
2018-03-03 07:29:11 +08:00
|
|
|
{
|
|
|
|
$this->journalRepo->deleteAllForObject($pirep);
|
|
|
|
}
|
|
|
|
|
2018-03-03 03:12:39 +08:00
|
|
|
/**
|
|
|
|
* Collect all of the fares and then post each fare class's profit and
|
|
|
|
* the costs for each seat and post it to the journal
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-03-03 03:12:39 +08:00
|
|
|
* @param $pirep
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-03-03 07:29:11 +08:00
|
|
|
* @throws \UnexpectedValueException
|
|
|
|
* @throws \InvalidArgumentException
|
2018-03-03 03:12:39 +08:00
|
|
|
* @throws \Prettus\Validator\Exceptions\ValidatorException
|
|
|
|
*/
|
|
|
|
public function payFaresForPirep($pirep): void
|
|
|
|
{
|
2018-03-02 06:20:13 +08:00
|
|
|
$fares = $this->getReconciledFaresForPirep($pirep);
|
2018-03-30 03:55:25 +08:00
|
|
|
|
2018-03-03 07:29:11 +08:00
|
|
|
/** @var \App\Models\Fare $fare */
|
2018-03-03 03:12:39 +08:00
|
|
|
foreach ($fares as $fare) {
|
2018-03-30 03:55:25 +08:00
|
|
|
Log::info('Finance: PIREP: '.$pirep->id.', Fare:', $fare->toArray());
|
2018-03-02 12:00:11 +08:00
|
|
|
|
2018-03-02 06:20:13 +08:00
|
|
|
$credit = Money::createFromAmount($fare->count * $fare->price);
|
|
|
|
$debit = Money::createFromAmount($fare->count * $fare->cost);
|
|
|
|
|
2018-03-30 03:55:25 +08:00
|
|
|
Log::info('Finance: Calculate: C='.$credit->toAmount().', D='.$debit->toAmount());
|
|
|
|
|
2020-07-10 21:51:33 +08:00
|
|
|
$memo = FareType::label($fare->type).' fare: '.$fare->code.': '.$fare->count
|
2020-03-07 04:10:03 +08:00
|
|
|
.'; price: '.$fare->price.', cost: '.$fare->cost;
|
|
|
|
|
2018-03-02 06:20:13 +08:00
|
|
|
$this->journalRepo->post(
|
2018-03-03 03:12:39 +08:00
|
|
|
$pirep->airline->journal,
|
2018-03-02 06:20:13 +08:00
|
|
|
$credit,
|
|
|
|
$debit,
|
|
|
|
$pirep,
|
2020-03-07 04:10:03 +08:00
|
|
|
$memo,
|
2018-03-02 06:20:13 +08:00
|
|
|
null,
|
2018-03-06 20:40:49 +08:00
|
|
|
'Fares',
|
|
|
|
'fare'
|
2018-03-02 06:20:13 +08:00
|
|
|
);
|
|
|
|
}
|
2018-03-03 03:12:39 +08:00
|
|
|
}
|
2018-03-02 06:20:13 +08:00
|
|
|
|
2019-07-23 20:41:20 +08:00
|
|
|
/**
|
|
|
|
* Calculate the fuel used by the PIREP and add those costs in
|
|
|
|
*
|
|
|
|
* @param Pirep $pirep
|
|
|
|
*
|
|
|
|
* @throws \Prettus\Validator\Exceptions\ValidatorException
|
|
|
|
*/
|
|
|
|
public function payFuelCosts(Pirep $pirep): void
|
|
|
|
{
|
|
|
|
$ap = $pirep->dpt_airport;
|
2021-03-18 23:32:40 +08:00
|
|
|
// Get Airport Fuel Cost or revert back to settings
|
2021-03-20 04:42:36 +08:00
|
|
|
if (empty($ap->fuel_jeta_cost)) {
|
|
|
|
$fuel_cost = setting('airports.default_jet_a_fuel_cost');
|
|
|
|
} else {
|
|
|
|
$fuel_cost = $ap->fuel_jeta_cost;
|
|
|
|
}
|
|
|
|
|
2021-03-02 04:03:27 +08:00
|
|
|
if (setting('pireps.advanced_fuel', false)) {
|
2021-02-25 01:22:52 +08:00
|
|
|
$ac = $pirep->aircraft;
|
|
|
|
// Reading second row by skip(1) to reach the previous accepted pirep. Current pirep is at the first row
|
|
|
|
$prev_flight = Pirep::where('aircraft_id', $ac->id)->where('state', 2)->where('status', 'ONB')->orderby('submitted_at', 'desc')->skip(1)->first();
|
|
|
|
if ($prev_flight) {
|
|
|
|
// If there is a pirep use its values to calculate the remaining fuel
|
|
|
|
// and calculate the uplifted fuel amount for this pirep
|
|
|
|
$fuel_amount = $pirep->block_fuel - ($prev_flight->block_fuel - $prev_flight->fuel_used);
|
|
|
|
// Aircraft has more than enough fuel in its tanks, no uplift necessary
|
|
|
|
if ($fuel_amount < 0) {
|
|
|
|
$fuel_amount = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// No pirep found for aircraft, debit full block fuel
|
|
|
|
$fuel_amount = $pirep->block_fuel;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Setting is false, switch back to basic calculation
|
|
|
|
$fuel_amount = $pirep->fuel_used;
|
|
|
|
}
|
2019-07-23 20:41:20 +08:00
|
|
|
|
2021-03-18 23:32:40 +08:00
|
|
|
$debit = Money::createFromAmount($fuel_amount * $fuel_cost);
|
|
|
|
Log::info('Finance: Fuel cost, (fuel='.$fuel_amount.', cost='.$fuel_cost.') D='
|
2019-07-23 20:41:20 +08:00
|
|
|
.$debit->getAmount());
|
|
|
|
|
2019-11-27 22:19:20 +08:00
|
|
|
$this->financeSvc->debitFromJournal(
|
2019-07-23 20:41:20 +08:00
|
|
|
$pirep->airline->journal,
|
|
|
|
$debit,
|
|
|
|
$pirep,
|
2021-03-18 23:32:40 +08:00
|
|
|
'Fuel Cost ('.$fuel_cost.'/'.config('phpvms.internal_units.fuel').')',
|
2019-07-23 20:41:20 +08:00
|
|
|
'Fuel',
|
|
|
|
'fuel'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-03-30 02:42:16 +08:00
|
|
|
/**
|
|
|
|
* Calculate what the cost is for the operating an aircraft
|
|
|
|
* in this subfleet, as-per the block time
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-03-30 02:42:16 +08:00
|
|
|
* @param Pirep $pirep
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-03-30 02:42:16 +08:00
|
|
|
* @throws \UnexpectedValueException
|
|
|
|
* @throws \InvalidArgumentException
|
|
|
|
* @throws \Prettus\Validator\Exceptions\ValidatorException
|
|
|
|
*/
|
|
|
|
public function payExpensesForSubfleet(Pirep $pirep): void
|
|
|
|
{
|
|
|
|
$sf = $pirep->aircraft->subfleet;
|
|
|
|
|
2018-08-27 00:40:04 +08:00
|
|
|
// Haven't entered a cost
|
2018-03-30 02:42:16 +08:00
|
|
|
if (!filled($sf->cost_block_hour)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-27 00:40:04 +08:00
|
|
|
// Convert to cost per-minute
|
2018-03-30 02:42:16 +08:00
|
|
|
$cost_per_min = round($sf->cost_block_hour / 60, 2);
|
|
|
|
|
2018-08-27 00:40:04 +08:00
|
|
|
// Time to use - use the block time if it's there, actual
|
|
|
|
// flight time if that hasn't been used
|
2018-03-30 02:42:16 +08:00
|
|
|
$block_time = $pirep->block_time;
|
2018-08-27 00:40:04 +08:00
|
|
|
if (!filled($block_time)) {
|
2018-03-30 03:55:25 +08:00
|
|
|
Log::info('Finance: No block time, using PIREP flight time');
|
2018-03-30 02:42:16 +08:00
|
|
|
$block_time = $pirep->flight_time;
|
|
|
|
}
|
|
|
|
|
|
|
|
$debit = Money::createFromAmount($cost_per_min * $block_time);
|
2018-03-30 03:55:25 +08:00
|
|
|
Log::info('Finance: Subfleet Block Hourly, D='.$debit->getAmount());
|
2018-03-30 02:42:16 +08:00
|
|
|
|
2019-11-27 22:19:20 +08:00
|
|
|
$this->financeSvc->debitFromJournal(
|
2018-03-30 02:42:16 +08:00
|
|
|
$pirep->airline->journal,
|
|
|
|
$debit,
|
|
|
|
$pirep,
|
|
|
|
'Subfleet '.$sf->type.': Block Time Cost',
|
|
|
|
'Subfleet '.$sf->type,
|
|
|
|
'subfleet'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-03-03 03:12:39 +08:00
|
|
|
/**
|
|
|
|
* Collect all of the expenses and apply those to the journal
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-03-03 03:12:39 +08:00
|
|
|
* @param Pirep $pirep
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-03-03 07:29:11 +08:00
|
|
|
* @throws \UnexpectedValueException
|
2018-03-03 03:12:39 +08:00
|
|
|
* @throws \InvalidArgumentException
|
|
|
|
*/
|
|
|
|
public function payExpensesForPirep(Pirep $pirep): void
|
|
|
|
{
|
2018-03-06 12:49:42 +08:00
|
|
|
$expenses = $this->expenseRepo->getAllForType(
|
|
|
|
ExpenseType::FLIGHT,
|
|
|
|
$pirep->airline_id
|
|
|
|
);
|
|
|
|
|
2018-08-27 00:40:04 +08:00
|
|
|
/*
|
2018-03-06 12:49:42 +08:00
|
|
|
* Go through the expenses and apply a mulitplier if present
|
|
|
|
*/
|
2020-05-27 06:41:25 +08:00
|
|
|
$expenses->map(function (Expense $expense, $i) use ($pirep) {
|
|
|
|
// Airport expenses are paid out separately
|
|
|
|
if ($expense->ref_model === Airport::class) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-03-06 20:17:45 +08:00
|
|
|
Log::info('Finance: PIREP: '.$pirep->id.', expense:', $expense->toArray());
|
2018-03-02 12:00:11 +08:00
|
|
|
|
2020-02-12 23:40:52 +08:00
|
|
|
// Check to see if there is a certain fleet or flight type set on this expense
|
|
|
|
// if there is and it doesn't match up the flight type for the PIREP, skip it
|
|
|
|
if ($expense->ref_model === Expense::class) {
|
|
|
|
if (is_array($expense->flight_type) && count($expense->flight_type) > 0) {
|
|
|
|
if (!in_array($pirep->flight_type, $expense->flight_type, true)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-27 00:40:04 +08:00
|
|
|
// Get the transaction group name from the ref_model name
|
|
|
|
// This way it can be more dynamic and don't have to add special
|
|
|
|
// tables or specific expense calls to accomodate all of these
|
2018-03-06 20:40:49 +08:00
|
|
|
$klass = 'Expense';
|
2018-04-02 03:32:01 +08:00
|
|
|
if ($expense->ref_model) {
|
|
|
|
$ref = explode('\\', $expense->ref_model);
|
2018-03-06 20:40:49 +08:00
|
|
|
$klass = end($ref);
|
2018-03-06 12:49:42 +08:00
|
|
|
}
|
|
|
|
|
2018-08-27 00:40:04 +08:00
|
|
|
// Form the memo, with some specific ones depending on the group
|
2020-05-27 06:41:25 +08:00
|
|
|
if ($expense->ref_model === Subfleet::class
|
|
|
|
&& $expense->ref_model_id === $pirep->aircraft->subfleet->id
|
|
|
|
) {
|
2018-03-06 20:40:49 +08:00
|
|
|
$memo = "Subfleet Expense: {$expense->name} ({$pirep->aircraft->subfleet->name})";
|
|
|
|
$transaction_group = "Subfleet: {$expense->name} ({$pirep->aircraft->subfleet->name})";
|
2020-05-27 06:41:25 +08:00
|
|
|
} elseif ($expense->ref_model === Aircraft::class
|
|
|
|
&& $expense->ref_model_id === $pirep->aircraft->id
|
|
|
|
) {
|
2018-03-06 20:40:49 +08:00
|
|
|
$memo = "Aircraft Expense: {$expense->name} ({$pirep->aircraft->name})";
|
2018-03-07 07:32:56 +08:00
|
|
|
$transaction_group = "Aircraft: {$expense->name} "
|
|
|
|
."({$pirep->aircraft->name}-{$pirep->aircraft->registration})";
|
2018-03-06 20:17:45 +08:00
|
|
|
} else {
|
2018-03-06 20:40:49 +08:00
|
|
|
$memo = "Expense: {$expense->name}";
|
2018-03-06 20:17:45 +08:00
|
|
|
$transaction_group = "Expense: {$expense->name}";
|
|
|
|
}
|
|
|
|
|
2018-03-02 06:20:13 +08:00
|
|
|
$debit = Money::createFromAmount($expense->amount);
|
2018-03-07 07:15:42 +08:00
|
|
|
|
2018-08-27 00:40:04 +08:00
|
|
|
// If the expense is marked to charge it to a user (only applicable to Flight)
|
|
|
|
// then change the journal to the user's to debit there
|
2018-03-07 07:15:42 +08:00
|
|
|
$journal = $pirep->airline->journal;
|
|
|
|
if ($expense->charge_to_user) {
|
|
|
|
$journal = $pirep->user->journal;
|
|
|
|
}
|
|
|
|
|
2019-11-27 22:19:20 +08:00
|
|
|
$this->financeSvc->debitFromJournal(
|
2018-03-07 07:15:42 +08:00
|
|
|
$journal,
|
2018-03-02 06:20:13 +08:00
|
|
|
$debit,
|
|
|
|
$pirep,
|
2018-03-06 20:17:45 +08:00
|
|
|
$memo,
|
2018-03-06 20:40:49 +08:00
|
|
|
$transaction_group,
|
|
|
|
strtolower($klass)
|
2018-03-02 06:20:13 +08:00
|
|
|
);
|
2018-03-06 12:49:42 +08:00
|
|
|
});
|
2018-03-03 03:12:39 +08:00
|
|
|
}
|
2018-03-02 06:20:13 +08:00
|
|
|
|
2020-05-27 06:41:25 +08:00
|
|
|
/**
|
|
|
|
* Pay the airport-specific expenses for a PIREP
|
|
|
|
*
|
|
|
|
* @param \App\Models\Pirep $pirep
|
|
|
|
*/
|
|
|
|
public function payAirportExpensesForPirep(Pirep $pirep): void
|
|
|
|
{
|
|
|
|
$expenses = $this->expenseRepo->getAllForType(
|
|
|
|
ExpenseType::FLIGHT,
|
|
|
|
$pirep->airline_id,
|
|
|
|
Airport::class,
|
2020-06-05 02:05:51 +08:00
|
|
|
$pirep->arr_airport_id
|
2020-05-27 06:41:25 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Go through the expenses and apply a mulitplier if present
|
|
|
|
*/
|
|
|
|
$expenses->map(function (Expense $expense, $i) use ($pirep) {
|
|
|
|
Log::info('Finance: PIREP: '.$pirep->id.', airport expense:', $expense->toArray());
|
|
|
|
|
|
|
|
$memo = "Airport Expense: {$expense->name} ({$expense->ref_model_id})";
|
|
|
|
$transaction_group = "Airport: {$expense->ref_model_id}";
|
|
|
|
|
|
|
|
$debit = Money::createFromAmount($expense->amount);
|
|
|
|
|
|
|
|
// Charge to the airlines journal
|
|
|
|
$journal = $pirep->airline->journal;
|
|
|
|
$this->financeSvc->debitFromJournal(
|
|
|
|
$journal,
|
|
|
|
$debit,
|
|
|
|
$pirep,
|
|
|
|
$memo,
|
|
|
|
$transaction_group,
|
|
|
|
'airport'
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-03-06 02:21:38 +08:00
|
|
|
/**
|
2018-03-06 12:49:42 +08:00
|
|
|
* Collect all of the expenses from the listeners and apply those to the journal
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-03-06 02:21:38 +08:00
|
|
|
* @param Pirep $pirep
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-03-06 12:49:42 +08:00
|
|
|
* @throws \UnexpectedValueException
|
|
|
|
* @throws \InvalidArgumentException
|
2018-03-06 02:21:38 +08:00
|
|
|
* @throws \Prettus\Validator\Exceptions\ValidatorException
|
|
|
|
*/
|
2018-03-06 12:49:42 +08:00
|
|
|
public function payExpensesEventsForPirep(Pirep $pirep): void
|
2018-03-06 02:21:38 +08:00
|
|
|
{
|
2018-03-06 12:49:42 +08:00
|
|
|
/**
|
|
|
|
* Throw an event and collect any expenses returned from it
|
|
|
|
*/
|
|
|
|
$gathered_expenses = event(new ExpensesEvent($pirep));
|
|
|
|
if (!\is_array($gathered_expenses)) {
|
2018-03-06 02:21:38 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-03-06 12:49:42 +08:00
|
|
|
foreach ($gathered_expenses as $event_expense) {
|
|
|
|
if (!\is_array($event_expense)) {
|
|
|
|
continue;
|
|
|
|
}
|
2018-03-06 02:21:38 +08:00
|
|
|
|
2018-03-06 12:49:42 +08:00
|
|
|
foreach ($event_expense as $expense) {
|
2018-08-27 00:40:04 +08:00
|
|
|
// Make sure it's of type expense Model
|
2018-03-06 12:49:42 +08:00
|
|
|
if (!($expense instanceof Expense)) {
|
|
|
|
continue;
|
|
|
|
}
|
2018-03-06 02:21:38 +08:00
|
|
|
|
2018-03-30 03:55:25 +08:00
|
|
|
Log::info('Finance: Expense from listener, N="'
|
|
|
|
.$expense->name.'", A='.$expense->amount);
|
|
|
|
|
2018-08-27 00:40:04 +08:00
|
|
|
// If an airline_id is filled, then see if it matches
|
2018-08-27 02:51:47 +08:00
|
|
|
/* @noinspection NotOptimalIfConditionsInspection */
|
2018-08-27 00:40:04 +08:00
|
|
|
if (filled($expense->airline_id) && $expense->airline_id !== $pirep->airline_id) {
|
2018-03-30 03:55:25 +08:00
|
|
|
Log::info('Finance: Expense has an airline ID and it doesn\'t match, skipping');
|
2018-03-06 12:49:42 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$debit = Money::createFromAmount($expense->amount);
|
|
|
|
|
2019-11-27 22:19:20 +08:00
|
|
|
$this->financeSvc->debitFromJournal(
|
2018-03-06 12:49:42 +08:00
|
|
|
$pirep->airline->journal,
|
|
|
|
$debit,
|
|
|
|
$pirep,
|
2018-03-20 09:50:40 +08:00
|
|
|
'Expense: '.$expense->name,
|
2018-03-06 20:40:49 +08:00
|
|
|
$expense->transaction_group ?? 'Expenses',
|
|
|
|
'expense'
|
2018-03-06 12:49:42 +08:00
|
|
|
);
|
|
|
|
}
|
2018-03-06 02:21:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-03 03:12:39 +08:00
|
|
|
/**
|
|
|
|
* Collect and apply the ground handling cost
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-03-03 03:12:39 +08:00
|
|
|
* @param Pirep $pirep
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-03-03 07:29:11 +08:00
|
|
|
* @throws \UnexpectedValueException
|
|
|
|
* @throws \InvalidArgumentException
|
2018-03-03 03:12:39 +08:00
|
|
|
* @throws \Prettus\Validator\Exceptions\ValidatorException
|
|
|
|
*/
|
2018-03-30 03:55:25 +08:00
|
|
|
public function payGroundHandlingForPirep(Pirep $pirep): void
|
2018-03-03 03:12:39 +08:00
|
|
|
{
|
2021-03-18 23:32:40 +08:00
|
|
|
$ground_handling_cost = $this->getGroundHandlingCost($pirep, $pirep->dpt_airport);
|
|
|
|
Log::info('Finance: PIREP: '.$pirep->id.'; dpt ground handling: '.$ground_handling_cost);
|
2019-11-27 22:19:20 +08:00
|
|
|
|
|
|
|
$this->financeSvc->debitFromJournal(
|
2018-03-03 03:12:39 +08:00
|
|
|
$pirep->airline->journal,
|
2018-03-02 06:20:13 +08:00
|
|
|
Money::createFromAmount($ground_handling_cost),
|
|
|
|
$pirep,
|
2021-03-18 23:32:40 +08:00
|
|
|
'Ground Handling (Departure)',
|
2018-03-06 02:21:38 +08:00
|
|
|
'Ground Handling',
|
2021-03-18 23:32:40 +08:00
|
|
|
'ground_handling'
|
|
|
|
);
|
|
|
|
|
|
|
|
$ground_handling_cost = $this->getGroundHandlingCost($pirep, $pirep->arr_airport);
|
2021-03-19 08:04:13 +08:00
|
|
|
Log::info('Finance: PIREP: '.$pirep->id.'; arr ground handling: '.$ground_handling_cost);
|
2021-03-18 23:32:40 +08:00
|
|
|
|
|
|
|
$this->financeSvc->debitFromJournal(
|
|
|
|
$pirep->airline->journal,
|
|
|
|
Money::createFromAmount($ground_handling_cost),
|
|
|
|
$pirep,
|
2021-03-19 08:04:13 +08:00
|
|
|
'Ground Handling (Arrival)',
|
2018-03-06 20:40:49 +08:00
|
|
|
'Ground Handling',
|
|
|
|
'ground_handling'
|
2018-03-02 06:20:13 +08:00
|
|
|
);
|
2018-03-03 03:12:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Figure out what the pilot pay is. Debit it from the airline journal
|
|
|
|
* But also reference the PIREP
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-03-03 03:12:39 +08:00
|
|
|
* @param Pirep $pirep
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-03-03 03:12:39 +08:00
|
|
|
* @throws \UnexpectedValueException
|
|
|
|
* @throws \InvalidArgumentException
|
|
|
|
* @throws \Prettus\Validator\Exceptions\ValidatorException
|
|
|
|
*/
|
2018-03-30 03:55:25 +08:00
|
|
|
public function payPilotForPirep(Pirep $pirep): void
|
2018-03-03 03:12:39 +08:00
|
|
|
{
|
|
|
|
$pilot_pay = $this->getPilotPay($pirep);
|
2018-03-02 06:20:13 +08:00
|
|
|
|
2020-03-07 00:36:02 +08:00
|
|
|
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);
|
|
|
|
}
|
2018-03-06 02:21:38 +08:00
|
|
|
|
2019-11-27 22:19:20 +08:00
|
|
|
$this->financeSvc->debitFromJournal(
|
2018-03-03 03:12:39 +08:00
|
|
|
$pirep->airline->journal,
|
|
|
|
$pilot_pay,
|
|
|
|
$pirep,
|
|
|
|
$memo,
|
2018-03-06 20:40:49 +08:00
|
|
|
'Pilot Pay',
|
|
|
|
'pilot_pay'
|
2018-03-03 03:12:39 +08:00
|
|
|
);
|
|
|
|
|
2019-11-27 22:19:20 +08:00
|
|
|
$this->financeSvc->creditToJournal(
|
2018-03-03 03:12:39 +08:00
|
|
|
$pirep->user->journal,
|
|
|
|
$pilot_pay,
|
|
|
|
$pirep,
|
|
|
|
$memo,
|
2018-03-06 20:40:49 +08:00
|
|
|
'Pilot Pay',
|
|
|
|
'pilot_pay'
|
2018-03-03 03:12:39 +08:00
|
|
|
);
|
2018-03-02 06:20:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return all of the fares for the PIREP. Reconcile the list;
|
|
|
|
* Get the fares that have been filled out for the PIREP, and
|
|
|
|
* then get the fares for the flight and subfleet. Then merge
|
|
|
|
* them together, and return the final list of:
|
|
|
|
* count = number of pax
|
|
|
|
* price = how much each pax unit paid
|
|
|
|
* capacity = max number of pax units
|
|
|
|
*
|
|
|
|
* If count > capacity, count will be adjusted to capacity
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-03-02 06:20:13 +08:00
|
|
|
* @param $pirep
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-03-02 06:20:13 +08:00
|
|
|
* @return \Illuminate\Support\Collection
|
|
|
|
*/
|
|
|
|
public function getReconciledFaresForPirep($pirep)
|
|
|
|
{
|
2018-08-27 00:40:04 +08:00
|
|
|
// Collect all of the fares and prices
|
2018-03-02 06:20:13 +08:00
|
|
|
$flight_fares = $this->fareSvc->getForPirep($pirep);
|
2018-03-20 09:50:40 +08:00
|
|
|
Log::info('Finance: PIREP: '.$pirep->id.', flight fares: ', $flight_fares->toArray());
|
2018-03-06 02:21:38 +08:00
|
|
|
|
2018-03-16 07:20:07 +08:00
|
|
|
$all_fares = $this->fareSvc->getAllFares($pirep->flight, $pirep->aircraft->subfleet);
|
2018-03-02 06:20:13 +08:00
|
|
|
|
2018-03-20 09:50:40 +08:00
|
|
|
$fares = $all_fares->map(function ($fare, $i) use ($flight_fares, $pirep) {
|
2018-03-06 02:21:38 +08:00
|
|
|
$fare_count = $flight_fares
|
|
|
|
->where('fare_id', $fare->id)
|
|
|
|
->first();
|
2018-03-02 06:20:13 +08:00
|
|
|
|
2018-03-20 09:50:40 +08:00
|
|
|
if ($fare_count) {
|
|
|
|
Log::info('Finance: PIREP: '.$pirep->id.', fare count: '.$fare_count);
|
2018-03-06 02:21:38 +08:00
|
|
|
|
2018-08-27 00:40:04 +08:00
|
|
|
// If the count is greater than capacity, then just set it
|
|
|
|
// to the maximum amount
|
2018-03-20 09:50:40 +08:00
|
|
|
if ($fare_count->count > $fare->capacity) {
|
2018-03-02 06:20:13 +08:00
|
|
|
$fare->count = $fare->capacity;
|
|
|
|
} else {
|
|
|
|
$fare->count = $fare_count->count;
|
|
|
|
}
|
2018-03-06 02:21:38 +08:00
|
|
|
} else {
|
2018-03-20 09:50:40 +08:00
|
|
|
Log::info('Finance: PIREP: '.$pirep->id.', no fare count found', $fare->toArray());
|
2018-03-02 06:20:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return $fare;
|
|
|
|
});
|
|
|
|
|
|
|
|
return $fares;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the costs for the ground handling, with the multiplier
|
|
|
|
* being applied from the subfleet
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2021-03-18 23:32:40 +08:00
|
|
|
* @param Pirep $pirep
|
|
|
|
* @param Airport $airport
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-03-02 06:20:13 +08:00
|
|
|
* @return float|null
|
|
|
|
*/
|
2021-03-18 23:32:40 +08:00
|
|
|
public function getGroundHandlingCost(Pirep $pirep, Airport $airport): ?float
|
2018-03-02 06:20:13 +08:00
|
|
|
{
|
2021-03-20 04:42:36 +08:00
|
|
|
if (empty($airport->ground_handling_cost)) {
|
|
|
|
$gh_cost = setting('airports.default_ground_handling_cost');
|
|
|
|
} else {
|
|
|
|
$gh_cost = $airport->ground_handling_cost;
|
|
|
|
}
|
|
|
|
|
2021-03-18 23:32:40 +08:00
|
|
|
if (!filled($pirep->aircraft->subfleet->ground_handling_multiplier)) {
|
|
|
|
return $gh_cost;
|
2018-03-02 06:20:13 +08:00
|
|
|
}
|
|
|
|
|
2021-03-18 23:32:40 +08:00
|
|
|
// force into percent mode
|
|
|
|
$multiplier = $pirep->aircraft->subfleet->ground_handling_multiplier.'%';
|
|
|
|
return Math::applyAmountOrPercent($gh_cost, $multiplier);
|
2018-03-02 06:20:13 +08:00
|
|
|
}
|
|
|
|
|
2018-02-28 04:29:45 +08:00
|
|
|
/**
|
|
|
|
* Return the pilot's hourly pay for the given PIREP
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-02-28 04:29:45 +08:00
|
|
|
* @param Pirep $pirep
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-03-01 03:34:49 +08:00
|
|
|
* @throws \InvalidArgumentException
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
|
|
|
* @return float
|
2018-02-28 04:29:45 +08:00
|
|
|
*/
|
2018-03-02 06:20:13 +08:00
|
|
|
public function getPilotPayRateForPirep(Pirep $pirep)
|
2018-02-28 04:29:45 +08:00
|
|
|
{
|
2018-08-27 00:40:04 +08:00
|
|
|
// Get the base rate for the rank
|
2018-02-28 04:29:45 +08:00
|
|
|
$rank = $pirep->user->rank;
|
2018-02-28 06:16:40 +08:00
|
|
|
$subfleet_id = $pirep->aircraft->subfleet_id;
|
|
|
|
|
2018-08-27 00:40:04 +08:00
|
|
|
// find the right subfleet
|
2018-02-28 06:16:40 +08:00
|
|
|
$override_rate = $rank->subfleets()
|
|
|
|
->where('subfleet_id', $subfleet_id)
|
2018-03-03 07:29:11 +08:00
|
|
|
->first();
|
|
|
|
|
2018-03-20 09:50:40 +08:00
|
|
|
if ($override_rate) {
|
2018-03-03 07:29:11 +08:00
|
|
|
$override_rate = $override_rate->pivot;
|
|
|
|
}
|
2018-02-28 06:16:40 +08:00
|
|
|
|
2018-03-20 09:50:40 +08:00
|
|
|
if ($pirep->source === PirepSource::ACARS) {
|
2018-03-03 03:12:39 +08:00
|
|
|
Log::debug('Source is ACARS');
|
2018-02-28 04:29:45 +08:00
|
|
|
$base_rate = $rank->acars_base_pay_rate;
|
2018-03-03 07:29:11 +08:00
|
|
|
|
2018-03-20 09:50:40 +08:00
|
|
|
if ($override_rate) {
|
2018-03-03 07:29:11 +08:00
|
|
|
$override_rate = $override_rate->acars_pay;
|
|
|
|
}
|
2018-02-28 04:29:45 +08:00
|
|
|
} else {
|
2018-03-03 03:12:39 +08:00
|
|
|
Log::debug('Source is Manual');
|
2018-02-28 04:29:45 +08:00
|
|
|
$base_rate = $rank->manual_base_pay_rate;
|
2018-03-03 07:29:11 +08:00
|
|
|
|
2018-03-20 09:50:40 +08:00
|
|
|
if ($override_rate) {
|
2018-03-03 07:29:11 +08:00
|
|
|
$override_rate = $override_rate->manual_pay;
|
|
|
|
}
|
2018-02-28 06:16:40 +08:00
|
|
|
}
|
|
|
|
|
2018-03-20 09:50:40 +08:00
|
|
|
Log::debug('pilot pay: base rate='.$base_rate.', override='.$override_rate);
|
|
|
|
|
2018-03-06 12:49:42 +08:00
|
|
|
return Math::applyAmountOrPercent(
|
2018-03-02 06:20:13 +08:00
|
|
|
$base_rate,
|
|
|
|
$override_rate
|
|
|
|
);
|
2018-02-28 06:16:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the user's payment amount for a PIREP
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-02-28 06:16:40 +08:00
|
|
|
* @param Pirep $pirep
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
2018-03-01 03:54:14 +08:00
|
|
|
* @throws \UnexpectedValueException
|
2018-02-28 06:16:40 +08:00
|
|
|
* @throws \InvalidArgumentException
|
2018-08-27 00:40:04 +08:00
|
|
|
*
|
|
|
|
* @return Money
|
2018-02-28 06:16:40 +08:00
|
|
|
*/
|
2018-03-03 03:12:39 +08:00
|
|
|
public function getPilotPay(Pirep $pirep)
|
2018-02-28 06:16:40 +08:00
|
|
|
{
|
2020-03-07 00:36:02 +08:00
|
|
|
// 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
|
2018-03-02 06:20:13 +08:00
|
|
|
$pilot_rate = $this->getPilotPayRateForPirep($pirep) / 60;
|
2018-03-01 03:34:49 +08:00
|
|
|
$payment = round($pirep->flight_time * $pilot_rate, 2);
|
2018-02-28 06:16:40 +08:00
|
|
|
|
2018-03-03 03:12:39 +08:00
|
|
|
Log::info('Pilot Payment: rate='.$pilot_rate);
|
|
|
|
$payment = Money::convertToSubunit($payment);
|
|
|
|
|
|
|
|
return new Money($payment);
|
2018-02-28 04:29:45 +08:00
|
|
|
}
|
2018-02-25 05:38:25 +08:00
|
|
|
}
|