Download the PHP package noclick11/click-nfse without Composer
On this page you can find all versions of the php package noclick11/click-nfse. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download noclick11/click-nfse
More information about noclick11/click-nfse
Files in noclick11/click-nfse
Package click-nfse
Short Description Emissão de NFS-e no padrão nacional (Sistema Nacional NFS-e / Sefin Nacional) para aplicações Laravel: DPS assinada em XMLDSIG, envio com mTLS, cancelamento, análise fiscal e dados do DANFSe.
License MIT
Informations about the package click-nfse
Click NFS-e
Emissão de NFS-e no padrão nacional para Laravel.
DPS assinada em XMLDSIG, envio com mTLS à Sefin Nacional, cancelamento,
análise fiscal e dados do DANFSe.
Desde 1º/09/2026 a Resolução CGSN nº 189/2026 obriga ME e EPP do Simples
Nacional a emitir NFS-e pelo Emissor Nacional. Integrar-se a ele é menos sobre
HTTP e mais sobre detalhe fiscal: a DPS precisa sair na ordem exata do
xs:sequence, assinada com parâmetros que não se negociam, com campos que são
obrigatórios num regime tributário e proibidos em outro — e cada erro só
aparece depois do envio, com o número da DPS já queimado.
Esta lib empacota esse conhecimento. O núcleo veio de um sistema em produção e foi extraído com as regras que ele aprendeu na prática, cada uma comentada com o código de rejeição que a motivou.
[!WARNING] Pré-lançamento. O núcleo fiscal é rodado em produção, mas a API de integração ainda está sendo definida e pode mudar antes do
1.0. Emissão de documento fiscal tem efeito legal e quase sempre irreversível: homologue em produção restrita e valide com a sua contabilidade antes de habilitar.
Sumário
- Recursos
- Como funciona
- Requisitos
- Instalação
- Configuração
- Uso
- 1. Implemente os contratos
- 2. Emita
- 3. Acompanhe
- Cancelamento
- Nota INAPTA
- DANFSe
- Comandos
- Tratamento de erros
- Rejeições cobertas
- Referência da API
- Esquemas XSD
- Antes de ir para produção
- Testes
- Roadmap
- Contribuindo
- Segurança
- Licença
Recursos
| DPS no leiaute v1.01 | Montada com DOMDocument, na ordem do xs:sequence, com escaping a cargo do DOM |
| Assinatura XMLDSIG | C14N inclusiva, RSA-SHA1, EndCertOnly, prefixo vazio — os parâmetros do Manual Integrado |
| Transporte mTLS | Certificado A1 convertido para PEM sob demanda, GZip + base64 no corpo JSON |
| Numeração transacional | nDPS reservado por ambiente e série, com avanço automático quando a Sefin já consumiu o número |
| Reconciliação | Consulta a Sefin pelo id da DPS antes de reenviar — nunca emite o mesmo documento duas vezes |
| Cancelamento com escalonamento | Evento 101101 e, se o prazo expirou, solicitação de análise fiscal (101103) com acompanhamento do desfecho |
| Nota INAPTA | O que não pode ser emitido vira registro visível com o motivo, em vez de sumir |
| Dados do DANFSe | XML autorizado achatado e formatado para impressão, sem impor motor de PDF |
| Diagnóstico do certificado | Validade, titular e EKU de autenticação cliente, com alerta de expiração |
| Desacoplado do seu domínio | Dois contratos e uma relação polimórfica: a lib não conhece as suas tabelas |
Como funciona
O ponto central: o número da DPS é reservado e a nota é persistida antes de qualquer chamada HTTP. A regra E0014 proíbe reutilizar um número, mas a legislação admite lacunas na sequência — então, se o envio falhar, a retentativa reaproveita o mesmo número em vez de queimar outro. Gerar número novo a cada tentativa arriscaria emitir duas notas para a mesma cobrança quando a Sefin processou o documento e apenas a resposta se perdeu.
Requisitos
| PHP | 8.2 ou superior, com dom, json, libxml, openssl, simplexml, zlib |
| Laravel | 12 ou 13 |
| Certificado | ICP-Brasil A1 (e-CNPJ) em PKCS#12, com EKU "Autenticação Cliente" |
| Município | Aderente ao Emissor Nacional — verificável pela consulta de convênio embutida |
[!NOTE] Laravel 11 ficou fora do range: todas as versões 11.x estão sob um aviso de segurança sem correção publicada, e o próprio Composer se recusa a instalá-las por padrão.
Instalação
Coloque o .pfx fora do diretório público e fora do versionamento:
Confira a instalação antes de qualquer emissão:
Configuração
O mínimo para começar:
Referência completa das variáveis
### Ambiente e emissão | Variável | Padrão | Descrição | |---|---|---| | `NFSE_AMBIENTE` | `2` | 1 = produção, 2 = produção restrita | | `NFSE_HABILITADA` | `false` | Enquanto `false`, nada é emitido automaticamente | | `NFSE_SERIE` | `00001` | Série da DPS, 5 posições | | `NFSE_VER_APLIC` | `nfse-nacional-php` | Identificação do sistema emissor (`verAplic`) | | `NFSE_TIMEZONE` | `America/Bahia` | Fuso em que `dhEmi` e `dCompet` são escritos | | `NFSE_MARGEM_DH_EMI` | `60` | Segundos de recuo do `dhEmi` (ver E0008) | ### Certificado | Variável | Padrão | Descrição | |---|---|---| | `NFSE_CERT_PATH` | `storage/app/private/certificados/nfse.pfx` | Absoluto ou relativo à raiz do projeto | | `NFSE_CERT_SENHA` | — | Senha do PKCS#12 | | `NFSE_CERT_ALERTA_DIAS` | `30` | Antecedência do alerta de expiração | ### Emitente | Variável | Descrição | |---|---| | `NFSE_EMITENTE_CNPJ` | CNPJ do prestador | | `NFSE_EMITENTE_COD_MUNICIPIO` | Código IBGE do município, 7 dígitos | | `NFSE_EMITENTE_RAZAO_SOCIAL` | Razão social | | `NFSE_EMITENTE_IM` | Inscrição municipal (exibida no DANFSe) | | `NFSE_EMITENTE_ENVIAR_IM` | **Deixe `false`** até o município registrar o contribuinte no CNC (ver E0120) | | `NFSE_EMITENTE_EMAIL`, `NFSE_EMITENTE_FONE` | Contato do prestador | | `NFSE_EMITENTE_LOGRADOURO`, `_NUMERO`, `_COMPLEMENTO`, `_BAIRRO`, `_CEP`, `_UF` | Endereço, usado na impressão | ### Regime tributário | Variável | Padrão | Descrição | |---|---|---| | `NFSE_OP_SIMP_NAC` | `3` | 1 = não optante, 2 = MEI, 3 = ME/EPP | | `NFSE_REG_AP_TRIB_SN` | `1` | Obrigatório quando `3`; proibido nos demais | | `NFSE_REG_ESP_TRIB` | `0` | Regime especial municipal | | `NFSE_TP_RET_ISSQN` | `1` | 1 = não retido, 2 = tomador, 3 = intermediário | | `NFSE_P_ALIQ` | — | Alíquota; só enviada quando há retenção | | `NFSE_P_TOT_TRIB_SN` | — | Percentual do Simples (Lei 12.741/2012) | ### Cancelamento | Variável | Descrição | |---|---| | `NFSE_CODIGOS_PRAZO_EXPIRADO` | Lista separada por vírgula dos códigos de rejeição que significam "prazo esgotado". **Vazio por padrão**: sem ela, o cancelamento não escala sozinho para análise fiscal |Uso
1. Implemente os contratos
A lib não conhece as suas tabelas. Implemente Faturavel no model que
representa o que gera a nota — um pagamento, uma cobrança, uma fatura — e a
nota guarda uma relação polimórfica com ele:
E Tomador em quem recebe o serviço — não precisa ser um model:
Tudo o que esses métodos devolvem é congelado na nota no momento da preparação: alterar o model depois não altera um documento já emitido, que é o comportamento correto para efeito fiscal.
2. Emita
Na fila, com retry e backoff próprios (fila nfse, 5 tentativas,
backoff de 1 min a 3 h, ShouldBeUnique por faturável):
Ou de forma síncrona, quando você quer o desfecho na hora:
prepararNota() é idempotente por design: chamadas repetidas para o mesmo
faturável devolvem sempre a mesma nota, o que protege contra webhook
reentregue.
3. Acompanhe
| Status | Significado | Reemite sozinha? |
|---|---|---|
PENDENTE |
Número reservado, ainda não enviada | ✅ |
PROCESSANDO |
Envio em andamento | — |
AUTORIZADA |
Documento existe na Sefin | ❌ |
REJEITADA |
Recusada por regra de negócio | ❌ (só manual, após correção) |
ERRO |
Falha técnica (rede, 5xx) | ✅ |
CANCELADA |
Cancelamento concluído | ❌ |
INAPTA |
Não pôde ser emitida; motivo registrado | ❌ (via emitirInapta()) |
Cancelamento
Códigos aceitos pelo schema: MOTIVO_ERRO_EMISSAO (1),
MOTIVO_SERVICO_NAO_PRESTADO (2), MOTIVO_OUTROS (9). A justificativa exige
15 caracteres — textos curtos são complementados em vez de derrubar o pedido.
O serviço tenta o evento 101101 e, se o prazo municipal já expirou, escala para solicitação de análise fiscal (101103), agendando o acompanhamento do deferimento (105104) ou indeferimento (105105).
[!IMPORTANT] O escalonamento só ocorre para os códigos de rejeição listados em
NFSE_CODIGOS_PRAZO_EXPIRADO. A Sefin não publica um código único para esse cenário, e abrir pedido de análise indevido cria trabalho para a fiscalização municipal — por isso o padrão é não escalar.
cancelamento_status |
Significado |
|---|---|
SOLICITADO |
Evento 101101 enviado |
DEFERIDO |
Cancelamento efetivado |
ANALISE_SOLICITADA |
Pedido 101103 registrado, aguardando a fiscalização |
INDEFERIDO |
A fiscalização recusou — a nota continua válida |
ERRO |
Falha no envio do evento |
Quando o estorno ocorre antes de a nota ter sido autorizada, use
cancelarLocalmente(): não há documento fiscal a cancelar, mas o número
reservado continua queimado.
Nota INAPTA
Quando o faturável não pode gerar nota — tomador sem CPF/CNPJ válido, código
de serviço ausente — a lib registra o caso como INAPTA com o motivo, em
vez de falhar em silêncio. A nota não reserva número nem gera DPS: é um
marcador visível para correção.
A reavaliação reusa o mesmo registro, preservando o histórico e o id já visível ao operador.
DANFSe
DanfseService::dadosParaView() devolve o XML autorizado já achatado e
formatado — prestador, tomador, valores, chave, URL para o QR Code. A
renderização é sua:
A lib não depende de motor de PDF nem de gerador de QR Code — essa escolha
é do seu projeto. Em examples/laravel-app/ há uma view Blade
completa e um controller que a imprime com dompdf.
O documento com valor legal é o XML autorizado. O PDF é só uma representação: gere sob demanda, não armazene.
Comandos
| Comando | Função |
|---|---|
nfse:verificar-certificado |
Valida o A1: legibilidade, validade, titular e autenticação cliente. Aceita --json |
nfse:reconciliar |
Consulta na Sefin o desfecho de notas travadas em PROCESSANDO. Aceita --minutos=15 |
nfse:acompanhar-analises |
Verifica se a fiscalização deferiu ou indeferiu os pedidos pendentes |
Tratamento de erros
Duas exceções, e a distinção entre elas é o que decide se vale reenviar:
NfseRejeicaoException estende NfseException, então capturar só a segunda
pega as duas — a ordem dos catch importa.
Rejeições cobertas
O que a lib faz para não esbarrar em cada uma. É a parte que custa caro descobrir sozinho:
| Código | O que significa | Como é tratado |
|---|---|---|
E0004 / E1263 |
Identificador não confere com o corpo | DpsIdGenerator monta e valida contra o pattern do schema |
E0008 |
dhEmi no mesmo segundo do processamento |
Recuo configurável (NFSE_MARGEM_DH_EMI) |
E0014 |
Série + número já utilizados | Reserva o número seguinte e reenvia, até 25 avanços — reconciliando antes |
E0015 |
Competência posterior à emissão | dCompet e dhEmi derivados do mesmo fuso |
E0120 |
IM do prestador não deve ser informada | IM só entra na DPS se NFSE_EMITENTE_ENVIAR_IM=true |
E0166 |
Falta regApTribSN no ME/EPP |
Enviado quando op_simp_nac = 3, omitido nos demais |
E0234 |
Endereço do tomador exigido | Não enviado: a incidência é no estabelecimento do prestador |
E0621 / E0625 / E0635 |
Alíquota obrigatória ou proibida | pAliq só é enviada quando há retenção |
E0712 |
indTotTrib recusado no Simples |
Optante declara pTotTribSN; os demais, indTotTrib |
E0714 |
Assinatura inválida | O XML assinado nunca é reserializado nem reindentado |
E0824 |
Cancelamento sem tomador identificado | Emissão é segurada (INAPTA) se o documento do tomador não valida |
E1235 |
Falha no esquema do DF-e | Id do pedido sem nPedRegEvento; descrições exatamente como enumeradas |
Referência da API
Serviços
| Classe | Papel | |---|---| | `NfseEmissaoService` | `prepararNota()`, `emitir()`, `reemitir()`, `emitirInapta()`, `reconciliar()` | | `NfseCancelamentoService` | `cancelar()`, `solicitarAnaliseFiscal()`, `consultarResultadoAnalise()`, `cancelarLocalmente()` | | `NfseElegibilidadeService` | `deveEmitir()`, `deveProcessar()`, `motivoInelegibilidade()` | | `SequenciaDpsService` | `proximoNumero()`, `ultimoNumero()` — reserva transacional do `nDPS` | | `DpsXmlBuilder` / `EventoXmlBuilder` | Montagem dos documentos | | `XmlDSigSigner` | `assinar()`, `verificar()` | | `CertificadoService` | `documentoTitular()`, `validoAte()`, `diasParaExpirar()`, `caminhosMtls()` | | `DanfseService` | `dadosParaView()`, `nomeArquivo()` | | `ConvenioMunicipalService` | `situacao()` — adesão do município ao Emissor Nacional, com cache | | `ValidadorDocumento` | `identificar()`, `cpfValido()`, `cnpjValido()` | | `DpsIdGenerator` | `paraDps()`, `paraPedidoRegistroEvento()`, `paraEvento()` | | `GzipBase64Codec` | `codificar()`, `decodificar()` | | `NfseNacionalGateway` | Transporte HTTP com mTLS — use os serviços acima, não este diretamente |Jobs
| Job | Fila | Tentativas | Backoff | |---|---|---|---| | `EmitirNfseJob` | `nfse` | 5 | 1 min → 3 h | | `CancelarNfseJob` | `nfse` | 5 | 2 min → 3 h | | `AcompanharAnaliseFiscalNfseJob` | `nfse` | 3 | reconsulta a cada 12 h, por até 30 dias | Os dois primeiros são `ShouldBeUnique`, o que impede que uma reentrega de webhook enfileire o mesmo documento em paralelo. Passados os 30 dias sem decisão da fiscalização, o acompanhamento é encerrado com um aviso no log — o caso fica para tratamento humano em vez de ocupar a fila indefinidamente.Esquemas XSD
resources/schemas/nfse/ traz o pacote oficial publicado pela
Secretaria-Executiva do CGNFS-e, versões 1.00 e 1.01, sem modificação —
inclusive nas quebras de linha. O caminho fica exposto por
ClickNfseServiceProvider::caminhoSchemas().
Veja o README daquele diretório para as
particularidades, inclusive um defeito conhecido no TSSerieDPS da v1.01 que
produz falso positivo na validação local.
Antes de ir para produção
- [ ]
php artisan nfse:verificar-certificadopassa, e o titular confere comNFSE_EMITENTE_CNPJ - [ ] O município aparece como aderente ao Emissor Nacional (
ConvenioMunicipalService::situacao()) - [ ] Emissão validada em
NFSE_AMBIENTE=2(produção restrita) de ponta a ponta - [ ] Cancelamento testado — inclusive o caso do prazo expirado
- [ ]
NFSE_P_TOT_TRIB_SNconfirmado com a contabilidade (alíquota efetiva vigente) - [ ]
NFSE_EMITENTE_ENVIAR_IMsó ligado depois que o município registrar o contribuinte no CNC - [ ]
NFSE_CODIGOS_PRAZO_EXPIRADOpreenchido com o que você observou em produção restrita - [ ] Worker da fila
nfserodando, e os três comandos agendados - [ ] Alerta de expiração do certificado chegando a alguém que age
Testes
A suíte roda sem rede e sem certificado real: a DPS e os eventos são validados contra o pacote oficial de XSD que acompanha o repositório, e a assinatura XMLDSIG é exercitada com um par autoassinado gerado na hora do teste. Nenhum material de certificado é versionado.
O CI cobre PHP 8.2, 8.3 e 8.4 contra Laravel 12 e 13.
Roadmap
- [ ] Validação local contra o XSD antes do envio, ligável por configuração
- [ ] Confirmar o formato da URL do QR Code do DANFSe conforme a NT 008/2026
- [ ] Núcleo em PHP puro, sem Laravel, com o pacote atual como adaptador
- [ ] Eventos de domínio (
NotaAutorizada,NotaRejeitada,NotaCancelada)
Contribuindo
Issues e pull requests são bem-vindos. Antes de abrir um PR:
composer testpassando;composer formataplicado;- mudança de comportamento acompanhada de teste.
Este é um pacote fiscal: alterações no caminho de emissão, assinatura ou cancelamento precisam citar a regra ou o código de rejeição que as justifica. "Achei mais limpo" não basta quando o custo de errar é um documento com efeito legal.
Segurança
- Nunca versione o
.pfx— o.gitignorejá cobre*.pfx,*.p12,*.peme*.key. - Os PEMs derivados para o mTLS são gravados com permissão
0600num diretório0700. - Encontrou uma vulnerabilidade? Escreva para [email protected] em vez de abrir issue pública.
Licença
MIT — veja LICENSE.
O software é fornecido sem garantias. Emissão de documento fiscal produz efeito legal e, em boa parte dos casos, irreversível.
Feito por Manuel Bahamonde
All versions of click-nfse with dependencies
ext-dom Version *
ext-json Version *
ext-libxml Version *
ext-openssl Version *
ext-simplexml Version *
ext-zlib Version *
illuminate/bus Version ^12.0|^13.0
illuminate/console Version ^12.0|^13.0
illuminate/contracts Version ^12.0|^13.0
illuminate/database Version ^12.0|^13.0
illuminate/http Version ^12.0|^13.0
illuminate/queue Version ^12.0|^13.0
illuminate/support Version ^12.0|^13.0
robrichards/xmlseclibs Version ^3.1