Skip to content

Instantly share code, notes, and snippets.

@maykonmeier
Created March 23, 2026 13:59
Show Gist options
  • Select an option

  • Save maykonmeier/51ef8291d1de154b8d592252755ce590 to your computer and use it in GitHub Desktop.

Select an option

Save maykonmeier/51ef8291d1de154b8d592252755ce590 to your computer and use it in GitHub Desktop.
Cenários de Teste — Portal do Cedente (Opera Capital) — 272 cenários
We can make this file beautiful and searchable if this error is corrected: Illegal quoting in line 2.
Nº;Bloco;Módulo;Sub-módulo;Cenário;Passos;Resultado Esperado;Tipo;Prioridade;Status
1;Bloco 1 — Autenticação;Login;Usuário Existente;Login com credenciais válidas (usuário existente);Acessar /login → Preencher user_name e password válidos → Clicar "Entrar";Token gerado (access_token), redirecionado para Dashboard (user) ou /operacoes (admin). Response com token_type: "Bearer" e expires_at;Funcional;Alta;✅ Validado
2;Bloco 1 — Autenticação;Login;Usuário Existente;Login com senha incorreta;Preencher user_name válido + senha errada → Clicar "Entrar";Erro 422: "As credenciais informadas estão incorretas." Banner vermelho no frontend;Funcional;Alta;✅ Validado
3;Bloco 1 — Autenticação;Login;Usuário Existente;Login com usuário inexistente no Opera Capital;Preencher user_name que não existe na API externa → Clicar "Entrar";Erro 403: API Opera Capital retorna exceção, tratada como UserNotActiveException;Funcional;Alta;✅ Validado
4;Bloco 1 — Autenticação;Login;Usuário Existente;Login com usuário inativo no Opera Capital;Preencher credenciais de usuário com situacaoUsuario = "I" (inativo);Erro 403: "Verifique sua situação com a Opera Capital... e-mail de suporte";Funcional;Alta;✅ Validado
5;Bloco 1 — Autenticação;Login;Validação;Login com campos vazios;Deixar user_name e/ou password em branco → Clicar "Entrar";Frontend: "Usuário é obrigatório" / "Senha é obrigatória". Backend: 422 com user_name.required / password.required;Validação;Alta;✅ Validado
6;Bloco 1 — Autenticação;Login;Validação;Login com user_name < 3 caracteres;Preencher user_name com 2 chars → Clicar "Entrar";Frontend (Zod): "Usuário deve ter no mínimo 3 caracteres". Backend aceita (sem min no LoginRequest);Validação;Média;✅ Validado
7;Bloco 1 — Autenticação;Login;Validação;Login com senha < 6 caracteres;Preencher senha com 5 chars → Clicar "Entrar";Frontend (Zod): "Senha deve ter no mínimo 6 caracteres". Backend aceita (sem min no LoginRequest);Validação;Média;✅ Validado
8;Bloco 1 — Autenticação;Pré-Registro;Novo Usuário;Login com usuário Opera sem cadastro local;Preencher credenciais de usuário ativo no Opera Capital mas sem cadastro local;Response 200: action: "pre_registration", pre_registration_id, message: "Código de autorização enviado para o e-mail cadastrado." E-mail AuthorizationCodeMail enviado;Funcional;Alta;✅ Validado
9;Bloco 1 — Autenticação;Verificação de Conta;Token;Verificação de conta com token válido;POST /verify-token com token válido;Response 200: "Token verificado com sucesso." + dados do pré-registro. Status muda para VERIFIED. Frontend redireciona para /redefinicao-senha;Funcional;Alta;✅ Validado
10;Bloco 1 — Autenticação;Verificação de Conta;Token;Verificação com token expirado;POST /verify-token após 15min (config authorization_code.expiry_minutes);Erro 422: "O código de autorização expirou. Solicite um novo código.";Funcional;Alta;✅ Validado
11;Bloco 1 — Autenticação;Verificação de Conta;Token;Verificação com token inexistente;POST /verify-token com token=invalido;Erro 404: "Código de autorização não encontrado.";Funcional;Média;✅ Validado
12;Bloco 1 — Autenticação;Verificação de Conta;Token;Verificação sem token na URL;Acessar /verificar-conta sem query param token;Erro 422: validação token.required. Frontend: "Token não encontrado...", redirect /login;Funcional;Média;✅ Validado
13;Bloco 1 — Autenticação;Registro;Senha;Registro com senha válida (todas as regras);POST /register com token válido + senha ≥8 chars completa + confirmação;Response 201: access_token, user. Usuário criado, role atribuída, pré-registro deletado;Funcional;Alta;✅ Validado
14;Bloco 1 — Autenticação;Registro;Validação;Registro com senhas não coincidentes;password ≠ password_confirmation;Erro 422: "A confirmação de senha não confere." Frontend: botão desabilitado;Validação;Alta;✅ Validado
15;Bloco 1 — Autenticação;Registro;Validação;Registro com senha sem caractere especial;Senha sem !@#$%...;Frontend: indicador vermelho, botão desabilitado. Backend aceita (RegisterRequest exige apenas min:8 e confirmed);Validação;Média;✅ Validado
16;Bloco 1 — Autenticação;Registro;Validação;Registro com senha sem maiúscula;Senha toda minúscula;Frontend: indicador vermelho, botão desabilitado. Backend aceita;Validação;Média;✅ Validado
17;Bloco 1 — Autenticação;Registro;Navegação;Acesso direto a /redefinicao-senha sem token;Navegar manualmente para a rota sem state;Frontend: warning notification, redirect /login pelo router guard;Navegação;Média;✅ Validado
18;Bloco 1 — Autenticação;Sessão;Proteção de Rotas;Acessar rota protegida sem token;Navegar para /dashboard sem autenticação;API: 401 Unauthenticated. Frontend: router guard redireciona para /login;Segurança;Alta;✅ Validado
19;Bloco 1 — Autenticação;Sessão;Token Expirado;Token expirado durante navegação;Request com token expirado (sanctum.expiration = 120min);Response 401 → Axios interceptor remove cookie → Reload → Redirect /login;Segurança;Alta;✅ Validado
20;Bloco 1 — Autenticação;Sessão;Logout;Logout;Clicar em logout → POST /logout;Response 200: "Logout realizado com sucesso." Token deletado, store resetado, cookie removido, redirect /login;Funcional;Alta;✅ Validado
21;Bloco 1 — Autenticação;Sessão;Navegação;Usuário autenticado acessa /login;Navegar para /login estando logado;Router guard detecta token → Valida via GET /me → Redirect para home ou /operacoes se admin;Navegação;Média;✅ Validado
22;Bloco 1 — Autenticação;Sessão;Rate Limiting;Rate limiting no login;Enviar 6+ requests em 1 minuto para POST /login;Erro 429 (Too Many Requests). Throttle: 5,1;Segurança;Alta;✅ Validado
23;Bloco 2 — Dashboard;Carregamento;Estados;Carregamento inicial do Dashboard;Acessar / (usuário comum);GET /dashboard/ com CNPJ do usuário. Spinner → DashboardResource renderizada;Funcional;Alta;✅ Validado
24;Bloco 2 — Dashboard;Carregamento;Erro;Erro ao carregar Dashboard;API Opera Capital retorna erro/timeout;Ícone de erro + "Erro ao carregar dashboard" + botão "Tentar novamente";Funcional;Alta;✅ Validado
25;Bloco 2 — Dashboard;Carregamento;Retry;Retry após erro;Clicar "Tentar novamente";TanStack Query refetch() disparado, spinner, dados recarregam;Funcional;Média;✅ Validado
26;Bloco 2 — Dashboard;Carregamento;Vazio;Dashboard sem dados (204);CNPJ sem dados ou inválido pelo CnpjHelper;Response 204 No Content. Frontend: tratamento de vazio;Funcional;Média;✅ Validado
27;Bloco 2 — Dashboard;Métricas Perfil;Exibição;Exibição das 5 métricas de perfil;Dashboard carregado com dados;CNPJ, Cliente Desde, Última Operação, Primeira Operação, Vencimento do Contrato — formatados dd/MM/yyyy;Funcional;Alta;✅ Validado
28;Bloco 2 — Dashboard;Métricas Perfil;Nulos;Métricas com datas nulas;Alguma data retorna null da API;Campo exibe string vazia (não "Invalid Date");Funcional;Média;✅ Validado
29;Bloco 2 — Dashboard;Cards;Operações e Limites;Cards de Operações, Limite Aprovado, Limite Disponível;Dashboard com dados;3 cards com valores em R$ formatados, sparklines de 14 pontos;Funcional;Alta;✅ Validado
30;Bloco 2 — Dashboard;Cards;Tranche;Cards secundários (Tranche);Dashboard com dados;Limite Tranche, Tranche Disponível + card Última Confirmação;Funcional;Alta;✅ Validado
31;Bloco 2 — Dashboard;Taxas;Exibição;Card de Taxas;Dashboard com dados;4 taxas visíveis (Deságio FIDC/SEC/Especial, Cobrança Trustee em %). 4 ocultas;Funcional;Média;✅ Validado
32;Bloco 2 — Dashboard;Títulos Negociados;Tabela;Tabela de Títulos Negociados;Dashboard com dados;Total geral + tabela com 4 tipos: Duplicata, Confissão de dívida, Cheque, Cartão de Crédito;Funcional;Alta;✅ Validado
33;Bloco 2 — Dashboard;Títulos Abertos;Colapsada;Tabela de Títulos Abertos (colapsada);Dashboard com dados;Total + 2 linhas: "A Vencer" e "Vencidos" com chevron para expandir;Funcional;Alta;✅ Validado
34;Bloco 2 — Dashboard;Títulos Abertos;Expandida;Expandir detalhamento de Títulos Abertos;Clicar no chevron;Sub-linhas: Até 5/15/30 dias, Acima de 30 dias — quantidade, valor, %;Funcional;Média;✅ Validado
35;Bloco 2 — Dashboard;Títulos Liquidados;Mini-cards;Mini-cards de Títulos Liquidados;Dashboard com dados;7 mini-cards coloridos com quantidade, valor e %;Funcional;Média;✅ Validado
36;Bloco 2 — Dashboard;Controladoria;Tabela;Tabela de Controladoria;Dashboard com dados;7 linhas com Descrição, Quantia, %, Valor, Tranche;Funcional;Média;✅ Validado
37;Bloco 2 — Dashboard;Concentração;Sacados;Tabela de Concentração de Sacados;Dashboard com dados;Top sacados: Sacado, CNPJ/CPF, Valor, % (barra de progresso);Funcional;Média;✅ Validado
38;Bloco 2 — Dashboard;Concentração;Grupos Econômicos;Tabela de Grupos Econômicos Sacados;Dashboard com dados;Tabela dinâmica: Grupo, Valor;Funcional;Média;✅ Validado
39;Bloco 2 — Dashboard;Grupo Econômico;Ativar;Ativar Grupo Econômico;Clicar botão "Grupo Econômico";Banner, query com grupo_economico=1, dados agregados;Funcional;Média;✅ Validado
40;Bloco 2 — Dashboard;Grupo Econômico;Desativar;Desativar Grupo Econômico;Clicar novamente no botão;Banner some, query sem grupo_economico, dados individuais;Funcional;Média;✅ Validado
41;Bloco 3 — Kanban;Carregamento;Inicial;Carga inicial da página de Operações;Acessar /operacoes;5 colunas carregam em paralelo (5 requests). Range: 30 dias. Cores: Digitando #64DCFF, Em análise #FFDC50, Assinatura #7200CA, Pago #00FF96, Reprovadas #FF7C62;Funcional;Alta;✅ Validado
42;Bloco 3 — Kanban;Carregamento;Loading;Loading state durante carga;Acessar /operacoes com API lenta;Spinner/loading em cada coluna;Funcional;Média;✅ Validado
43;Bloco 3 — Kanban;Carregamento;Vazio;Kanban sem operações (período vazio);Filtrar período sem dados;5 colunas com estado vazio;Funcional;Média;✅ Validado
44;Bloco 3 — Kanban;Carregamento;Badges;Badges de contagem nas colunas;Página carregada;Cada coluna exibe badge "N OP" com total (meta.total);Funcional;Média;✅ Validado
45;Bloco 3 — Kanban;Cards;Digitando;Card na coluna Digitando;Visualizar card em "Digitando";Data de criação, Qnt Títulos, Valor Total. Sem opera_id (null em EM_DIGITACAO);Funcional;Alta;✅ Validado
46;Bloco 3 — Kanban;Cards;Outras Colunas;Card em colunas não-Digitando;Visualizar card nas demais colunas;"Operação [num_aditivo ou opera_id]", data importação, Qnt Títulos, Valor Total;Funcional;Alta;✅ Validado
47;Bloco 3 — Kanban;Cards;Processando;Card com substatus "Processando";Card em "Em análise" com substatus;Badge amarelo "Processando" + ícone info. Valores podem estar zerados;Funcional;Média;✅ Validado
48;Bloco 3 — Kanban;Cards;Formatação;Formatação de valores monetários;Qualquer card;Valor em R$ com separador de milhares pt-BR (R$ 1.500,00);Funcional;Média;✅ Validado
49;Bloco 3 — Kanban;Navegação;Digitando;Clicar card em "Digitando";Clicar em card da coluna Digitando;Navega para /operacoes/{id} (página de edição);Navegação;Alta;✅ Validado
50;Bloco 3 — Kanban;Navegação;Em Análise;Clicar card em "Em análise" (não processando);Clicar em card sem substatus Processando;Navega para /operacoes/{id}/detalhamento;Navegação;Alta;✅ Validado
51;Bloco 3 — Kanban;Navegação;Processando;Clicar card "Processando";Clicar em card com badge Processando;Dialog de aviso. Não navega;Navegação;Média;✅ Validado
52;Bloco 3 — Kanban;Navegação;Outras Colunas;Clicar card em Assinatura/Pago/Reprovadas;Clicar em card nessas colunas;Navega para /operacoes/{id}/detalhamento;Navegação;Alta;✅ Validado
53;Bloco 3 — Kanban;Paginação;Ver Mais Visível;Coluna com mais de 10 operações;Coluna com total > 10;Botão "VER MAIS" visível (ITEMS_PER_PAGE = 10);Funcional;Média;✅ Validado
54;Bloco 3 — Kanban;Paginação;Carregar Mais;Clicar "Ver Mais";Clicar no botão;Loading → Próxima página adicionada (append) à coluna;Funcional;Média;✅ Validado
55;Bloco 3 — Kanban;Paginação;Sem Mais Páginas;Coluna sem mais páginas;Todas carregadas (page >= total_pages);Botão desabilitado com tooltip informativo;Funcional;Baixa;✅ Validado
56;Bloco 3 — Kanban;Paginação;Independente;Ver Mais em múltiplas colunas;Clicar "Ver Mais" em colunas diferentes;Cada coluna pagina independentemente;Funcional;Média;✅ Validado
57;Bloco 3 — Kanban;Filtros;Status;Filtrar por status específico;Selecionar "Digitando" → Clicar filtrar;Apenas dados do status selecionado recarregam;Funcional;Alta;✅ Validado
58;Bloco 3 — Kanban;Filtros;Todos;Filtrar por "Todos";Selecionar "Todos" → Filtrar;Todas as 5 colunas recarregam;Funcional;Média;✅ Validado
59;Bloco 3 — Kanban;Filtros;Datas Válidas;Filtrar por intervalo de datas válido;start_date e end_date ≤ 60 dias → Filtrar;Operações recarregadas para o período;Funcional;Alta;✅ Validado
60;Bloco 3 — Kanban;Filtros;> 60 dias Frontend;Filtrar com intervalo > 60 dias (frontend);Período > 60 dias → Filtrar;Notificação de erro frontend: período excede 60 dias;Validação;Média;✅ Validado
61;Bloco 3 — Kanban;Filtros;> 90 dias Backend;Filtrar com intervalo > 90 dias (backend);Request direto com período > 90 dias;Erro 422: "O período de consulta não pode ser maior que 90 dias...";Validação;Alta;✅ Validado
62;Bloco 3 — Kanban;Filtros;Mesmo Dia;Filtro com mesma data início e fim;Mesmo dia para ambos → Filtrar;Operações daquele dia. Validação before_or_equal/after_or_equal passa;Funcional;Baixa;✅ Validado
63;Bloco 3 — Kanban;Filtros;Tooltip;Tooltip informativo dos filtros;Hover no ícone de info;Tooltip: "Os registros referem-se ao período selecionado (padrão: 30 dias)...";UI;Baixa;✅ Validado
64;Bloco 3 — Kanban;Admin;Seletor Visível;Seletor de Cedente visível para admin;Acessar /operacoes como admin;AdminCedenteSelector exibido. CNPJ obrigatório;Funcional;Alta;✅ Validado
65;Bloco 3 — Kanban;Admin;Selecionar Cedente;Selecionar cedente;Escolher CNPJ no seletor;Filtro cnpj aplicado, operações recarregadas;Funcional;Alta;✅ Validado
66;Bloco 3 — Kanban;Admin;Limpar Cedente;Limpar cedente;Clicar botão limpar;Filtro cnpj removido, página recarrega;Funcional;Média;✅ Validado
67;Bloco 3 — Kanban;Admin;Oculto p/ User;Seletor oculto para usuário comum;Acessar /operacoes como user;AdminCedenteSelector não renderizado. CNPJ via user.resolveCnpj();Funcional;Média;✅ Validado
68;Bloco 3 — Kanban;Criação;Modal;Abrir modal de nova operação;Clicar "Adicionar Operação";Modal AdicionarOperacaoModal com seleção de tipo (Duplicata, Cheque, XML);Funcional;Alta;✅ Validado
69;Bloco 3 — Kanban;Criação;Sucesso;Criar operação com sucesso;Preencher dados → Confirmar;POST /operations/ → 201. Redirect para /operacoes/{id};Funcional;Alta;✅ Validado
70;Bloco 3 — Kanban;Responsividade;Desktop;Desktop (1920px+);Tela grande;5 colunas visíveis, base 220px, max 260px;UI;Baixa;✅ Validado
71;Bloco 3 — Kanban;Responsividade;Laptop;Laptop (1440px);Notebook;5 colunas com espaçamento ajustado;UI;Baixa;✅ Validado
72;Bloco 3 — Kanban;Responsividade;Mobile;Tablet/Mobile (<1024px);Tela menor;Scroll horizontal, min-width 180px;UI;Baixa;✅ Validado
73;Bloco 4 — Detalhe Operação;Edição;Carregamento;Carregar operação em digitação;Clicar card "Digitando" → /operacoes/{id};GET /operations/{id} → OperationResource com invoices, checks, files, endorser;Funcional;Alta;✅ Validado
74;Bloco 4 — Detalhe Operação;Edição;Loading;Loading state da operação;Acessar /operacoes/{id};Spinner durante carregamento;Funcional;Média;✅ Validado
75;Bloco 4 — Detalhe Operação;Edição;404;Operação não encontrada;/operacoes/{id} com ID inexistente;API: 404 "Operação não encontrada";Funcional;Alta;✅ Validado
76;Bloco 4 — Detalhe Operação;Títulos;Adicionar;Adicionar título manualmente;Modal → Preencher número, NF, valor, vencimento, sacado, tipo, chave NF-e;POST /invoices/ → 201. Título na tabela;Funcional;Alta;✅ Validado
77;Bloco 4 — Detalhe Operação;Títulos;Validação Obrigatórios;Validação de campos obrigatórios do título;Submeter vazio;Erros 422: operation_id, payer_id, number, number_nf, value, due_date, type;Validação;Alta;✅ Validado
78;Bloco 4 — Detalhe Operação;Títulos;NF-e Max Chars;Validação de chave NF-e (máx 44 chars);nfe_key > 44 chars;Erro 422: "O campo chave da NF-e não pode ter mais de 44 caracteres.";Validação;Média;✅ Validado
79;Bloco 4 — Detalhe Operação;Títulos;NF-e Duplicada;Chave NF-e duplicada;nfe_key já existente (unique whereNull deleted_at);Erro 422: "Esta chave de NF-e já está cadastrada no sistema.";Validação;Alta;✅ Validado
80;Bloco 4 — Detalhe Operação;Títulos;Editar;Editar título existente;Modal EditarNotaModal → Alterar valor/data → Salvar;PUT /invoices/{id} → 200. Dados atualizados;Funcional;Alta;✅ Validado
81;Bloco 4 — Detalhe Operação;Títulos;Atualização Parcial;Atualização parcial de título;PUT com apenas 1 campo;UpdateInvoiceRequest usa sometimes — apenas campos enviados validados;Funcional;Média;✅ Validado
82;Bloco 4 — Detalhe Operação;Títulos;Excluir;Excluir título;Excluir → Confirmar;DELETE /invoices/{id} → 200 "Nota fiscal excluída com sucesso". Soft delete;Funcional;Alta;✅ Validado
83;Bloco 4 — Detalhe Operação;Títulos;Valor Negativo;Valor do título < 0;Valor negativo;Erro 422: "O campo valor deve ser maior ou igual a zero." (min:0);Validação;Média;✅ Validado
84;Bloco 4 — Detalhe Operação;Cheques;Adicionar;Adicionar cheque;Modal AdicionarChequeModal → CMC7, agência, conta, valor;POST /checks/ → 201;Funcional;Alta;✅ Validado
85;Bloco 4 — Detalhe Operação;Cheques;CMC7 Inválido;Validação de CMC7 inválido;CMC7 fora do formato;Erro 422: Cmc7Rule — CMC7 inválido;Validação;Alta;✅ Validado
86;Bloco 4 — Detalhe Operação;Cheques;Obrigatórios;Campos obrigatórios do cheque;Submeter vazio;Erros 422: operation_id, payer_id, cmc7, agency, account, value;Validação;Alta;✅ Validado
87;Bloco 4 — Detalhe Operação;Cheques;Editar;Editar cheque existente;Alterar valor/conta → Salvar;PUT /checks/{id} → 200;Funcional;Alta;✅ Validado
88;Bloco 4 — Detalhe Operação;Cheques;Excluir;Excluir cheque;Excluir → Confirmar;DELETE /checks/{id} → 200 "Cheque excluído com sucesso". Soft delete;Funcional;Alta;✅ Validado
89;Bloco 4 — Detalhe Operação;Sacados;Criar;Criar sacado manualmente;Preencher CNPJ/CPF, razão social, CEP, estado, cidade, endereço, e-mail;POST /payers/ → 201;Funcional;Alta;✅ Validado
90;Bloco 4 — Detalhe Operação;Sacados;CNPJ/CPF Inválido;Validação de CNPJ/CPF inválido;Dígitos incorretos;Erro 422: CnpjCpfRule — documento inválido;Validação;Alta;✅ Validado
91;Bloco 4 — Detalhe Operação;Sacados;Obrigatórios;Campos obrigatórios do sacado;Submeter vazio;Erros 422: cnpj_cpf, company_name, zip_code, state, city, address, email;Validação;Alta;✅ Validado
92;Bloco 4 — Detalhe Operação;Sacados;Editar;Editar sacado existente;Alterar endereço → Salvar;PUT /payers/{id} → 200. UpdatePayerRequest usa sometimes;Funcional;Média;✅ Validado
93;Bloco 4 — Detalhe Operação;Sacados;Excluir c/ Invoices;Excluir sacado com títulos vinculados;DELETE sacado que tem invoices;Erro 422: "Não é possível deletar o sacado pois existem notas fiscais vinculadas.";Funcional;Alta;✅ Validado
93b;Bloco 4 — Detalhe Operação;Sacados;Excluir c/ Checks;Excluir sacado com cheques vinculados;DELETE sacado que tem checks;Erro 422: "Não é possível deletar o sacado pois existem cheques vinculados.";Funcional;Alta;✅ Validado
94;Bloco 4 — Detalhe Operação;Sacados;Excluir Livre;Excluir sacado sem vínculos;DELETE sacado sem invoices/checks;200: "Sacado excluído com sucesso.";Funcional;Média;✅ Validado
95;Bloco 4 — Detalhe Operação;Operação;Excluir;Excluir operação em digitação;DELETE /operations/{id} → Confirmar;200: "Operação excluída com sucesso". Soft delete cascata (invoices + checks). Nota: backend NÃO valida se a operação já foi submetida;Funcional;Alta;✅ Validado
96;Bloco 4 — Detalhe Operação;Operação;Excluir Outro User;Tentar excluir operação de outro usuário;DELETE operação que pertence a outro user;404: "Operação não encontrada" (getOperation() filtra por user_id);Segurança;Alta;✅ Validado
97;Bloco 4 — Detalhe Operação;Detalhamento;Carregar;Carregar detalhamento de operação;Card não-Digitando → /operacoes/{id}/detalhamento;GET /consulta-detalhes-operacao/ com cnpj_cedente + num_aditivo;Funcional;Alta;✅ Validado
98;Bloco 4 — Detalhe Operação;Detalhamento;Loading;Loading state do detalhamento;Acessar página;Spinner "Carregando detalhes da operação...";Funcional;Média;✅ Validado
99;Bloco 4 — Detalhe Operação;Detalhamento;Erro;Erro ao carregar detalhamento;API erro/timeout;Ícone de erro + "Erro ao carregar detalhes da operação" + botão voltar;Funcional;Alta;✅ Validado
100;Bloco 4 — Detalhe Operação;Detalhamento;Processando;Operação em processamento (substatus);Substatus "processando";Tooltip info: dados serão atualizados após processamento;Funcional;Média;✅ Validado
101;Bloco 4 — Detalhe Operação;Detalhamento;Métricas Cedente;Métricas do cedente no topo;Página carregada;5 métricas: Limite, Limite Tranche, Tranche disponível, Limite disponível, Última confirmação;Funcional;Alta;✅ Validado
102;Bloco 4 — Detalhe Operação;Detalhamento;Dados Lateral;Card "Dados da Operação" lateral;Página carregada;Valor de face, Abatimento, Deságio, Desconto, Ad.Valorem, Recompras, Valor a pagar, Tax, Taxa, Prazo médio;Funcional;Alta;✅ Validado
103;Bloco 4 — Detalhe Operação;Detalhamento;Responsivo;Layout responsivo (< 1280px);Viewport < 1280px;Card lateral move para baixo do card principal;UI;Baixa;✅ Validado
104;Bloco 4 — Detalhe Operação;Tabela Sacados;Colapsada;Tabela de sacados colapsada;Página carregada;Colunas: CPF/CNPJ, Sacado, Valor, Nr títulos;Funcional;Alta;✅ Validado
105;Bloco 4 — Detalhe Operação;Tabela Sacados;Expandir;Expandir sacado para ver títulos;Clicar na linha de um sacado;Sub-tabela: Nº NF, Nr Doc, T Doc, Vencimento, Prazo médio, Deságio, Desconto, Valor face, Status;Funcional;Alta;✅ Validado
106;Bloco 4 — Detalhe Operação;Tabela Sacados;Status Pills;Status pills nos títulos;Expandir sacado;Pills: Aprovado (verde), Pendente (laranja), Reprovado (cinza), Info (azul);UI;Média;✅ Validado
107;Bloco 4 — Detalhe Operação;Tabela Sacados;Tooltip NF;Tooltip de NF truncado;NF com número longo;Últimos 8 dígitos na tabela, tooltip mostra completo;UI;Baixa;✅ Validado
108;Bloco 4 — Detalhe Operação;Filtros Detalhe;Por Status;Filtrar títulos por status;Selecionar "Aprovado";Apenas títulos aprovados. Sacados sem títulos filtrados ocultados;Funcional;Média;✅ Validado
109;Bloco 4 — Detalhe Operação;Filtros Detalhe;Por Período;Filtrar por período/ano;Selecionar ano (gerado dinamicamente);Apenas títulos com vencimento naquele ano;Funcional;Média;✅ Validado
110;Bloco 4 — Detalhe Operação;Filtros Detalhe;Combinado;Filtrar status + período combinados;Ambos os filtros;Interseção: títulos que atendem ambos;Funcional;Média;✅ Validado
111;Bloco 4 — Detalhe Operação;Filtros Detalhe;Sem Resultado;Filtro sem resultados;Filtro sem dados;"Nenhum sacado encontrado";Funcional;Baixa;✅ Validado
112;Bloco 4 — Detalhe Operação;Filtros Detalhe;Reset Período;Reset de filtro de período;Opções mudam após filtro status;Dropdown reseta para "Todos" se opção indisponível;Funcional;Baixa;✅ Validado
113;Bloco 4 — Detalhe Operação;Favorecidos;Tabela;Tabela de favorecidos;Página carregada;Tabela: CPF/CNPJ, Favorecido, Valor, Tipo pagto;Funcional;Média;✅ Validado
114;Bloco 4 — Detalhe Operação;Favorecidos;Vazio;Sem favorecidos;Operação sem favorecidos;"Nenhum favorecido encontrado";Funcional;Baixa;✅ Validado
115;Bloco 4 — Detalhe Operação;Extras;Download REM;Download arquivo .REM;Clicar botão download (se arquivo existe);Arquivo .REM baixado via Blob, loading state;Funcional;Média;✅ Validado
116;Bloco 4 — Detalhe Operação;Extras;REM Oculto;Botão .REM oculto;Operação sem arquivo .REM;Botão não renderizado;UI;Baixa;✅ Validado
117;Bloco 4 — Detalhe Operação;Extras;Erro Download;Erro ao baixar .REM;Falha no download;Toast: "Erro ao baixar arquivo .rem";Funcional;Média;✅ Validado
118;Bloco 4 — Detalhe Operação;Extras;Imprimir;Imprimir operação;Clicar "Imprimir";window.print(). CSS @media print formata layout;Funcional;Baixa;✅ Validado
119;Bloco 4 — Detalhe Operação;Admin;Detalhamento;Admin acessa detalhamento;Admin com cedente selecionado;CNPJ via cedenteStore;Funcional;Média;✅ Validado
120;Bloco 4 — Detalhe Operação;CNPJ;Fallback;Fallback de CNPJ;Usuário sem CNPJ direto;Chain: authLocal.cnpj → user.cnpj → perfil.cnpj_digits → perfil.cnpj;Funcional;Média;✅ Validado
121;Bloco 5 — Submissão;Resumo;Carregar;Carregar resumo da operação;"Avançar" → /operacoes/{id}/resumo;GET /operations/{id}/summary → operation, fee, beneficiaries;Funcional;Alta;✅ Validado
122;Bloco 5 — Submissão;Resumo;Loading;Loading state do resumo;Acessar página;Spinner durante carregamento;Funcional;Média;✅ Validado
123;Bloco 5 — Submissão;Resumo;404;Operação não encontrada no resumo;ID inexistente;API: 404 "Operação não encontrada";Funcional;Alta;✅ Validado
124;Bloco 5 — Submissão;Resumo;Métricas;Exibição de métricas do resumo;Página carregada;Quantidade de títulos, Valor Face total, Taxa de deságio (%);Funcional;Alta;✅ Validado
125;Bloco 5 — Submissão;Favorecidos;Listagem;Listagem de contas bancárias;Página carregada;Grid de cards com contas (Banco, Tipo, Agência, Conta, Dígito). Radio button;Funcional;Alta;✅ Validado
126;Bloco 5 — Submissão;Favorecidos;Conta Única;Selecionar conta única;Radio button em uma conta;Conta selecionada, valor preenchido com total da operação;Funcional;Alta;✅ Validado
127;Bloco 5 — Submissão;Favorecidos;Split;Split de pagamento (múltiplas contas);Selecionar mais de uma conta;Campos de valor para cada conta. Soma deve igualar total;Funcional;Alta;✅ Validado
128;Bloco 5 — Submissão;Favorecidos;Soma Incorreta;Validação de soma dos valores;Soma ≠ total;Botão "Aceitar" desabilitado. Mensagem de aviso;Validação;Alta;✅ Validado
129;Bloco 5 — Submissão;Favorecidos;Sem Contas;Sem contas bancárias;Cedente sem favorecidos;Lista vazia. Botão "Aceitar" desabilitado;Funcional;Média;✅ Validado
130;Bloco 5 — Submissão;Observações;Adicionar;Adicionar observação;Modal AdicionarObservacaoModal → Texto → Confirmar;Texto salvo. Máximo 1000 chars (backend obs: max:1000);Funcional;Baixa;✅ Validado
131;Bloco 5 — Submissão;Observações;Vazia;Observação vazia;Não preencher;Envio sem obs — campo opcional (nullable);Funcional;Baixa;✅ Validado
132;Bloco 5 — Submissão;Envio;Sucesso;Submeter operação com sucesso;Conta(s) + valores → "Aceitar" → Confirmar;POST /operations/{id}/submit com fee + beneficiaries[]. opera_id atribuído, status → PROCESSANDO. Redirect /operacoes;Funcional;Alta;✅ Validado
133;Bloco 5 — Submissão;Envio;Sem Beneficiários;Validação de beneficiários obrigatórios;Sem contas selecionadas;Erro 422: "É necessário informar pelo menos um favorecido." (beneficiaries: required, min:1);Validação;Alta;✅ Validado
134;Bloco 5 — Submissão;Envio;Valor < 0.01;Validação de valor do beneficiário < 0.01;Valor = 0;Erro 422: "O valor do favorecido deve ser maior que zero." (beneficiaries.*.value: min:0.01);Validação;Média;✅ Validado
135;Bloco 5 — Submissão;Envio;Payment Method;Validação de método de pagamento;payment_method inválido;Erro 422: "A forma de pagamento deve ser 1 (TED), 2 (DOC) ou 3 (PIX).";Validação;Média;✅ Validado
136;Bloco 5 — Submissão;Envio;Indicator;Validação de indicador;indicator inválido;Erro 422: "O indicador do favorecido deve ser P (Próprio) ou T (Terceiro).";Validação;Média;✅ Validado
137;Bloco 5 — Submissão;Envio;Soma Diverge;Soma dos beneficiários ≠ total da operação;Total diverge;Erro 422: "A soma dos valores dos favorecidos (R$ X) não corresponde ao total da operação (R$ Y).";Validação;Alta;✅ Validado
138;Bloco 5 — Submissão;Envio;Já Submetida;Operação já submetida;Status ≠ EM_DIGITACAO;Erro 422: "A operação já foi submetida." (OperationSubmitException::operationAlreadySubmitted);Funcional;Alta;✅ Validado
139;Bloco 5 — Submissão;Envio;Erro API;Erro na API Opera Capital durante envio;enviarOperacao() retorna erro;Erro tratado pelo OperationSubmitException. Operação permanece EM_DIGITACAO;Funcional;Alta;✅ Validado
140;Bloco 5 — Submissão;Envio;XML ZIP;Envio com arquivos XML (ZIP);Invoices com media collection 'xml';ZIP criado automaticamente, enviado multipart, deletado no finally;Funcional;Média;✅ Validado
141;Bloco 5 — Submissão;Importação;XML Upload;Upload de XML (NF-e/CT-e);Arrastar .xml para zona de upload;POST /operations/import com FormData. ImportSummaryResource retornada. Max 10MB por arquivo;Funcional;Alta;✅ Validado
142;Bloco 5 — Submissão;Importação;CNAB Upload;Upload de CNAB 240/400 (.rem);Selecionar .rem;Detectado via ImportFileType::fromExtension(). Job ImportFromRem enfileirado;Funcional;Alta;✅ Validado
143;Bloco 5 — Submissão;Importação;Tracking;Import batch tracking;Acompanhar progresso;GET /operations/import/{batchKey}/summary → total_files, processed_files;Funcional;Média;✅ Validado
144;Bloco 5 — Submissão;Importação;Sucesso;Resultado da importação (sucesso);Processada com sucesso;Toast: X títulos importados. Títulos na tabela;Funcional;Alta;✅ Validado
145;Bloco 5 — Submissão;Importação;Erro;Resultado da importação (erro);Formato inválido ou extensão não suportada;Erro 422: "Apenas arquivos xml, rem são permitidos." ou ImportLog com status erro;Funcional;Alta;✅ Validado
146;Bloco 6 — Relatórios;Página;Carregamento;Carregamento da página de relatórios;Acessar /relatorios;Grid 3x2 com 6 cards: Posição Abertos, Posição Liquidados, Borderô, Status Aceite, Termo Cessão, Demonstrativo Financeiro;Funcional;Alta;✅ Validado
147;Bloco 6 — Relatórios;Página;Admin Bloqueado;Admin não acessa relatórios;/relatorios como admin;Menu desabilitado (disabled: isAdmin). Tooltip: "Área ainda não habilitada para admin";Funcional;Média;✅ Validado
148;Bloco 6 — Relatórios;Página;Responsividade;Responsividade da grid;Reduzir viewport;3 cols > 1400px, 2 cols 900-1400px, 1 col < 900px;UI;Baixa;✅ Validado
149;Bloco 6 — Relatórios;Com Datas;Modal;Abrir modal relatório com datas;Clicar "Gerar" em Posição Abertos/Liquidados;Modal GerarRelatorioModal: CNPJ sacado (masked), Data início, Data fim;Funcional;Alta;✅ Validado
150;Bloco 6 — Relatórios;Com Datas;Gerar Sucesso;Gerar relatório com dados válidos;Preencher tudo → Gerar;POST /gerar-relatorio/ com codigo_relatorio 1 ou 2. Response: RelatorioBase64. PDF em iframe;Funcional;Alta;✅ Validado
151;Bloco 6 — Relatórios;Com Datas;CNPJ Cedente;CNPJ do cedente indisponível;Sem CNPJ no localStorage;Toast: "CNPJ/CPF do cedente (usuário) indisponível";Validação;Média;✅ Validado
152;Bloco 6 — Relatórios;Com Datas;Sem Sacado;CNPJ do sacado não informado;Gerar sem CNPJ sacado;Toast: "Informe o CNPJ do sacado";Validação;Média;✅ Validado
153;Bloco 6 — Relatórios;Com Datas;Datas Ausentes;Datas obrigatórias ausentes;Request sem data_de ou data_ate;Erro 422: "A data de início/fim é obrigatória para este relatório.";Validação;Alta;✅ Validado
154;Bloco 6 — Relatórios;Com Datas;Formato Data;Formato de data inválido;Data fora de AAAA-MM-DD;Erro 422: "A data deve estar no formato AAAA-MM-DD.";Validação;Média;✅ Validado
155;Bloco 6 — Relatórios;Com Datas;Sem PDF;PDF não retornado pela API;Response sem RelatorioBase64;Toast: "PDF não retornado pela API";Funcional;Média;✅ Validado
156;Bloco 6 — Relatórios;Com Aditivo;Modal;Abrir modal relatório com aditivo;Clicar "Gerar" em Borderô/Status Aceite/Termo/Demonstrativo;Modal GerarRelatorioAditivoModal: Sequencial Aditivo (inteiro);Funcional;Alta;✅ Validado
157;Bloco 6 — Relatórios;Com Aditivo;Gerar Sucesso;Gerar relatório por aditivo;Preencher aditivo → Gerar;POST /gerar-relatorio/ com codigo_relatorio 3-6 + sequencial_aditivo. PDF em iframe;Funcional;Alta;✅ Validado
158;Bloco 6 — Relatórios;Com Aditivo;Sem Aditivo;Aditivo não informado;Request sem sequencial_aditivo;Erro 422: "O sequencial do aditivo é obrigatório para este relatório.";Validação;Alta;✅ Validado
159;Bloco 6 — Relatórios;Com Aditivo;Aditivo Texto;Aditivo não numérico;Texto no campo;Erro 422: "O sequencial do aditivo deve ser um número inteiro.";Validação;Média;✅ Validado
160;Bloco 6 — Relatórios;Validações;Código Inválido;Código de relatório inválido;codigo_relatorio fora de 1-6;Erro 422: "O código do relatório deve ser entre 1 e 6.";Validação;Média;✅ Validado
161;Bloco 6 — Relatórios;Validações;Empresa;Código da empresa obrigatório;Sem codigo_empresa;Erro 422: "O código da empresa é obrigatório.";Validação;Média;✅ Validado
162;Bloco 6 — Relatórios;Validações;Filial;Código da filial obrigatório;Sem codigo_filial;Erro 422: "O código da filial é obrigatório.";Validação;Média;✅ Validado
163;Bloco 6 — Relatórios;Erros API;400;Erro 400 da API QProf;API retorna 400;"Dados inválidos. Verifique os campos obrigatórios para este tipo de relatório.";Funcional;Alta;✅ Validado
164;Bloco 6 — Relatórios;Erros API;502;Erro 502 da API QProf;Serviço indisponível;"Falha ao consultar o QProf. Serviço temporariamente indisponível.";Funcional;Alta;✅ Validado
165;Bloco 6 — Relatórios;Erros API;500;Erro 500 interno;Erro configuração/interno;"Erro interno ao gerar relatório. Tente novamente.";Funcional;Alta;✅ Validado
166;Bloco 6 — Relatórios;Erros API;Loading;Loading state durante geração;Clicar "Gerar" e aguardar;Botão com loading (isGenerating=true), desabilitado durante processamento;Funcional;Média;✅ Validado
167;Bloco 7 — Cedentes;Admin Selector;Visível;AdminCedenteSelector visível para admin;Qualquer página como admin;Barra roxa com seletor. Nome e CNPJ formatado do cedente;Funcional;Alta;✅ Validado
168;Bloco 7 — Cedentes;Busca;Buscar;Buscar cedente por nome/CNPJ;≥4 chars no campo;Debounce 350ms → GET /assignors?q=texto → AssignorResource collection;Funcional;Alta;✅ Validado
169;Bloco 7 — Cedentes;Busca;< 4 chars;Busca com < 4 caracteres;3 chars;Erro 422: "O parâmetro de busca deve ter no mínimo 4 caracteres.";Validação;Média;✅ Validado
170;Bloco 7 — Cedentes;Busca;Sem Resultado;Busca sem resultados;Texto sem correspondência;Dropdown vazio ou "Nenhum cedente encontrado";Funcional;Média;✅ Validado
171;Bloco 7 — Cedentes;Seleção;Selecionar;Selecionar cedente;Clicar em resultado;Salvo no cedenteStore (code, cnpj, name). sessionStorage. CNPJ formatado XX.XXX.XXX/XXXX-XX;Funcional;Alta;✅ Validado
172;Bloco 7 — Cedentes;Seleção;Limpar;Limpar cedente selecionado;Clicar "X";cedenteStore resetado. Dados recarregam sem filtro;Funcional;Média;✅ Validado
173;Bloco 7 — Cedentes;Persistência;Navegação;Persistência entre navegação;Selecionar → Navegar → Voltar;Cedente mantido (sessionStorage);Funcional;Média;✅ Validado
174;Bloco 7 — Cedentes;Persistência;Fechar Aba;Cedente perdido ao fechar aba;Fechar aba → Reabrir;Cedente resetado (sessionStorage limpa);Funcional;Baixa;✅ Validado
175;Bloco 7 — Cedentes;Favorecidos;User;Consultar favorecidos como usuário;GET /beneficiaries/;CNPJ via user.resolveCnpj(). BeneficiaryResource retornada;Funcional;Alta;✅ Validado
176;Bloco 7 — Cedentes;Favorecidos;Admin s/ CNPJ;Consultar favorecidos admin sem CNPJ;GET /beneficiaries/ como admin sem cnpj;Erro 422: "O campo CNPJ é obrigatório para administradores.";Validação;Alta;✅ Validado
177;Bloco 7 — Cedentes;Favorecidos;Admin c/ CNPJ;Consultar favorecidos admin com CNPJ;GET /beneficiaries/?cnpj=xxx;Favorecidos do CNPJ retornados;Funcional;Alta;✅ Validado
178;Bloco 7 — Cedentes;Favorecidos;Vazio;Sem favorecidos cadastrados;CNPJ sem contas na API;Response 204 No Content;Funcional;Média;✅ Validado
179;Bloco 7 — Cedentes;Detalhes API;Válido;Consultar detalhes com dados válidos;GET /consulta-detalhes-operacao/ válido;DetalhesOperacaoResource com sacados, títulos, favorecidos;Funcional;Alta;✅ Validado
180;Bloco 7 — Cedentes;Detalhes API;Inválido;Consultar detalhes com borderô/aditivo inválido;Parâmetros inválidos;"Esta operação não possui detalhamento disponível. Operações em digitação devem ser acessadas pela tela de edição.";Funcional;Alta;✅ Validado
181;Bloco 7 — Cedentes;Detalhes API;Não Autorizado;CNPJ não autorizado;CNPJ de outro usuário;Erro 403: "Detalhes não encontrados ou CNPJ não autorizado.";Segurança;Alta;✅ Validado
182;Bloco 7 — Cedentes;Detalhes API;Erro Interno;Erro interno na consulta;API erro inesperado;"Erro interno ao consultar detalhes da operação. Tente novamente.";Funcional;Alta;✅ Validado
183;Bloco 8 — Layout;Sidebar;Menu;Menu lateral renderizado após login;Login com sucesso;Sidebar roxo #221C42. Logo, 3 itens: Dashboard, Operações, Relatórios. "Sair" no rodapé;Funcional;Alta;✅ Validado
184;Bloco 8 — Layout;Sidebar;Navegação;Navegação via menu;Clicar itens do menu;Router navega. Item ativo com fundo #6359E9;Navegação;Alta;✅ Validado
185;Bloco 8 — Layout;Sidebar;Dashboard Admin;Dashboard desabilitado para admin;Login como admin;opacity: 0.5, cursor: not-allowed. Tooltip: "Área ainda não habilitada para admin";Funcional;Média;✅ Validado
186;Bloco 8 — Layout;Sidebar;Relatórios Admin;Relatórios desabilitado para admin;Login como admin;Mesmo comportamento desabilitado;Funcional;Média;✅ Validado
187;Bloco 8 — Layout;Sidebar;Tela Pequena;Menu em tela pequena (< md);Viewport < 1024px;Sidebar overlay (drawer). Fecha após navegação;UI;Média;✅ Validado
188;Bloco 8 — Layout;Sidebar;Logo Fallback;Logo com fallback;Logo não carrega (404);Fallback texto "opera CAPITAL" branco;UI;Baixa;✅ Validado
189;Bloco 8 — Layout;Logout;Dialog;Fluxo de logout;Clicar "Sair";Dialog: "Deseja realmente sair?" com "Cancelar" / "Sair";Funcional;Alta;✅ Validado
190;Bloco 8 — Layout;Logout;Confirmar;Confirmar logout;Clicar "Sair" no dialog;POST /logout → Cookie removido → Store reset → PostHog reset → Redirect /login;Funcional;Alta;✅ Validado
191;Bloco 8 — Layout;Logout;Cancelar;Cancelar logout;Clicar "Cancelar";Dialog fecha. Nenhuma ação. Permanece na página;Funcional;Média;✅ Validado
192;Bloco 8 — Layout;Interceptors;Token;Token automaticamente injetado;Qualquer request autenticado;Authorization: Bearer {token} do cookie "authorization";Segurança;Alta;✅ Validado
193;Bloco 8 — Layout;Interceptors;Toast Sucesso;Toast de sucesso em mutations;POST/PUT/DELETE com sucesso;Toast verde: mensagem da API ou "Operação realizada com sucesso!" (12s);Funcional;Média;✅ Validado
194;Bloco 8 — Layout;Interceptors;Toast Erro;Toast de erro em requests;Request falha (4xx/5xx);Toast vermelho. Login: timeout infinito + botão fechar. Outros: 12s;Funcional;Média;✅ Validado
195;Bloco 8 — Layout;Interceptors;401 Global;401 global — sessão expirada;Request retorna 401 (exceto /login e /logout);PostHog reset → Cookie removido → reload() após 100ms → Redirect /login;Segurança;Alta;✅ Validado
196;Bloco 8 — Layout;Interceptors;FormData;FormData handling;Upload de arquivos;Content-Type removido para browser definir multipart/form-data;Funcional;Média;✅ Validado
197;Bloco 8 — Layout;Preferências;Tema Auto;Tema padrão (auto);Primeiro acesso;theme = 'auto'. Quasar Dark.set('auto');Funcional;Baixa;✅ Validado
198;Bloco 8 — Layout;Preferências;Toggle Tema;Alternar tema;Toggle light ↔ dark;setTheme() atualiza store e Quasar Dark. Persistido localStorage;Funcional;Baixa;✅ Validado
199;Bloco 8 — Layout;Preferências;Idioma;Idioma (pt padrão);Primeiro acesso;language = 'pt'. Reservado para futura i18n;Funcional;Baixa;✅ Validado
200;Bloco 8 — Layout;Preferências;Sidebar;Sidebar colapsada;Toggle sidebar;sidebarCollapsed atualizado. Persistido localStorage;Funcional;Baixa;✅ Validado
201;Bloco 8 — Layout;Chatbot;Inicialização;Inicialização do chatbot;Primeiro carregamento MainLayout;Script Typebot injetado (check data-typebot-injected). Bubble verde #5c8a2f;Funcional;Baixa;✅ Validado
202;Bloco 8 — Layout;Chatbot;Não Duplica;Chatbot não duplica;Navegar entre páginas;querySelector impede reinjeção do script;Funcional;Baixa;✅ Validado
203;Bloco 8 — Layout;404;Rota Inexistente;Rota inexistente;URL que não existe;ErrorNotFound.vue via /:catchAll(.*)*;Funcional;Média;✅ Validado
204;Bloco 9 — Complementares;Download Mídia;Owner CNAB;Download de arquivo CNAB (owner);GET /media/{media}/download como dono;Middleware EnsureMediaOwnership valida collection 'cnab' → user_id match. Download OK;Funcional;Alta;✅ Validado
205;Bloco 9 — Complementares;Download Mídia;Owner XML;Download de arquivo XML de invoice (owner);GET /media/{media}/download para XML de invoice;Middleware valida collection 'xml' → operation.user_id match. Download OK;Funcional;Alta;✅ Validado
206;Bloco 9 — Complementares;Download Mídia;Outro Usuário;Download de arquivo de outro usuário;GET /media/{media}/download como usuário diferente;Erro 403: "Acesso não autorizado." via EnsureMediaOwnership;Segurança;Alta;✅ Validado
207;Bloco 9 — Complementares;Download Mídia;Collection Desconhecida;Download com collection desconhecida;Arquivo com collection não mapeada;userId = null → 403 "Acesso não autorizado.";Segurança;Média;✅ Validado
208;Bloco 9 — Complementares;Rate Limiting;Verify Token;Rate limiting no verify-token;4+ requests em 1 min para POST /verify-token;Erro 429. Throttle: 3,1;Segurança;Alta;✅ Validado
209;Bloco 9 — Complementares;Rate Limiting;Preview;Rate limiting no pre-registration-preview;11+ requests em 1 min para POST /pre-registration-preview;Erro 429. Throttle: 10,1;Segurança;Média;✅ Validado
210;Bloco 9 — Complementares;Validação CMC7;< 30 dígitos;CMC7 com menos de 30 dígitos;Cheque com CMC7 de 29 dígitos;Erro 422: "O campo CMC7 informado é inválido. Verifique o código e tente novamente.";Validação;Alta;✅ Validado
211;Bloco 9 — Complementares;Validação CMC7;> 30 dígitos;CMC7 com mais de 30 dígitos;Cheque com CMC7 de 31 dígitos;Mesmo erro 422 da Cmc7Rule;Validação;Média;✅ Validado
212;Bloco 9 — Complementares;Validação CMC7;Repetidos;CMC7 com 30 dígitos repetidos;CMC7 = "111111111111111111111111111111";Erro 422: regex detecta repetição. CMC7 inválido;Validação;Média;✅ Validado
213;Bloco 9 — Complementares;Validação CPF;Dígitos Incorretos;CPF com dígitos verificadores incorretos;Sacado com CPF que falha validação algorítmica;Erro 422: "O campo cnpj_cpf deve ser um CPF ou CNPJ válido." (CnpjCpfRule);Validação;Alta;✅ Validado
214;Bloco 9 — Complementares;Validação CPF;Repetidos;CPF com 11 dígitos repetidos;CPF = "11111111111";Erro 422: regex rejeita. CPF inválido;Validação;Média;✅ Validado
215;Bloco 9 — Complementares;Validação CNPJ;Inválido;CNPJ inválido via CnpjHelper;CNPJ com dígitos incorretos;Erro 422: "O campo cnpj deve ser um CNPJ válido." (CnpjRule);Validação;Alta;✅ Validado
216;Bloco 9 — Complementares;Validação CPF/CNPJ;CPF no campo;Documento que é CPF válido mas não CNPJ;CPF válido no campo cnpj_cpf;Aceito — CnpjCpfRule testa CPF e CNPJ. Basta um ser válido;Validação;Média;✅ Validado
217;Bloco 9 — Complementares;Importação;Extensão Inválida;Upload de arquivo com extensão não suportada;Enviar .pdf ou .txt via import;Erro 422: "Apenas arquivos xml, rem são permitidos." (ImportFileType::fromExtension);Validação;Alta;✅ Validado
218;Bloco 9 — Complementares;Importação;> 10MB;Upload de arquivo > 10MB;Arquivo XML > 10MB;Erro 422: "Cada arquivo não pode exceder o tamanho máximo de 10 MB." (max:10240);Validação;Média;✅ Validado
219;Bloco 9 — Complementares;Importação;Sem Arquivos;Import sem arquivos;POST /operations/import sem campo files;Erro 422: "É necessário enviar pelo menos um arquivo para importação.";Validação;Alta;✅ Validado
220;Bloco 9 — Complementares;Importação;Op Inexistente;Import com operation_id inexistente;operation_id que não existe;Erro 422: "A operação especificada não existe." (exists:operations,id);Validação;Média;✅ Validado
221;Bloco 9 — Complementares;Importação;Banco Não Suportado;Import CNAB com banco não suportado;CNAB 400 com código de banco não mapeado;UnsupportedBankException: "Banco com código 'XXX' não é suportado para importação CNAB 400." ImportLog: ERROR;Funcional;Alta;✅ Validado
222;Bloco 9 — Complementares;Importação;Título Duplicado;Import com título duplicado (mesma NF-e);XML com NF-e já existente;updateOrCreateByBankTitle() faz upsert — atualiza existente. ImportLog: IMPORTED;Funcional;Média;✅ Validado
223;Bloco 9 — Complementares;Importação;Batch Inexistente;Import batch não encontrado;GET /operations/import/{batchKey}/summary inexistente;404: "Lote de importação não encontrado.";Funcional;Média;✅ Validado
224;Bloco 9 — Complementares;Importação;Logs Operação;Import logs de operação;GET /operations/{id}/import-logs;Lista de ImportBatch com ImportSummaryResource;Funcional;Média;✅ Validado
225;Bloco 9 — Complementares;CNPJ;Sem CNPJ Store;Criar operação sem CNPJ disponível;POST /operations/ como user sem CNPJ;Erro 422: "CNPJ não disponível." (controller verifica resolveCnpj);Funcional;Alta;✅ Validado
226;Bloco 9 — Complementares;CNPJ;Import s/ CNPJ;Import sem CNPJ disponível;POST /operations/import como user sem CNPJ;Erro 422: "CNPJ não disponível.";Funcional;Alta;✅ Validado
227;Bloco 9 — Complementares;Admin;Ops s/ CNPJ;Admin lista operações sem CNPJ;GET /operations/?status=DIGITANDO como admin sem cnpj;Erro 422: "O campo CNPJ é obrigatório para usuários Opera.";Validação;Alta;✅ Validado
228;Bloco 9 — Complementares;Rotas;GET /user;GET /user (rota inline);GET /user autenticado;Retorna request->user() — dados do user sem UserResource wrapper;Funcional;Baixa;✅ Validado
229;Bloco 9 — Complementares;Isolamento;Invoice Outro User;Usuário visualiza invoice de outro usuário;GET /invoices/{id} com invoice de outro user;404: "Nota fiscal não encontrada" (findUserInvoice filtra por user);Segurança;Alta;✅ Validado
230;Bloco 9 — Complementares;Isolamento;Check Outro User;Usuário visualiza cheque de outro usuário;GET /checks/{id} com check de outro user;404: "Cheque não encontrado";Segurança;Alta;✅ Validado
231;Bloco 9 — Complementares;Isolamento;Payer Outro User;Usuário visualiza sacado de outro usuário;GET /payers/{id} com payer de outro user;404: "Sacado não encontrado." (getPayer filtra por user_id);Segurança;Alta;✅ Validado
232;Bloco 9 — Complementares;Op Submetida;Criar Invoice;Criar invoice em operação submetida;POST /invoices/ com operation_id de op PROCESSANDO;422: "Operação não encontrada ou já submetida." (canModifyOperation);Funcional;Alta;✅ Validado
233;Bloco 9 — Complementares;Op Submetida;Editar Invoice;Editar invoice em operação submetida;PUT /invoices/{id} de op submetida;404: "Nota fiscal não encontrada" (updateInvoice retorna null);Funcional;Alta;✅ Validado
234;Bloco 9 — Complementares;Op Submetida;Excluir Invoice;Excluir invoice em operação submetida;DELETE /invoices/{id} de op submetida;404: "Nota fiscal não encontrada" (deleteInvoice retorna false);Funcional;Alta;✅ Validado
235;Bloco 9 — Complementares;Op Submetida;Criar Check;Criar check em operação submetida;POST /checks/ com operation_id de op PROCESSANDO;422: "Operação não encontrada ou já submetida.";Funcional;Alta;✅ Validado
236;Bloco 9 — Complementares;Op Submetida;Editar Check;Editar check em operação submetida;PUT /checks/{id} de op submetida;404: "Cheque não encontrado";Funcional;Alta;✅ Validado
237;Bloco 9 — Complementares;Op Submetida;Excluir Check;Excluir check em operação submetida;DELETE /checks/{id} de op submetida;404: "Cheque não encontrado";Funcional;Alta;✅ Validado
238;Bloco 9 — Complementares;API Opera;Timeout;Timeout na API Opera Capital;Request excede 30s;Retry 3x com 100ms delay. Se falhar: OperaCapitalException;Funcional;Alta;✅ Validado
239;Bloco 9 — Complementares;API Opera;Token Expirado;Token JWT expirado durante operação;Cache de token expira entre requests;OperaCapitalClient reauthentifica automaticamente (cache 55min);Funcional;Média;✅ Validado
240;Bloco 9 — Complementares;API Opera;Erro Desconhecido;API retorna erro desconhecido;Response com formato inesperado;OperaCapitalException::fromResponse() extrai 'detail' ou 'error' ou fallback;Funcional;Média;✅ Validado
241;Bloco 9 — Complementares;NF-e/NFS-e;Sem Nenhuma Chave;Criar título sem nfe_key NEM nfs_e_key;POST /invoices/ com ambos nulos (tipo DUPLICATA/XML);Erro 422: "O campo chave da NF-e é obrigatório quando a chave da NFS-e não for informada.";Validação;Alta;✅ Validado
242;Bloco 9 — Complementares;NF-e/NFS-e;Apenas NFS-e;Criar título com apenas nfs_e_key;POST /invoices/ com nfs_e_key válida e nfe_key nulo;201 Created — requiredIf(empty nfe_key) satisfeito;Funcional;Média;✅ Validado
243;Bloco 9 — Complementares;NF-e/NFS-e;NFS-e > 50 chars;NFS-e key > 50 caracteres;nfs_e_key com 51 chars;Erro 422: "O campo chave da NFS-e não pode ter mais de 50 caracteres.";Validação;Média;✅ Validado
244;Bloco 9 — Complementares;NF-e/NFS-e;Duplicata Standalone;NF-e key duplicada em StoreInvoiceRequest;POST /invoices/ com nfe_key existente;Aceita — StoreInvoiceRequest NÃO tem unique constraint (potencial duplicata);Validação;Alta;✅ Validado
245;Bloco 9 — Complementares;NF-e/NFS-e;Duplicata Operação;NF-e key duplicada ao criar operação;POST /operations/ com invoice.nfe_key existente;Erro 422: "Esta chave de NF-e já está cadastrada no sistema." (unique whereNull deleted_at);Validação;Alta;✅ Validado
246;Bloco 9 — Complementares;Filtros Listagem;Payer por CNPJ;Filtrar sacados por cnpj_cpf;GET /payers/?cnpj_cpf=12345678000190;Retorna sacados com CNPJ/CPF correspondente (service limpa máscara);Funcional;Média;✅ Validado
247;Bloco 9 — Complementares;Filtros Listagem;Payer por Nome;Filtrar sacados por razão social (parcial);GET /payers/?company_name=empresa;Busca LIKE retorna matches parciais;Funcional;Média;✅ Validado
248;Bloco 9 — Complementares;Filtros Listagem;Payer por Cidade;Filtrar sacados por cidade;GET /payers/?city=São Paulo;Retorna sacados da cidade;Funcional;Baixa;✅ Validado
249;Bloco 9 — Complementares;Filtros Listagem;Payer por Estado;Filtrar sacados por estado;GET /payers/?state=SP;Retorna sacados do estado (max:2 chars);Funcional;Baixa;✅ Validado
250;Bloco 9 — Complementares;Filtros Listagem;Payer por Email;Filtrar sacados por e-mail;GET /payers/?email=teste@empresa.com;Match exato do e-mail;Funcional;Baixa;✅ Validado
251;Bloco 9 — Complementares;Filtros Listagem;Payer Multi-filtro;Filtrar sacados com múltiplos filtros;GET /payers/?state=SP&city=São Paulo;AND lógico — ambos critérios aplicados;Funcional;Média;✅ Validado
252;Bloco 9 — Complementares;Filtros Listagem;Payer Sem Filtro;Filtrar sacados sem parâmetros;GET /payers/ (sem filtros);Retorna todos os sacados do usuário;Funcional;Baixa;✅ Validado
253;Bloco 9 — Complementares;Filtros Listagem;Invoice por Op;Filtrar invoices por operation_id;GET /invoices/?operation_id={id};Retorna invoices da operação;Funcional;Média;✅ Validado
254;Bloco 9 — Complementares;Filtros Listagem;Invoice por Número;Filtrar invoices por número (parcial);GET /invoices/?number=001;LIKE retorna matches parciais;Funcional;Média;✅ Validado
255;Bloco 9 — Complementares;Filtros Listagem;Check por CMC7;Filtrar checks por cmc7 (parcial);GET /checks/?cmc7=12345;LIKE retorna matches parciais;Funcional;Média;✅ Validado
256;Bloco 9 — Complementares;Detalhes Params;Snake Case;Parâmetros em snake_case;GET /consulta-detalhes-operacao/?cnpj_cedente=XXX&num_bordero=123;prepareForValidation() converte para camelCase. Request aceita;Funcional;Média;✅ Validado
257;Bloco 9 — Complementares;Detalhes Params;Camel Case;Parâmetros em camelCase;GET /consulta-detalhes-operacao/?CNPJCedente=XXX&NumBordero=123;Aceita diretamente;Funcional;Média;✅ Validado
258;Bloco 9 — Complementares;Detalhes Params;Sem Borderô/Aditivo;Sem borderô nem aditivo;GET /consulta-detalhes-operacao/?CNPJCedente=XXX;Erro 422: "Informe o número do borderô ou do aditivo." (required_without);Validação;Alta;✅ Validado
259;Bloco 9 — Complementares;Detalhes Params;Ambos;Com borderô e aditivo;GET ?CNPJCedente=XXX&NumBordero=1&NumAditivo=2;Ambos aceitos (required_without permite ter os dois);Funcional;Baixa;✅ Validado
260;Bloco 9 — Complementares;Detalhes Params;CNPJ Inválido;CNPJ do cedente inválido na consulta;GET ?CNPJCedente=invalido&NumBordero=1;Erro 422: "O CNPJ do cedente informado é inválido." (CnpjHelper);Validação;Alta;✅ Validado
261;Bloco 9 — Complementares;Multi-Upload;2 XMLs;Upload de 2 XMLs em um request;POST /operations/import com files[]=[file1.xml, file2.xml];Ambos processados. ImportBatch total_files=2;Funcional;Média;✅ Validado
262;Bloco 9 — Complementares;Multi-Upload;XML + CNAB;Upload de XML + CNAB no mesmo request;files[]=[file.xml, file.rem];Cada arquivo roteado para job correto;Funcional;Média;✅ Validado
263;Bloco 9 — Complementares;Multi-Upload;Parcial Falha;Upload parcial: 1 falha, 2 sucedem;3 arquivos, 1 malformado;ImportLog: 2 IMPORTED, 1 ERROR. processed_files=3;Funcional;Alta;✅ Validado
264;Bloco 9 — Complementares;Modal Readonly;Nota Submetida;EditarNotaModal em operação submetida;Clicar título em op EM_ANALISE/ASSINATURA/PAGO;Modal readonly: campos desabilitados, botão salvar oculto;UI;Média;✅ Validado
265;Bloco 9 — Complementares;Modal Readonly;Cheque Submetido;EditarChequeModal em operação submetida;Clicar cheque em op submetida;Modal readonly: campos desabilitados, botão salvar oculto;UI;Média;✅ Validado
266;Bloco 9 — Complementares;Submissão;Fee Zero;Fee = 0 na submissão;POST /operations/{id}/submit com fee=0;Aceito — fee nullable, numeric, min:0. Zero é válido;Funcional;Média;✅ Validado
267;Bloco 9 — Complementares;Submissão;Fee Negativa;Fee negativa na submissão;POST /operations/{id}/submit com fee=-1;Erro 422: "O campo taxa de deságio não pode ser menor que zero.";Validação;Média;✅ Validado
268;Bloco 9 — Complementares;Submissão;Obs Beneficiário;Observação do beneficiário > 255 chars;beneficiaries[0].observation com 256 chars;Erro 422: "A observação do favorecido não pode ter mais de 255 caracteres.";Validação;Baixa;✅ Validado
269;Bloco 9 — Complementares;Admin;Criar Op s/ CNPJ;Admin cria operação sem CNPJ;POST /operations/ como admin sem cnpj;Erro 422: "O campo CNPJ é obrigatório para administradores.";Validação;Alta;✅ Validado
270;Bloco 9 — Complementares;Rotas;GET /me;GET /me retorna UserResource;GET /me autenticado;Response formatada via UserResource (id, name, user_name, email, cnpj, role);Funcional;Média;✅ Validado
271;Bloco 9 — Complementares;Rotas;GET /user Raw;GET /user retorna objeto raw;GET /user autenticado;Response com objeto User direto sem wrapper Resource;Funcional;Baixa;✅ Validado
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment