Download the PHP package ownerpro/nfsen-php-sdk without Composer

On this page you can find all versions of the php package ownerpro/nfsen-php-sdk. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package nfsen-php-sdk

NFSe Nacional

CI PHPStan Level 10 Latest Version on Packagist PHP Version

Pacote PHP para emissão, cancelamento, substituição e consulta de NFSe Padrão Nacional (nfse.gov.br) via API REST. Funciona com Laravel 11/12/13 ou standalone (sem framework).

Funcionalidades

Requisitos

Instalação

Configuração

Laravel

Publique o arquivo de configuração:

Adicione as variáveis de ambiente no .env:

A variavel NFSE_VALIDATE_IDENTITY (padrao: true) controla se o SDK verifica que o CNPJ ou CPF do certificado digital corresponde ao prestador informado na DPS antes de enviar a requisicao. Desative (false) apenas quando um representante legal (contador ou procurador com procuracao eletronica) emite notas em nome de terceiros.

Standalone (sem Laravel)

A validação de identidade confere o certificado contra o emitente da DPS, que infDPS/tpEmit designa — o prestador (1), o tomador (2) ou o intermediário (3). Com tpEmit 2 ou 3, quem assina é o tomador ou o intermediário, e é o CNPJ/CPF dele que precisa bater. Certificado e emitente que se identificam por documentos de tipos diferentes (e-CPF contra emitente que só declara CNPJ, ou o inverso) também são recusados: não há como conferir se são a mesma pessoa.

Para desabilitar a validacao de identidade (representante legal / contador):

Uso

Emitir NFSe

Emitir NFSe por decisão judicial — não suportado

emitirDecisaoJudicial() existe na interface, mas lança NfseException na entrada, antes de qualquer evento ou requisição. A operação não é implementável a partir de uma DPS:

O decisao-judicial/nfse recebe o documento NFS-e completo, não a DPS — o corpo é NFSeBypassPostRequest.xmlGZipB64, descrito no SefinNacional-swagger.json como "Documento XML da NFSe compactado no padrão GZIP". Em TCInfNFSe a DPS é apenas o último filho, ao lado de campos que só o gerador da nota preenche — nNFSe, nDFSe, cStat (102 = NFS-e de Decisão Judicial), dhProc e os valores já apurados (vBC, pAliqAplic, vISSQN). O ambGer (TSAmbGeradorNFSe) admite apenas 1-Prefeitura e 2-Sistema Nacional da NFS-e: não há valor para contribuinte, e tpEmis 2 descreve "emissão original em leiaute próprio do município com transcrição para o modelo nacional".

Emitir por decisão judicial cabe, portanto, a quem gera a NFS-e. Se você detém essa autorização e já monta o XML da nota, a chamada é um POST direto ao endpoint — este SDK não constrói nem assina documentos NFSe.

Cancelar NFSe

Codigos de cancelamento: ErroEmissao, ServicoNaoPrestado, Outros.

Solicitar análise fiscal para cancelamento

Cada município parametriza o prazo de cancelamento direto. Passado esse prazo, a SEFIN rejeita cancelar() com o código E0822 ("O prazo para o cancelamento da NFS-e expirou, conforme parametrização do município emissor da NFS-e") e o único caminho é pedir análise fiscal — o evento e101103, mesmo fluxo que o portal nacional oferece.

Os códigos de motivo são os mesmos do cancelamento: ErroEmissao, ServicoNaoPrestado, Outros.

Sucesso aqui significa pedido registrado, não nota cancelada: a NFS-e segue válida até o fisco decidir. O SDK dispara NfseFiscalAnalysisRequested, nunca NfseCancelled.

Acompanhar a análise

TStat (situação da NFS-e) não tem estado para análise em curso — a nota continua "Gerada" o tempo todo. O que muda são os eventos vinculados à chave, e situacaoCancelamento() os resume numa chamada ao ADN:

Vence o evento de maior NSU, então um pedido novo depois de um indeferimento volta a reportar EmAnalise. Consulta rejeitada pelo ADN lança NfseException: rejeição não é situação da nota.

Se você já consome distribuicao()->documentos($nsu), os eventos 105104/105105 chegam nesse fluxo por NSU — o desfecho vem por lote, sem varrer nota a nota.

Substituir NFSe

