seed([AuthorizationSeeder::class, SocialMediaSeeder::class]); WebsiteType::query()->create([ 'codigo' => 'onticket', 'nombre' => 'OnTicket', ]); } public function test_authentication_is_required(): void { $this->getJson('/api/v1/adminapp/tenant/event')->assertUnauthorized(); $this->putJson('/api/v1/adminapp/tenant/event', $this->eventPayload())->assertUnauthorized(); } public function test_an_adminapp_user_can_create_the_active_event_and_contact_information(): void { $tenant = $this->createTenant('acme'); Sanctum::actingAs($this->createAdminAppUser($tenant)); $response = $this->putJson('/api/v1/adminapp/tenant/event', $this->eventPayload()) ->assertOk() ->assertJsonPath('data.title', 'Festival Acme') ->assertJsonPath('data.location', 'Predio Ferial, Rosario') ->assertJsonPath('data.dates.0.date', '2026-10-09') ->assertJsonPath('data.dates.0.start_time', '09:00') ->assertJsonPath('data.dates.0.end_time', '18:30') ->assertJsonPath('data.contact.whatsapp_url', 'https://wa.me/5493415550101') ->assertJsonPath('data.contact.instagram_url', 'https://instagram.com/acme') ->assertJsonPath('data.contact.facebook_url', null); $eventId = $response->json('data.id'); $this->assertDatabaseHas('events', [ 'id' => $eventId, 'tenant_code' => $tenant->codigo, 'name' => 'Festival Acme', 'address' => 'Predio Ferial, Rosario', ]); $this->assertSame($eventId, $tenant->fresh()->active_event_id); $this->assertDatabaseHas('event_dates', [ 'event_id' => $eventId, 'date' => '2026-10-09', 'time_start' => '09:00:00', 'time_end' => '18:30:00', ]); $this->assertDatabaseHas('tenant_social_media', [ 'tenant_code' => $tenant->codigo, 'social_media_code' => 'whatsapp', 'url' => 'https://wa.me/5493415550101', ]); } public function test_an_adminapp_user_can_read_only_its_tenant_active_event(): void { $tenant = $this->createTenant('acme'); $otherTenant = $this->createTenant('other'); $this->createActiveEvent($tenant, 'Acme Event'); $this->createActiveEvent($otherTenant, 'Other Event'); Sanctum::actingAs($this->createAdminAppUser($tenant)); $this->getJson('/api/v1/adminapp/tenant/event') ->assertOk() ->assertJsonPath('data.title', 'Acme Event') ->assertJsonMissing(['title' => 'Other Event']); } public function test_reading_a_tenant_without_an_active_event_returns_not_found(): void { $tenant = $this->createTenant('acme'); Sanctum::actingAs($this->createAdminAppUser($tenant)); $this->getJson('/api/v1/adminapp/tenant/event')->assertNotFound(); } public function test_updating_reuses_the_active_event_and_synchronizes_dates_and_contact(): void { $tenant = $this->createTenant('acme'); $event = $this->createActiveEvent($tenant, 'Old Event'); $firstDate = $event->dates()->create([ 'date' => '2026-10-01', 'time_start' => '08:00', 'time_end' => '12:00', ]); $removedDate = $event->dates()->create([ 'date' => '2026-10-02', 'time_start' => '08:00', 'time_end' => '12:00', ]); $tenant->socialMedia()->attach('facebook', [ 'url' => 'https://facebook.com/old', 'orden' => 2, ]); $tenant->socialMedia()->attach('linkedin', [ 'url' => 'https://linkedin.com/company/acme', 'orden' => 3, ]); Sanctum::actingAs($this->createAdminAppUser($tenant)); $payload = $this->eventPayload(); $payload['dates'] = [[ 'date' => '2026-11-15', 'start_time' => '10:00', 'end_time' => '20:00', ]]; $this->putJson('/api/v1/adminapp/tenant/event', $payload) ->assertOk() ->assertJsonPath('data.id', $event->id) ->assertJsonPath('data.dates.0.id', $firstDate->id) ->assertJsonPath('data.contact.facebook_url', null); $this->assertDatabaseHas('event_dates', [ 'id' => $firstDate->id, 'date' => '2026-11-15', ]); $this->assertDatabaseMissing('event_dates', ['id' => $removedDate->id]); $this->assertDatabaseMissing('tenant_social_media', [ 'tenant_code' => $tenant->codigo, 'social_media_code' => 'facebook', ]); $this->assertDatabaseHas('tenant_social_media', [ 'tenant_code' => $tenant->codigo, 'social_media_code' => 'linkedin', 'url' => 'https://linkedin.com/company/acme', ]); } public function test_update_validates_event_dates_and_contact_urls(): void { $tenant = $this->createTenant('acme'); Sanctum::actingAs($this->createAdminAppUser($tenant)); $this->putJson('/api/v1/adminapp/tenant/event', [ 'title' => '', 'location' => '', 'dates' => [ ['date' => '09/10/2026', 'start_time' => '9am', 'end_time' => '18:00'], ['date' => '09/10/2026', 'start_time' => '09:00', 'end_time' => '18:00'], ], 'contact' => [ 'whatsapp_url' => 'not-a-url', 'instagram_url' => null, 'facebook_url' => null, ], ]) ->assertUnprocessable() ->assertJsonValidationErrors([ 'title', 'location', 'dates.0.date', 'dates.0.start_time', 'dates.1.date', 'contact.whatsapp_url', ]); $this->assertDatabaseCount('events', 0); } public function test_social_media_accepts_any_registered_code_and_rejects_unknown_codes(): void { $tenant = $this->createTenant('acme'); Sanctum::actingAs($this->createAdminAppUser($tenant)); $payload = $this->eventPayload(); unset($payload['contact']); $payload['social_media'] = [[ 'code' => 'linkedin', 'url' => 'https://linkedin.com/company/acme', 'orden' => 5, ]]; $this->putJson('/api/v1/adminapp/tenant/event', $payload) ->assertOk() ->assertJsonPath('data.social_media.0.code', 'linkedin') ->assertJsonPath('data.social_media.0.url', 'https://linkedin.com/company/acme') ->assertJsonPath('data.social_media.0.orden', 5); $this->assertDatabaseHas('tenant_social_media', [ 'tenant_code' => $tenant->codigo, 'social_media_code' => 'linkedin', 'url' => 'https://linkedin.com/company/acme', 'orden' => 5, ]); $payload['social_media'][0]['code'] = 'unknown'; $this->putJson('/api/v1/adminapp/tenant/event', $payload) ->assertUnprocessable() ->assertJsonValidationErrors(['social_media.0.code']); } public function test_a_customer_cannot_manage_an_event(): void { Sanctum::actingAs(User::factory()->create([ 'rol_codigo' => RoleCode::User->value, 'tenant_codigo' => null, ])); $this->getJson('/api/v1/adminapp/tenant/event')->assertForbidden(); } /** @return array */ private function eventPayload(): array { return [ 'title' => 'Festival Acme', 'location' => 'Predio Ferial, Rosario', 'dates' => [[ 'date' => '2026-10-09', 'start_time' => '09:00', 'end_time' => '18:30', ]], 'contact' => [ 'whatsapp_url' => 'https://wa.me/5493415550101', 'instagram_url' => 'https://instagram.com/acme', 'facebook_url' => null, ], ]; } private function createTenant(string $code): Tenant { return Tenant::query()->create([ 'codigo' => $code, 'nombre' => ucfirst($code), 'dominio' => "{$code}.test", 'website_type_code' => 'onticket', ]); } private function createAdminAppUser(Tenant $tenant): User { return User::factory()->create([ 'rol_codigo' => RoleCode::AdminApp->value, 'tenant_codigo' => $tenant->codigo, ]); } private function createActiveEvent(Tenant $tenant, string $name): Event { $event = $tenant->events()->create([ 'name' => $name, 'address' => 'Rosario', ]); $tenant->update(['active_event_id' => $event->id]); return $event; } }