Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Claim verification model #10434

Merged
merged 15 commits into from
May 23, 2024
11 changes: 11 additions & 0 deletions api/app/Enums/ClaimVerificationResult.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace App\Enums;

enum ClaimVerificationResult
{
case ACCEPTED;
case REJECTED;
case UNVERIFIED;
// a null value represents "unclaimed"
}
10 changes: 10 additions & 0 deletions api/app/Models/PoolCandidate.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@
* @property Illuminate\Support\Carbon $removed_at
* @property string $removal_reason
* @property string $removal_reason_other
* @property string $veteran_verification
* @property Illuminate\Support\Carbon $veteran_verification_expiry
* @property string $priority_verification
* @property Illuminate\Support\Carbon $priority_verification_expiry
*/
class PoolCandidate extends Model
{
Expand All @@ -72,6 +76,8 @@ class PoolCandidate extends Model
'placed_at' => 'datetime',
'final_decision_at' => 'datetime',
'removed_at' => 'datetime',
'veteran_verification_expiry' => 'date',
'priority_verification_expiry' => 'date',
];

/**
Expand All @@ -91,6 +97,10 @@ class PoolCandidate extends Model
'pool_candidate_status',
'submitted_steps',
'education_requirement_option',
'veteran_verification',
'veteran_verification_expiry',
'priority_verification',
'priority_verification_expiry',
];

protected $touches = ['user'];
Expand Down
10 changes: 10 additions & 0 deletions api/app/Providers/GraphQLServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use App\Enums\CandidateRemovalReason;
use App\Enums\CandidateSuspendedFilter;
use App\Enums\CitizenshipStatus;
use App\Enums\ClaimVerificationResult;
use App\Enums\DirectiveForms\AdvertisementType;
use App\Enums\DirectiveForms\AdvertisingPlatform;
use App\Enums\DirectiveForms\ContractAuthority;
Expand Down Expand Up @@ -134,6 +135,15 @@ static function (): EnumType {
]);
}
);
$typeRegistry->registerLazy(
'ClaimVerificationResult',
static function (): EnumType {
return new EnumType([
'name' => 'ClaimVerificationResult',
'values' => array_column(ClaimVerificationResult::cases(), 'name'),
]);
}
);
$typeRegistry->registerLazy(
'ArmedForcesStatus',
static function (): EnumType {
Expand Down
16 changes: 16 additions & 0 deletions api/database/factories/PoolCandidateFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
namespace Database\Factories;

use App\Enums\ApplicationStep;
use App\Enums\ArmedForcesStatus;
use App\Enums\AssessmentResultType;
use App\Enums\CandidateRemovalReason;
use App\Enums\ClaimVerificationResult;
use App\Enums\EducationRequirementOption;
use App\Enums\PoolCandidateStatus;
use App\Models\AssessmentResult;
Expand Down Expand Up @@ -161,6 +163,20 @@ public function configure()
]);
$poolCandidate->educationRequirementWorkExperiences()->sync([$experience->id]);
}

// claim verification
if ($poolCandidate->user->armed_forces_status == ArmedForcesStatus::VETERAN->name) {
$poolCandidate->update([
'veteran_verification' => $this->faker->randomElement(array_column(ClaimVerificationResult::cases(), 'name')),
'veteran_verification_expiry' => $this->faker->dateTimeBetween('6 months', '24 months'),
petertgiles marked this conversation as resolved.
Show resolved Hide resolved
]);
}
if ($poolCandidate->user->has_priority_entitlement) {
$poolCandidate->update([
'priority_verification' => $this->faker->randomElement(array_column(ClaimVerificationResult::cases(), 'name')),
'priority_verification_expiry' => $this->faker->dateTimeBetween('6 months', '24 months'),
]);
}
});
}

Expand Down
4 changes: 3 additions & 1 deletion api/database/factories/UserFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ public function definition()
'accepted_operational_requirements' => $this->faker->optional->randomElements(array_column(OperationalRequirement::cases(), 'name'), 2),
'gov_employee_type' => $isGovEmployee ? $this->faker->randomElement(GovEmployeeType::cases())->name : null,
'citizenship' => $this->faker->randomElement(CitizenshipStatus::cases())->name,
'armed_forces_status' => $this->faker->randomElement(ArmedForcesStatus::cases())->name,
'armed_forces_status' => $this->faker->boolean() ?
ArmedForcesStatus::NON_CAF->name
: $this->faker->randomElement(ArmedForcesStatus::cases())->name,
Comment on lines -122 to +124
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before 2/3 of users were current/past armed forces which seemed a bit egregiously high. This small tweak just halves it.

'has_priority_entitlement' => $hasPriorityEntitlement,
'priority_number' => $hasPriorityEntitlement ? $this->faker->word() : null,
'indigenous_declaration_signature' => $isDeclared ? $this->faker->firstName() : null,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

use App\Models\PoolCandidate;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('pool_candidates', function (Blueprint $table) {
$table->string('veteran_verification')->nullable();
$table->date('veteran_verification_expiry')->nullable();
$table->string('priority_verification')->nullable();
$table->date('priority_verification_expiry')->nullable();
});

PoolCandidate::whereHas('user', function (Builder $query) {
$query->where('armed_forces_status', 'VETERAN');
})->update(['veteran_verification' => 'UNVERIFIED']);
PoolCandidate::whereHas('user', function (Builder $query) {
$query->where('has_priority_entitlement', true);
})->update(['priority_verification' => 'UNVERIFIED']);
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('pool_candidates', function (Blueprint $table) {
$table->dropColumn('veteran_verification');
$table->dropColumn('veteran_verification_expiry');
$table->dropColumn('priority_verification');
$table->dropColumn('priority_verification_expiry');
});
}
};
29 changes: 29 additions & 0 deletions api/graphql/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,20 @@ type PoolCandidate {
@rename(attribute: "placed_at")
@canRoot(ability: "viewStatus")
placedDepartment: Department @belongsTo @canRoot(ability: "viewStatus")

# claim verification
veteranVerification: ClaimVerificationResult
@rename(attribute: "veteran_verification")
@canRoot(ability: "viewNotes")
veteranVerificationExpiry: Date
@rename(attribute: "veteran_verification_expiry")
@canRoot(ability: "viewNotes")
priorityVerification: ClaimVerificationResult
@rename(attribute: "priority_verification")
@canRoot(ability: "viewNotes")
priorityVerificationExpiry: Date
@rename(attribute: "priority_verification_expiry")
@canRoot(ability: "viewNotes")
}

type PoolCandidateWithSkillCount {
Expand Down Expand Up @@ -1170,6 +1184,17 @@ input UpdatePoolCandidateStatusInput {
status: PoolCandidateStatus @rename(attribute: "pool_candidate_status")
}

input UpdatePoolCandidateClaimVerificationInput {
veteranVerification: ClaimVerificationResult
@rename(attribute: "veteran_verification")
veteranVerificationExpiry: Date
@rename(attribute: "veteran_verification_expiry")
priorityVerification: ClaimVerificationResult
@rename(attribute: "priority_verification")
priorityVerificationExpiry: Date
@rename(attribute: "priority_verification_expiry")
}

input PlaceCandidateInput {
placementType: PlacementType!
departmentId: UUID!
Expand Down Expand Up @@ -1716,6 +1741,10 @@ type Mutation {
model: "PoolCandidate"
injectArgs: true
)
updatePoolCandidateClaimVerification(
petertgiles marked this conversation as resolved.
Show resolved Hide resolved
id: UUID!
poolCandidate: UpdatePoolCandidateClaimVerificationInput! @spread
): PoolCandidate @update @guard @canFind(ability: "updateNotes", find: "id")
updatePoolCandidateNotes(id: UUID!, notes: String): PoolCandidate
@update
@guard
Expand Down
18 changes: 18 additions & 0 deletions api/storage/app/lighthouse-schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ type Mutation {
createPoolCandidateAsAdmin(poolCandidate: CreatePoolCandidateAsAdminInput!): PoolCandidate
updatePoolCandidateStatus(id: UUID!, poolCandidate: UpdatePoolCandidateStatusInput!): PoolCandidate
togglePoolCandidateBookmark(id: ID!): Boolean
updatePoolCandidateClaimVerification(id: UUID!, poolCandidate: UpdatePoolCandidateClaimVerificationInput!): PoolCandidate
updatePoolCandidateNotes(id: UUID!, notes: String): PoolCandidate
removeCandidate(id: UUID!, removalReason: CandidateRemovalReason!, removalReasonOther: String): PoolCandidate
reinstateCandidate(id: UUID!): PoolCandidate
Expand Down Expand Up @@ -449,6 +450,10 @@ type PoolCandidate {
finalDecisionAt: DateTime
placedAt: DateTime
placedDepartment: Department
veteranVerification: ClaimVerificationResult
veteranVerificationExpiry: Date
priorityVerification: ClaimVerificationResult
priorityVerificationExpiry: Date
}

type PoolCandidateWithSkillCount {
Expand Down Expand Up @@ -1024,6 +1029,13 @@ input UpdatePoolCandidateStatusInput {
status: PoolCandidateStatus
}

input UpdatePoolCandidateClaimVerificationInput {
veteranVerification: ClaimVerificationResult
veteranVerificationExpiry: Date
priorityVerification: ClaimVerificationResult
priorityVerificationExpiry: Date
}

input PlaceCandidateInput {
placementType: PlacementType!
departmentId: UUID!
Expand Down Expand Up @@ -2066,6 +2078,12 @@ enum CitizenshipStatus {
OTHER
}

enum ClaimVerificationResult {
ACCEPTED
REJECTED
UNVERIFIED
}

enum ArmedForcesStatus {
VETERAN
MEMBER
Expand Down
71 changes: 71 additions & 0 deletions api/tests/Feature/PoolCandidateUpdateTest.php
petertgiles marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?php

use App\Enums\ArmedForcesStatus;
use App\Enums\CandidateRemovalReason;
use App\Enums\ClaimVerificationResult;
use App\Enums\DisqualificationReason;
use App\Enums\EducationRequirementOption;
use App\Enums\PlacementType;
Expand Down Expand Up @@ -808,4 +810,73 @@ public function testPoolCandidateReinstatement(): void
->assertGraphQLErrorMessage('CandidateUnexpectedStatus');
}
}

public function testUpdatePoolCandidateClaimVerification(): void
{
$user = User::factory()->create([
'armed_forces_status' => ArmedForcesStatus::VETERAN->name,
'has_priority_entitlement' => true,

]);
$candidate = PoolCandidate::factory()->create([
'user_id' => $user->id,
'pool_id' => $this->teamPool->id,
'veteran_verification' => ClaimVerificationResult::UNVERIFIED->name,
'veteran_verification_expiry' => null,
'priority_verification' => ClaimVerificationResult::UNVERIFIED->name,
'priority_verification_expiry' => null,
]);

$updateClaimVerificationDocument =
/** @lang GraphQL */
'
mutation updatePoolCandidateClaimVerification($id: UUID!, $poolCandidate: UpdatePoolCandidateClaimVerificationInput!) {
updatePoolCandidateClaimVerification (id: $id, poolCandidate: $poolCandidate){
id
veteranVerification
veteranVerificationExpiry
priorityVerification
priorityVerificationExpiry
}
}
';