O método substituir() emite uma DPS com o grupo subst preenchido automaticamente. O ADN (Ambiente de Dados Nacional) cancela a nota original ao processar a DPS substituta — uma única requisição.

Nota: O registro do evento de cancelamento por substituição (e105102) via API Eventos (POST /nfse/{chave}/eventos) é restrito a sistemas municipais conveniados com o ADN — o autor desse evento é o município emissor (MEmis), não o contribuinte. O cancelamento da nota original ocorre automaticamente ao emitir a DPS com o grupo subst preenchido.

Codigos de substituição: DesenquadramentoSimplesNacional, EnquadramentoSimplesNacional, InclusaoRetroativaImunidadeIsencao, ExclusaoRetroativaImunidadeIsencao, RejeicaoTomadorIntermediario, Outros.

Consultas

Gerar o ID da DPS sem montar o XML

O identificador de 45 posições da DPS (TSIdDPS) pode ser calculado fora da emissão — útil para reconciliar após um timeout, consultando a DPS antes de qualquer retry:

DpsId é a fonte única da regra fiscal de formação do ID — o mesmo código usado internamente na construção do XML da DPS. O retorno é validado contra o padrão DPS[0-9]{42} do schema nacional; entrada inválida lança InvalidDpsArgument. cLocEmi, cnpj e cpf são conferidos na largura exata do schema (7, 14 e 11 dígitos, sem máscara): como entram no ID com largura fixa, um valor de tamanho errado seria acomodado — cortado ou preenchido com zeros — e produziria um identificador bem formado apontando para outro município ou outra inscrição. Informe o mesmo CNPJ ou CPF usado na emissão — ambos null lança InvalidDpsArgument (inscrição zerada só é válida para prestador estrangeiro com NIF/cNaoNIF, via allowEmptyInscricao: true).

Reconciliação após resultado indeterminado na emissão

Reconciliação após resultado indeterminado no cancelamento

Mesma régua da emissão, ancorada na consulta de eventos:

Distribuição (ADN Contribuinte)

Consulta em lote de documentos fiscais via NSU (Número Sequencial Único) através do ADN (Ambiente de Dados Nacional). Útil para importação em massa de NFS-e.

Por padrão o cnpjConsulta vem do certificado. Com um e-CPF não há CNPJ a enviar, e o parâmetro — opcional no contrato do ADN — é omitido da URL; informe-o explicitamente se a consulta precisar dele.

O fluxo típico de importação:

  1. Comece com NSU 0
  2. Chame documentos($nsu) — receba um lote
  3. Guarde o maior NSU do lote
  4. Repita com o próximo NSU até statusProcessamento ser NenhumDocumentoLocalizado

Laravel Facade

Eventos

O pacote dispara eventos Laravel que podem ser escutados na sua aplicação:

Evento Propriedades Descricao
NfseEmitted chave NFSe emitida com sucesso
NfseCancelled chave NFSe cancelada com sucesso
NfseFiscalAnalysisRequested chave Pedido de análise fiscal para cancelamento registrado (a NFS-e segue válida até o fisco decidir)
NfseSubstituted chave, chaveSubstituta NFSe substituída com sucesso
NfseQueried operacao Consulta realizada
NfseRequested operacao, metadata Operação iniciada
NfseRejected operacao, codigoErro, mensagemErro, correcao Operação rejeitada pela API (mensagemErro e correcao ficam null quando a API não retorna os campos correspondentes ou no fallback SEM_CHAVE)
NfseFailed operacao, mensagem, throwable Falha na operação

Substituição: como substituir delega ao emitir internamente, a sequência de eventos disparados é: NfseRequested('emitir') → NfseEmitted → NfseSubstituted

Objetos de Resposta

Cada operação retorna um DTO tipado e imutável:

NfseResponse

Retornado por emitir(), cancelar(), substituir(), consultar()->nfse() e consultar()->dps().

Propriedade Tipo Descricao
sucesso bool Se a operação foi aceita
chave ?string Chave de acesso da NFSe (50 dígitos)
xml ?string XML da NFSe processada
idDps ?string Identificador da DPS
alertas list<ProcessingMessage> Alertas não-bloqueantes
erros list<ProcessingMessage> Erros de processamento
tipoAmbiente ?int 1 = Produção, 2 = Homologação
versaoAplicativo ?string Versão do aplicativo da SEFIN
dataHoraProcessamento ?string Data/hora do processamento
raw ?array Corpo JSON decodificado, como a SEFIN o devolveu — ver Corpo bruto

