create([ 'codigo' => RoleCode::Scanner->value, 'nombre' => 'Scanner', ]); $permission = Permission::query()->create([ 'codigo' => PermissionCode::ScanTickets->value, 'nombre' => 'Escanear tickets', ]); $scannerRole->permissions()->attach($permission->codigo); $tenant = $this->createTenant(); $home = Menu::query()->create([ 'code' => 'scanner.inicio', 'label' => 'Inicio', 'route' => '/scanner/inicio', ]); $scan = Menu::query()->create([ 'code' => 'scanner.scan', 'label' => 'Escanear', 'route' => '/scanner/scan', ]); $foreign = Menu::query()->create([ 'code' => 'adminapp.inicio', 'label' => 'Administración', 'route' => '/admin/inicio', ]); $scannerRole->menus()->sync([$home->code, $scan->code]); $tenant->menues()->sync([$home->code, $scan->code, $foreign->code]); $user = User::factory()->create([ 'rol_codigo' => $scannerRole->codigo, 'tenant_codigo' => $tenant->codigo, ]); Sanctum::actingAs($user); $this->getJson('/api/v1/scanner/me') ->assertOk() ->assertJsonPath('data.user.id', $user->id) ->assertJsonPath('data.tenant.codigo', $tenant->codigo) ->assertJsonCount(2, 'data.tenant.menues') ->assertJsonMissing(['code' => $foreign->code]); } public function test_it_rejects_an_adminapp_user_even_with_scan_permission(): void { $adminAppRole = Role::query()->create([ 'codigo' => RoleCode::AdminApp->value, 'nombre' => 'Administrador', ]); $permission = Permission::query()->create([ 'codigo' => PermissionCode::ScanTickets->value, 'nombre' => 'Escanear tickets', ]); $adminAppRole->permissions()->attach($permission->codigo); $tenant = $this->createTenant(); $adminApp = User::factory()->create([ 'rol_codigo' => $adminAppRole->codigo, 'tenant_codigo' => $tenant->codigo, ]); Sanctum::actingAs($adminApp); $this->getJson('/api/v1/scanner/me')->assertForbidden(); } public function test_it_returns_assigned_scan_categories_when_validation_is_enabled(): void { $this->createScannerRole(); $tenant = $this->createTenant(); $scanner = User::factory()->create([ 'rol_codigo' => RoleCode::Scanner->value, 'tenant_codigo' => $tenant->codigo, ]); $meals = Category::query()->create(['tenant_code' => $tenant->codigo, 'nombre' => 'Comidas']); $entries = Category::query()->create(['tenant_code' => $tenant->codigo, 'nombre' => 'Entradas']); $scanner->scanCategories()->attach([$meals->id, $entries->id]); Sanctum::actingAs($scanner); $this->getJson('/api/v1/scanner/me') ->assertOk() ->assertJsonPath('data.user.categories.0.id', $meals->id) ->assertJsonPath('data.user.categories.0.nombre', 'Comidas') ->assertJsonPath('data.user.categories.1.id', $entries->id) ->assertJsonPath('data.user.categories.1.nombre', 'Entradas'); } public function test_it_omits_scan_categories_when_validation_is_disabled_or_none_are_assigned(): void { $this->createScannerRole(); $tenant = $this->createTenant(); $scanner = User::factory()->create([ 'rol_codigo' => RoleCode::Scanner->value, 'tenant_codigo' => $tenant->codigo, ]); Sanctum::actingAs($scanner); $this->getJson('/api/v1/scanner/me') ->assertOk() ->assertJsonMissingPath('data.user.categories'); $category = Category::query()->create(['tenant_code' => $tenant->codigo, 'nombre' => 'Entradas']); $scanner->scanCategories()->attach($category); $tenant->update(['scanner_category_validation_enabled' => false]); $this->getJson('/api/v1/scanner/me') ->assertOk() ->assertJsonMissingPath('data.user.categories'); } private function createScannerRole(): Role { $role = Role::query()->create([ 'codigo' => RoleCode::Scanner->value, 'nombre' => 'Scanner', ]); $permission = Permission::query()->create([ 'codigo' => PermissionCode::ScanTickets->value, 'nombre' => 'Escanear tickets', ]); $role->permissions()->attach($permission->codigo); return $role; } private function createTenant(): Tenant { $logo = Attachment::query()->create([ 'key' => (string) Str::uuid(), 'path' => 'tests/scanner-me-logo.png', 'filename' => 'scanner-me-logo.png', 'type' => 'image', 'mime_type' => 'image/png', 'extension' => 'png', 'size' => 1, ]); return Tenant::query()->create([ 'codigo' => 'acme', 'nombre' => 'Acme', 'dominio' => 'acme.test', 'primary_color' => '#000000', 'secondary_color' => '#000000', 'danger_color' => '#000000', 'header_bg_color' => '#000000', 'footer_bg_color' => '#000000', 'header_logo_id' => $logo->id, 'footer_logo_id' => $logo->id, ]); } }