# Correções do módulo Financeiro + Emissão de Boletos (PagBank)

Este pacote contém **apenas os arquivos alterados ou criados**, na mesma
estrutura de pastas do sistema original. Copie-os por cima do projeto atual
(nenhum arquivo existente foi removido) e rode o script SQL.

## 1) Instalação

1. Copie os arquivos deste pacote para dentro da pasta `sistema/` do projeto.
2. Rode o script de migração no banco de dados:
   `INSTALACAO/SQL_ATUALIZACAO/06_financeiro_correcoes_e_boleto.sql`
   (pode ser executado mais de uma vez sem erro — todos os comandos verificam
   se a tabela/coluna já existe antes de criar).
3. Acesse **Financeiro > Config. PagBank** no sistema e cadastre o token de
   API (sandbox e/ou produção). Enquanto não configurar, os botões de
   emissão de boleto mostram um aviso e não fazem nada.

## 2) Bugs corrigidos no módulo Financeiro

1. **Tabelas/colunas usadas no código mas inexistentes no banco** — o
   controller/model já usavam `fin_contas`, `fin_transferencias`,
   `fin_config` e várias colunas de `fin_lancamentos` (`conta_id`,
   `fornecedor`, `competencia_mes`, `tax_id`, `tax_valor`, `anexo`,
   `gdrive_file_id`, `gdrive_link`, `recorrente` e afins) que **não existiam
   em nenhum script de instalação**. Isso quebrava as telas de Contas
   Bancárias, Transferências, anexos, recorrência e configuração de recibo.
   Corrigido pelo script `06_financeiro_correcoes_e_boleto.sql`.
2. **Variável `$new_id` não inicializada** em `add_lancamento()` — ao editar
   um lançamento, a lógica de recorrência usava uma variável que só existia
   no fluxo de criação. Corrigido: `$new_id` agora é sempre inicializada, e a
   recorrência só é (re)criada na criação do lançamento (evita duplicar a
   série toda vez que um lançamento recorrente é editado).
3. **Injeção de SQL em `get_categorias($tipo)`** — o valor vinha direto do
   `$_POST`/`$_GET` (usado em `ajax_sugerir_categoria` e na rota
   `lancamentos/{tipo}`) e era concatenado cru na cláusula `WHERE`. Corrigido
   com `where_in()` (bind automático do CodeIgniter).
4. **Ações destrutivas via link GET sem proteção**, somadas ao fato de a
   proteção CSRF global do CodeIgniter estar desabilitada
   (`$config['csrf_protection'] = FALSE`) — `delete_lancamento`,
   `delete_conta` e `baixar` agora exigem POST + um token de formulário por
   sessão (gerado no construtor do controller, validado antes de executar a
   ação). Os links de exclusão nas telas foram trocados de `<a href="delete/...">`
   para um envio seguro via `postDelete()` (função JS adicionada ao
   `footer.php`, reaproveitável em qualquer tela do sistema).
5. Indentação/formatação do bloco de recorrência (estava fora do padrão do
   arquivo, sinal de um patch anterior mal aplicado).
6. **Método inexistente `get_client()`** — `bpo_cliente()` e `bpo_pdf()`
   chamavam `$this->clients_model->get_client($id)`, mas esse método nunca
   existiu no model (só existe `get_client_by_id($id)`). Isso quebrava com
   erro fatal a ficha BPO do cliente e a geração do PDF de BPO. Corrigido.
7. **Upload de anexo sem nenhuma restrição de tipo/tamanho** — em
   `add_lancamento()`, o upload do comprovante/nota fiscal aceitava
   `allowed_types = '*'` (qualquer arquivo) e `max_size = 0` (sem limite),
   salvando dentro de uma pasta sob o webroot (`FCPATH`). Isso permitia, na
   prática, que qualquer usuário com acesso ao financeiro enviasse um
   arquivo `.php` para dentro do site — um risco real de execução remota de
   código. Corrigido: agora só aceita `pdf, jpg, jpeg, png, gif, doc, docx,
   xls, xlsx, csv, txt`, com limite de 10 MB, e a pasta de upload passa a
   ganhar um `.htaccess` que bloqueia execução de script nela (defesa em
   profundidade, caso algum arquivo malicioso escape do filtro de tipos).

> Observação: a proteção CSRF global do CodeIgniter continua desabilitada
> para o restante do sistema. O que foi feito aqui é uma blindagem pontual
> das ações mais sensíveis do módulo financeiro; o ideal a médio prazo é
> avaliar habilitar `$config['csrf_protection']` globalmente.

## 3) Emissão de Boletos via PagBank