DanfseResponse

Retornado por consultar()->danfse().

Propriedade Tipo Descricao
sucesso bool Se o PDF foi obtido
pdf ?string Conteúdo binário do PDF
erros list<ProcessingMessage> Erros de processamento

A API remota de DANFSe foi sobrestada em 01/07/2026. A Nota Técnica nº 008, de 05/05/2026 (storage/danfse/nt-008-se-cgnfse-danfse-20260505.pdf, seção 1), suspendeu https://adn.nfse.gov.br/danfse e transferiu a geração do documento para o emissor. Toda falha de consultar()->danfse() passa a trazer, além do erro original, uma mensagem com o código DanfseResponse::API_SOBRESTADA.

Gere o documento localmente a partir do XML da NFS-e:

EventsResponse

Retornado por consultar()->eventos().

Propriedade Tipo Descricao
sucesso bool Se a consulta teve sucesso
xml ?string XML do primeiro evento de eventos, já descomprimido
erros list<ProcessingMessage> Erros de processamento
tipoAmbiente ?int 1 = Produção, 2 = Homologação
versaoAplicativo ?string Versão do aplicativo da SEFIN
dataHoraProcessamento ?string Data/hora do processamento
raw ?array Corpo JSON decodificado, como a SEFIN o devolveu — ver Corpo bruto
eventos list<EventoConsultado> Os eventos devolvidos para o par (tipoEvento, nSequencial)

Constante EventsResponse::EVENT_NOT_FOUND: presente em erros[0]->codigo quando a SEFIN responde 404 — o evento comprovadamente não existe (distinto de erro transitório, que permanece sucesso: false sem esse código).

EventoConsultado

Um item de EventsResponse::$eventos.

Propriedade Tipo Descricao
chaveAcesso ?string Chave de acesso da NFS-e a que o evento se vincula
tipoEvento ?TipoEvento null quando o código não consta no enum
numeroPedidoRegistroEvento ?int Sequencial do pedido de registro
dataHoraRecebimento ?string Quando a SEFIN recebeu o evento
xml ?string XML do evento, já descomprimido
parseError ?string Por que o evento não pôde ser interpretado por completo; null quando íntegro

Um item que não pôde ser lido por completo não interrompe a resposta: os campos afetados vêm null e parseError diz o que faltou.

DistribuicaoResponse

Retornado por distribuicao()->documentos(), distribuicao()->documento() e distribuicao()->eventos().

Propriedade Tipo Descricao
sucesso bool true quando statusProcessamento é DocumentosLocalizados
statusProcessamento StatusDistribuicao Status: Rejeicao, NenhumDocumentoLocalizado, DocumentosLocalizados
lote list<DocumentoFiscal> Documentos fiscais retornados
alertas list<ProcessingMessage> Alertas não-bloqueantes
erros list<ProcessingMessage> Erros de processamento
tipoAmbiente ?int 1 = Produção, 2 = Homologação
versaoAplicativo ?string Versão do aplicativo
dataHoraProcessamento ?string Data/hora do processamento
raw ?array Corpo JSON decodificado, como o ADN o devolveu — ver Corpo bruto

DocumentoFiscal

Cada item do lote na DistribuicaoResponse.

Propriedade Tipo Descricao
nsu ?int Número Sequencial Único
chaveAcesso ?string Chave de acesso da NFS-e
tipoDocumento ?TipoDocumentoFiscal Tipo: Nfse, Dps, Evento, Cnc, PedidoRegistroEvento, Nenhum. null quando ausente ou desconhecido — veja parseError
tipoEvento ?TipoEventoDistribuicao Tipo do evento (quando tipoDocumento é Evento). null quando ausente ou desconhecido
arquivoXml ?string XML do documento (já descomprimido). null quando ausente ou indecodificável
dataHoraGeracao ?string Data/hora de geração
parseError ?string Por que o documento não pôde ser interpretado por completo; null quando íntegro. Nenhum campo de DistribuicaoNSU é obrigatório no contrato do ADN, e o governo pode emitir tipos que esta versão do SDK ainda não conhece — campo ausente ou com valor desconhecido entra no lote com aquele campo em null e o motivo aqui, em vez de derrubar o lote inteiro. O mesmo vale, por precaução, para valor fora do tipo que o swagger declara

