gildonei / nfse-nacional
Emissor de Nota Fiscal de Serviço Eletrônica (NFS-e) Nacional em PHP
Installs: 9
Dependents: 0
Suggesters: 0
Security: 0
Stars: 4
Watchers: 1
Forks: 0
Open Issues: 0
pkg:composer/gildonei/nfse-nacional
Requires
- php: ^8.3
- guzzlehttp/guzzle: ^7.0
- robrichards/xmlseclibs: ^3.1
- symfony/dotenv: ^7.4
- symfony/var-dumper: ^7.4
Requires (Dev)
- phpunit/phpunit: ^10.0
README
Biblioteca PHP para emissão de Nota Fiscal de Serviço Eletrônica (NFS-e) Nacional, seguindo os padrões da Receita Federal do Brasil.
⚠️ AVISO IMPORTANTE
- Todos os dados utilizados nos exemplos são fictícios e servem apenas para demonstração.
- Para emissão real de NFS-e, é necessário utilizar dados reais (CNPJ, certificado digital ICP-Brasil válido, etc.).
- Esta biblioteca é fornecida "como está", sem garantias de qualquer tipo, expressas ou implícitas.
- O desenvolvedor não se responsabiliza por quaisquer danos ou prejuízos decorrentes do uso desta biblioteca.
- Teste sempre em ambiente de homologação antes de utilizar em produção.
Características
- ✅ Clean Architecture
- ✅ PHP 8.3+
- ✅ Suporte a certificado digital ICP-Brasil (Value Object)
- ✅ Assinatura XML digital (XMLDSIG)
- ✅ Autenticação SSL/TLS com certificado digital
- ✅ Integração com API Sefin Nacional
- ✅ Compressão GZip e codificação Base64
- ✅ Validação de dados com Enums type-safe
- ✅ Type-safe com tipos estritos
- ✅ Geração automática de IDs conforme padrão NFS-e Nacional
- ✅ Validação de campos obrigatórios
- ✅ Suporte completo a CPF e CNPJ
- ✅ Timezone padrão: Brasília (America/Sao_Paulo)
- ✅ Encoding UTF-8 garantido
- ✅ XML otimizado (sem quebras de linha)
Requisitos
- PHP 8.3 ou superior
- Certificado digital ICP-Brasil (A1 ou A3) com CNPJ (.pfx ou .p12)
- Extensão OpenSSL habilitada
- Extensão ZIP habilitada (para compressão GZip)
- Extensão DOM habilitada (para manipulação XML)
- Extensão mbstring habilitada (para validação de encoding)
- Guzzle HTTP Client (via Composer)
Instalação
composer require gildonei/nfse-nacional
Estrutura do Projeto
src/
├── Domain/ # Regras de negócio
│ ├── Entity/ # Entidades do domínio
│ │ ├── Dps.php # Documento de Prestação de Serviços
│ │ ├── Prestador.php # Prestador de serviços
│ │ ├── Tomador.php # Tomador de serviços
│ │ ├── Emitente.php # Emitente da NFS-e
│ │ └── Pessoa.php # Classe base para pessoas
│ │
│ ├── Enum/ # Enumerações para validação
│ │ ├── AmbienteGeradorNfse.php
│ │ ├── ModoPrestacao.php
│ │ ├── MotivoNaoInformarNif.php
│ │ ├── OptanteSimplesNacional.php
│ │ ├── ProcessoEmissao.php
│ │ ├── RegimeEspecialTributacaoMunicipal.php
│ │ ├── RegimeTributacaoSimplesNacional.php
│ │ ├── SituacoesPossiveisNfse.php
│ │ ├── TipoBeneficioMunicipal.php
│ │ ├── TipoEmissaoNfse.php
│ │ ├── TipoEmitente.php
│ │ ├── TributacaoIssqn.php
│ │ ├── VinculoEntrePartes.php
│ │ ├── ListaServicosNacional.php # Lista de Serviços LC 116/2003
│ │ └── ListaNbs.php # Nomenclatura Brasileira de Serviços
│ │
│ ├── ValueObject/ # Value Objects
│ │ ├── Certificado.php # Certificado digital PKCS#12
│ │ ├── Cpf.php # Validação e formatação de CPF
│ │ ├── Cnpj.php # Validação e formatação de CNPJ
│ │ ├── Email.php # Validação de e-mail
│ │ ├── Endereco.php # Endereço completo
│ │ └── Telefone.php # Telefone com DDD
│ │
│ ├── Xml/ # Geração de XML
│ │ └── DpsXml.php # Gerador de XML da DPS
│ │
│ ├── Contract/ # Interfaces de domínio
│ │ ├── AssinadorXmlInterface.php
│ │ └── HttpClientInterface.php
│ │
│ ├── Factory/ # Factories
│ └── Exception/ # Exceções de domínio
│
├── Application/ # Camada de aplicação
│ └── Service/ # Serviços de aplicação
│ └── SefinNacionalService.php # Serviço de integração com API
│
└── Infrastructure/ # Implementações técnicas
├── Security/ # Segurança
│ └── AssinadorXml.php # Assinatura XML digital
└── Http/ # Comunicação HTTP
└── HttpClient.php # Cliente HTTP (Guzzle)
docs/
├── emissao-dps.php # Exemplo completo de emissão de DPS
└── consulta-nfse.php # Exemplo de consulta de NFS-e
Uso Básico
Exemplo Completo
Consulte o arquivo docs/emissao-dps.php para um exemplo completo e detalhado de como criar, assinar e enviar uma DPS para a API Sefin Nacional.
Exemplo Simplificado
<?php use NfseNacional\Domain\Entity\Dps; use NfseNacional\Domain\Entity\Prestador; use NfseNacional\Domain\Entity\Tomador; use NfseNacional\Domain\Entity\Emitente; use NfseNacional\Domain\Enum\ProcessoEmissao; use NfseNacional\Domain\Enum\TipoEmissaoNfse; use NfseNacional\Domain\Enum\AmbienteGeradorNfse; use NfseNacional\Domain\Enum\SituacoesPossiveisNfse; use NfseNacional\Domain\Enum\OptanteSimplesNacional; use NfseNacional\Domain\Enum\RegimeEspecialTributacaoMunicipal; use NfseNacional\Domain\ValueObject\Certificado; use NfseNacional\Domain\ValueObject\Cnpj; use NfseNacional\Domain\ValueObject\Cpf; use NfseNacional\Domain\ValueObject\Endereco; use NfseNacional\Domain\ValueObject\Email; use NfseNacional\Domain\ValueObject\Telefone; use NfseNacional\Domain\Xml\DpsXml; use NfseNacional\Application\Service\SefinNacionalService; use NfseNacional\Infrastructure\Security\AssinadorXml; use DateTime; use DateTimeZone; // 1. Criar Prestador $prestador = new Prestador( nome: 'Empresa Prestadora LTDA', documento: new Cnpj('50600661000126'), endereco: new Endereco( logradouro: 'Rua Exemplo', numero: '123', bairro: 'Centro', codigoMunicipio: 4205407, // Florianópolis/SC uf: 'SC', cep: '88010000' ), optanteSimplesNacional: OptanteSimplesNacional::OptanteMEEPP, regimeEspecialTributacao: RegimeEspecialTributacaoMunicipal::Nenhum ); // 2. Criar Tomador $tomador = new Tomador( nome: 'Cliente Tomador LTDA', documento: new Cnpj('12345678000190'), endereco: new Endereco( logradouro: 'Av. Cliente', numero: '456', bairro: 'Bairro Cliente', codigoMunicipio: 4205407, uf: 'SC', cep: '88020000' ) ); // 3. Criar DPS $dps = new Dps(); $dps->definirPrestador($prestador) ->definirTomador($tomador) ->definirTipoAmbiente(2) // Homologação ->definirVersaoAplicacao('1.0.0') ->definirSerie('1') ->definirNumeroDps('1') ->definirDataHoraEmissao(new DateTime('now', new DateTimeZone('America/Sao_Paulo'))) ->definirDataCompetencia(new DateTime('now', new DateTimeZone('America/Sao_Paulo'))) ->definirValorServico(1000.00) ->definirValorRecebido(1000.00); // 4. Criar Certificado $certificado = new Certificado('/caminho/certificado.pfx', 'senha123'); // 5. Criar Emitente $emitente = new Emitente( nome: 'Empresa Emitente LTDA', documento: new Cnpj('50600661000126'), endereco: $prestador->obterEndereco(), telefone: new Telefone(codigoPais: 55, codigoArea: 48, numero: 33334444), email: 'emitente@empresa.com.br', certificado: $certificado ); // 6. Gerar XML $dpsXml = new DpsXml( dps: $dps, emitente: $emitente, nNFSe: 1, processoEmissao: ProcessoEmissao::AplicativoContribuinte, tipoEmissaoNfse: TipoEmissaoNfse::EmissaoNormal, ambienteGeradorNfse: AmbienteGeradorNfse::SefinNacionalNfse, situacaoPossivelNfse: SituacoesPossiveisNfse::NfseGerada ); // 7. Assinar e Enviar para API $assinador = new AssinadorXml(); $sefinService = new SefinNacionalService( emitente: $emitente, assinador: $assinador, tipoAmbiente: SefinNacionalService::AMBIENTE_HOMOLOGACAO ); $resposta = $sefinService->enviarDps($dpsXml); print_r($resposta);
Enums Disponíveis
A biblioteca utiliza enums para garantir type-safety e validação de campos:
ProcessoEmissao
AplicativoContribuinte(1) - Emissão com aplicativo do contribuinte (via Web Service)AplicativoFiscoWeb(2) - Emissão com aplicativo disponibilizado pelo fisco (Web)AplicativoFiscoApp(3) - Emissão com aplicativo disponibilizado pelo fisco (App)
TipoEmissaoNfse
EmissaoNormal(1) - Emissão normal no modelo da NFS-e NacionalEmissaoOriginalLeiauteProprio(2) - Emissão original em leiaute próprio do município
AmbienteGeradorNfse
SistemaProprioMunicipio(1) - Sistema Próprio do MunicípioSefinNacionalNfse(2) - Sefin Nacional NFS-e
TipoBeneficioMunicipal
Isencao(1) - IsençãoReducaoBCPercentual(2) - Redução da BC em 'ppBM' %ReducaoBCValor(3) - Redução da BC em R$ 'vInfoBM'AliquotaDiferenciada(4) - Alíquota Diferenciada de 'aliqDifBM' %
TipoEmitente
Prestador(1) - PrestadorTomador(2) - TomadorIntermediario(3) - Intermediário
OptanteSimplesNacional
NaoOptante(1) - Não OptanteOptanteMEI(2) - Optante - Microempreendedor Individual (MEI)OptanteMEEPP(3) - Optante - Microempresa ou Empresa de Pequeno Porte (ME/EPP)
RegimeTributacaoSimplesNacional
RegimeApuracaoTributosFederaisMunicipalSN(1) - Regime de apuração dos tributos federais e municipal pelo SNRegimeApuracaoTributosFederaisSNISSQNNfse(2) - Regime de apuração dos tributos federais pelo SN e o ISSQN pela NFS-eRegimeApuracaoTributosFederaisMunicipalNfse(3) - Regime de apuração dos tributos federais e municipal pela NFS-e
RegimeEspecialTributacaoMunicipal
Nenhum(0) - NenhumAtoCooperado(1) - Ato CooperadoEstimativa(2) - EstimativaMicroempresaMunicipal(3) - Microempresa MunicipalNotarioOuRegistrador(4) - Notário ou RegistradorProfissionalAutonomo(5) - Profissional AutônomoSociedadeDeProfissionais(6) - Sociedade de Profissionais
MotivoNaoInformarNif
NaoInformadoNotaOrigem(0) - Não informado na nota de origemDispensadoNIF(1) - Dispensado do NIFNaoExigenciaNIF(2) - Não exigência do NIF
ModoPrestacao
Desconhecido(0) - Desconhecido (tipo não informado na nota de origem)Transfronteirico(1) - TransfronteiriçoConsumoNoBrasil(2) - Consumo no BrasilPresencaComercialExterior(3) - Presença Comercial no ExteriorMovimentoTemporarioPessoasFisicas(4) - Movimento Temporário de Pessoas Físicas
VinculoEntrePartes
SemVinculo(0) - Sem vínculo com o tomador/PrestadorControlada(1) - ControladaControladora(2) - ControladoraColigada(3) - ColigadaMatriz(4) - MatrizFilialOuSucursal(5) - Filial ou sucursalOutroVinculo(6) - Outro vínculo
TributacaoIssqn
OperacaoTributavel(1) - Operação tributávelImunidade(2) - ImunidadeExportacaoServico(3) - Exportação de serviçoNaoIncidencia(4) - Não Incidência
ListaServicosNacional
Enum com a Lista de Serviços da LC 116/2003 para validação do Código de Tributação Nacional (cTribNac).
Código de 6 dígitos no formato IISSDD:
- II = Item (01-40) - Grupo de serviços da LC 116/2003
- SS = Subitem (01-99) - Subdivisão do item
- DD = Desdobro (01-99) - Detalhamento do subitem
Nota: Quando o código de tributação nacional (cTribNac) está vazio na tabela oficial, utiliza-se a concatenação dos campos Item + Subitem + Desdobro. Foi utilizado o prefixo "S" na lista dos serviços devido ao Item ("grupo") poder iniciar com Zeros
Exemplos de uso:
use NfseNacional\Domain\Enum\ListaServicosNacional; // Usando enum diretamente $dps->definirCodigoTributacaoNacional(ListaServicosNacional::S010601); // Obtendo a descrição echo ListaServicosNacional::S010601->descricao(); // "Assessoria e consultoria em informática" // Obtendo o código echo ListaServicosNacional::S010601->codigo(); // "010601" // Obtendo partes do código echo ListaServicosNacional::S010601->item(); // "01" - Item (grupo da LC 116) echo ListaServicosNacional::S010601->subitem(); // "06" - Subitem echo ListaServicosNacional::S010601->desdobro(); // "01" - Desdobro // Verificando se um código é válido if (ListaServicosNacional::isValid('010106')) { echo "Código válido!"; } // Buscando serviços por item (grupo) $servicosTI = ListaServicosNacional::byItem('01'); // Todos os serviços de informática
Principais itens (grupos da LC 116/2003):
01- Serviços de informática e congêneres04- Serviços de saúde, assistência médica e congêneres07- Serviços de engenharia, arquitetura, geologia08- Serviços de educação, ensino14- Serviços relativos a bens de terceiros17- Serviços de apoio técnico, administrativo, jurídico, contábil
ListaNbs
Enum com os códigos da Nomenclatura Brasileira de Serviços (NBS) para classificação de serviços em operações internacionais.
Código de 9 dígitos no formato S.DDGG.CC.SS:
- S = Seção (1 dígito)
- DD = Divisão (2 dígitos)
- GG = Grupo (2 dígitos)
- CC = Classe (2 dígitos)
- SS = Subclasse (2 dígitos)
Nota: Foi utilizado o prefixo "N" nos cases do enum pois nomes de constantes não podem iniciar com números em PHP.
Exemplos de uso:
use NfseNacional\Domain\Enum\ListaNbs; // Usando enum diretamente para serviços de TI $codigoNbs = ListaNbs::N121011000; // Consultoria em TI // Obtendo a descrição echo ListaNbs::N121011000->descricao(); // "Serviços de consultoria em tecnologia da informação" // Obtendo o código echo ListaNbs::N121011000->codigo(); // "121011000" // Obtendo partes do código echo ListaNbs::N121011000->secao(); // "1" - Seção echo ListaNbs::N121011000->divisao(); // "21" - Divisão echo ListaNbs::N121011000->grupo(); // "01" - Grupo echo ListaNbs::N121011000->classe(); // "10" - Classe echo ListaNbs::N121011000->subclasse(); // "00" - Subclasse // Verificando se um código é válido if (ListaNbs::isValid('121011000')) { echo "Código NBS válido!"; } // Buscando serviços por seção $servicosSecao1 = ListaNbs::bySecao('1'); // Todos os serviços da seção 1
Principais divisões (Seção 1):
01- Serviços de construção12- Serviços financeiros16- Serviços jurídicos e contábeis17- Serviços de negócios e gestão18- Serviços de telecomunicações21- Serviços de informática (TI)22- Serviços de seguros23- Serviços técnicos e profissionais27- Serviços de educação28- Serviços de saúde
Principais divisões (Seção 2):
01- Serviços de cessão de direitos de propriedade intelectual02- Outros intangíveis
SituacoesPossiveisNfse
NfseGerada(100) - NFS-e GeradaNfseSubstituicaoGerada(101) - NFS-e de Substituição GeradaNfseDecisaoJudicial(102) - NFS-e de Decisão JudicialNfseAvulsa(103) - NFS-e Avulsa
Geração de IDs
A biblioteca gera automaticamente os IDs conforme o padrão NFS-e Nacional:
ID do infNFSe (53 caracteres)
Formato: NFS + Cód.Mun. (7) + Amb.Ger. (1) + Tipo de Inscrição Federal (1) + Inscrição Federal (14) + nNFSe (13) + AnoMes Emis. (4) + Valor do node nNFSe com 9 dígitos + DV (1)
ID do infDPS (45 caracteres)
Formato: DPS + Cód.Mun. (7) + Tipo de Inscrição Federal (1) + Inscrição Federal (14) + Série DPS (5) + Núm. DPS (15)
Chave de Acesso da NFS-e (50 dígitos)
A chave de acesso é composta por:
- Código do Município (7 dígitos)
- Ambiente Gerador (1 dígito)
- Tipo de Inscrição Federal (1 dígito)
- Inscrição Federal (14 dígitos)
- Número da NFS-e (13 dígitos)
- Ano/Mês de Emissão (4 dígitos)
- Valor do nNFSe (9 dígitos)
- Dígito Verificador (1 dígito)
Determinação Automática de TipoEmitente
O campo tpEmit é determinado automaticamente pela comparação dos documentos:
- Se o documento do Emitente for igual ao do Prestador →
TipoEmitente::Prestador(1) - Se o documento do Emitente for igual ao do Tomador →
TipoEmitente::Tomador(2) - Caso contrário →
TipoEmitente::Intermediario(3)
Timezone
O timezone padrão utilizado é Brasília (America/Sao_Paulo) para todos os campos de data/hora.
Certificado Digital
O certificado digital é encapsulado em um Value Object Certificado que:
- Valida o certificado PKCS#12
- Gerencia o conteúdo e a senha de forma segura
- Pode ser criado a partir de caminho de arquivo ou conteúdo
// Criar certificado a partir de arquivo $certificado = new Certificado('/caminho/certificado.pfx', 'senha123'); // Validar certificado $certificado->validar();
Integração com API Sefin Nacional
O SefinNacionalService fornece métodos para integração com a API:
Métodos Disponíveis
enviarDps(DpsXml $dpsXml)- Envia DPS e gera NFS-econsultarDps(string $idDps)- Consulta chave de acesso pelo ID do DPSverificarDps(string $idDps)- Verifica se NFS-e foi emitidaconsultarNfse(string $chaveAcesso)- Consulta NFS-e pela chave de acessoenviarNfseDecisaoJudicial(string $xmlNfseAssinado)- Envia NFS-e com decisão judicialregistrarEvento(string $chaveAcesso, string $xmlEventoAssinado)- Registra evento na NFS-econsultarEvento(string $chaveAcesso, int $tipoEvento, int $numSeqEvento)- Consulta evento específico
Ambientes
SefinNacionalService::AMBIENTE_PRODUCAO(1) - Ambiente de produçãoSefinNacionalService::AMBIENTE_HOMOLOGACAO(2) - Ambiente de homologação
Autenticação SSL/TLS
O serviço utiliza automaticamente o certificado do emitente para autenticação SSL/TLS em todas as requisições HTTP.
Resposta da API
Quando a emissão da DPS é bem-sucedida (statusCode 201), a resposta contém o campo nfseXmlGZipB64 com o XML da NFS-e comprimido em GZip e codificado em Base64.
// Verificar se a emissão foi bem-sucedida if ($resposta['statusCode'] === 201) { $body = $resposta['body']; if (isset($body['nfseXmlGZipB64'])) { // Decodificar Base64 e descomprimir GZip $xmlDecodificado = base64_decode($body['nfseXmlGZipB64'], true); $xmlNfse = gzdecode($xmlDecodificado); // $xmlNfse contém o XML completo da NFS-e echo $xmlNfse; } // Outros campos disponíveis na resposta: // $body['tipoAmbiente'] - 1 = Produção, 2 = Homologação // $body['versaoAplicativo'] - Versão do aplicativo Sefin Nacional // $body['dataHoraProcessamento'] - Data/hora do processamento // $body['chaveAcesso'] - Chave de acesso da NFS-e (50 dígitos) // $body['idDPS'] - ID do DPS }
Processamento de XML
O XML gerado é processado antes do envio:
- ✅ Encoding UTF-8 garantido
- ✅ Quebras de linha removidas
- ✅ Espaços em branco otimizados
- ✅ Compressão GZip
- ✅ Codificação Base64
Exemplos
Emissão de DPS
O arquivo docs/emissao-dps.php contém um exemplo completo de:
- Criação de Certificado, Emitente, Prestador e Tomador
- Criação e configuração da DPS
- Geração do XML
- Assinatura digital
- Envio para a API Sefin Nacional
- Exibição do XML da NFS-e emitida (quando statusCode 201)
# Executar o exemplo de emissão
php docs/emissao-dps.php
Consulta de NFS-e
O arquivo docs/consulta-nfse.php contém um exemplo de:
- Consulta de NFS-e pela chave de acesso (50 dígitos)
- Decodificação do XML da NFS-e (Base64 + GZip)
- Exibição formatada do XML
# Executar o exemplo de consulta
php docs/consulta-nfse.php
Desenvolvimento
# Instalar dependências composer install # Executar testes composer test
Licença
MIT License
ISENÇÃO DE RESPONSABILIDADE: Esta biblioteca é fornecida "como está", sem garantias de qualquer tipo. O uso é de inteira responsabilidade do usuário. O desenvolvedor não se responsabiliza por erros, falhas, perdas financeiras ou quaisquer outros danos decorrentes do uso desta biblioteca.
Autor
Gildonei M A Junior