--- tags: [projeto, intranet, sessao, blog, gotechbr-site, nfse] date: 2026-04-28 --- # Sessão 28/04/2026 — Blog GoTechBr + NFSe rejeitada Duas frentes: imagens dos posts do blog (site GotechBr) que não carregavam, e NFSe rejeitada com erro de CEP. ## 1. Blog GoTechBr — imagens dos posts ### Sintoma Cards do blog em `https://gotechbr.com.br/noticias` mostravam só o ícone de jornal (fallback), nenhuma foto. ### Causa raiz - DB de produção tem 78 posts publicados, todos com `imagem_destaque` cadastrado - Mas só **32** dos 46 nomes de arquivo existiam no disco em `uploads/site/blog/` - 46 posts referenciavam arquivos inexistentes → 404 ao servir via rota `/site-img/blog/*` ### Por que faltavam arquivos `BlogPostGenerator::buscarImagem()` tinha cadeia frágil: 1. Pixabay (chave estava OK no .env de produção, mas em algum momento falhou) 2. Fallback: `source.unsplash.com` — **descontinuado** desde 2024 (HTTP 503) 3. Sem terceira camada → posts ficavam com referência a arquivo nunca criado ### Fix 1 — substituir as 46 imagens faltantes por fotos reais Script `replace_blog_pixabay.php` rodado em produção: - Para cada um dos 46 IDs (33-78), buscou foto temática no Pixabay com termos em inglês mapeados por categoria - Heurística do título corrige a categoria do DB (ex: "Auditoria SEO" → categoria=`seo`, não `desenvolvimento web`) - Salvou com o **mesmo nome de arquivo** já cadastrado no DB → não precisou alterar a tabela - Resultado: 46/46 OK, fotos reais (100KB-650KB cada), todas HTTP 200 Mapeamento de termos de busca por categoria fica em `replace_blog_pixabay.php` (no writable, auto-deletado). ### Fix 2 — patch do `BlogPostGenerator` para garantir imagem em posts futuros `app/Libraries/BlogPostGenerator.php`: - `buscarImagem()` virou cascata robusta: 1. **Pixabay** (foto de qualidade, chave `24153424-be1776f84b...` no .env do site) 2. **Loremflickr** — substitui `source.unsplash.com` morto. Foto Flickr CC, sem key 3. **GD branded** — método novo `gerarCapaGD()`. Cria capa local (gradiente verde GoTechBr + título escalado + tag de categoria colorida). Não depende de nada externo - Tipo de retorno mudou de `?string` para `string` — nunca mais retorna null - Trava extra no `gerarPost()`: `if (empty($imagem)) $imagem = $this->gerarCapaGD(...)` antes do INSERT. Garantia de que **fisicamente** não dá pra gravar post sem imagem Pixabay key real está em `/home/gotechbr/public_html/.env` (não no .env da intranet). É necessária para a primeira camada da cadeia. ### Onde foi aplicado - Arquivo deployado em `/home/gotechbr/public_html/app/Libraries/BlogPostGenerator.php` - Backup `.bak.20260428` no servidor ## 2. NFSe rejeitada — CEP correto, mas cMun errado no XML ### Sintoma NFSe ID 55 (cliente Juliana Maria Raia, CNPJ 19.235.953/0001-67, valor R$ 725,00) rejeitada pela SEFIN com erro: > E0240: O CEP informado para o endereço nacional do tomador do serviço não existe ou não pertence ao município do endereço do tomador. ### Investigação - CEP do cliente: 31720-490 (Belo Horizonte/MG, IBGE 3106200) — **válido**, ViaCEP confirma - XML enviado para a SEFIN (`xml_envio` no DB) tinha: - `31720490` ✅ - `3154606` ❌ — esse é o IBGE de **Ribeirão das Neves** (município do **prestador**, GoTechBR) - SEFIN estava certa em rejeitar: CEP de BH não pertence a Ribeirão das Neves ### Causa raiz Função `NfseNacionalApi::buscarCodigoMunicipioPorCep()` usava ViaCEP com timeout 5s. No momento da emissão (21/03 08:00) ViaCEP falhou (timeout/SSL hiccup pontual). O fallback estava em `NfseNacionalApi::montarDPS` linha 603: ```php 'tomador_cMun' => $this->buscarCodigoMunicipioPorCep(...) ?? ($config['codigo_municipio'] ?? '3154606'), ``` Quando ViaCEP retornava null, **caía silenciosamente para o município do prestador** — bug grave porque permitia emissão com dado errado. ### Fix — 3 correções em paralelo **A. Library `app/Libraries/NfseNacionalApi.php`**: - `buscarCodigoMunicipioPorCep()` virou `resolverCodigoMunicipioCliente(array $cliente)`: 1. Lê `cliente['codigo_ibge']` primeiro (cache) 2. Se vazio: chama `buscarIbgePorCep()` que tenta ViaCEP (timeout 10s) → fallback **BrasilAPI** (`brasilapi.com.br/api/cep/v2/`) 3. Sucesso → persiste em `clientes.codigo_ibge` para próximas emissões 4. **Throw `RuntimeException`** se nada funcionar — emissão para em vez de mandar dado errado - Funções novas: `buscarIbgePorCep()`, `cepViaCep()`, `cepBrasilApi()` **B. Tabela `clientes`** — coluna nova: ```sql ALTER TABLE clientes ADD COLUMN codigo_ibge CHAR(7) NULL AFTER cep, ADD INDEX idx_codigo_ibge (codigo_ibge) ``` - Adicionada em prod e local - `ClienteModel::$allowedFields` atualizado para incluir `codigo_ibge` - Script `preencher_ibge_clientes.php` rodou em prod e populou os 18 clientes ativos com IBGE correto **C. Endpoint diagnóstico para reemissão silenciosa**: - `Nfse::reemitirDiagnostico($id)` — token-guarded, igual padrão `cancelarDiagnostico` - Marca a nota original como `cancelada` com motivo registrado - Reemite com mesmos dados (cliente, valor, descrição, contrato) - Passa flag `$notificarCliente=false` para `processarEmissao` — **suprime WhatsApp/email** - Rota: `nfse/reemitir-diagnostico/(:num)` em `Routes.php` - Excluída do auth em `Filters.php` `processarEmissao` ganhou parâmetro `bool $notificarCliente = true`. Default mantém comportamento original; quem chama com `false` evita disparar mensagens. ### Reemissão da nota 55 (sem notificar cliente) - URL: `https://sistema.gotechbr.com.br/nfse/reemitir-diagnostico/55?token=58253c6b...` - Resultado: - Nota 55 → status `cancelada`, motivo: `"E0240... | Reemitida sem notificar cliente"` - Nota **102** (nova) → status `autorizada`, num_dps 69, chave `31546062228347294000141000000000005226040240187384`, valor R$ 725,00 - XML novo: `3106200` ✅ + `31720490` ✅ - Cliente 30: `codigo_ibge` cacheado = 3106200 - **Cliente Juliana NÃO recebeu notificação** (suprimida via flag) ### Deploy - 4 arquivos: `NfseNacionalApi.php`, `Nfse.php`, `Routes.php`, `Filters.php`, `ClienteModel.php` - Procedimento: tr -d CRLF → pscp /tmp → php -l → cp .bak.20260428 → mv → chown gotechbr:gotechbr - OPcache reciclada via `pkill php-cgi` (servidor tem `validate_timestamps=0`) ## Pendentes - Verificar se cron `*/30 8-21 * * *` de NFSe automática vai usar o cache de `codigo_ibge` corretamente nas próximas emissões (deveria — `montarDPS` lê `cliente['codigo_ibge']` agora) - Se algum cliente novo for cadastrado sem CEP, a primeira emissão vai falhar com `RuntimeException` em vez de mandar dado errado — comportamento intencional, mas precisa validar no front que o CEP é obrigatório