ProcessingMessage

Representa uma mensagem de erro ou alerta da API:

Propriedade Tipo Descricao
mensagem ?string Mensagem principal
codigo ?string Código do erro/alerta
descricao ?string Descrição detalhada
complemento ?string Informação complementar
parametros list<string> Parâmetros adicionais da mensagem

Corpo bruto

NfseResponse, EventsResponse e DistribuicaoResponse carregam em raw o corpo JSON decodificado, exatamente como a API o devolveu — em sucesso e em rejeição. É o que sobrevive quando a normalização não alcança a resposta: envelope renomeado, campo novo, mensagem em forma que o SDK ainda não conhece.

O conteúdo vem da API sem filtro nenhum: decida o que registrar antes de mandar para o log. raw é [] quando o corpo não trouxe JSON legível (5xx de gateway, 204) e null apenas em respostas construídas à mão. DanfseResponse não tem o campo — o corpo dela é o PDF binário, que já está em pdf.

A SEFIN envia o envelope de erro em três formas — erros: [...], erro: {...} e erro: [...] (lista, confirmada em produção com SefinNacional_1.6.0) —, e o SDK normaliza as três nesta lista. Se a mensagem vier sem nenhuma chave conhecida, codigo recebe a constante ProcessingMessage::FORMATO_DESCONHECIDO e complemento carrega o item original em JSON, para que um formato novo da API não chegue vazio ao consumidor.

Exceções

Exceção Pai Quando
NfseException RuntimeException Erros gerais (XML inválido, falha de compressão, etc.)
CommunicationException NfseException Base abstrata das falhas de comunicação (nenhuma resposta completa e legível). Capture-a para tratar tudo como indeterminado; capture as subclasses para distinguir
IndeterminateResultException CommunicationException Resultado indeterminado: a requisição pode ou não ter sido processada pela SEFIN. Reconcilie antes de retry (veja abaixo). phase indica a fase da falha quando detectável (connect, dns, read, tls, transfer, body); é null quando a resposta chegou inteira e o que falta é evidência de processamento, como num 5xx sem rejeição da SEFIN
RequestNotDeliveredException CommunicationException Não entregue: a falha ocorreu comprovadamente antes de qualquer byte HTTP ser enviado (phase: dns, connect ou tls). A operação não foi processada — retry direto é seguro, sem reconciliação
HttpException NfseException Resposta HTTP de erro recebida sem corpo estruturado (redirect, 4xx vazio, 5xx em consulta; status inesperado em verificarDps()/dps()). Acesse getResponseBody() para detalhes. Num 5xx a operações que alteram estado (emitir, cancelar, substituir) o SDK lança IndeterminateResultException, não esta
CertificateExpiredException NfseException Certificado PFX/P12 expirado (validTo no passado)
CertificateNotYetValidException NfseException Certificado PFX/P12 com início de vigência no futuro (validFrom à frente do relógio) — renovação antecipada ou host com clock skew
InvalidDpsArgument InvalidArgumentException Campos mutuamente exclusivos ou obrigatórios violados na DPS; ID de DPS fora do padrão TSIdDPS

Contrato de indeterminação: capturar IndeterminateResultException significa que a SEFIN pode ou não ter recebido e processado a requisição. Ela cobre cinco situações:

  1. Falha antes de qualquer resposta (timeout, DNS, conexão recusada, TLS) — a requisição pode nem ter chegado ao servidor;
  2. Falha no meio da transferência (conexão resetada, corpo truncado) — o servidor processou, mas o resultado não pôde ser lido;
  3. Resposta 2xx com corpo ilegível (JSON inválido ou vazio) — o servidor confirmou o processamento, mas o resultado não pôde ser interpretado;
  4. Resposta com JSON válido porém sem o campo obrigatório da operação — um 2xx de consultar()->nfse() sem nfseXmlGZipB64, de consultar()->eventos() sem eventos nem eventoXmlGZipB64, ou de consultar()->dps() sem chaveAcesso, ou a resposta ao POST do evento em cancelar() sem rejeição estruturada nem o recibo eventoXmlGZipB64, qualquer que seja o status — shape que não ocorre em operação normal; ausência comprovada é sinalizada por HTTP 404, nunca por corpo vazio;
  5. Resposta 5xx a uma operação que altera estado (emitir, cancelar, substituir) sem rejeição estruturada da SEFIN no corpo — o erro pode ter vindo de um proxy antes da SEFIN, ou da própria SEFIN depois de gravar a nota, e nada no corpo distingue os dois. Um 5xx que traz erros/erro preenchido é rejeição definitiva: prova que a requisição chegou e foi processada. Em consultas, 5xx continua lançando HttpException — não há estado a reconciliar.