// user can't update own claim
$this->actingAs($user, 'api')
->graphQL(
$updateClaimVerificationDocument,
[
'id' => $candidate->id,
'poolCandidate' => [
'veteranVerification' => ClaimVerificationResult::ACCEPTED->name,
'veteranVerificationExpiry' => '',
'priorityVerification' => ClaimVerificationResult::ACCEPTED->name,
'priorityVerificationExpiry' => '',
],
]
)
->assertGraphQLErrorMessage($this->unauthorizedMessage);

// operator successfully updates claim verification
$this->actingAs($this->poolOperatorUser, 'api')
->graphQL(
$updateClaimVerificationDocument,
[
'id' => $candidate->id,
'poolCandidate' => [
'veteranVerification' => ClaimVerificationResult::ACCEPTED->name,
'veteranVerificationExpiry' => config('constants.far_future_date'),
'priorityVerification' => ClaimVerificationResult::REJECTED->name,
'priorityVerificationExpiry' => '',
],
]
)
->assertJsonFragment([
'id' => $candidate->id,
'veteranVerification' => ClaimVerificationResult::ACCEPTED->name,
'veteranVerificationExpiry' => config('constants.far_future_date'),
'priorityVerification' => ClaimVerificationResult::REJECTED->name,
'priorityVerificationExpiry' => null,
]);
}
}