seed(RoleSeeder::class); $this->organisation = Organisation::factory()->create(); $this->otherOrganisation = Organisation::factory()->create(); $this->orgAdmin = User::factory()->create(); $this->organisation->users()->attach($this->orgAdmin, ['role' => 'org_admin']); $this->member = User::factory()->create([ 'first_name' => 'Jan', 'last_name' => 'de Vries', 'email' => 'jan@test.nl', ]); $this->organisation->users()->attach($this->member, ['role' => 'org_member']); $this->outsider = User::factory()->create(); $this->otherOrganisation->users()->attach($this->outsider, ['role' => 'org_admin']); $this->event = Event::factory()->create(['organisation_id' => $this->organisation->id]); $this->crowdType = CrowdType::factory()->systemType('CREW')->create([ 'organisation_id' => $this->organisation->id, ]); } // --- Available for event --- public function test_available_for_event_returns_members_not_yet_person(): void { Sanctum::actingAs($this->orgAdmin); $response = $this->getJson( "/api/v1/organisations/{$this->organisation->id}/members/available-for-event/{$this->event->id}" ); $response->assertOk(); $data = $response->json('data'); // Both orgAdmin and member should be available (neither is a person yet) $this->assertCount(2, $data); $ids = collect($data)->pluck('id')->all(); $this->assertContains($this->orgAdmin->id, $ids); $this->assertContains($this->member->id, $ids); } public function test_available_for_event_excludes_already_added_members(): void { // Add member as a person $person = Person::factory()->create([ 'event_id' => $this->event->id, 'crowd_type_id' => $this->crowdType->id, ]); $person->user_id = $this->member->id; $person->save(); Sanctum::actingAs($this->orgAdmin); $response = $this->getJson( "/api/v1/organisations/{$this->organisation->id}/members/available-for-event/{$this->event->id}" ); $response->assertOk(); $ids = collect($response->json('data'))->pluck('id')->all(); $this->assertNotContains($this->member->id, $ids); $this->assertContains($this->orgAdmin->id, $ids); } public function test_available_for_event_returns_correct_fields(): void { Sanctum::actingAs($this->orgAdmin); $response = $this->getJson( "/api/v1/organisations/{$this->organisation->id}/members/available-for-event/{$this->event->id}" ); $response->assertOk() ->assertJsonStructure([ 'data' => [ '*' => ['id', 'first_name', 'last_name', 'full_name', 'email'], ], ]); } public function test_available_for_event_unauthenticated_returns_401(): void { $response = $this->getJson( "/api/v1/organisations/{$this->organisation->id}/members/available-for-event/{$this->event->id}" ); $response->assertUnauthorized(); } public function test_available_for_event_wrong_org_returns_403(): void { Sanctum::actingAs($this->outsider); $response = $this->getJson( "/api/v1/organisations/{$this->organisation->id}/members/available-for-event/{$this->event->id}" ); $response->assertForbidden(); } // --- Create person from member --- public function test_create_from_member_creates_person_with_user_id(): void { Sanctum::actingAs($this->orgAdmin); $response = $this->postJson( "/api/v1/organisations/{$this->organisation->id}/events/{$this->event->id}/persons/from-member", [ 'user_id' => $this->member->id, 'crowd_type_id' => $this->crowdType->id, ], ); $response->assertCreated() ->assertJsonPath('data.first_name', 'Jan') ->assertJsonPath('data.last_name', 'de Vries') ->assertJsonPath('data.email', 'jan@test.nl') ->assertJsonPath('data.status', 'approved') ->assertJsonPath('data.has_user_account', true); $this->assertDatabaseHas('persons', [ 'event_id' => $this->event->id, 'user_id' => $this->member->id, 'first_name' => 'Jan', 'last_name' => 'de Vries', 'status' => 'approved', ]); } public function test_create_from_member_duplicate_returns_422(): void { // Add member as a person first $person = Person::factory()->create([ 'event_id' => $this->event->id, 'crowd_type_id' => $this->crowdType->id, ]); $person->user_id = $this->member->id; $person->save(); Sanctum::actingAs($this->orgAdmin); $response = $this->postJson( "/api/v1/organisations/{$this->organisation->id}/events/{$this->event->id}/persons/from-member", [ 'user_id' => $this->member->id, 'crowd_type_id' => $this->crowdType->id, ], ); $response->assertUnprocessable() ->assertJsonValidationErrors('user_id'); } public function test_create_from_member_user_not_in_org_returns_422(): void { Sanctum::actingAs($this->orgAdmin); $response = $this->postJson( "/api/v1/organisations/{$this->organisation->id}/events/{$this->event->id}/persons/from-member", [ 'user_id' => $this->outsider->id, 'crowd_type_id' => $this->crowdType->id, ], ); $response->assertUnprocessable() ->assertJsonValidationErrors('user_id'); } public function test_create_from_member_unauthenticated_returns_401(): void { $response = $this->postJson( "/api/v1/organisations/{$this->organisation->id}/events/{$this->event->id}/persons/from-member", [ 'user_id' => $this->member->id, 'crowd_type_id' => $this->crowdType->id, ], ); $response->assertUnauthorized(); } public function test_create_from_member_wrong_org_returns_403(): void { Sanctum::actingAs($this->outsider); $response = $this->postJson( "/api/v1/organisations/{$this->organisation->id}/events/{$this->event->id}/persons/from-member", [ 'user_id' => $this->member->id, 'crowd_type_id' => $this->crowdType->id, ], ); $response->assertForbidden(); } public function test_create_from_member_logs_activity(): void { Sanctum::actingAs($this->orgAdmin); $this->postJson( "/api/v1/organisations/{$this->organisation->id}/events/{$this->event->id}/persons/from-member", [ 'user_id' => $this->member->id, 'crowd_type_id' => $this->crowdType->id, ], )->assertCreated(); $this->assertDatabaseHas('activity_log', [ 'description' => 'person.created_from_member', 'causer_id' => $this->orgAdmin->id, ]); } }