diff --git a/api/database/seeders/DevSeeder.php b/api/database/seeders/DevSeeder.php index b99fb9df..2433ab4c 100644 --- a/api/database/seeders/DevSeeder.php +++ b/api/database/seeders/DevSeeder.php @@ -586,8 +586,9 @@ class DevSeeder extends Seeder // Person with unique email (no match expected) Person::create(['event_id' => $festival->id, 'crowd_type_id' => $vol, 'first_name' => 'Unique', 'last_name' => 'Persoon', 'email' => 'unique.persoon@nowhere.test', 'phone' => '+31612345044', 'status' => 'pending']); + $linked = $this->linkUsersToApprovedPersons($festival); $personCount = Person::where('event_id', $festival->id)->count(); - $this->command->info(" {$personCount} persons created"); + $this->command->info(" {$personCount} persons created ({$linked} user accounts linked)"); // ── Named shift assignments (22) ── @@ -975,6 +976,8 @@ class DevSeeder extends Seeder Person::factory()->count(3)->create(['event_id' => $braderie->id, 'crowd_type_id' => $vol, 'status' => 'pending']); Person::factory()->count(2)->create(['event_id' => $braderie->id, 'crowd_type_id' => $vol, 'status' => 'applied']); + $this->linkUsersToApprovedPersons($braderie); + $this->command->info(' Braderie Dorpstown 2026 complete'); }); } @@ -1094,6 +1097,8 @@ class DevSeeder extends Seeder Person::factory()->count(2)->create(['event_id' => $ijsbaan->id, 'crowd_type_id' => $crewType, 'status' => 'pending']); Person::factory()->count(5)->approved()->create(['event_id' => $ijsbaan->id, 'crowd_type_id' => $guestType]); + $this->linkUsersToApprovedPersons($ijsbaan); + // ── Shift assignments (~80) ── $openShifts = collect($allShifts)->filter(fn (Shift $shift) => $shift->status === 'open' && $shift->slots_open_for_claiming > 0); @@ -1241,6 +1246,8 @@ class DevSeeder extends Seeder // 2 suppliers Person::factory()->count(2)->approved()->create(['event_id' => $koningsdag->id, 'crowd_type_id' => $supplierType]); + $this->linkUsersToApprovedPersons($koningsdag); + // ── Shift assignments (~150) ── // 120 completed + 12 cancelled + 8 no-show + 5 rejected + 5 pending @@ -1348,6 +1355,36 @@ class DevSeeder extends Seeder // Helpers // ========================================================================= + /** + * Create User accounts for approved/no_show persons that lack one. + * Mirrors the production approval flow (PersonController::approve). + */ + private function linkUsersToApprovedPersons(Event $event): int + { + $linked = 0; + + Person::withoutGlobalScopes() + ->where('event_id', $event->id) + ->whereIn('status', ['approved', 'no_show']) + ->whereNull('user_id') + ->each(function (Person $person) use (&$linked): void { + $user = User::firstOrCreate( + ['email' => strtolower($person->email)], + [ + 'first_name' => $person->first_name, + 'last_name' => $person->last_name, + 'password' => Hash::make('password'), + ] + ); + + $person->user_id = $user->id; + $person->save(); + $linked++; + }); + + return $linked; + } + private function createCrowdList( Event $event, string $name, diff --git a/api/tests/Feature/Person/PersonTest.php b/api/tests/Feature/Person/PersonTest.php index a6e0a291..60572577 100644 --- a/api/tests/Feature/Person/PersonTest.php +++ b/api/tests/Feature/Person/PersonTest.php @@ -196,4 +196,47 @@ class PersonTest extends TestCase $response->assertUnauthorized(); } + + public function test_approve_creates_user_account_for_person(): void + { + $person = Person::factory()->create([ + 'event_id' => $this->event->id, + 'crowd_type_id' => $this->crowdType->id, + 'status' => 'pending', + 'email' => 'volunteer@example.com', + ]); + + $this->assertNull($person->user_id); + + Sanctum::actingAs($this->orgAdmin); + + $response = $this->postJson("/api/v1/organisations/{$this->organisation->id}/events/{$this->event->id}/persons/{$person->id}/approve"); + + $response->assertOk(); + $person->refresh(); + + $this->assertNotNull($person->user_id); + $this->assertDatabaseHas('users', ['email' => 'volunteer@example.com']); + } + + public function test_approve_reuses_existing_user_account(): void + { + $existingUser = User::factory()->create(['email' => 'existing@example.com']); + + $person = Person::factory()->create([ + 'event_id' => $this->event->id, + 'crowd_type_id' => $this->crowdType->id, + 'status' => 'pending', + 'email' => 'existing@example.com', + ]); + + Sanctum::actingAs($this->orgAdmin); + + $this->postJson("/api/v1/organisations/{$this->organisation->id}/events/{$this->event->id}/persons/{$person->id}/approve") + ->assertOk(); + + $person->refresh(); + + $this->assertEquals($existingUser->id, $person->user_id); + } }