### Onde configurar
A configuração do PagBank (token, ambiente, comportamento automático) fica em
**Configurações > aba "PagBank"** (`admin/settings#tab-pagbank`), junto com as
demais integrações do sistema (WhatsApp, IA, Assinatura Eletrônica etc.). A
antiga tela separada `admin/financeiro_boleto/config` foi removida e agora
apenas redireciona para lá, para não quebrar links salvos.

Em **Financeiro > Boletos (PagBank)** continua a lista de boletos emitidos
(status, reenvio por e-mail/WhatsApp, consulta de status), e o link "Ver
boletos emitidos" na aba de Configurações leva direto para essa lista.

### Como funciona
- Na tela **Financeiro > Contas a Receber**, lançamentos pendentes vinculados
  a um cliente ganham um botão de código de barras (**Emitir boleto**).
- Ao clicar, o sistema **tenta extrair automaticamente** do cadastro do
  cliente: CPF/CNPJ (se já existir um confirmado, ou por heurística no
  texto do nome/endereço), e endereço estruturado (rua, número,
  complemento, bairro, cidade, UF, CEP) a partir do campo de endereço em
  texto livre — que hoje é o único campo de endereço existente no cadastro.
- **Esses dados são sempre exibidos em um formulário para conferência e
  correção antes de qualquer envio ao PagBank** — a extração automática é
  só um ponto de partida, nunca é enviada "às cegas", pois o texto de
  origem não segue um padrão fixo.
- Ao confirmar, o boleto é criado via API do PagBank (Orders API) e o
  CPF/CNPJ confirmado é salvo no cadastro do cliente (`users.cpf_cnpj`),
  para não perguntar de novo da próxima vez.
- O boleto pode ser reenviado por **e-mail** (reaproveitando o SMTP já
  configurado em Configurações > E-mail) e por **WhatsApp** (reaproveitando
  a integração já existente, `application/libraries/Whatsapp.php`).
- Em **Financeiro > Boletos (PagBank)** fica a lista de todos os boletos
  emitidos, com status (aguardando/pago/recusado/em atraso), botão para
  reenviar e-mail/WhatsApp e botão "Consultar status" (chama a API do
  PagBank sob demanda).
