From 88a8fd2bbd3b976bc6caadb928746dcecb1de86a Mon Sep 17 00:00:00 2001 From: Nabeel Shahzad Date: Mon, 5 Mar 2018 21:24:49 -0600 Subject: [PATCH] Remove subfleet_expenses and combine into main expenses table; select expense type on subfleet #130 #136 --- app/Database/factories/ExpenseFactory.php | 2 + .../factories/SubfleetExpenseFactory.php | 11 ----- ...17_06_23_011011_create_subfleet_tables.php | 21 ++------- ...018_02_26_185121_create_expenses_table.php | 8 +++- app/Database/seeds/sample.yml | 28 ++++++++--- .../Controllers/Admin/ExpenseController.php | 6 ++- .../Controllers/Admin/SubfleetController.php | 11 +++-- app/Models/Airport.php | 4 +- app/Models/Expense.php | 2 + app/Models/Subfleet.php | 11 ++--- app/Models/SubfleetExpense.php | 47 ------------------- .../{ExpensableTrait.php => Expensable.php} | 8 ++-- app/Repositories/ExpenseRepository.php | 29 ++++++++++-- app/Repositories/JournalRepository.php | 6 +-- app/Services/FinanceService.php | 14 ++++-- app/helpers.php | 25 ++++++++++ .../views/admin/expenses/index.blade.php | 2 +- .../views/admin/subfleets/expenses.blade.php | 18 +++++-- .../views/admin/subfleets/script.blade.php | 21 +++++++-- tests/FinanceTest.php | 24 ++++++---- 20 files changed, 160 insertions(+), 138 deletions(-) delete mode 100644 app/Database/factories/SubfleetExpenseFactory.php delete mode 100644 app/Models/SubfleetExpense.php rename app/Models/Traits/{ExpensableTrait.php => Expensable.php} (68%) diff --git a/app/Database/factories/ExpenseFactory.php b/app/Database/factories/ExpenseFactory.php index 997927297..e074e3a9d 100644 --- a/app/Database/factories/ExpenseFactory.php +++ b/app/Database/factories/ExpenseFactory.php @@ -13,6 +13,8 @@ 'amount' => $faker->randomFloat(2, 100, 1000), 'type' => ExpenseType::FLIGHT, 'multiplier' => false, + 'ref_class' => \App\Models\Expense::class, + 'ref_class_id' => null, 'active' => true, ]; }); diff --git a/app/Database/factories/SubfleetExpenseFactory.php b/app/Database/factories/SubfleetExpenseFactory.php deleted file mode 100644 index 9ece17960..000000000 --- a/app/Database/factories/SubfleetExpenseFactory.php +++ /dev/null @@ -1,11 +0,0 @@ -define(App\Models\SubfleetExpense::class, function (Faker $faker) { - return [ - 'subfleet_id' => null, - 'name' => $faker->text(20), - 'amount' => $faker->randomFloat(2, 100, 1000), - ]; -}); diff --git a/app/Database/migrations/2017_06_23_011011_create_subfleet_tables.php b/app/Database/migrations/2017_06_23_011011_create_subfleet_tables.php index f0bc297f2..beff35f0b 100644 --- a/app/Database/migrations/2017_06_23_011011_create_subfleet_tables.php +++ b/app/Database/migrations/2017_06_23_011011_create_subfleet_tables.php @@ -3,14 +3,11 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; +/** + * Class CreateSubfleetTables + */ class CreateSubfleetTables extends Migration { - - /** - * Run the migrations. - * - * @return void - */ public function up() { Schema::create('subfleets', function (Blueprint $table) { @@ -26,17 +23,6 @@ public function up() $table->timestamps(); }); - Schema::create('subfleet_expenses', function(Blueprint $table) { - $table->increments('id'); - $table->unsignedBigInteger('subfleet_id'); - $table->string('name', 50); - $table->unsignedTinyInteger('type'); # ExpenseType - $table->unsignedDecimal('amount'); - $table->timestamps(); - - $table->index('subfleet_id'); - }); - Schema::create('subfleet_fare', function (Blueprint $table) { $table->unsignedInteger('subfleet_id'); $table->unsignedInteger('fare_id'); @@ -76,7 +62,6 @@ public function up() public function down() { Schema::dropIfExists('subfleets'); - Schema::dropIfExists('subfleet_expenses'); Schema::dropIfExists('subfleet_fare'); Schema::dropIfExists('subfleet_flight'); Schema::dropIfExists('subfleet_rank'); diff --git a/app/Database/migrations/2018_02_26_185121_create_expenses_table.php b/app/Database/migrations/2018_02_26_185121_create_expenses_table.php index bf59172f1..5098782aa 100644 --- a/app/Database/migrations/2018_02_26_185121_create_expenses_table.php +++ b/app/Database/migrations/2018_02_26_185121_create_expenses_table.php @@ -16,15 +16,19 @@ public function up() Schema::create('expenses', function (Blueprint $table) { $table->increments('id'); $table->unsignedInteger('airline_id')->nullable(); + $table->string('name'); $table->unsignedInteger('amount'); $table->unsignedTinyInteger('type'); $table->boolean('multiplier')->nullable()->default(0); $table->boolean('active')->nullable()->default(true); - # Internal fields are expenses tied to some system object + # ref fields are expenses tied to some model object # EG, the airports has an internal expense for gate costs - $table->nullableMorphs('expensable'); + $table->string('ref_class')->nullable(); + $table->string('ref_class_id', 36)->nullable(); + $table->index(['ref_class', 'ref_class_id']); + $table->timestamps(); }); } diff --git a/app/Database/seeds/sample.yml b/app/Database/seeds/sample.yml index 409b5ed46..86b46b60a 100644 --- a/app/Database/seeds/sample.yml +++ b/app/Database/seeds/sample.yml @@ -184,25 +184,38 @@ expenses: amount: 100 type: 0 active: 1 + ref_class: App\Models\Expense - name: Per-Flight (multiplier) amount: 100 type: 0 multiplier: 1 active: 1 + ref_class: App\Models\Expense - name: Per-Flight (multiplier, on airline) airline_id: 1 amount: 200 type: 0 multiplier: 1 active: 1 + ref_class: App\Models\Expense - name: A daily fee amount: 800 type: 1 active: 1 + ref_class: App\Models\Expense - name: A monthly fee amount: 5000 type: 2 active: 1 + ref_class: App\Models\Expense + - name: Catering + amount: 1000 + type: 0 + active: 1 + ref_class: App\Models\Subfleet + ref_class_id: 1 + created_at: now + updated_at: now fares: - id: 1 @@ -238,13 +251,14 @@ subfleets: type: 772-36ER-GE90-115B ground_handling_multiplier: 150 -subfleet_expenses: - - id: 1 - subfleet_id: 1 - name: Catering - amount: 1000 - created_at: now - updated_at: now +#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: diff --git a/app/Http/Controllers/Admin/ExpenseController.php b/app/Http/Controllers/Admin/ExpenseController.php index bb9c24172..dc085b8e5 100644 --- a/app/Http/Controllers/Admin/ExpenseController.php +++ b/app/Http/Controllers/Admin/ExpenseController.php @@ -5,6 +5,7 @@ use App\Http\Requests\CreateAirlineRequest; use App\Http\Requests\UpdateAirlineRequest; use App\Models\Enums\ExpenseType; +use App\Models\Expense; use App\Repositories\AirlineRepository; use App\Repositories\ExpenseRepository; use Flash; @@ -39,7 +40,9 @@ public function __construct( public function index(Request $request) { $this->expenseRepo->pushCriteria(new RequestCriteria($request)); - $expenses = $this->expenseRepo->all(); + $expenses = $this->expenseRepo->findWhere([ + 'ref_class' => Expense::class + ]); return view('admin.expenses.index', [ 'expenses' => $expenses @@ -66,6 +69,7 @@ public function create() public function store(Request $request) { $input = $request->all(); + $input['ref_class'] = Expense::class; $this->expenseRepo->create($input); Flash::success('Expense saved successfully.'); diff --git a/app/Http/Controllers/Admin/SubfleetController.php b/app/Http/Controllers/Admin/SubfleetController.php index f5d21ac18..45189400e 100644 --- a/app/Http/Controllers/Admin/SubfleetController.php +++ b/app/Http/Controllers/Admin/SubfleetController.php @@ -6,8 +6,8 @@ use App\Http\Requests\UpdateSubfleetRequest; use App\Models\Airline; use App\Models\Enums\FuelType; +use App\Models\Expense; use App\Models\Subfleet; -use App\Models\SubfleetExpense; use App\Repositories\AircraftRepository; use App\Repositories\FareRepository; use App\Repositories\RankRepository; @@ -338,17 +338,18 @@ public function expenses($id, Request $request) * update specific rank data */ if ($request->isMethod('post')) { - $expense = new SubfleetExpense($request->post()); - $expense->subfleet_id = $subfleet->id; + $expense = new Expense($request->post()); + $expense->ref_class = Subfleet::class; + $expense->ref_class_id = $subfleet->id; $expense->save(); $subfleet->refresh(); } elseif ($request->isMethod('put')) { - $expense = SubfleetExpense::findOrFail($request->input('expense_id')); + $expense = Expense::findOrFail($request->input('expense_id')); $expense->{$request->name} = $request->value; $expense->save(); } // dissassociate fare from teh aircraft elseif ($request->isMethod('delete')) { - $expense = SubfleetExpense::findOrFail($request->input('expense_id')); + $expense = Expense::findOrFail($request->input('expense_id')); $expense->delete(); } diff --git a/app/Models/Airport.php b/app/Models/Airport.php index a257f995d..38c356e18 100644 --- a/app/Models/Airport.php +++ b/app/Models/Airport.php @@ -2,7 +2,7 @@ namespace App\Models; -use App\Models\Traits\ExpensableTrait; +use App\Models\Traits\Expensable; use Illuminate\Notifications\Notifiable; /** @@ -12,7 +12,7 @@ */ class Airport extends BaseModel { - use ExpensableTrait; + use Expensable; use Notifiable; public $table = 'airports'; diff --git a/app/Models/Expense.php b/app/Models/Expense.php index c015efe75..27301a8b6 100644 --- a/app/Models/Expense.php +++ b/app/Models/Expense.php @@ -18,6 +18,8 @@ class Expense extends BaseModel 'amount', 'type', 'multiplier', + 'ref_class', + 'ref_class_id', 'active', ]; diff --git a/app/Models/Subfleet.php b/app/Models/Subfleet.php index ec45c2829..94f765b7a 100644 --- a/app/Models/Subfleet.php +++ b/app/Models/Subfleet.php @@ -3,6 +3,7 @@ namespace App\Models; use App\Models\Enums\AircraftStatus; +use App\Models\Traits\Expensable; /** * Class Subfleet @@ -10,6 +11,8 @@ */ class Subfleet extends BaseModel { + use Expensable; + public $table = 'subfleets'; public $fillable = [ @@ -88,14 +91,6 @@ public function airline() return $this->belongsTo(Airline::class, 'airline_id'); } - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function expenses() - { - return $this->hasMany(SubfleetExpense::class, 'subfleet_id'); - } - public function fares() { return $this->belongsToMany(Fare::class, 'subfleet_fare') diff --git a/app/Models/SubfleetExpense.php b/app/Models/SubfleetExpense.php deleted file mode 100644 index ab7f94c07..000000000 --- a/app/Models/SubfleetExpense.php +++ /dev/null @@ -1,47 +0,0 @@ - 'float', - 'type' => 'integer', - ]; - - public static $rules = [ - 'name' => 'required', - 'amount' => 'required|numeric', - ]; - - /** - * Relationships - */ - - /** - * Has a subfleet - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function subfleet() - { - return $this->belongsTo(Subfleet::class, 'subfleet_id'); - } -} diff --git a/app/Models/Traits/ExpensableTrait.php b/app/Models/Traits/Expensable.php similarity index 68% rename from app/Models/Traits/ExpensableTrait.php rename to app/Models/Traits/Expensable.php index 7aa479f99..51fc6f8eb 100644 --- a/app/Models/Traits/ExpensableTrait.php +++ b/app/Models/Traits/Expensable.php @@ -4,13 +4,12 @@ use App\Models\Expense; -trait ExpensableTrait +trait Expensable { - /** * Initialize a new journal when a new record is created */ - public static function bootExpensableTrait() + public static function bootExpensable() { /*static::created(function ($model) { $model->initJournal(config('phpvms.currency')); @@ -23,6 +22,7 @@ public static function bootExpensableTrait() */ public function expenses() { - return $this->morphToMany(Expense::class, 'expensable'); + return $this->hasMany(Expense::class, 'ref_class_id') + ->where('ref_class', __CLASS__); } } diff --git a/app/Repositories/ExpenseRepository.php b/app/Repositories/ExpenseRepository.php index 960c0f321..ad0b39da5 100644 --- a/app/Repositories/ExpenseRepository.php +++ b/app/Repositories/ExpenseRepository.php @@ -24,20 +24,39 @@ public function model() * Get all of the expenses for a given type, and also * include expenses for a given airline ID * @param $type + * @param null $airline_id + * @param null $ref_class * @return Collection */ - public function getAllForType($type, $airline_id=null) + public function getAllForType($type, $airline_id=null, $ref_class=null) { - $expenses = $this->findWhere([ + $where = [ 'type' => $type, ['airline_id', '=', null] - ]); + ]; + + if($ref_class) { + $where['ref_class'] = $ref_class; + } else { + $where[] = ['ref_class', '=', null]; + } + + $expenses = $this->findWhere($where); if($airline_id) { - $airline_expenses = $this->findWhere([ + + $where = [ 'type' => $type, 'airline_id' => $airline_id - ]); + ]; + + if ($ref_class) { + $where['ref_class'] = $ref_class; + } else { + $where[] = ['ref_class', '=', null]; + } + + $airline_expenses = $this->findWhere($where); $expenses = $expenses->concat($airline_expenses); } diff --git a/app/Repositories/JournalRepository.php b/app/Repositories/JournalRepository.php index 234fc3dc4..a7d8fad16 100644 --- a/app/Repositories/JournalRepository.php +++ b/app/Repositories/JournalRepository.php @@ -61,6 +61,7 @@ public function post( 'currency' => config('phpvms.currency'), 'memo' => $memo, 'post_date' => $post_date ?? Carbon::now(), + 'transaction_group' => $transaction_group, ]; if($reference !== null) { @@ -68,11 +69,6 @@ public function post( $attrs['ref_class_id'] = $reference->id; } - if($transaction_group) { - $transaction_group = str_replace(' ', '_', $transaction_group); - $attrs['transaction_group'] = $transaction_group; - } - try { $transaction = $this->create($attrs); } catch (ValidatorException $e) { diff --git a/app/Services/FinanceService.php b/app/Services/FinanceService.php index 3cea95252..3e359e897 100644 --- a/app/Services/FinanceService.php +++ b/app/Services/FinanceService.php @@ -7,7 +7,7 @@ use App\Models\Enums\PirepSource; use App\Models\Expense; use App\Models\Pirep; -use App\Models\SubfleetExpense; +use App\Models\Subfleet; use App\Repositories\ExpenseRepository; use App\Repositories\JournalRepository; use App\Support\Math; @@ -178,8 +178,9 @@ public function payExpensesForPirep(Pirep $pirep): void public function paySubfleetExpenses(Pirep $pirep) { $subfleet = $pirep->aircraft->subfleet; - $subfleet_expenses = SubfleetExpense::where([ - 'subfleet_id' => $subfleet->id, + $subfleet_expenses = Expense::where([ + 'ref_class' => Subfleet::class, + 'ref_class_id' => $subfleet->id, ])->get(); if(!$subfleet_expenses) { @@ -344,8 +345,11 @@ public function getExpenses(Pirep $pirep) { $event_expenses = []; - $expenses = $this->expenseRepo - ->getAllForType(ExpenseType::FLIGHT, $pirep->airline_id); + $expenses = $this->expenseRepo->getAllForType( + ExpenseType::FLIGHT, + $pirep->airline_id, + Expense::class + ); /** * Go through the expenses and apply a mulitplier if present diff --git a/app/helpers.php b/app/helpers.php index 3d28f4f5b..d1014297a 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -56,6 +56,31 @@ function list_to_assoc(array $list) } } +if(!function_exists('list_to_editable')) { + /** + * Convert a list (select box) into an editable list + * https://vitalets.github.io/x-editable/docs.html#select + * Takes a list of: + * [value => text, valueN => textN, ...] + * Return: + * [{value: 1, text: "text1"}, {value: 2, text: "text2"}, ...] + * @param array $list + * @return array + */ + function list_to_editable(array $list) + { + $editable = []; + foreach($list as $value => $key) { + $editable[] = [ + 'text' => $key, + 'value' => $value, + ]; + } + + return $editable; + } +} + if (!function_exists('skin_view')) { /** * Render a skin diff --git a/resources/views/admin/expenses/index.blade.php b/resources/views/admin/expenses/index.blade.php index b595d02c2..724289feb 100644 --- a/resources/views/admin/expenses/index.blade.php +++ b/resources/views/admin/expenses/index.blade.php @@ -14,7 +14,7 @@
@if(!filled($expenses))

