diff --git a/app/Http/Controllers/ChamadoController.php b/app/Http/Controllers/ChamadoController.php index b572aa6..4cc2aeb 100644 --- a/app/Http/Controllers/ChamadoController.php +++ b/app/Http/Controllers/ChamadoController.php @@ -539,7 +539,7 @@ public function storePessoa(Request $request, Chamado $chamado) $request->validate( [ - 'codpes' => ['required', 'regex:/^((codpes|id)-)?\d+$/'], + 'codpes' => User::identificadorRules, 'papel' => 'required|in:' . implode(',', Chamado::pessoaPapeis()), ] ); @@ -552,15 +552,7 @@ public function storePessoa(Request $request, Chamado $chamado) $this->authorize('atendente'); } - if (is_numeric($codpesField)) { - $user = User::obterOuCriarPorCodpes((int) $codpesField); - } else { - [$searchField, $valueField] = explode('-', $codpesField, 2); - - $user = $searchField === 'codpes' - ? User::obterOuCriarPorCodpes((int) $valueField) - : User::find((int) $valueField); - } + $user = User::obterOuCriarPorIdentificador($codpesField); if (empty($user)) { return back()->withErrors(['codpes' => 'Usuário não encontrado.'])->withInput(); diff --git a/app/Http/Controllers/FilaController.php b/app/Http/Controllers/FilaController.php index 6090a98..a9b00f5 100644 --- a/app/Http/Controllers/FilaController.php +++ b/app/Http/Controllers/FilaController.php @@ -183,11 +183,19 @@ public function storePessoa(Request $request, Fila $fila) { $this->authorize('filas.update', $fila); - [$searchField, $valueField] = explode('-', $request->codpes_id); + // codpes era o nome usado por clientes antigos; o formulário atual usa codpes_id. + $identificador = $request->input('codpes_id', $request->input('codpes')); + $request->merge(['codpes_id' => $identificador]); + $request->validate([ + 'codpes_id' => User::identificadorRules, + 'funcao' => 'required|in:Gerente,Atendente', + ]); + + $user = User::obterOuCriarPorIdentificador($identificador); + if (empty($user)) { + return back()->withErrors(['codpes_id' => 'Usuário não encontrado.'])->withInput(); + } - $user = $searchField === 'codpes' ? - User::obterOuCriarPorCodpes($valueField) : - User::find($valueField); $fila->users()->detach($user->id); $fila->users()->attach($user->id, ['funcao' => $request->funcao]); diff --git a/app/Http/Controllers/SetorController.php b/app/Http/Controllers/SetorController.php index 46e1f49..a8e2388 100644 --- a/app/Http/Controllers/SetorController.php +++ b/app/Http/Controllers/SetorController.php @@ -136,7 +136,15 @@ public function storePessoa(Request $request, Setor $setor) { $this->authorize('setores.view', $setor); - $user = User::obterOuCriarPorCodpes($request->codpes); + $request->validate([ + 'codpes' => User::identificadorRules, + ]); + + $user = User::obterOuCriarPorIdentificador($request->codpes); + if (empty($user)) { + return back()->withErrors(['codpes' => 'Usuário não encontrado.'])->withInput(); + } + Setor::vincularPessoa($setor, $user, 'Gerente'); $request->session()->flash('alert-info', 'Pessoa adicionada com sucesso'); diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index a0fe951..b0cbdf7 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -50,7 +50,16 @@ public function create() public function store(Request $request) { $this->authorize('admin'); - User::obterOuCriarPorCodpes($request->codpes); + + $request->validate([ + 'codpes' => User::identificadorRules, + ]); + + $user = User::obterOuCriarPorIdentificador($request->codpes); + if (empty($user)) { + return back()->withErrors(['codpes' => 'Usuário não encontrado.'])->withInput(); + } + $request->session()->flash('alert-info', 'Atendente adicionado com sucesso'); return redirect('/users'); } diff --git a/app/Models/User.php b/app/Models/User.php index 7172078..ce68a13 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -62,6 +62,11 @@ class User extends Authenticatable 'telefone' => '', ]; + public const identificadorRules = [ + 'required', + 'regex:/^((codpes|id)-)?\d+$/', + ]; + protected const fields = [ [ 'name' => 'codpes', @@ -106,6 +111,7 @@ public static function getFields() public static function criarPorCodpes($codpes) { + $codpes = (int) $codpes; $user = new User; $user->codpes = $codpes; if (config('chamados.usar_replicado')) { @@ -131,6 +137,35 @@ public static function obterPorCodpes($codpes) return User::where('codpes', $codpes)->first(); } + /** + * Resolve um identificador vindo da busca de pessoas. + * + * Identificadores codpes-* apontam para uma pessoa do Replicado e + * identificadores id-* apontam para um usuário já existente na base local. + * Números sem prefixo são aceitos para compatibilidade com chamadas antigas. + * + * @param string|int|null $identificador + * @return User|null + */ + public static function obterOuCriarPorIdentificador($identificador) + { + $identificador = (string) $identificador; + + if (ctype_digit($identificador)) { + return self::obterOuCriarPorCodpes((int) $identificador); + } + + if (!preg_match('/^(codpes|id)-(\d+)$/', $identificador, $matches)) { + return null; + } + + $valor = (int) $matches[2]; + + return $matches[1] === 'codpes' + ? self::obterOuCriarPorCodpes($valor) + : self::find($valor); + } + /** * Obtém se já existir ou cria um novo objeto de usuário * diff --git a/tests/Unit/UserIdentifierTest.php b/tests/Unit/UserIdentifierTest.php new file mode 100644 index 0000000..8385f96 --- /dev/null +++ b/tests/Unit/UserIdentifierTest.php @@ -0,0 +1,232 @@ + false]); + } + + public function test_it_resolves_a_replication_person_by_prefixed_codpes(): void + { + $user = User::factory()->create(['codpes' => 17971882]); + + $resolved = User::obterOuCriarPorIdentificador('codpes-17971882'); + + $this->assertTrue($resolved->is($user)); + } + + public function test_it_resolves_a_local_user_by_prefixed_id(): void + { + $user = User::factory()->create(['codpes' => null, 'local' => true]); + + $resolved = User::obterOuCriarPorIdentificador('id-' . $user->id); + + $this->assertTrue($resolved->is($user)); + } + + public function test_it_creates_a_user_with_a_prefixed_codpes_identifier(): void + { + $user = User::obterOuCriarPorIdentificador('codpes-17971882'); + + $this->assertSame(17971882, (int) $user->codpes); + $this->assertDatabaseHas('users', ['codpes' => 17971882]); + } + + public function test_it_passes_an_integer_codpes_to_the_replication_client(): void + { + $pessoa = \Mockery::mock('alias:Uspdev\\Replicado\\Pessoa'); + $pessoa->shouldReceive('email')->once()->with(17971882)->andReturn('pessoa@example.com'); + $pessoa->shouldReceive('dump')->once()->with(17971882)->andReturn([ + 'nompesttd' => 'Pessoa do Replicado', + ]); + $pessoa->shouldReceive('obterRamalUsp')->once()->with(17971882)->andReturn(false); + $pessoa->shouldReceive('email')->once()->with(17971883)->andReturn('outra-pessoa@example.com'); + $pessoa->shouldReceive('dump')->once()->with(17971883)->andReturn([ + 'nompesttd' => 'Outra pessoa do Replicado', + ]); + $pessoa->shouldReceive('obterRamalUsp')->once()->with(17971883)->andReturn(false); + + config(['chamados.usar_replicado' => true]); + + $user = User::obterOuCriarPorIdentificador('codpes-17971882'); + $legacyUser = User::obterOuCriarPorCodpes('17971883'); + + $this->assertSame(17971882, (int) $user->codpes); + $this->assertSame(17971883, (int) $legacyUser->codpes); + } + + public function test_it_adds_a_replication_person_as_a_sector_manager(): void + { + $admin = User::factory()->create(['is_admin' => true]); + $target = User::factory()->create(['codpes' => 17971882]); + $setor = Setor::factory()->create(); + + $response = $this->withSession(['perfil' => 'admin']) + ->actingAs($admin) + ->post('/setores/' . $setor->id . '/pessoas', [ + 'codpes' => 'codpes-17971882', + ]); + + $response->assertRedirect(); + $this->assertDatabaseHas('user_setor', [ + 'user_id' => $target->id, + 'setor_id' => $setor->id, + 'funcao' => 'Gerente', + ]); + $this->assertDatabaseCount('users', 2); + } + + public function test_it_adds_a_local_user_as_a_sector_manager(): void + { + $admin = User::factory()->create(['is_admin' => true]); + $localUser = User::factory()->create(['codpes' => null, 'local' => true]); + $setor = Setor::factory()->create(); + + $response = $this->withSession(['perfil' => 'admin']) + ->actingAs($admin) + ->post('/setores/' . $setor->id . '/pessoas', [ + 'codpes' => 'id-' . $localUser->id, + ]); + + $response->assertRedirect(); + $this->assertDatabaseHas('user_setor', [ + 'user_id' => $localUser->id, + 'setor_id' => $setor->id, + 'funcao' => 'Gerente', + ]); + $this->assertDatabaseCount('users', 2); + } + + public function test_it_rejects_an_invalid_sector_user_identifier(): void + { + $admin = User::factory()->create(['is_admin' => true]); + $setor = Setor::factory()->create(); + + $response = $this->withSession(['perfil' => 'admin']) + ->actingAs($admin) + ->post('/setores/' . $setor->id . '/pessoas', [ + 'codpes' => 'id-999999', + ]); + + $response->assertSessionHasErrors('codpes'); + } + + public function test_it_adds_a_local_user_to_a_queue(): void + { + $admin = User::factory()->create(['is_admin' => true]); + $localUser = User::factory()->create(['codpes' => null, 'local' => true]); + $setor = Setor::factory()->create(); + $fila = Fila::factory()->create(['setor_id' => $setor->id]); + + $response = $this->withSession(['perfil' => 'admin']) + ->actingAs($admin) + ->post('/filas/' . $fila->id . '/pessoas', [ + 'codpes_id' => 'id-' . $localUser->id, + 'funcao' => 'Gerente', + ]); + + $response->assertRedirect(); + $this->assertDatabaseHas('user_fila', [ + 'user_id' => $localUser->id, + 'fila_id' => $fila->id, + 'funcao' => 'Gerente', + ]); + } + + public function test_it_keeps_supporting_the_legacy_queue_codpes_field(): void + { + $admin = User::factory()->create(['is_admin' => true]); + $target = User::factory()->create(['codpes' => 17971882]); + $setor = Setor::factory()->create(); + $fila = Fila::factory()->create(['setor_id' => $setor->id]); + + $response = $this->withSession(['perfil' => 'admin']) + ->actingAs($admin) + ->post('/filas/' . $fila->id . '/pessoas', [ + 'codpes' => (string) $target->codpes, + 'funcao' => 'Atendente', + ]); + + $response->assertRedirect(); + $this->assertDatabaseHas('user_fila', [ + 'user_id' => $target->id, + 'fila_id' => $fila->id, + 'funcao' => 'Atendente', + ]); + } + + public function test_it_rejects_an_unknown_local_user_in_a_queue(): void + { + $admin = User::factory()->create(['is_admin' => true]); + $setor = Setor::factory()->create(); + $fila = Fila::factory()->create(['setor_id' => $setor->id]); + + $response = $this->withSession(['perfil' => 'admin']) + ->actingAs($admin) + ->post('/filas/' . $fila->id . '/pessoas', [ + 'codpes_id' => 'id-999999', + 'funcao' => 'Gerente', + ]); + + $response->assertSessionHasErrors('codpes_id'); + } + + public function test_it_adds_a_local_user_to_a_ticket(): void + { + $admin = User::factory()->create(['is_admin' => true]); + $localUser = User::factory()->create(['codpes' => null, 'local' => true]); + $setor = Setor::factory()->create(); + $fila = Fila::factory()->create(['setor_id' => $setor->id]); + $chamado = Chamado::withoutEvents(function () use ($fila) { + return Chamado::factory()->create([ + 'fila_id' => $fila->id, + 'status' => 'Triagem', + ]); + }); + Mail::fake(); + + $response = $this->withSession(['perfil' => 'admin']) + ->actingAs($admin) + ->post('/chamados/' . $chamado->id . '/pessoas', [ + 'codpes' => 'id-' . $localUser->id, + 'papel' => 'Observador', + ]); + + $response->assertRedirect(); + $this->assertDatabaseHas('user_chamado', [ + 'user_id' => $localUser->id, + 'chamado_id' => $chamado->id, + 'papel' => 'Observador', + ]); + } + + public function test_it_adds_a_replication_person_from_the_users_screen(): void + { + $admin = User::factory()->create(['is_admin' => true]); + $target = User::factory()->create(['codpes' => 17971882]); + + $response = $this->actingAs($admin)->post('/users', [ + 'codpes' => 'codpes-17971882', + ]); + + $response->assertRedirect('/users'); + $this->assertDatabaseHas('users', ['id' => $target->id]); + $this->assertDatabaseCount('users', 2); + } +}