/* * This file is part of Treeunfe DFe. * * Treeunfe DFe is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Treeunfe DFe is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Treeunfe DFe. If not, see . */ import { Environment, GerarConsulta, applyDefaultTmpStoragePaths, logger, SaveFiles, Utility, XmlBuilder, } from '@treeunfe/shared'; import { DpsConsultaPorId, NFSeNFP_EnviarLoteRps, NFSeNFP_V2_PedidoEnvioLoteRPS, NFSeAlteracaoBeneficioMunicipal, NFSeAlteracaoRetencoes, NFSeConfig, NFSeConsultaAliquota, NFSeConsultaBeneficio, NFSeConsultaConvenio, NFSeConsultaHistoricoAliquotas, NFSeConsultaPorChave, NFSeConsultaRegimesEspeciais, NFSeDistribuicaoPorNSU, NFSeEventoConsulta, NFSeEventoRequest, NFSeEventosPorChave, NFSe as NFSeType, NFSeGerarDanfseProps, } from '@treeunfe/types'; import type { AxiosInstance } from 'axios'; import { NFSeAutorizacao, NFSeConsulta, NFSeDistribuicao, NFSeEventos, NFSeParametrosMunicipais, NFSeNFP_SPAutorizacao, NFSeNFP_SPAutorizacao_V1, NFSeNFP_SPAutorizacao_V2, NFSeNFP_SPTesteAutorizacao_V2, } from '../operations'; import { NFSeAutorizacaoService, NFSeConsultaService, NFSeDistribuicaoService, NFSeEventosService, NFSeParametrosMunicipaisService, NFSeNFP_SPAutorizacaoService, NFSeNFP_SPAutorizacaoService_V1, NFSeNFP_SPAutorizacaoService_V2, NFSeNFP_SPTesteAutorizacaoService_V2, } from '../services'; import { NFSeGerarDanfse } from '@treeunfe/danfe'; export default class NFSe { private environment: Environment; private axios!: AxiosInstance; private utility!: Utility; private xmlBuilder!: XmlBuilder; private saveFiles!: SaveFiles; private gerarConsulta!: GerarConsulta; private loadEnvironmentPromise: Promise; constructor(config: NFSeConfig) { // Valida se a configuração obrigatória foi fornecida if (!config.ambiente) { throw new Error('Configuração NFSe incompleta. Por favor, forneça "ambiente".'); } const environment = new Environment(applyDefaultTmpStoragePaths(config, 'NFSe')); this.environment = environment; // Carrega o environment automaticamente this.loadEnvironmentPromise = (async () => { try { const { axios: axiosInstance } = await environment.loadEnvironment(); this.axios = axiosInstance; this.utility = new Utility(environment); this.saveFiles = new SaveFiles(environment, this.utility); this.xmlBuilder = new XmlBuilder(environment); this.gerarConsulta = new GerarConsulta(environment, this.utility, this.xmlBuilder); } catch (error) { logger.error(``, error, { context: 'NFSE_LoadEnvironment' }); throw new Error(`Erro ao inicializar a lib NFSe: ${error}`); } })(); } /** * Autorização de NFSe * * Quando o prestador (emissor) for do município de São Paulo/SP (cLocEmi = '3550308'), * o fluxo é redirecionado automaticamente para `Autorizacao_NFP_SP`, pois a cidade de SP * ainda não aderiu ao padrão nacional REST e utiliza WebService SOAP próprio. * Nesse caso, o parâmetro `data` deve seguir o formato `NFSeNFP_EnviarLoteRps`. */ async Autorizacao(data: NFSeType | NFSeNFP_EnviarLoteRps) { await this.loadEnvironmentPromise; const isSaoPaulo = ('LoteRps' in data) || ( 'DPS' in data && data.DPS !== undefined && (Array.isArray(data.DPS) ? data.DPS[0]?.infDps?.cLocEmi === '3550308' : (data.DPS as any)?.infDps?.cLocEmi === '3550308') ); if (isSaoPaulo) { return this.Autorizacao_NFP_SP(data as NFSeNFP_EnviarLoteRps); } try { const service = new NFSeAutorizacaoService(this.environment, this.utility, this.xmlBuilder, this.axios, this.saveFiles, this.gerarConsulta); const operation = new NFSeAutorizacao(service); const response = await operation.Exec(data as NFSeType); console.log('Retorno NFSE_Autorizacao'); console.log(` Chave de Acesso: ${response.response.chaveAcesso || 'N/A'}`); console.log('==================================='); return response; } catch (error: any) { logger.error(``, error, { context: 'NFSE_Autorizacao' }); throw new Error(`NFSE_Autorizacao: ${error.message}`); } } /** * Consulta NFSe por chave de acesso */ async Consulta(data: NFSeConsultaPorChave) { await this.loadEnvironmentPromise; try { const service = new NFSeConsultaService(this.environment, this.utility, this.xmlBuilder, this.axios, this.saveFiles, this.gerarConsulta); const operation = new NFSeConsulta(service); const response = await operation.Exec(data); console.log('Retorno NFSE_Consulta'); console.log(` Chave de Acesso: ${response.chaveAcesso || 'N/A'}`); console.log('==================================='); return response; } catch (error: any) { logger.error(``, error, { context: 'NFSE_Consulta' }); throw new Error(`NFSE_Consulta: ${error.message}`); } } /** * Consulta DPS por ID */ async ConsultaDPS(data: DpsConsultaPorId) { await this.loadEnvironmentPromise; try { const service = new NFSeConsultaService(this.environment, this.utility, this.xmlBuilder, this.axios, this.saveFiles, this.gerarConsulta); const operation = new NFSeConsulta(service); const response = await operation.ConsultaDPS(data); console.log('Retorno NFSE_ConsultaDPS'); console.log(` Chave de Acesso: ${response.chaveAcesso || 'N/A'}`); console.log('==================================='); return response; } catch (error: any) { logger.error(``, error, { context: 'NFSE_ConsultaDPS' }); throw new Error(`NFSE_ConsultaDPS: ${error.message}`); } } /** * Registro de Eventos */ async RegistrarEvento(data: NFSeEventoRequest) { await this.loadEnvironmentPromise; try { const service = new NFSeEventosService(this.environment, this.utility, this.xmlBuilder, this.axios, this.saveFiles, this.gerarConsulta); const operation = new NFSeEventos(service); const response = await operation.RegistrarEvento(data); console.log('Retorno NFSE_RegistrarEvento'); console.log(` Processado com sucesso`); console.log('==================================='); return response; } catch (error: any) { logger.error(``, error, { context: 'NFSE_RegistrarEvento' }); throw new Error(`NFSE_RegistrarEvento: ${error.message}`); } } /** * Consulta de Eventos */ async ConsultarEvento(data: NFSeEventoConsulta) { await this.loadEnvironmentPromise; try { const service = new NFSeEventosService(this.environment, this.utility, this.xmlBuilder, this.axios, this.saveFiles, this.gerarConsulta); const operation = new NFSeEventos(service); const response = await operation.ConsultarEvento(data); console.log('Retorno NFSE_ConsultarEvento'); console.log(` Processado com sucesso`); console.log('==================================='); return response; } catch (error: any) { logger.error(``, error, { context: 'NFSE_ConsultarEvento' }); throw new Error(`NFSE_ConsultarEvento: ${error.message}`); } } /** * Distribuição por NSU */ async DistribuicaoPorNSU(data: NFSeDistribuicaoPorNSU) { await this.loadEnvironmentPromise; try { const service = new NFSeDistribuicaoService(this.environment, this.utility, this.xmlBuilder, this.axios, this.saveFiles, this.gerarConsulta); const operation = new NFSeDistribuicao(service); const response = await operation.DistribuicaoPorNSU(data); console.log('Retorno NFSE_DistribuicaoPorNSU'); console.log(` Status: ${response.StatusProcessamento || 'N/A'}`); console.log('==================================='); return response; } catch (error: any) { logger.error(``, error, { context: 'NFSE_DistribuicaoPorNSU' }); throw new Error(`NFSE_DistribuicaoPorNSU: ${error.message}`); } } /** * Eventos por chave de acesso */ async EventosPorChave(data: NFSeEventosPorChave) { await this.loadEnvironmentPromise; try { const service = new NFSeDistribuicaoService(this.environment, this.utility, this.xmlBuilder, this.axios, this.saveFiles, this.gerarConsulta); const operation = new NFSeDistribuicao(service); const response = await operation.EventosPorChave(data); console.log('Retorno NFSE_EventosPorChave'); console.log(` Status: ${response.StatusProcessamento || 'N/A'}`); console.log('==================================='); return response; } catch (error: any) { logger.error(``, error, { context: 'NFSE_EventosPorChave' }); throw new Error(`NFSE_EventosPorChave: ${error.message}`); } } /** * Consulta Alíquota */ async ConsultarAliquota(data: NFSeConsultaAliquota) { await this.loadEnvironmentPromise; try { const service = new NFSeParametrosMunicipaisService(this.environment, this.utility, this.xmlBuilder, this.axios, this.saveFiles, this.gerarConsulta); const operation = new NFSeParametrosMunicipais(service); const response = await operation.ConsultarAliquota(data); console.log('Retorno NFSE_ConsultarAliquota'); console.log(` Mensagem: ${response.mensagem || 'N/A'}`); console.log('==================================='); return response; } catch (error: any) { logger.error(``, error, { context: 'NFSE_ConsultarAliquota' }); throw new Error(`NFSE_ConsultarAliquota: ${error.message}`); } } /** * Consulta Histórico de Alíquotas */ async ConsultarHistoricoAliquotas(data: NFSeConsultaHistoricoAliquotas) { await this.loadEnvironmentPromise; try { const service = new NFSeParametrosMunicipaisService(this.environment, this.utility, this.xmlBuilder, this.axios, this.saveFiles, this.gerarConsulta); const operation = new NFSeParametrosMunicipais(service); const response = await operation.ConsultarHistoricoAliquotas(data); console.log('Retorno NFSE_ConsultarHistoricoAliquotas'); console.log(` Mensagem: ${response.mensagem || 'N/A'}`); console.log('==================================='); return response; } catch (error: any) { logger.error(``, error, { context: 'NFSE_ConsultarHistoricoAliquotas' }); throw new Error(`NFSE_ConsultarHistoricoAliquotas: ${error.message}`); } } /** * Consulta Benefício Municipal */ async ConsultarBeneficio(data: NFSeConsultaBeneficio) { await this.loadEnvironmentPromise; try { const service = new NFSeParametrosMunicipaisService(this.environment, this.utility, this.xmlBuilder, this.axios, this.saveFiles, this.gerarConsulta); const operation = new NFSeParametrosMunicipais(service); const response = await operation.ConsultarBeneficio(data); console.log('Retorno NFSE_ConsultarBeneficio'); console.log(` Mensagem: ${response.mensagem || 'N/A'}`); console.log('==================================='); return response; } catch (error: any) { logger.error(``, error, { context: 'NFSE_ConsultarBeneficio' }); throw new Error(`NFSE_ConsultarBeneficio: ${error.message}`); } } /** * Consulta Convênio Municipal */ async ConsultarConvenio(data: NFSeConsultaConvenio) { await this.loadEnvironmentPromise; try { const service = new NFSeParametrosMunicipaisService(this.environment, this.utility, this.xmlBuilder, this.axios, this.saveFiles, this.gerarConsulta); const operation = new NFSeParametrosMunicipais(service); const response = await operation.ConsultarConvenio(data); console.log('Retorno NFSE_ConsultarConvenio'); console.log(` Mensagem: ${response.mensagem || 'N/A'}`); console.log('==================================='); return response; } catch (error: any) { logger.error(``, error, { context: 'NFSE_ConsultarConvenio' }); throw new Error(`NFSE_ConsultarConvenio: ${error.message}`); } } /** * Consulta Regimes Especiais */ async ConsultarRegimesEspeciais(data: NFSeConsultaRegimesEspeciais) { await this.loadEnvironmentPromise; try { const service = new NFSeParametrosMunicipaisService(this.environment, this.utility, this.xmlBuilder, this.axios, this.saveFiles, this.gerarConsulta); const operation = new NFSeParametrosMunicipais(service); const response = await operation.ConsultarRegimesEspeciais(data); console.log('Retorno NFSE_ConsultarRegimesEspeciais'); console.log(` Mensagem: ${response.mensagem || 'N/A'}`); console.log('==================================='); return response; } catch (error: any) { logger.error(``, error, { context: 'NFSE_ConsultarRegimesEspeciais' }); throw new Error(`NFSE_ConsultarRegimesEspeciais: ${error.message}`); } } /** * Alterar Benefício Municipal */ async AlterarBeneficioMunicipal(data: NFSeAlteracaoBeneficioMunicipal) { await this.loadEnvironmentPromise; try { const service = new NFSeParametrosMunicipaisService(this.environment, this.utility, this.xmlBuilder, this.axios, this.saveFiles, this.gerarConsulta); const operation = new NFSeParametrosMunicipais(service); const response = await operation.AlterarBeneficioMunicipal(data); console.log('Retorno NFSE_AlterarBeneficioMunicipal'); console.log(` Sucesso: ${response.sucesso}`); console.log(` Mensagem: ${response.mensagem || 'N/A'}`); console.log('==================================='); return response; } catch (error: any) { logger.error(``, error, { context: 'NFSE_AlterarBeneficioMunicipal' }); throw new Error(`NFSE_AlterarBeneficioMunicipal: ${error.message}`); } } /** * Alterar Retenções */ async AlterarRetencoes(data: NFSeAlteracaoRetencoes) { await this.loadEnvironmentPromise; try { const service = new NFSeParametrosMunicipaisService(this.environment, this.utility, this.xmlBuilder, this.axios, this.saveFiles, this.gerarConsulta); const operation = new NFSeParametrosMunicipais(service); const response = await operation.AlterarRetencoes(data); console.log('Retorno NFSE_AlterarRetencoes'); console.log(` Sucesso: ${response.sucesso}`); console.log(` Mensagem: ${response.mensagem || 'N/A'}`); console.log('==================================='); return response; } catch (error: any) { logger.error(``, error, { context: 'NFSE_AlterarRetencoes' }); throw new Error(`NFSE_AlterarRetencoes: ${error.message}`); } } /** * Gerar DANFSe * * Gera localmente o PDF do DANFSe (Documento Auxiliar da NFS-e Nacional) * conforme NT-008 v1.0 (SE/CGNFS-e, 05/05/2026), a partir do `LayoutNFSe` * tipado. Substitui o método HTTP legado (API SefIN suspensa em 01/07/2026). * * Use `parseNFSeXml` + `decodeNFSeB64Gzip` exportados de `@treeunfe/nfse` para * converter o `nfseXmlGZipB64` retornado pela `Autorizacao` em `LayoutNFSe`. */ async GerarDanfse(data: NFSeGerarDanfseProps) { await this.loadEnvironmentPromise; try { const { exibirMarcaDaguaDanfe } = this.environment.getConfig(); const danfse = new NFSeGerarDanfse(data); const response = await danfse.generatePDF(exibirMarcaDaguaDanfe); console.log('Retorno NFSE_GerarDanfse'); console.log(response.message); console.log('==================================='); return response; } catch (error: any) { logger.error(``, error, { context: 'NFSE_GerarDanfse' }); throw new Error(`NFSE_GerarDanfse: ${error.message}`); } } /** * Autorização de NFS-e no padrão próprio Nota Fiscal Paulistana (NFP) para a Prefeitura de São Paulo (SP). * * Utilizado para municípios que NÃO aderiram ao padrão nacional REST. * São Paulo mantém seu próprio WebService SOAP (LoteNFe), com namespace http://www.prefeitura.sp.gov.br/nfe. * * WebService: https://nfews.prefeitura.sp.gov.br/lotenfe.asmx * Operação: EnviarLoteRpsSincrono * * @example * const result = await client.Autorizacao_NFP_SP({ * LoteRps: { * NumeroLote: '1', * Cnpj: '00000000000000', * InscricaoMunicipal: '00000000', * QuantidadeRps: 1, * ListaRps: { * Rps: { * InfRps: { * IdentificacaoRps: { Numero: '1', Serie: 'A1', Tipo: 1 }, * DataEmissao: '2026-01-01T00:00:00', * NaturezaOperacao: 1, * OptanteSimplesNacional: 2, * IncentivadorCultural: 2, * Servico: { * Valores: { ValorServicos: 100.00, IssRetido: 2 }, * ItemListaServico: '01.01', * Discriminacao: 'Serviço prestado', * CodigoMunicipio: 3550308, * ExigibilidadeISS: 1, * }, * Prestador: { Cnpj: '00000000000000', InscricaoMunicipal: '00000000' }, * } * } * } * } * }); */ async Autorizacao_NFP_SP(data: NFSeNFP_EnviarLoteRps) { await this.loadEnvironmentPromise; try { const service = new NFSeNFP_SPAutorizacaoService( this.environment, this.utility, this.xmlBuilder, this.axios, this.saveFiles, this.gerarConsulta, ); const operation = new NFSeNFP_SPAutorizacao(service); const response = await operation.Exec(data); console.log('Retorno NFSE_Autorizacao_NFP_SP'); if (response.success) { const numero = response.nfseGerada?.InfNfse?.Numero || response.protocolo || 'N/A'; console.log(` NFS-e / Protocolo: ${numero}`); } else { console.log(' Erros retornados pelo WebService Nota Fiscal Paulistana (SP)'); } console.log('==================================='); return response; } catch (error: any) { logger.error(``, error, { context: 'NFSE_Autorizacao_NFP_SP' }); throw new Error(`NFSE_Autorizacao_NFP_SP: ${error.message}`); } } /** * Autorização de NFS-e no padrão Nota Fiscal Paulistana (NFP) - VERSÃO 1 * * Layout antigo (fato gerador até 31/12/2025) * Usa PedidoEnvioLoteRPS_v01.xsd * * WebService: https://nfews.prefeitura.sp.gov.br/lotenfe.asmx * Operação: EnvioLoteRPS * * @example * const result = await client.Autorizacao_NFP_SP_V1({ * LoteRps: { * NumeroLote: '1', * Cnpj: '00000000000000', * InscricaoMunicipal: '00000000', * QuantidadeRps: 1, * ListaRps: { * Rps: { * InfRps: { * IdentificacaoRps: { Numero: '1', Serie: 'A1', Tipo: 1 }, * DataEmissao: '2025-12-31T00:00:00', * NaturezaOperacao: 1, * OptanteSimplesNacional: 2, * IncentivadorCultural: 2, * Servico: { * Valores: { * ValorServicos: 100.00, * ValorDeducoes: 0.00, * IssRetido: 2, * Aliquota: 0.05 * }, * ItemListaServico: '01.01', * Discriminacao: 'Serviço prestado', * CodigoMunicipio: 3550308, * ExigibilidadeISS: 1, * }, * Prestador: { Cnpj: '00000000000000', InscricaoMunicipal: '00000000' }, * Tomador: { * IdentificacaoTomador: { * CpfCnpj: { Cnpj: '00000000000000' } * }, * RazaoSocial: 'Tomador Exemplo' * } * } * } * } * } * }); */ async Autorizacao_NFP_SP_V1(data: NFSeNFP_EnviarLoteRps) { await this.loadEnvironmentPromise; try { const service = new NFSeNFP_SPAutorizacaoService_V1( this.environment, this.utility, this.xmlBuilder, this.axios, this.saveFiles, this.gerarConsulta, ); const operation = new NFSeNFP_SPAutorizacao_V1(service); const response = await operation.Exec(data); console.log('Retorno NFSE_Autorizacao_NFP_SP_V1'); if (response.success) { const numero = response.nfseGerada?.InfNfse?.Numero || response.protocolo || 'N/A'; console.log(` NFS-e / Protocolo: ${numero}`); } else { console.log(' Erros retornados pelo WebService Nota Fiscal Paulistana (SP) V1'); } console.log('==================================='); return response; } catch (error: any) { logger.error(``, error, { context: 'NFSE_Autorizacao_NFP_SP_V1' }); throw new Error(`NFSE_Autorizacao_NFP_SP_V1: ${error.message}`); } } /** * Autorização de NFS-e no padrão Nota Fiscal Paulistana (NFP) - REFORMA TRIBUTÁRIA 2026 * * Novo formato que usa PedidoEnvioLoteRPS (Layout versão 2.x) * Para uso a partir de Janeiro/2026 * * WebService: https://nfews.prefeitura.sp.gov.br/lotenfe.asmx * Operação: EnvioLoteRPS * * @example * const today = new Date(); * const result = await client.Autorizacao_NFP_SP_V2({ * Cabecalho: { * CPFCNPJRemetente: { CNPJ: '00000000000000' }, * dtInicio: '2026-01-01', * dtFim: '2026-01-31', * QtdRPS: 1, * Versao: '2', * }, * RPS: { * InfRps: { * IdentificacaoRps: { Numero: '1', Serie: 'A1', Tipo: 1 }, * DataEmissao: '2026-01-01T00:00:00', * NaturezaOperacao: 1, * OptanteSimplesNacional: 2, * IncentivadorCultural: 2, * Servico: { * Valores: { ValorServicos: 100.00, IssRetido: 2 }, * ItemListaServico: '01.01', * Discriminacao: 'Serviço prestado', * CodigoMunicipio: 3550308, * ExigibilidadeISS: 1, * }, * Prestador: { Cnpj: '00000000000000', InscricaoMunicipal: '00000000' }, * IBSCBS: { * cClassTrib: '123456', * CST: '01', * vBC: 100.00, * pAliqIBS: 0.025, * vIBS: 2.50, * pAliqCBS: 0.015, * vCBS: 1.50, * } * } * } * }); */ async Autorizacao_NFP_SP_V2(data: NFSeNFP_V2_PedidoEnvioLoteRPS) { await this.loadEnvironmentPromise; try { const service = new NFSeNFP_SPAutorizacaoService_V2( this.environment, this.utility, this.xmlBuilder, this.axios, this.saveFiles, this.gerarConsulta, ); const operation = new NFSeNFP_SPAutorizacao_V2(service); const response = await operation.Exec(data); console.log('Retorno NFSE_Autorizacao_NFP_SP_V2 (Reforma Tributária 2026)'); if (response.success) { const numero = response.nfseGerada?.InfNfse?.Numero || response.protocolo || 'N/A'; console.log(` NFS-e / Protocolo: ${numero}`); } else { console.log(' Erros retornados pelo WebService Nota Fiscal Paulistana (SP)'); } console.log('==================================='); return response; } catch (error: any) { logger.error(``, error, { context: 'NFSE_Autorizacao_NFP_SP_V2' }); throw new Error(`NFSE_Autorizacao_NFP_SP_V2: ${error.message}`); } } /** * TESTE de Autorização de NFS-e no padrão Nota Fiscal Paulistana (NFP) - REFORMA TRIBUTÁRIA 2026 * * Este método NÃO gera NFS-e real, apenas valida a estrutura XML. * Use para testar a integração durante a fase de adaptação. * * WebService: https://nfews.prefeitura.sp.gov.br/lotenfe.asmx * Operação: TesteEnvioLoteRPS * * @example * const result = await client.TesteAutorizacao_NFP_SP_V2({ * Cabecalho: { * CPFCNPJRemetente: { CNPJ: '00000000000000' }, * dtInicio: '2026-01-01', * dtFim: '2026-01-31', * QtdRPS: 1, * Versao: '2', * }, * RPS: { ... } * }); */ async TesteAutorizacao_NFP_SP_V2(data: NFSeNFP_V2_PedidoEnvioLoteRPS) { await this.loadEnvironmentPromise; try { const service = new NFSeNFP_SPTesteAutorizacaoService_V2( this.environment, this.utility, this.xmlBuilder, this.axios, this.saveFiles, this.gerarConsulta, ); const operation = new NFSeNFP_SPTesteAutorizacao_V2(service); const response = await operation.Exec(data); console.log('Retorno NFSE_TesteAutorizacao_NFP_SP_V2 (Reforma Tributária 2026)'); if (response.success) { console.log(' Teste concluído com sucesso - estrutura XML válida'); } else { console.log(' Erros retornados pelo WebService Nota Fiscal Paulistana (SP)'); } console.log('==================================='); return response; } catch (error: any) { logger.error(``, error, { context: 'NFSE_TesteAutorizacao_NFP_SP_V2' }); throw new Error(`NFSE_TesteAutorizacao_NFP_SP_V2: ${error.message}`); } } }