- You must add a subfleet before you can add an aircraft! + There are no expenses

@else @include('admin.expenses.table') diff --git a/resources/views/admin/subfleets/expenses.blade.php b/resources/views/admin/subfleets/expenses.blade.php index b89870724..e2e867b25 100644 --- a/resources/views/admin/subfleets/expenses.blade.php +++ b/resources/views/admin/subfleets/expenses.blade.php @@ -11,6 +11,7 @@ Name Cost {!! currency(config('phpvms.currency')) !!} + Type @endif @@ -19,16 +20,24 @@

- {!! $expense->name !!}

- {!! $expense->amount !!}

+ +

+ {!! \App\Models\Enums\ExpenseType::label($expense->type) !!} +

+ {!! Form::open(['url' => url('/admin/subfleets/'.$subfleet->id.'/expenses'), 'method' => 'delete', 'class' => 'modify_expense form-inline']) !!} @@ -49,8 +58,9 @@
{!! Form::open(['url' => url('/admin/subfleets/'.$subfleet->id.'/expenses'), 'method' => 'post', 'class' => 'modify_expense form-inline']) !!} - {!! Form::input('text', 'name', null, ['class' => 'form-control input-sm']) !!} - {!! Form::number('cost', null, ['class' => 'form-control input-sm']) !!} + {!! Form::input('text', 'name', null, ['class' => 'form-control input-sm', 'placeholder' => 'Name']) !!} + {!! Form::number('cost', null, ['class' => 'form-control input-sm', 'placeholder' => 'Amount']) !!} + {!! Form::select('type', \App\Models\Enums\ExpenseType::select(), null, ['class' => 'select2']) !!} {!! Form::button(' Add', ['type' => 'submit', 'class' => 'btn btn-success btn-small']) !!} {!! Form::close() !!} diff --git a/resources/views/admin/subfleets/script.blade.php b/resources/views/admin/subfleets/script.blade.php index 818586a6a..925dfa870 100644 --- a/resources/views/admin/subfleets/script.blade.php +++ b/resources/views/admin/subfleets/script.blade.php @@ -33,14 +33,29 @@ function setEditable() { } }); - $('#subfleet-expenses a').editable({ - type: 'text', - mode: 'inline', + $('#subfleet-expenses a.text').editable({ + emptytext: '0', + url: '{!! url('/admin/subfleets/'.$subfleet->id.'/expenses') !!}', + title: 'Enter override value', + ajaxOptions: {'type': 'put'}, + params: function (params) { + return { + expense_id: params.pk, + name: params.name, + value: params.value + } + } + }); + + $('#subfleet-expenses a.dropdown').editable({ + type: 'select', emptytext: '0', + source: {!! json_encode(list_to_editable(\App\Models\Enums\ExpenseType::select())) !!}, url: '{!! url('/admin/subfleets/'.$subfleet->id.'/expenses') !!}', title: 'Enter override value', ajaxOptions: {'type': 'put'}, params: function (params) { + console.log(params); return { expense_id: params.pk, name: params.name, diff --git a/tests/FinanceTest.php b/tests/FinanceTest.php index ce3520661..cd803c9d4 100644 --- a/tests/FinanceTest.php +++ b/tests/FinanceTest.php @@ -98,8 +98,9 @@ public function createFullPirep() ]); # Add a subfleet expense - factory(App\Models\SubfleetExpense::class)->create([ - 'subfleet_id' => $subfleet['subfleet']->id, + factory(App\Models\Expense::class)->create([ + 'ref_class' => \App\Models\Subfleet::class, + 'ref_class_id' => $subfleet['subfleet']->id, 'amount' => 200 ]); @@ -570,7 +571,7 @@ public function testPirepExpenses() $airline = factory(App\Models\Airline::class)->create(); $airline2 = factory(App\Models\Airline::class)->create(); - factory(App\Models\Expense::class)->create([ + $expense = factory(App\Models\Expense::class)->create([ 'airline_id' => $airline->id ]); @@ -582,8 +583,11 @@ public function testPirepExpenses() 'airline_id' => null ]); - $expenses = $this->expenseRepo - ->getAllForType(ExpenseType::FLIGHT, $airline->id); + $expenses = $this->expenseRepo->getAllForType( + ExpenseType::FLIGHT, + $airline->id, + \App\Models\Expense::class + ); $this->assertCount(2, $expenses); @@ -632,11 +636,11 @@ public function testPirepFinances() # Check that all the different transaction types are there $transaction_types = [ - 'expenses' => 1, - 'fares' => 3, - 'ground_handling' => 1, - 'pilot_pay' => 2, # debit on the airline, credit to the pilot - 'subfleet_expense' => 1, + 'Expenses' => 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) {