- Quando o PagBank confirma o pagamento (via **webhook** ou via "Consultar
  status"), o lançamento correspondente é **automaticamente marcado como
  pago** no financeiro.

### Emissão automática (opcional)
Em **Financeiro > Config. PagBank** há a opção "Emitir boleto automaticamente
ao criar um lançamento a receber". Quando ligada, todo novo lançamento "a
receber" tenta emitir boleto sozinho — mas **só emite se o cliente já tiver
CPF/CNPJ confirmado** (de uma emissão manual anterior) **e endereço
completo**; caso contrário, ele simplesmente pula e registra no log, deixando
a emissão manual disponível normalmente. Isso evita mandar dados incompletos
ou não conferidos ao PagBank.

### Webhook (atualização automática de status)
A URL de notificação é enviada automaticamente em cada boleto emitido e
também fica visível em **Financeiro > Config. PagBank**:
`{seu-domínio}/admin/financeiro_boleto/webhook`

Isso só funciona se o sistema estiver acessível publicamente pela internet
nesse endereço (o `base_url` atual do sistema, `sistema.brenopaiva.com.br`,
já é público, então deve funcionar sem configuração adicional). Se em algum
momento o sistema rodar em ambiente local/sem acesso externo, use o botão
"Consultar status" na lista de boletos para atualizar manualmente.

> O webhook não valida uma assinatura/segredo do PagBank (a documentação
> pública não expõe esse mecanismo de forma simples) — ele só aceita
> atualizações para pedidos (`order_id`) que o próprio sistema gerou antes,
> então um terceiro precisaria adivinhar um ID de pedido real do PagBank
> para forjar uma notificação, o que é de baixa probabilidade prática.

### Arquivos novos
- `application/libraries/Pagbank.php` — cliente da API (Orders/Boleto).
- `application/helpers/endereco_helper.php` — extração de CPF/CNPJ,
  endereço estruturado e telefone a partir de texto livre, com validação de
  dígito verificador de CPF/CNPJ.
- `application/modules/admin/controllers/financeiro_boleto.php` — telas,
  emissão, envio por e-mail/WhatsApp, consulta de status e webhook.
- `application/modules/admin/models/financeiro_boleto_model.php`
- `application/modules/admin/views/financeiro/boletos.php` — listagem.
- Tabelas novas: `fin_boletos` (um registro por boleto emitido) e
  `fin_boletos_eventos` (log bruto de cada notificação recebida do PagBank,
  para auditoria).
- Coluna nova: `users.cpf_cnpj`.

### Arquivos alterados nesta parte
- `application/modules/admin/views/setting/setting.php` — nova aba "PagBank".
- `application/modules/admin/controllers/settings.php` — carrega a config do
  PagBank para a nova aba.
- `application/modules/admin/views/financeiro/boletos.php` — link do aviso
  de "não configurado" atualizado para a nova aba.
- `application/modules/admin/views/template/header.php` — menu do
  Financeiro agora só tem "Boletos (PagBank)" (sem o item de config, que
  mudou de lugar).

### O que ainda depende de você
- Criar a conta/token no PagBank (sandbox para testar, produção quando
  estiver pronto) e colar em Configurações > PagBank.
- Testar a extração automática de endereço com alguns clientes reais —
  como o cadastro atual só tem um campo de texto livre, endereços fora dos
  padrões mais comuns (ex.: endereços de condomínio/síndico, endereços sem
  CEP) podem vir incompletos e vão precisar de preenchimento manual no
  próprio formulário de emissão — o que já é suportado.

## 4) Bug nas abas de Configurações (corrigido de brinde)

Aproveitando que mexi na tela de Configurações, corrigi um bug real que
causava instabilidade ao clicar entre as abas: a aba "OAB / Monitoramento"
tinha **dois listeners de clique idênticos e duplicados** (um dentro do
primeiro bloco de script, outro dentro de um `DOMContentLoaded` mais abaixo),
então toda vez que essa aba era aberta, a busca do log de sincronização era
disparada **duas vezes** ao mesmo tempo — e cada aba nova que foi sendo
adicionada ao longo do tempo (Google Drive, PagBank etc.) tinha sua própria
lógica solta e repetida para abrir via hash da URL.

Troquei tudo isso por um único handler, usando o evento oficial do Bootstrap
(`shown.bs.tab`) — que já é a forma correta de "escutar troca de aba" — em
vez de vários `$(document).on('click', ...)` soltos e duplicados. Também
padronizei a abertura de aba via hash da URL (ex.: `#tab-pagbank`) num só
lugar, funcionando para qualquer aba, não só as duas que tinham tratamento
especial antes, e adicionei uma atualização defensiva do Chosen.js ao trocar
de aba (evita selects com largura quebrada quando renderizados enquanto a
aba ainda estava oculta).

> Se depois de aplicar isso o problema de abas ainda aparecer, me avise com
> o passo a passo exato de como reproduzir (quais abas, em que ordem) e,
> se possível, o que aparece no console do navegador (F12 > Console) — isso
> ajuda muito a identificar se é outra causa.

**Atualização 1 (causa raiz real):** hoje a página de Configurações tem 11
abas com rótulos longos (Detalhes, DataJud/CNJ, OAB, Google Drive, IA,
WhatsApp, Assinatura, PagBank, RH, SMTP, Segurança), e elas simplesmente não
cabem mais numa linha só em boa parte das telas. O Bootstrap, por padrão,
quebra a lista de abas pra uma segunda linha quando não cabe — e é
exatamente essa quebra que desalinha o visual "de caixa" do
`nav-tabs-custom` (a borda que conecta a aba ativa ao conteúdo abaixo fica
na linha errada).

**Atualização 2:** a pedido, troquei a lista única e rolável por **dois
blocos de abas empilhados**, que ficam mais agradáveis principalmente no
celular:
- **Bloco 1** (configurações principais): Detalhes, Configurações de RH,
  Configurações de SMTP, Segurança.
- **Bloco 2** (integrações): DataJud/CNJ, OAB/Monitoramento, Google Drive,
  Inteligência Artificial, WhatsApp, Assinatura Eletrônica, PagBank.

Cada bloco continua com rolagem horizontal própria caso não caiba tudo numa
tela pequena, mas agora só precisa rolar dentro do seu próprio grupo — bem
mais curto que a lista toda de 11 abas de uma vez.

## 6) Páginas do Financeiro sem link no menu (e bugs que isso escondia)

Você reportou que `admin/financeiro/contas` não tinha botão de acesso.
Conferindo, o menu lateral do Financeiro realmente só linkava para: Visão
Geral, A Receber, A Pagar, Recibos, BPO, Relatórios e Boletos. As páginas
abaixo **já existiam no sistema, funcionais no controller, mas sem nenhum
link visível** — ou só eram alcançáveis por um botão escondido dentro de
outro card:

- **Contas Bancárias** (`admin/financeiro/contas`) — só tinha um botão
  pequeno "Gerenciar" dentro do card de saldo na Visão Geral.
- **Transferências** (`admin/financeiro/transferencias`) — só tinha um botão
  no topo da Visão Geral.
- **Categorias** (`admin/financeiro/categorias`) — **sem nenhum acesso**
  (só existia um link para ela num arquivo de menu antigo, já fora de uso).
- **Pró-labore** (`admin/financeiro/prolabore`) — mesma situação: **sem
  nenhum acesso** na versão atual do menu.
- **Comissões** (`admin/financeiro/comissoes`) — idem, **sem nenhum
  acesso**.

Adicionei as 5 ao menu lateral do Financeiro.

### Bugs reais que isso deixou passar despercebido
Como praticamente ninguém conseguia chegar nessas telas, alguns bugs nunca
tinham sido notados:

1. **Pró-labore: o botão "Salvar" não fazia nada.** O controller nunca lia
   os dados do formulário — clicar em Salvar só recarregava a página, sem
   gravar nada. Também faltava mandar para a view os totais dos cards
   (sempre apareciam zerados) e a consulta excluía "Despesa Fixa" da
   listagem mesmo o formulário permitindo cadastrar esse tipo. Tudo
   corrigido: o formulário salva de verdade, os cards somam certo e despesa
   fixa aparece na lista.
2. **Comissões: o botão "Pagar" não existia de verdade** — o link apontava
   para uma ação (`pagar_comissao`) que nunca tinha sido criada no
   controller (daria erro/página não encontrada ao clicar). Criei a ação
   completa (marca como paga, com confirmação e proteção contra
   forjamento de requisição, igual às outras ações sensíveis do módulo).
   Também corrigi nomes de coluna errados na consulta que faziam o nome do
   advogado e a descrição do lançamento aparecerem sempre como "-".
3. **Contas Bancárias: editar uma conta zerava o saldo atual.** Ao editar
   uma conta só para trocar o nome ou a cor, o sistema sobrescrevia o saldo
   atual com o saldo inicial informado no formulário — apagando o efeito de
   todos os lançamentos e transferências já contabilizados nela. Agora o
   saldo atual é sempre recalculado a partir do histórico, nunca
   sobrescrito diretamente.
4. **Recibos: número do processo nunca aparecia** — faltava um JOIN com a
   tabela de processos na consulta. Corrigido.

Ainda vale registrar: a funcionalidade de **Comissões** tem uma lacuna maior
que não dava para resolver só "de brinde" — não existe hoje nenhuma tela
para *criar* uma comissão (o botão "Novo Lançamento" simplesmente leva para
a tela comum de lançamento, sem nenhum campo de advogado/percentual). A
tabela e a listagem existem, mas falta decidir como uma comissão nasce: é
digitada manualmente, calculada automaticamente a partir de um percentual
por advogado/processo, ou outra regra? Se quiser, me diga como deveria
funcionar que eu implemento essa parte.

## 7) Botão de emitir boleto "sumindo" sem aviso

Você reportou não estar conseguindo ver o botão de emitir boleto. O motivo:
ele só aparecia quando o lançamento cumpria **três** condições ao mesmo
tempo — ser "a receber", estar "Pendente" **e** já ter um cliente vinculado.
Faltando qualquer uma dessas (o mais comum: lançamento sem cliente
vinculado), o botão simplesmente desaparecia da linha, sem nenhuma
explicação — dava a impressão de bug ou de botão "sumido".

Corrigido: agora o botão **sempre aparece** para lançamentos a receber
pendentes. Se o lançamento não tiver cliente vinculado, ele aparece
desabilitado (cinza), com uma dica ao passar o mouse explicando o motivo
("edite o lançamento e selecione o cliente"). Também adicionei o mesmo
botão (e o mesmo modal de emissão) na tabela "A Receber" da **Visão Geral**
do Financeiro — antes só existia na tela de Contas a Receber; se você usa
mais o painel inicial, era mais um lugar onde parecia que o botão não
existia.

**Atualização:** o motivo real de "nada acontecer" ao clicar era outro —
quando o lançamento não tinha cliente vinculado, o botão ficava com o
atributo HTML `disabled`, e um botão desabilitado **não dispara nenhum
evento de clique no navegador** (isso é ainda mais fácil de não perceber no
celular, onde não existe "passar o mouse" pra ler a dica). Ou seja, não
era um bug de JavaScript — o botão realmente não fazia nada por design,
só que sem nenhum aviso visível.

Troquei essa abordagem: agora o botão **é sempre clicável**, mesmo sem
cliente vinculado (só fica com o ícone acinzentado, como indicativo visual).
Ao clicar, o modal sempre abre — se faltar cliente, ele mostra uma mensagem
de erro clara dentro do próprio modal, já com um botão "Editar lançamento"
levando direto para a tela onde dá pra vincular o cliente. Assim, clicar
sempre dá algum retorno, nunca fica "mudo".
