diff --git a/app/Models/Atc/PositionGroup.php b/app/Models/Atc/PositionGroup.php index cbbffc45f2..e0a45df5fe 100644 --- a/app/Models/Atc/PositionGroup.php +++ b/app/Models/Atc/PositionGroup.php @@ -27,7 +27,7 @@ public function conditions() public function positions() { - return $this->belongsToMany(Position::class, 'position_group_positions', 'position_group_id', 'position_id')->using(PositionGroupPosition::class); + return $this->belongsToMany(Position::class, 'position_group_positions', 'position_group_id', 'position_id'); } public function endorsement() diff --git a/app/Models/Atc/PositionGroupPosition.php b/app/Models/Atc/PositionGroupPosition.php index 3b9444a5b1..9ac55ae95e 100644 --- a/app/Models/Atc/PositionGroupPosition.php +++ b/app/Models/Atc/PositionGroupPosition.php @@ -2,9 +2,9 @@ namespace App\Models\Atc; -use Illuminate\Database\Eloquent\Relations\Pivot; +use App\Models\Model; -class PositionGroupPosition extends Pivot +class PositionGroupPosition extends Model { public function positionGroup() { diff --git a/app/Models/Roster.php b/app/Models/Roster.php index f2f13a02f6..22189a8ebf 100644 --- a/app/Models/Roster.php +++ b/app/Models/Roster.php @@ -6,7 +6,6 @@ use App\Models\Atc\PositionGroup; use App\Models\Atc\PositionGroupPosition; use App\Models\Mship\Account; -use App\Models\Mship\Account\Endorsement; use App\Models\Mship\Qualification; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; @@ -68,20 +67,11 @@ public function accountCanControl(Position $position) return false; } - $assignedPositionGroupsWithPosition = Endorsement::where('account_id', $this->account->id) - ->whereHasMorph('endorsable', PositionGroup::class, fn ($query) => $query->whereHas('positions', fn ($query) => $query->where('positions.id', $position->id))) - ->get() - ->map(fn ($endorsement) => $endorsement->endorsable); - - $unassignedPositionGroupsWithPosition = PositionGroup::whereHas('positions', fn ($query) => $query->where('positions.id', $position->id)) - ->whereDoesntHave('membershipEndorsement', fn ($query) => $query->where('account_id', $this->account->id)) - ->get(); - - $checkPositionForPositionGroup = function (PositionGroupPosition $positionGroupPosition) { - // If the position is part of a group, - // a) are they a home member with a rating above the position's maximum? - // b) are they a visiting or transferring member with an endorsement up to a rating above the position group's maximum? - // c) are they endorsed on this specific position group? + // If the position is part of a group, + // a) are they a home member with a rating above the position's maximum? + // b) are they a visiting or transferring member with an endorsement up to a rating above the position group's maximum? + // c) are they endorsed on this specific position group? + if ($positionGroupPosition = PositionGroupPosition::where('position_id', $position->id)->first()) { $isEntitledByHomeMemberRating = isset($positionGroupPosition->positionGroup?->maximumAtcQualification) && $this->account->hasState('DIVISION') && $this->account->qualification_atc->vatsim > $positionGroupPosition->positionGroup?->maximumAtcQualification?->vatsim; @@ -108,28 +98,6 @@ public function accountCanControl(Position $position) ->exists(); return $isEntitledByHomeMemberRating || $isEndorsedToRating || $hasEndorsementForPositionGroup; - }; - - /** If there are a PositionGroup(s) which contain the specified position - * perform a series of checks to determine if the account is entitled to - * control the position */ - if ($assignedPositionGroupsWithPosition->count() > 0) { - return $assignedPositionGroupsWithPosition->some(fn ($positionGroup) => $checkPositionForPositionGroup($positionGroup->positions->where('id', $position->id)->first()->pivot)); - } - - /** Check any unassigned position groups have a maximum atc qualification - * if so, check if the account has a rating above the maximum specified - * qualification and if so, they are entitled to control even if the - * position group hasn't been endorsed to that member. */ - $unassignedPositionGroupsWithPositionWithMaxRating = $unassignedPositionGroupsWithPosition->filter(fn ($positionGroup) => isset($positionGroup->maximumAtcQualification)); - if ($unassignedPositionGroupsWithPositionWithMaxRating->count() > 0) { - return $unassignedPositionGroupsWithPosition->some( - function (PositionGroup $positionGroup) use ($position) { - $positionGroupPosition = $positionGroup->positions->where('id', $position->id)->first()->pivot; - - return $this->account->qualification_atc->vatsim > $positionGroupPosition->positionGroup->maximumAtcQualification->vatsim; - } - ); } // If the position is above their rating, do they diff --git a/tests/Unit/Roster/AccountCanControlTest.php b/tests/Unit/Roster/AccountCanControlTest.php deleted file mode 100644 index 0837168869..0000000000 --- a/tests/Unit/Roster/AccountCanControlTest.php +++ /dev/null @@ -1,358 +0,0 @@ -first(); - $account = Account::factory()->create(); - $account->addQualification($qualification); - $account->addState(State::findByCode('DIVISION')); - - $position = Position::factory()->create([ - 'type' => Position::TYPE_TOWER, - ]); - - $roster = Roster::create([ - 'account_id' => $account->id, - ]); - - $this->assertTrue($roster->accountCanControl($position)); - } - - public function test_detects_cannot_control_with_rating_when_visiting_without_endorsement() - { - $qualification = Qualification::code('S2')->first(); - $account = Account::factory()->create(); - $account->addQualification($qualification); - $account->addState(State::findByCode('VISITING')); - - $position = Position::factory()->create([ - 'type' => Position::TYPE_TOWER, - ]); - - $roster = Roster::create([ - 'account_id' => $account->id, - ]); - - $this->assertFalse($roster->accountCanControl($position)); - } - - public function test_detects_cannot_control_with_rating_when_transferring_without_endorsement() - { - $qualification = Qualification::code('S2')->first(); - $account = Account::factory()->create(); - $account->addQualification($qualification); - $account->addState(State::findByCode('TRANSFERRING')); - - $position = Position::factory()->create([ - 'type' => Position::TYPE_TOWER, - ]); - - $roster = Roster::create([ - 'account_id' => $account->id, - ]); - - $this->assertFalse($roster->accountCanControl($position)); - } - - public function test_detects_can_control_with_rating_when_visiting_with_endorsement() - { - $qualification = Qualification::code('S2')->first(); - $account = Account::factory()->create(); - $account->addQualification($qualification); - $account->addState(State::findByCode('VISITING')); - - $position = Position::factory()->create([ - 'type' => Position::TYPE_TOWER, - ]); - - $roster = Roster::create([ - 'account_id' => $account->id, - ]); - - Endorsement::create([ - 'account_id' => $account->id, - 'endorsable_type' => Qualification::class, - 'endorsable_id' => $qualification->id, - 'created_by' => $this->privacc->id, - ]); - - $this->assertTrue($roster->accountCanControl($position)); - } - - public function test_detects_can_control_with_rating_when_transferring_with_endorsement() - { - $qualification = Qualification::code('S2')->first(); - $account = Account::factory()->create(); - $account->addQualification($qualification); - $account->addState(State::findByCode('TRANSFERRING')); - - $position = Position::factory()->create([ - 'type' => Position::TYPE_TOWER, - ]); - - $roster = Roster::create([ - 'account_id' => $account->id, - ]); - - Endorsement::create([ - 'account_id' => $account->id, - 'endorsable_type' => Qualification::class, - 'endorsable_id' => $qualification->id, - 'created_by' => $this->privacc->id, - ]); - - $this->assertTrue($roster->accountCanControl($position)); - } - - public function test_detects_cannot_control_if_region_member() - { - $qualification = Qualification::code('S2')->first(); - $account = Account::factory()->create(); - $account->addQualification($qualification); - $account->addState(State::findByCode('REGION')); - - $position = Position::factory()->create([ - 'type' => Position::TYPE_TOWER, - ]); - - $roster = Roster::create([ - 'account_id' => $account->id, - ]); - - $this->assertFalse($roster->accountCanControl($position)); - } - - public function test_detects_cannot_control_if_international_member() - { - $qualification = Qualification::code('S2')->first(); - $account = Account::factory()->create(); - $account->addQualification($qualification); - $account->addState(State::findByCode('INTERNATIONAL')); - - $position = Position::factory()->create([ - 'type' => Position::TYPE_TOWER, - ]); - - $roster = Roster::create([ - 'account_id' => $account->id, - ]); - - $this->assertFalse($roster->accountCanControl($position)); - } - - public function test_handles_position_being_part_of_multiple_position_groups_when_endorsed() - { - $position = Position::factory()->create(); - - $positionGroup1 = PositionGroup::factory()->create(); - $positionGroup2 = PositionGroup::factory()->create(['id' => $positionGroup1->id + 1]); - $positionGroup1->positions()->attach($position); - $positionGroup2->positions()->attach($position); - - Endorsement::create([ - 'account_id' => $this->user->id, - 'endorsable_type' => PositionGroup::class, - 'endorsable_id' => $positionGroup2->id, - 'created_by' => $this->privacc->id, - ]); - - $roster = Roster::create([ - 'account_id' => $this->user->id, - ]); - - $this->assertEquals($roster->accountCanControl($position), true); - } - - public function test_detects_can_control_with_position_group_assigned() - { - $position = Position::factory()->create(); - $positionGroup = PositionGroup::factory()->create(); - $positionGroup->positions()->attach($position); - - Endorsement::create([ - 'account_id' => $this->user->id, - 'endorsable_type' => PositionGroup::class, - 'endorsable_id' => $positionGroup->id, - 'created_by' => $this->privacc->id, - ]); - - $roster = Roster::create([ - 'account_id' => $this->user->id, - ]); - - $this->assertEquals($roster->accountCanControl($position), true); - } - - public function test_detects_cannot_control_position_when_not_grated_to_user_as_visitor_even_if_rated() - { - $position = Position::factory(['type' => Position::TYPE_TOWER])->create(); - $positionGroup = PositionGroup::factory()->create(); - $positionGroup->positions()->attach($position); - - $visitorAccount = Account::factory()->create(); - $visitorAccount->addQualification(Qualification::code('S2')->first()); - $visitorAccount->addState(State::findByCode('VISITING')); - - $roster = Roster::create([ - 'account_id' => $visitorAccount->id, - ]); - - $this->assertEquals($roster->accountCanControl($position), false); - } - - public function test_detects_cannot_control_position_when_not_grated_to_user_as_transferring_even_if_rated() - { - $position = Position::factory(['type' => Position::TYPE_TOWER])->create(); - $positionGroup = PositionGroup::factory()->create(); - $positionGroup->positions()->attach($position); - - $transferringAccount = Account::factory()->create(); - $transferringAccount->addQualification(Qualification::code('S2')->first()); - $transferringAccount->addState(State::findByCode('TRANSFERRING')); - - $roster = Roster::create([ - 'account_id' => $transferringAccount->id, - ]); - - $this->assertEquals($roster->accountCanControl($position), false); - } - - public function test_detects_solo_endorsement_when_position_above_rating() - { - $qualification = Qualification::code('S2')->first(); - Qualification::code('S3')->first(); - - $account = Account::factory()->create(); - $account->addQualification($qualification); - - // approach exceeds the 'S2' requirements' VATSIM attribute. - $position = Position::factory()->create([ - 'type' => Position::TYPE_APPROACH, - 'temporarily_endorsable' => true, - ]); - - $roster = Roster::create([ - 'account_id' => $account->id, - ]); - - Endorsement::create([ - 'account_id' => $account->id, - 'endorsable_type' => Position::class, - 'endorsable_id' => $position->id, - 'created_by' => $this->privacc->id, - 'expires_at' => now()->addDays(1), - ]); - - $this->assertTrue($roster->accountCanControl($position)); - } - - public function test_detects_when_solo_endorsement_expired() - { - $qualification = Qualification::code('S2')->first(); - - $account = Account::factory()->create(); - $account->addQualification($qualification); - $account->addState(State::findByCode('DIVISION')); - - $roster = Roster::create([ - 'account_id' => $account->id, - ]); - - // approach exceeds the 'S2' requirements' VATSIM attribute. - $position = Position::factory()->create([ - 'type' => Position::TYPE_APPROACH, - 'temporarily_endorsable' => true, - ]); - - Endorsement::create([ - 'account_id' => $account->id, - 'endorsable_type' => Position::class, - 'endorsable_id' => $position->id, - 'created_by' => $this->privacc->id, - 'expires_at' => now()->subDays(1), - ]); - - $this->assertFalse($roster->accountCanControl($position)); - } - - public function test_detects_can_control_with_direct_endorsement_without_expiry() - { - $position = Position::factory()->create(); - - $roster = Roster::create([ - 'account_id' => $this->user->id, - ]); - - Endorsement::create([ - 'account_id' => $this->user->id, - 'endorsable_type' => Position::class, - 'endorsable_id' => $position->id, - 'created_by' => $this->privacc->id, - ]); - - $this->assertTrue($roster->accountCanControl($position)); - } - - public function test_can_control_when_endorsement_not_assigned_but_rating_facilitates() - { - $lowerQualification = Qualification::code('S1')->first(); - $qualification = Qualification::code('S2')->first(); - $account = Account::factory()->create(); - $account->addQualification($qualification); - $account->addState(State::findByCode('DIVISION')); - - $position = Position::factory()->create([ - 'type' => Position::TYPE_TOWER, - ]); - - $positionGroup = PositionGroup::factory()->create(['maximum_atc_qualification_id' => $lowerQualification->id]); - $positionGroup->positions()->attach($position); - - $roster = Roster::create([ - 'account_id' => $account->id, - ]); - - $this->assertTrue($roster->accountCanControl($position)); - } - - public function test_can_control_when_endorsed_to_qualification() - { - $qualification = Qualification::code('S2')->first(); - $account = Account::factory()->create(); - $account->addQualification($qualification); - $account->addState(State::findByCode('VISITING')); - - $position = Position::factory()->create([ - 'type' => Position::TYPE_TOWER, - ]); - - Endorsement::create([ - 'account_id' => $account->id, - 'endorsable_type' => Qualification::class, - 'endorsable_id' => $qualification->id, - 'created_by' => $this->privacc->id, - ]); - - $roster = Roster::create([ - 'account_id' => $account->id, - ]); - - $this->assertTrue($roster->accountCanControl($position)); - } -}