204 não entra nesta lista. "No Content" define corpo vazio, então a ausência de JSON ali é a resposta correta e não estado indeterminado — distribuicao() devolve sucesso: false com o código EMPTY_RESPONSE.

A exceção carrega a resposta que a motivou, para que o diagnóstico saia do log em vez de exigir reproduzir a chamada:

Propriedade Tipo Descricao
phase ?string Fase da falha de transporte (dns, connect, tls, transfer, read, body), quando detectável
statusCode ?int Status HTTP, quando a resposta chegou
body ?string Corpo cru, truncado em 8 KiB
raw ?array Corpo JSON decodificado, sem truncar

Preenche-se o que o ponto da falha tinha em mãos: body/statusCode ficam null nas rotas em que o SDK só recebe o JSON já decodificado, e raw fica null quando não houve JSON legível (é justamente a causa) ou quando a falha antecedeu a resposta. O mesmo objeto chega ao listener em NfseFailed::$throwable.

Nos cinco casos a ação é a mesma: nunca faça retry cego de emissão (a NFS-e pode já existir e um retry causaria dupla emissão). Calcule o ID com DpsId::generate() e consulte consultar()->dps($id): se encontrou, a nota foi emitida; se retornar NfseResponse::DPS_NOT_FOUND, é seguro re-emitir com o mesmo nDPS. Qualquer outra exceção ou resposta do SDK é uma resposta definitiva do servidor.

Distinguindo "não entregue" de "indeterminado": falhas de DNS, conexão TCP e handshake TLS acontecem antes de qualquer byte HTTP ser enviado — a requisição comprovadamente não chegou à SEFIN e o retry direto é seguro, sem reconciliação. Esses casos lançam RequestNotDeliveredException em vez de IndeterminateResultException:

A classificação usa apenas o errno do cURL (evidência inequívoca: 6, 7, 35, 58, 60); qualquer ambiguidade — incluindo todo timeout (cURL 28, cuja fase não é provável em conexões keep-alive reutilizadas) — permanece indeterminada. Vale para todas as operações do SDK (emissão, cancelamento, consultas, distribuição), não apenas emitir(). O default é false para não alterar catches existentes de IndeterminateResultException; catch (CommunicationException) cobre os dois tipos e equivale a tratar tudo como indeterminado (sempre seguro).

Nota: com a flag ativa, um timeout de connect (cURL 28) reporta phase: 'read' na IndeterminateResultException — a fase de um timeout não é provável por errno, então ele nunca vira "não entregue". Com a flag desativada, a fase legada vinda do texto da mensagem ('connect') é mantida. Não use phase para decidir retry; ela é apenas diagnóstico.

Renderização local do DANFSE

O SDK gera o DANFSE (PDF ou HTML) localmente a partir do XML da NFS-e autorizada.

