addData('base'); $this->expenseRepo = app(ExpenseRepository::class); $this->fareSvc = app(FareService::class); $this->financeSvc = app(PirepFinanceService::class); $this->fleetSvc = app(FleetService::class); $this->pirepSvc = app(PirepService::class); } /** * Create a user and a PIREP, that has all of the data filled out * so that we can test all of the disparate parts of the finances * @return array * @throws Exception */ public function createFullPirep() { /** * Setup tests */ $subfleet = $this->createSubfleetWithAircraft(2); $subfleet['subfleet']->cost_block_hour = 10; $subfleet['subfleet']->save(); $rank = $this->createRank(10, [$subfleet['subfleet']->id]); $rank->acars_base_pay_rate = 10; $rank->save(); $this->fleetSvc->addSubfleetToRank($subfleet['subfleet'], $rank); $airport = factory(App\Models\Airport::class)->create([ 'ground_handling_cost' => 10 ]); $user = factory(App\Models\User::class)->create([ 'rank_id' => $rank->id, ]); $flight = factory(App\Models\Flight::class)->create([ 'airline_id' => $user->airline_id, 'arr_airport_id' => $airport->icao, ]); $pirep = factory(App\Models\Pirep::class)->create([ 'flight_number' => $flight->flight_number, 'route_code' => $flight->route_code, 'route_leg' => $flight->route_leg, 'arr_airport_id' => $airport->id, 'user_id' => $user->id, 'airline_id' => $user->airline_id, 'aircraft_id' => $subfleet['aircraft']->random(), 'source' => PirepSource::ACARS, 'flight_time' => 120, ]); /** * Add fares to the subfleet, and then add the fares * to the PIREP when it's saved, and set the capacity */ $fares = factory(App\Models\Fare::class, 3)->create([ 'price' => 100, 'cost' => 50, 'capacity' => 10, ]); foreach ($fares as $fare) { $this->fareSvc->setForSubfleet($subfleet['subfleet'], $fare); } # Add an expense factory(App\Models\Expense::class)->create([ 'airline_id' => null, 'amount' => 100 ]); # Add a subfleet expense factory(App\Models\Expense::class)->create([ 'ref_model' => \App\Models\Subfleet::class, 'ref_model_id' => $subfleet['subfleet']->id, 'amount' => 200 ]); $pirep = $this->pirepSvc->create($pirep, []); return [$user, $pirep, $fares]; } /** * */ public function testFlightFaresNoOverride() { $flight = factory(App\Models\Flight::class)->create(); $fare = factory(App\Models\Fare::class)->create(); $this->fareSvc->setForFlight($flight, $fare); $subfleet_fares = $this->fareSvc->getForFlight($flight); $this->assertCount(1, $subfleet_fares); $this->assertEquals($fare->price, $subfleet_fares->get(0)->price); $this->assertEquals($fare->capacity, $subfleet_fares->get(0)->capacity); # # set an override now # $this->fareSvc->setForFlight($flight, $fare, [ 'price' => 50, 'capacity' => 400 ]); # look for them again $subfleet_fares = $this->fareSvc->getForFlight($flight); $this->assertCount(1, $subfleet_fares); $this->assertEquals(50, $subfleet_fares[0]->price); $this->assertEquals(400, $subfleet_fares[0]->capacity); # delete $this->fareSvc->delFareFromFlight($flight, $fare); $this->assertCount(0, $this->fareSvc->getForFlight($flight)); } /** * Assign percentage values and make sure they're valid */ public function testFlightFareOverrideAsPercent() { $flight = factory(App\Models\Flight::class)->create(); $fare = factory(App\Models\Fare::class)->create(); $percent_incr = '20%'; $percent_decr = '-20%'; $percent_200 = '200%'; $new_price = Math::addPercent($fare->price, $percent_incr); $new_cost = Math::addPercent($fare->cost, $percent_decr); $new_capacity = Math::addPercent($fare->capacity, $percent_200); $this->fareSvc->setForFlight($flight, $fare, [ 'price' => $percent_incr, 'cost' => $percent_decr, 'capacity' => $percent_200, ]); $ac_fares = $this->fareSvc->getForFlight($flight); $this->assertCount(1, $ac_fares); $this->assertEquals($new_price, $ac_fares[0]->price); $this->assertEquals($new_cost, $ac_fares[0]->cost); $this->assertEquals($new_capacity, $ac_fares[0]->capacity); } public function testSubfleetFaresNoOverride() { $subfleet = factory(App\Models\Subfleet::class)->create(); $fare = factory(App\Models\Fare::class)->create(); $this->fareSvc->setForSubfleet($subfleet, $fare); $subfleet_fares = $this->fareSvc->getForSubfleet($subfleet); $this->assertCount(1, $subfleet_fares); $this->assertEquals($fare->price, $subfleet_fares->get(0)->price); $this->assertEquals($fare->capacity, $subfleet_fares->get(0)->capacity); # # set an override now # $this->fareSvc->setForSubfleet($subfleet, $fare, [ 'price' => 50, 'capacity' => 400 ]); # look for them again $subfleet_fares = $this->fareSvc->getForSubfleet($subfleet); $this->assertCount(1, $subfleet_fares); $this->assertEquals(50, $subfleet_fares[0]->price); $this->assertEquals(400, $subfleet_fares[0]->capacity); # delete $this->fareSvc->delFareFromSubfleet($subfleet, $fare); $this->assertCount(0, $this->fareSvc->getForSubfleet($subfleet)); } public function testSubfleetFaresOverride() { $subfleet = factory(App\Models\Subfleet::class)->create(); $fare = factory(App\Models\Fare::class)->create(); $this->fareSvc->setForSubfleet($subfleet, $fare, [ 'price' => 50, 'capacity' => 400 ]); $ac_fares = $this->fareSvc->getForSubfleet($subfleet); $this->assertCount(1, $ac_fares); $this->assertEquals(50, $ac_fares[0]->price); $this->assertEquals(400, $ac_fares[0]->capacity); # # update the override to a different amount and make sure it updates # $this->fareSvc->setForSubfleet($subfleet, $fare, [ 'price' => 150, 'capacity' => 50 ]); $ac_fares = $this->fareSvc->getForSubfleet($subfleet); $this->assertCount(1, $ac_fares); $this->assertEquals(150, $ac_fares[0]->price); $this->assertEquals(50, $ac_fares[0]->capacity); # delete $this->fareSvc->delFareFromSubfleet($subfleet, $fare); $this->assertCount(0, $this->fareSvc->getForSubfleet($subfleet)); } /** * Assign percentage values and make sure they're valid */ public function testSubfleetFareOverrideAsPercent() { $subfleet = factory(App\Models\Subfleet::class)->create(); $fare = factory(App\Models\Fare::class)->create(); $percent_incr = '20%'; $percent_decr = '-20%'; $percent_200 = '200%'; $new_price = Math::addPercent($fare->price, $percent_incr); $new_cost = Math::addPercent($fare->cost, $percent_decr); $new_capacity = Math::addPercent($fare->capacity, $percent_200); $this->fareSvc->setForSubfleet($subfleet, $fare, [ 'price' => $percent_incr, 'cost' => $percent_decr, 'capacity' => $percent_200, ]); $ac_fares = $this->fareSvc->getForSubfleet($subfleet); $this->assertCount(1, $ac_fares); $this->assertEquals($new_price, $ac_fares[0]->price); $this->assertEquals($new_cost, $ac_fares[0]->cost); $this->assertEquals($new_capacity, $ac_fares[0]->capacity); } /** * Test getting the fares from the flight svc. Have a few base fares * and then override some of them */ public function testGetFaresWithOverrides() { $flight = factory(App\Models\Flight::class)->create(); $subfleet = factory(App\Models\Subfleet::class)->create(); [$fare1, $fare2, $fare3, $fare4] = factory(App\Models\Fare::class, 4)->create(); # add to the subfleet, and just override one of them $this->fareSvc->setForSubfleet($subfleet, $fare1); $this->fareSvc->setForSubfleet($subfleet, $fare2, [ 'price' => 100, 'cost' => 50, 'capacity' => 25, ]); $this->fareSvc->setForSubfleet($subfleet, $fare3); # Now set the last one to the flight and then override stuff $this->fareSvc->setForFlight($flight, $fare3, [ 'price' => '300%', 'cost' => 250, ]); $fare3_price = Math::addPercent($fare3->price, 300); # Assign another one to the flight, that's not on the subfleet # This one should NOT be returned in the list of fares $this->fareSvc->setForFlight($flight, $fare4); $fares = $this->fareSvc->getAllFares($flight, $subfleet); $this->assertCount(3, $fares); foreach($fares as $fare) { switch($fare->id) { case $fare1->id: $this->assertEquals($fare->price, $fare1->price); $this->assertEquals($fare->cost, $fare1->cost); $this->assertEquals($fare->capacity, $fare1->capacity); break; case $fare2->id: $this->assertEquals($fare->price, 100); $this->assertEquals($fare->cost, 50); $this->assertEquals($fare->capacity, 25); break; case $fare3->id: $this->assertEquals($fare->price, $fare3_price); $this->assertEquals($fare->cost, 250); $this->assertEquals($fare->capacity, $fare3->capacity); break; } } } public function testGetFaresNoFlightOverrides() { $subfleet = factory(App\Models\Subfleet::class)->create(); [$fare1, $fare2, $fare3] = factory(App\Models\Fare::class, 3)->create(); # add to the subfleet, and just override one of them $this->fareSvc->setForSubfleet($subfleet, $fare1); $this->fareSvc->setForSubfleet($subfleet, $fare2, [ 'price' => 100, 'cost' => 50, 'capacity' => 25, ]); $this->fareSvc->setForSubfleet($subfleet, $fare3); $fares = $this->fareSvc->getAllFares(null, $subfleet); $this->assertCount(3, $fares); foreach ($fares as $fare) { switch ($fare->id) { case $fare1->id: $this->assertEquals($fare->price, $fare1->price); $this->assertEquals($fare->cost, $fare1->cost); $this->assertEquals($fare->capacity, $fare1->capacity); break; case $fare2->id: $this->assertEquals($fare->price, 100); $this->assertEquals($fare->cost, 50); $this->assertEquals($fare->capacity, 25); break; case $fare3->id: $this->assertEquals($fare->price, $fare3->price); $this->assertEquals($fare->cost, $fare3->cost); $this->assertEquals($fare->capacity, $fare3->capacity); break; } } } /** * Get the pilot pay, derived from the rank */ public function testGetPilotPayNoOverride() { $subfleet = $this->createSubfleetWithAircraft(2); $rank = $this->createRank(10, [$subfleet['subfleet']->id]); $this->fleetSvc->addSubfleetToRank($subfleet['subfleet'], $rank); $this->user = factory(App\Models\User::class)->create([ 'rank_id' => $rank->id, ]); $pirep = factory(App\Models\Pirep::class)->create([ 'user_id' => $this->user->id, 'aircraft_id' => $subfleet['aircraft']->random(), 'source' => PirepSource::ACARS, ]); $rate = $this->financeSvc->getPilotPayRateForPirep($pirep); $this->assertEquals($rank->acars_base_pay_rate, $rate); } /** * Get the pilot pay, but include different overrides */ public function testGetPilotPayWithOverride() { $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, ]); $pirep_acars = factory(App\Models\Pirep::class)->create([ 'user_id' => $this->user->id, 'aircraft_id' => $subfleet['aircraft']->random(), 'source' => PirepSource::ACARS, ]); $rate = $this->financeSvc->getPilotPayRateForPirep($pirep_acars); $this->assertEquals($acars_pay_rate, $rate); # Change to a percentage $manual_pay_rate = '50%'; $manual_pay_adjusted = Math::addPercent( $rank->manual_base_pay_rate, $manual_pay_rate); $this->fleetSvc->addSubfleetToRank($subfleet['subfleet'], $rank, [ 'manual_pay' => $manual_pay_rate, ]); $pirep_manual = factory(App\Models\Pirep::class)->create([ 'user_id' => $this->user->id, 'aircraft_id' => $subfleet['aircraft']->random(), 'source' => PirepSource::MANUAL, ]); $rate = $this->financeSvc->getPilotPayRateForPirep($pirep_manual); $this->assertEquals($manual_pay_adjusted, $rate); # And make sure the original acars override still works $rate = $this->financeSvc->getPilotPayRateForPirep($pirep_acars); $this->assertEquals($acars_pay_rate, $rate); } /** * Get the payment for a pilot */ public function testGetPirepPilotPay() { $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, ]); $pirep_acars = factory(App\Models\Pirep::class)->create([ 'user_id' => $this->user->id, 'aircraft_id' => $subfleet['aircraft']->random(), 'source' => PirepSource::ACARS, 'flight_time' => 60, ]); $payment = $this->financeSvc->getPilotPay($pirep_acars); $this->assertEquals(100, $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 */ public function testJournalOperations(): void { $journalRepo = app(JournalRepository::class); $user = factory(App\Models\User::class)->create(); $journal = factory(App\Models\Journal::class)->create(); $journalRepo->post( $journal, Money::createFromAmount(100), null, $user ); $balance = $journalRepo->getBalance($journal); $this->assertEquals(100, $balance->getValue()); $this->assertEquals(100, $journal->balance->getValue()); # add another transaction $journalRepo->post( $journal, Money::createFromAmount(25), null, $user ); $balance = $journalRepo->getBalance($journal); $this->assertEquals(125, $balance->getValue()); $this->assertEquals(125, $journal->balance->getValue()); # debit an amount $journalRepo->post( $journal, null, Money::createFromAmount(25), $user ); $balance = $journalRepo->getBalance($journal); $this->assertEquals(100, $balance->getValue()); $this->assertEquals(100, $journal->balance->getValue()); # find all transactions $transactions = $journalRepo->getAllForObject($user); $this->assertCount(3, $transactions['transactions']); $this->assertEquals(125, $transactions['credits']->getValue()); $this->assertEquals(25, $transactions['debits']->getValue()); } /** * * @throws Exception */ public function testPirepFares() { [$user, $pirep, $fares] = $this->createFullPirep(); # Override the fares $fare_counts = []; foreach ($fares as $fare) { $fare_counts[] = [ 'fare_id' => $fare->id, 'price' => $fare->price, 'count' => round($fare->capacity / 2), ]; } $this->fareSvc->saveForPirep($pirep, $fare_counts); $all_fares = $this->financeSvc->getReconciledFaresForPirep($pirep); $fare_counts = collect($fare_counts); foreach($all_fares as $fare) { $set_fare = $fare_counts->where('fare_id', $fare->id)->first(); $this->assertEquals($set_fare['count'], $fare->count); $this->assertEquals($set_fare['price'], $fare->price); } } /** * Test that all expenses are pulled properly */ public function testPirepExpenses() { $airline = factory(App\Models\Airline::class)->create(); $airline2 = factory(App\Models\Airline::class)->create(); factory(App\Models\Expense::class)->create([ 'airline_id' => $airline->id ]); factory(App\Models\Expense::class)->create([ 'airline_id' => $airline2->id ]); factory(App\Models\Expense::class)->create([ 'airline_id' => null ]); $expenses = $this->expenseRepo->getAllForType( ExpenseType::FLIGHT, $airline->id, \App\Models\Expense::class ); $this->assertCount(2, $expenses); $found = $expenses->where('airline_id', null); $this->assertCount(1, $found); $found = $expenses->where('airline_id', $airline->id); $this->assertCount(1, $found); $found = $expenses->where('airline_id', $airline2->id); $this->assertCount(0, $found); /* * Test the subfleet class */ $subfleet = factory(App\Models\Subfleet::class)->create(); factory(App\Models\Expense::class)->create([ 'airline_id' => null, 'ref_model' => \App\Models\Subfleet::class, 'ref_model_id' => $subfleet->id, ]); $expenses = $this->expenseRepo->getAllForType( ExpenseType::FLIGHT, $airline->id, $subfleet ); $this->assertCount(1, $expenses); $expense = $expenses->random(); $this->assertEquals(\App\Models\Subfleet::class, $expense->ref_model); $obj = $expense->getReferencedObject(); $this->assertEquals($obj->id, $expense->ref_model_id); } /** * * @throws Exception */ public function testPirepFinances() { $journalRepo = app(JournalRepository::class); [$user, $pirep, $fares] = $this->createFullPirep(); $user->airline->initJournal(config('phpvms.currency')); # Override the fares $fare_counts = []; foreach ($fares as $fare) { $fare_counts[] = [ 'fare_id' => $fare->id, 'price' => $fare->price, 'count' => 100, ]; } $this->fareSvc->saveForPirep($pirep, $fare_counts); # This should process all of the $pirep = $this->pirepSvc->accept($pirep); $transactions = $journalRepo->getAllForObject($pirep); $this->assertCount(9, $transactions['transactions']); $this->assertEquals(3020, $transactions['credits']->getValue()); $this->assertEquals(1860, $transactions['debits']->getValue()); # Check that all the different transaction types are there # test by the different groups that exist $transaction_tags = [ 'expense' => 1, 'subfleet' => 2, 'fare' => 3, 'ground_handling' => 1, 'pilot_pay' => 2, # debit on the airline, credit to the pilot ]; foreach($transaction_tags as $type => $count) { $find = $transactions['transactions']->where('tags', $type); $this->assertEquals($count, $find->count()); } } }