This commit is contained in:
parent
db10ebf807
commit
9d3953f3ac
@ -6,9 +6,7 @@ use Faker\Generator as Faker;
|
||||
$factory->define(App\Models\Expense::class, function (Faker $faker) {
|
||||
return [
|
||||
'id' => null,
|
||||
'airline_id' => function () {
|
||||
return factory(App\Models\Airline::class)->create()->id;
|
||||
},
|
||||
'airline_id' => null,
|
||||
'name' => $faker->text(20),
|
||||
'amount' => $faker->randomFloat(2, 100, 1000),
|
||||
'type' => ExpenseType::FLIGHT,
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Enums\NavaidType;
|
||||
use Faker\Generator as Faker;
|
||||
use \App\Models\Enums\NavaidType;
|
||||
|
||||
$factory->define(App\Models\Navdata::class, function (Faker $faker) {
|
||||
return [
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Faker\Generator as Faker;
|
||||
use App\Models\Enums\UserState;
|
||||
use Faker\Generator as Faker;
|
||||
|
||||
$factory->define(App\Models\User::class, function (Faker $faker)
|
||||
{
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateExpensesTable extends Migration
|
||||
{
|
||||
|
@ -251,15 +251,6 @@ subfleets:
|
||||
type: 772-36ER-GE90-115B
|
||||
ground_handling_multiplier: 150
|
||||
|
||||
#subfleet_expenses:
|
||||
# - id: 1
|
||||
# subfleet_id: 1
|
||||
# name: Catering
|
||||
# amount: 1000
|
||||
# type: 0
|
||||
# created_at: now
|
||||
# updated_at: now
|
||||
|
||||
# add a few mods to aircraft and fares
|
||||
subfleet_fare:
|
||||
|
||||
|
@ -7,7 +7,7 @@ use App\Models\Journal;
|
||||
use App\Models\JournalTransaction;
|
||||
use App\Repositories\AirlineRepository;
|
||||
use App\Repositories\JournalRepository;
|
||||
use App\Services\FinanceService;
|
||||
use App\Services\Finance\PirepFinanceService;
|
||||
use App\Support\Dates;
|
||||
use App\Support\Money;
|
||||
use Illuminate\Http\Request;
|
||||
@ -23,12 +23,12 @@ class FinanceController extends BaseController
|
||||
$journalRepo;
|
||||
|
||||
/**
|
||||
* @param FinanceService $financeSvc
|
||||
* @param PirepFinanceService $financeSvc
|
||||
* @param JournalRepository $journalRepo
|
||||
*/
|
||||
public function __construct(
|
||||
AirlineRepository $airlineRepo,
|
||||
FinanceService $financeSvc,
|
||||
PirepFinanceService $financeSvc,
|
||||
JournalRepository $journalRepo
|
||||
) {
|
||||
$this->airlineRepo = $airlineRepo;
|
||||
|
@ -26,7 +26,7 @@ use App\Models\PirepComment;
|
||||
use App\Repositories\AcarsRepository;
|
||||
use App\Repositories\JournalRepository;
|
||||
use App\Repositories\PirepRepository;
|
||||
use App\Services\FinanceService;
|
||||
use App\Services\Finance\PirepFinanceService;
|
||||
use App\Services\GeoService;
|
||||
use App\Services\PIREPService;
|
||||
use App\Services\UserService;
|
||||
@ -47,7 +47,7 @@ class PirepController extends RestController
|
||||
/**
|
||||
* PirepController constructor.
|
||||
* @param AcarsRepository $acarsRepo
|
||||
* @param FinanceService $financeSvc
|
||||
* @param PirepFinanceService $financeSvc
|
||||
* @param GeoService $geoSvc
|
||||
* @param JournalRepository $journalRepo
|
||||
* @param PirepRepository $pirepRepo
|
||||
@ -56,7 +56,7 @@ class PirepController extends RestController
|
||||
*/
|
||||
public function __construct(
|
||||
AcarsRepository $acarsRepo,
|
||||
FinanceService $financeSvc,
|
||||
PirepFinanceService $financeSvc,
|
||||
GeoService $geoSvc,
|
||||
JournalRepository $journalRepo,
|
||||
PirepRepository $pirepRepo,
|
||||
|
@ -4,7 +4,7 @@ namespace App\Listeners;
|
||||
|
||||
use App\Events\PirepAccepted;
|
||||
use App\Events\PirepRejected;
|
||||
use App\Services\FinanceService;
|
||||
use App\Services\Finance\PirepFinanceService;
|
||||
|
||||
/**
|
||||
* Subscribe for events that we do some financial processing for
|
||||
@ -16,7 +16,7 @@ class FinanceEvents
|
||||
private $financeSvc;
|
||||
|
||||
public function __construct(
|
||||
FinanceService $financeSvc
|
||||
PirepFinanceService $financeSvc
|
||||
) {
|
||||
$this->financeSvc = $financeSvc;
|
||||
}
|
||||
|
@ -37,8 +37,6 @@ class ExpenseRepository extends BaseRepository implements CacheableInterface
|
||||
|
||||
if($ref_class) {
|
||||
$where['ref_class'] = $ref_class;
|
||||
} else {
|
||||
$where[] = ['ref_class', '=', null];
|
||||
}
|
||||
|
||||
$expenses = $this->findWhere($where);
|
||||
@ -52,12 +50,9 @@ class ExpenseRepository extends BaseRepository implements CacheableInterface
|
||||
|
||||
if ($ref_class) {
|
||||
$where['ref_class'] = $ref_class;
|
||||
} else {
|
||||
$where[] = ['ref_class', '=', null];
|
||||
}
|
||||
|
||||
$airline_expenses = $this->findWhere($where);
|
||||
|
||||
$expenses = $expenses->concat($airline_expenses);
|
||||
}
|
||||
|
||||
|
20
app/Services/Finance/DailyFinanceService.php
Normal file
20
app/Services/Finance/DailyFinanceService.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Finance;
|
||||
|
||||
use App\Services\BaseService;
|
||||
|
||||
/**
|
||||
* Class DailyFinanceService
|
||||
* @package App\Services\Finance
|
||||
*/
|
||||
class DailyFinanceService extends BaseService
|
||||
{
|
||||
/**
|
||||
* Run all of the daily expense/financials
|
||||
*/
|
||||
public function processFinances()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
20
app/Services/Finance/MonthlyFinanceService.php
Normal file
20
app/Services/Finance/MonthlyFinanceService.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Finance;
|
||||
|
||||
use App\Services\BaseService;
|
||||
|
||||
/**
|
||||
* Class MonthlyFinanceService
|
||||
* @package App\Services\Finance
|
||||
*/
|
||||
class MonthlyFinanceService extends BaseService
|
||||
{
|
||||
/**
|
||||
* Run all of the daily expense/financials
|
||||
*/
|
||||
public function processFinances()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -1,15 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
namespace App\Services\Finance;
|
||||
|
||||
use App\Events\Expenses as ExpensesEvent;
|
||||
use App\Models\Enums\ExpenseType;
|
||||
use App\Models\Enums\PirepSource;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Pirep;
|
||||
use App\Models\Subfleet;
|
||||
use App\Repositories\ExpenseRepository;
|
||||
use App\Repositories\JournalRepository;
|
||||
use App\Services\BaseService;
|
||||
use App\Services\FareService;
|
||||
use App\Services\PIREPService;
|
||||
use App\Support\Math;
|
||||
use App\Support\Money;
|
||||
use Log;
|
||||
@ -19,7 +21,7 @@ use Log;
|
||||
* @package App\Services
|
||||
*
|
||||
*/
|
||||
class FinanceService extends BaseService
|
||||
class PirepFinanceService extends BaseService
|
||||
{
|
||||
private $expenseRepo,
|
||||
$fareSvc,
|
||||
@ -45,27 +47,6 @@ class FinanceService extends BaseService
|
||||
$this->pirepSvc = $pirepSvc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine from the base rate, if we want to return the overridden rate
|
||||
* or if the overridden rate is a percentage, then return that amount
|
||||
* @param $base_rate
|
||||
* @param $override_rate
|
||||
* @return float|null
|
||||
*/
|
||||
public function applyAmountOrPercent($base_rate, $override_rate=null): ?float
|
||||
{
|
||||
if (!$override_rate) {
|
||||
return $base_rate;
|
||||
}
|
||||
|
||||
# Not a percentage override
|
||||
if (substr_count($override_rate, '%') === 0) {
|
||||
return $override_rate;
|
||||
}
|
||||
|
||||
return Math::addPercent($base_rate, $override_rate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process all of the finances for a pilot report. This is called
|
||||
* from a listener (FinanceEvents)
|
||||
@ -92,7 +73,7 @@ class FinanceService extends BaseService
|
||||
# Now start and pay from scratch
|
||||
$this->payFaresForPirep($pirep);
|
||||
$this->payExpensesForPirep($pirep);
|
||||
$this->paySubfleetExpenses($pirep);
|
||||
$this->payExpensesEventsForPirep($pirep);
|
||||
$this->payGroundHandlingForPirep($pirep);
|
||||
$this->payPilotForPirep($pirep);
|
||||
|
||||
@ -147,16 +128,34 @@ class FinanceService extends BaseService
|
||||
* @param Pirep $pirep
|
||||
* @throws \UnexpectedValueException
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \Prettus\Validator\Exceptions\ValidatorException
|
||||
*/
|
||||
public function payExpensesForPirep(Pirep $pirep): void
|
||||
{
|
||||
$expenses = $this->getExpenses($pirep);
|
||||
/** @var \App\Models\Expense $expense */
|
||||
foreach ($expenses as $expense) {
|
||||
$expenses = $this->expenseRepo->getAllForType(
|
||||
ExpenseType::FLIGHT,
|
||||
$pirep->airline_id
|
||||
);
|
||||
|
||||
/**
|
||||
* Go through the expenses and apply a mulitplier if present
|
||||
*/
|
||||
$expenses->map(function ($expense, $i) use ($pirep)
|
||||
{
|
||||
if ($expense->multiplier) {
|
||||
# TODO: Modify the amount
|
||||
}
|
||||
|
||||
Log::info('Finance: PIREP: ' . $pirep->id . ', expense:', $expense->toArray());
|
||||
|
||||
# Get the transaction group name from the ref_class 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
|
||||
$transaction_group = 'Expense';
|
||||
if($expense->ref_class) {
|
||||
$ref = explode('\\', $expense->ref_class);
|
||||
$transaction_group = end($ref);
|
||||
}
|
||||
|
||||
$debit = Money::createFromAmount($expense->amount);
|
||||
$this->journalRepo->post(
|
||||
$pirep->airline->journal,
|
||||
@ -165,42 +164,56 @@ class FinanceService extends BaseService
|
||||
$pirep,
|
||||
'Expense: ' . $expense->name,
|
||||
null,
|
||||
'Expenses'
|
||||
$transaction_group
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Pay out the expenses for the subfleet
|
||||
* Collect all of the expenses from the listeners and apply those to the journal
|
||||
* @param Pirep $pirep
|
||||
* @throws \UnexpectedValueException
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \Prettus\Validator\Exceptions\ValidatorException
|
||||
*/
|
||||
public function paySubfleetExpenses(Pirep $pirep)
|
||||
public function payExpensesEventsForPirep(Pirep $pirep): void
|
||||
{
|
||||
$subfleet = $pirep->aircraft->subfleet;
|
||||
$subfleet_expenses = Expense::where([
|
||||
'ref_class' => Subfleet::class,
|
||||
'ref_class_id' => $subfleet->id,
|
||||
])->get();
|
||||
|
||||
if(!$subfleet_expenses) {
|
||||
/**
|
||||
* Throw an event and collect any expenses returned from it
|
||||
*/
|
||||
$gathered_expenses = event(new ExpensesEvent($pirep));
|
||||
if (!\is_array($gathered_expenses)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($subfleet_expenses as $expense) {
|
||||
foreach ($gathered_expenses as $event_expense) {
|
||||
if (!\is_array($event_expense)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Log::info('Finance: PIREP: '.$pirep->id
|
||||
.'; subfleet expense: "'.$expense->name.'", cost: "'.$expense->amount);
|
||||
foreach ($event_expense as $expense) {
|
||||
# Make sure it's of type expense Model
|
||||
if (!($expense instanceof Expense)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->journalRepo->post(
|
||||
$pirep->airline->journal,
|
||||
null,
|
||||
Money::createFromAmount($expense->amount),
|
||||
$pirep,
|
||||
'Subfleet ('.$subfleet->type.'): '.$expense->name,
|
||||
null,
|
||||
'Subfleet Expense'
|
||||
);
|
||||
# If an airline_id is filled, then see if it matches
|
||||
if ($expense->airline_id !== $pirep->airline_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$debit = Money::createFromAmount($expense->amount);
|
||||
|
||||
$this->journalRepo->post(
|
||||
$pirep->airline->journal,
|
||||
null,
|
||||
$debit,
|
||||
$pirep,
|
||||
'Expense: ' . $expense->name,
|
||||
null,
|
||||
$expense->transaction_group ?? 'Expenses'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -325,7 +338,7 @@ class FinanceService extends BaseService
|
||||
if(filled($pirep->aircraft->subfleet->ground_handling_multiplier)) {
|
||||
// force into percent mode
|
||||
$multiplier = $pirep->aircraft->subfleet->ground_handling_multiplier.'%';
|
||||
return $this->applyAmountOrPercent(
|
||||
return Math::applyAmountOrPercent(
|
||||
$pirep->arr_airport->ground_handling_cost,
|
||||
$multiplier
|
||||
);
|
||||
@ -334,68 +347,6 @@ class FinanceService extends BaseService
|
||||
return $pirep->arr_airport->ground_handling_cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send out an event called ExpensesEvent, which picks up any
|
||||
* event listeners and check if they return a list of additional
|
||||
* Expense model objects.
|
||||
* @param Pirep $pirep
|
||||
* @return mixed
|
||||
*/
|
||||
public function getExpenses(Pirep $pirep)
|
||||
{
|
||||
$event_expenses = [];
|
||||
|
||||
$expenses = $this->expenseRepo->getAllForType(
|
||||
ExpenseType::FLIGHT,
|
||||
$pirep->airline_id,
|
||||
Expense::class
|
||||
);
|
||||
|
||||
/**
|
||||
* Go through the expenses and apply a mulitplier if present
|
||||
*/
|
||||
$expenses = $expenses->map(function($expense, $i) use ($pirep) {
|
||||
if(!$expense->multiplier) {
|
||||
return $expense;
|
||||
}
|
||||
|
||||
// TODO Apply the multiplier from the subfleet
|
||||
return $expense;
|
||||
});
|
||||
|
||||
/**
|
||||
* Throw an event and collect any expenses returned from it
|
||||
*/
|
||||
$gathered_expenses = event(new ExpensesEvent($pirep));
|
||||
if (!\is_array($gathered_expenses)) {
|
||||
return $expenses;
|
||||
}
|
||||
|
||||
foreach ($gathered_expenses as $event_expense) {
|
||||
if (!\is_array($event_expense)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach($event_expense as $expense) {
|
||||
# Make sure it's of type expense Model
|
||||
if(!($expense instanceof Expense)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
# If an airline_id is filled, then see if it matches
|
||||
if($expense->airline_id !== $pirep->airline_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$event_expenses[] = $expense;
|
||||
}
|
||||
}
|
||||
|
||||
$expenses = $expenses->concat($event_expenses);
|
||||
|
||||
return $expenses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the pilot's hourly pay for the given PIREP
|
||||
* @param Pirep $pirep
|
||||
@ -435,7 +386,7 @@ class FinanceService extends BaseService
|
||||
}
|
||||
|
||||
Log::debug('pilot pay: base rate=' . $base_rate . ', override=' . $override_rate);
|
||||
return $this->applyAmountOrPercent(
|
||||
return Math::applyAmountOrPercent(
|
||||
$base_rate,
|
||||
$override_rate
|
||||
);
|
@ -8,6 +8,26 @@ namespace App\Support;
|
||||
*/
|
||||
class Math
|
||||
{
|
||||
/**
|
||||
* Determine from the base rate, if we want to return the overridden rate
|
||||
* or if the overridden rate is a percentage, then return that amount
|
||||
* @param $base_rate
|
||||
* @param $override_rate
|
||||
* @return float|null
|
||||
*/
|
||||
public static function applyAmountOrPercent($base_rate, $override_rate = null): ?float
|
||||
{
|
||||
if (!$override_rate) {
|
||||
return $base_rate;
|
||||
}
|
||||
|
||||
# Not a percentage override
|
||||
if (substr_count($override_rate, '%') === 0) {
|
||||
return $override_rate;
|
||||
}
|
||||
|
||||
return static::addPercent($base_rate, $override_rate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add/subtract a percentage to a number
|
||||
@ -25,8 +45,6 @@ class Math
|
||||
$percent = (float) $percent;
|
||||
}
|
||||
|
||||
|
||||
return $number + ($number * ($percent/100));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use App\Repositories\ExpenseRepository;
|
||||
use App\Services\PIREPService;
|
||||
use App\Repositories\JournalRepository;
|
||||
use App\Services\FareService;
|
||||
use App\Services\FinanceService;
|
||||
use App\Services\Finance\PirepFinanceService;
|
||||
use App\Services\FleetService;
|
||||
use App\Support\Math;
|
||||
use App\Support\Money;
|
||||
@ -28,7 +28,7 @@ class FinanceTest extends TestCase
|
||||
|
||||
$this->expenseRepo = app(ExpenseRepository::class);
|
||||
$this->fareSvc = app(FareService::class);
|
||||
$this->financeSvc = app(FinanceService::class);
|
||||
$this->financeSvc = app(PirepFinanceService::class);
|
||||
$this->fleetSvc = app(FleetService::class);
|
||||
$this->pirepSvc = app(PIREPService::class);
|
||||
}
|
||||
@ -80,7 +80,6 @@ class FinanceTest extends TestCase
|
||||
* Add fares to the subfleet, and then add the fares
|
||||
* to the PIREP when it's saved, and set the capacity
|
||||
*/
|
||||
$fare_counts = [];
|
||||
$fares = factory(App\Models\Fare::class, 3)->create([
|
||||
'price' => 100,
|
||||
'cost' => 50,
|
||||
@ -571,7 +570,7 @@ class FinanceTest extends TestCase
|
||||
$airline = factory(App\Models\Airline::class)->create();
|
||||
$airline2 = factory(App\Models\Airline::class)->create();
|
||||
|
||||
$expense = factory(App\Models\Expense::class)->create([
|
||||
factory(App\Models\Expense::class)->create([
|
||||
'airline_id' => $airline->id
|
||||
]);
|
||||
|
||||
@ -599,6 +598,23 @@ class FinanceTest extends TestCase
|
||||
|
||||
$found = $expenses->where('airline_id', $airline2->id);
|
||||
$this->assertCount(0, $found);
|
||||
|
||||
/*
|
||||
* Test the subfleet class
|
||||
*/
|
||||
|
||||
factory(App\Models\Expense::class)->create([
|
||||
'airline_id' => null,
|
||||
'ref_class' => \App\Models\Subfleet::class,
|
||||
]);
|
||||
|
||||
$expenses = $this->expenseRepo->getAllForType(
|
||||
ExpenseType::FLIGHT,
|
||||
$airline->id,
|
||||
\App\Models\Subfleet::class
|
||||
);
|
||||
|
||||
$this->assertCount(1, $expenses);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -610,8 +626,7 @@ class FinanceTest extends TestCase
|
||||
$journalRepo = app(JournalRepository::class);
|
||||
|
||||
[$user, $pirep, $fares] = $this->createFullPirep();
|
||||
|
||||
$journal = $user->airline->initJournal(config('phpvms.currency'));
|
||||
$user->airline->initJournal(config('phpvms.currency'));
|
||||
|
||||
# Override the fares
|
||||
$fare_counts = [];
|
||||
@ -635,12 +650,13 @@ class FinanceTest extends TestCase
|
||||
$this->assertEquals(1840, $transactions['debits']->getValue());
|
||||
|
||||
# Check that all the different transaction types are there
|
||||
# test by the different groups that exist
|
||||
$transaction_types = [
|
||||
'Expenses' => 1,
|
||||
'Expense' => 1,
|
||||
'Subfleet' => 1,
|
||||
'Fares' => 3,
|
||||
'Ground Handling' => 1,
|
||||
'Pilot Pay' => 2, # debit on the airline, credit to the pilot
|
||||
'Subfleet Expense' => 1,
|
||||
];
|
||||
|
||||
foreach($transaction_types as $type => $count) {
|
||||
|
Loading…
Reference in New Issue
Block a user