Este é o único caminho desde 01/07/2026. A Nota Técnica nº 008, de 05/05/2026, sobrestou a API de geração do DANFSe (https://adn.nfse.gov.br/danfse) e transferiu a geração para o emissor. consultar()->danfse(), que chama aquele endpoint, passa a devolver falha com o código DanfseResponse::API_SOBRESTADA.

Uso básico

Sem customização

danfse() não recebe argumentos, e é de propósito. O layout inteiro vem da NT 008 e o conteúdo, do XML da NFS-e — o item 2.1 é explícito: "não poderão ser impressas informações que não constem do arquivo da NFS-e".

Isso vale também para as duas imagens que um DANFSe pode sugerir. A NT reserva um único quadro para logomarca, no canto esquerdo do cabeçalho, e o item 2.4.3 diz de quem ele é: da NFS-e, com o arquivo oficial indicado em gov.br. Ele vem embarcado no pacote (storage/danfse/logo-nfse.png) e é sempre impresso. Não há quadro reservado à marca do emitente nem à identificação da prefeitura em lugar nenhum do documento.

NFS-e cancelada ou substituída

Os itens 2.5.1 e 2.5.2 da NT 008 exigem marca d'água diagonal — "CANCELADA" ou "SUBSTITUÍDA" — no DANFSe da nota que saiu de vigência. Passe-a como segundo argumento:

A marca não sai do XML, e por isso não é inferida: infNFSe/cStat só descreve como a nota foi gerada (Gerada, Decisão Judicial, Avulsa, MEI), enquanto cancelamento e substituição chegam depois, como evento separado. Quem consultou os eventos é quem sabe — omitir o argumento imprime o DANFSe sem marca, como nota vigente.

Debug: obter o HTML intermediário

Diferente de toPdf(), que devolve DanfseResponse com sucesso: false em caso de falha, toHtml() retorna string e portanto propaga a exceção: XmlParseException quando o XML está malformado ou não traz algum grupo obrigatório da NFS-e.

Conformidade com a NT 008 (DANFSe v2.0)

O layout segue a Nota Técnica nº 008, que define o DANFSe v2.0. A seção 2.4.5 dela tabula 94 campos, cada um com o caminho no XML de onde sai — e os 94 são lidos. A tabela está versionada em tests/fixtures/nt008/campos-2.4.5.json, extraída por tools/extract-nt008.py, e um teste confere a cada execução que cada caminho dela ainda existe no XSD e que o builder continua lendo todos.

Blocos do documento, na ordem do Anexo I:

Bloco Origem no XML
Dados da NFS-e infNFSe/ + infDPS/
Prestador / Fornecedor infDPS/prest/, com infNFSe/emit/ de reserva
Tomador / Adquirente infDPS/toma/
Destinatário da Operação infDPS/IBSCBS/dest/
Intermediário da Operação infDPS/interm/
Serviço Prestado infDPS/serv/
Tributação Municipal (ISSQN) infDPS/valores/trib/tribMun/ + infNFSe/valores/
Tributação Federal infDPS/valores/trib/tribFed/
Tributação IBS / CBS infDPS/IBSCBS/ + infNFSe/IBSCBS/
Valor Total da NFS-e infNFSe/valores/ + infNFSe/IBSCBS/totCIBS/
Informações Complementares dez campos espalhados pelo leiaute (ver abaixo)

Comportamentos que valem conhecer:

Objetos do DANFSE

toPdf() e toHtml() montam um NfseData a partir do XML. Ele é público — útil para quem quer os dados já normalizados (códigos traduzidos, valores formatados) sem gerar o PDF:

Propriedade de NfseData Tipo Descrição
chaveAcesso, numeroNfse, competencia string Identificação da NFS-e
emissaoNfse, numeroDps, serieDps, emissaoDps string Datas e identificação da DPS
ambiente NfseAmbiente Produção ou homologação
situacao string Descrição de cStat
finalidade string Descrição de finNFSe
emitidaPor string Descrição de tpEmit
ambienteGerador string Descrição de ambGer
municipioEmitente string xLocEmi / UF; vazio quando a NT manda não exibir
emitente DanfseParticipante Prestador
tomador, intermediario, destinatario ?DanfseParticipante null quando ausentes; o bloco vira a frase de "não identificado" da NT
destinatarioEhTomador bool indDest = 0
servico DanfseServico Códigos e descrições do serviço
tribMun, tribFed, tribIbsCbs DTOs de tributação ISSQN, federal e IBS/CBS
totais, totaisTributos DanfseTotais, DanfseTotaisTributos Valores e percentuais
informacoesComplementares string União dos dez campos, com reticências acima de 1997 caracteres
marcaDagua ?MarcaDagua "CANCELADA"/"SUBSTITUÍDA"; null na nota vigente

Em DanfseParticipante, municipio, codigoIbge e cep cobrem os dois ramos de endereço do leiaute: end/endNac (município da tabela do IBGE e CEP) e end/endExt (cidade, província e código postal do exterior, este último sem máscara, por ser alfanumérico). No exterior não há código do IBGE e codigoIbge sai -; codigoIbgeCep() monta o campo único "CÓDIGO IBGE / CEP" do item 2.4.5, com um lado só quando o participante está fora do país.

Nome e endereço saem com reticências acima de 77 caracteres, como as descrições de opção do Simples Nacional (37), do regime de apuração pelo SN (77) e do benefício municipal (37) — os limites da tabela do item 2.4.5.

Enums com label(), que devolvem a descrição do leiaute — todos conferidos contra a <xs:documentation> do XSD por teste:

SituacaoNfse, AmbienteGerador, TipoBeneficioMunicipal, NfseAmbiente, FinNFSe, TpEmit, TpImunidade, TpSusp, TpRetPisCofins, TpRetISSQN, TribISSQN, RegEspTrib, OpSimpNac, RegApTribSN, CNaoNIF.

Página única

O item 2.2 da NT exige que o DANFSe caiba em uma página, e ele cabe com os limites da própria NT — 1297 caracteres de descrição do serviço e 1997 de informações complementares, ambos com reticências acima disso. Não há corte extra do SDK.

O que sustenta isso são as medidas da norma, não folga improvisada: margens de 0,176 cm (item 2.2.2 admite de 0,15 a 0,20), rótulos de 6pt e conteúdo de 7pt (item 2.4). Os dois quadros de texto livre crescem à vontade, como o item 2.3.1 prevê ao mandar "aumentar a altura do quadro 'Descrição do Serviço' e/ou 'Informações Complementares'".

No pior caso da norma — todos os blocos preenchidos e os dois campos livres no teto, em caixa alta — sobram cerca de 6pt na página. É pouco, e por isso tests/Unit/Danfse/DanfseSinglePageTest.php renderiza o PDF e conta as páginas a cada execução, incluindo a verificação de que a linha fixa de totais aproximados continua impressa.

Geração automática do DANFSE

Desligada por padrão. Ligada, anexa o PDF ao NfseResponse em emitir(), substituir() e consultar()->nfse() — cerca de 300 ms e 15 KB por nota, gastos mesmo que ninguém abra o documento. Sem ela, gere sob demanda com $client->danfse()->toPdf($resp->xml).

A flag é lida com cast para bool. Se a config vier de outra fonte que não env() — banco, YAML, painel —, converta antes: 'false', 'off' e 'no' são strings verdadeiras em PHP e ligariam o auto-render.

Ligar pontualmente (mesmo com NFSE_AUTO_DANFSE=false):

Desligar pontualmente (mesmo com NFSE_AUTO_DANFSE=true):

A facade Nfsen::for() aceita o mesmo parâmetro: Nfsen::for($pfx, $senha, $ibge, danfse: true).

Quando o PDF falha ($resp->sucesso === true mas $resp->pdf === null): a NFS-e foi emitida com sucesso. Regenere sob demanda com $client->danfse()->toPdf($resp->xml) e inspecione $resp->pdfErrors.

Atribuição

A renderização do DANFSE foi portada da biblioteca andrevabo/danfse-nacional (MIT) e adaptada à arquitetura deste SDK. A tabela de municípios IBGE vem de kelvins/municipios-brasileiros (MIT).

Exemplos

Exemplos completos de cada operação estão disponíveis no diretório examples/.

Testes

Para executar todas as verificações de qualidade:

Contribuindo

Veja CONTRIBUTING.md para detalhes.

Créditos

Este pacote teve como base o trabalho do projeto original nfse-nacional de Fernando Friedrich, que por sua vez foi construído sobre o NFePHP de Roberto L. Machado.

Agradecimento a todos os contribuidores que ajudaram a evoluir este projeto.

Licença

MIT. Veja LICENSE.


All versions of nfsen-php-sdk with dependencies

PHP Build Version
Package Version
Requires php Version ^8.3
nfephp-org/sped-common Version ^5.1
dompdf/dompdf Version ^3.0
bacon/bacon-qr-code Version ^3.0
guzzlehttp/guzzle Version ^7.5
illuminate/http Version ^11.0|^12.0|^13.0
illuminate/support Version ^11.0|^12.0|^13.0
illuminate/contracts Version ^11.0|^12.0|^13.0
ext-curl Version *
ext-dom Version *
ext-zlib Version *
ext-openssl Version *
ext-mbstring Version *
ext-libxml Version *
ext-simplexml Version *
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package ownerpro/nfsen-php-sdk contains the following files

Loading the files please wait ...