From 8b4583180c2e9246024f33c31fe59b26ca79486a Mon Sep 17 00:00:00 2001 From: Junior Tada Date: Fri, 16 Oct 2015 12:14:02 -0300 Subject: [PATCH 1/6] Aliquota e credito para crt=1 csosn=101 --- pynfe/entidades/produto.py | 2 ++ pynfe/processamento/serializacao.py | 4 ++-- pynfe/utils/__init__.py | 1 - 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pynfe/entidades/produto.py b/pynfe/entidades/produto.py index 43be459..d663ced 100644 --- a/pynfe/entidades/produto.py +++ b/pynfe/entidades/produto.py @@ -83,6 +83,8 @@ class Produto(Entidade): icms_modalidade = str() icms_origem = int() icms_csosn = str() + icms_aliquota = Decimal() + icms_credito= Decimal() # # PIS pis_modalidade = str() diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py index c727e21..f1f717e 100644 --- a/pynfe/processamento/serializacao.py +++ b/pynfe/processamento/serializacao.py @@ -256,8 +256,8 @@ class SerializacaoXML(Serializacao): icms_item = etree.SubElement(icms, 'ICMS'+produto_servico.icms_modalidade) etree.SubElement(icms_item, 'orig').text = str(produto_servico.icms_origem) etree.SubElement(icms_item, 'CSOSN').text = produto_servico.icms_csosn - etree.SubElement(icms_item, 'pCredSN').text = '' # Alíquota aplicável de cálculo do crédito (Simples Nacional). - etree.SubElement(icms_item, 'vCredICMSSN').text = '' # Valor crédito do ICMS que pode ser aproveitado nos termos do art. 23 da LC 123 (Simples Nacional) + etree.SubElement(icms_item, 'pCredSN').text = str(produto_servico.icms_aliquota) # Alíquota aplicável de cálculo do crédito (Simples Nacional). + etree.SubElement(icms_item, 'vCredICMSSN').text = str(produto_servico.icms_credito) # Valor crédito do ICMS que pode ser aproveitado nos termos do art. 23 da LC 123 (Simples Nacional) elif produto_servico.icms_modalidade == 'ST': icms_item = etree.SubElement(icms, 'ICMS'+produto_servico.icms_modalidade) etree.SubElement(icms_item, 'orig').text = str(produto_servico.icms_origem) diff --git a/pynfe/utils/__init__.py b/pynfe/utils/__init__.py index 319c596..7259a5c 100644 --- a/pynfe/utils/__init__.py +++ b/pynfe/utils/__init__.py @@ -18,7 +18,6 @@ try: from . import flags except ImportError: raise Exception('Falhou ao importar flags') -# from geraldo.utils import memoize # @memoize From 82909be299bd5e33845c6a28b6e0d5541534a47e Mon Sep 17 00:00:00 2001 From: Junior Tada Date: Fri, 16 Oct 2015 12:26:40 -0300 Subject: [PATCH 2/6] Pis/cofins modalidade 99 --- pynfe/processamento/serializacao.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py index f1f717e..d67cbeb 100644 --- a/pynfe/processamento/serializacao.py +++ b/pynfe/processamento/serializacao.py @@ -299,8 +299,9 @@ class SerializacaoXML(Serializacao): etree.SubElement(pis_item, 'CST').text = produto_servico.pis_modalidade etree.SubElement(pis_item, 'vBC').text = produto_servico.pis_valor_base_calculo etree.SubElement(pis_item, 'pPIS').text = produto_servico.pis_aliquota_percentual - etree.SubElement(pis_item, 'qBCProd').text = produto_servico.quantidade_comercial - etree.SubElement(pis_item, 'vAliqProd').text = produto_servico.pis_aliquota_percentual + if produto_servico.pis_modalidade is not '99': + etree.SubElement(pis_item, 'qBCProd').text = produto_servico.quantidade_comercial + etree.SubElement(pis_item, 'vAliqProd').text = produto_servico.pis_aliquota_percentual etree.SubElement(pis_item, 'vPIS').text = produto_servico.pis_valor_base_calculo ## PISST @@ -334,7 +335,8 @@ class SerializacaoXML(Serializacao): etree.SubElement(cofins_item, 'CST').text = produto_servico.cofins_modalidade etree.SubElement(cofins_item, 'vBC').text = produto_servico.cofins_valor_base_calculo etree.SubElement(cofins_item, 'pCOFINS').text = produto_servico.cofins_aliquota_percentual - etree.SubElement(cofins_item, 'vAliqProd').text = produto_servico.cofins_aliquota_percentual + if produto_servico.cofins_modalidade is not '99': + etree.SubElement(cofins_item, 'vAliqProd').text = produto_servico.cofins_aliquota_percentual etree.SubElement(cofins_item, 'vCOFINS').text = produto_servico.cofins_valor ## COFINSST From 6f113430ea83323c532cdf52456dc7e17cd1ac69 Mon Sep 17 00:00:00 2001 From: Junior Tada Date: Tue, 27 Oct 2015 18:15:37 -0200 Subject: [PATCH 3/6] Bug converte indicador de ie em str --- pynfe/processamento/serializacao.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py index d67cbeb..66bfb45 100644 --- a/pynfe/processamento/serializacao.py +++ b/pynfe/processamento/serializacao.py @@ -152,7 +152,7 @@ class SerializacaoXML(Serializacao): etree.SubElement(raiz, 'IE').text = 'ISENTO' else: # Indicador da IE do destinatário: 1 – Contribuinte ICMSpagamento à vista; - etree.SubElement(raiz, 'indIEDest').text = cliente.indicador_ie + etree.SubElement(raiz, 'indIEDest').text = str(cliente.indicador_ie) etree.SubElement(raiz, 'IE').text = cliente.inscricao_estadual # Suframa if cliente.inscricao_suframa: From 4403b05f13e5913fd5fd58643bb82cf668c1d136 Mon Sep 17 00:00:00 2001 From: Junior Tada Date: Tue, 27 Oct 2015 18:23:05 -0200 Subject: [PATCH 4/6] Bug tag ICMSSN para icms modalidade 101 --- pynfe/processamento/serializacao.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py index 66bfb45..5073e7a 100644 --- a/pynfe/processamento/serializacao.py +++ b/pynfe/processamento/serializacao.py @@ -253,7 +253,7 @@ class SerializacaoXML(Serializacao): etree.SubElement(icms_item, 'orig').text = str(produto_servico.icms_origem) etree.SubElement(icms_item, 'CSOSN').text = produto_servico.icms_csosn elif produto_servico.icms_modalidade == '101': - icms_item = etree.SubElement(icms, 'ICMS'+produto_servico.icms_modalidade) + icms_item = etree.SubElement(icms, 'ICMSSN'+produto_servico.icms_modalidade) etree.SubElement(icms_item, 'orig').text = str(produto_servico.icms_origem) etree.SubElement(icms_item, 'CSOSN').text = produto_servico.icms_csosn etree.SubElement(icms_item, 'pCredSN').text = str(produto_servico.icms_aliquota) # Alíquota aplicável de cálculo do crédito (Simples Nacional). From 847935f611e14dcc43105878de0571245c20d352 Mon Sep 17 00:00:00 2001 From: Junior Tada Date: Wed, 11 Nov 2015 00:40:36 -0200 Subject: [PATCH 5/6] =?UTF-8?q?Inicio=20implanta=C3=A7=C3=A3o=20de=20NFS-e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pynfe/entidades/__init__.py | 1 + pynfe/entidades/notafiscal.py | 26 ++++++++++ pynfe/entidades/servico.py | 21 ++++++++ pynfe/processamento/__init__.py | 1 + pynfe/processamento/assinatura.py | 38 +++++++++++++++ pynfe/processamento/serializacao.py | 95 ++++++++++++++++++++++++++++++++++++- pynfe/utils/flags.py | 2 + pynfe/utils/webservices.py | 30 ++++++++++++ 8 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 pynfe/entidades/servico.py diff --git a/pynfe/entidades/__init__.py b/pynfe/entidades/__init__.py index f4fa7d4..f2c8464 100644 --- a/pynfe/entidades/__init__.py +++ b/pynfe/entidades/__init__.py @@ -7,4 +7,5 @@ from .lotes import LoteNotaFiscal from .fonte_dados import _fonte_dados from .certificado import CertificadoA1 from .evento import EventoCancelarNota +from .servico import Servico diff --git a/pynfe/entidades/notafiscal.py b/pynfe/entidades/notafiscal.py index 0d276a7..5a00190 100644 --- a/pynfe/entidades/notafiscal.py +++ b/pynfe/entidades/notafiscal.py @@ -905,3 +905,29 @@ class NotaFiscalEntregaRetirada(Entidade): # - Telefone endereco_telefone = str() +class NotaFiscalServico(Entidade): + + # Empresa que implementa o webservice + autorizador = str() # betha + # id do rps + identificador = str() + # tag competencia + data_emissao = None + # Serviço executado pelo prestador + servico = None + # Emitente da NFS-e + emitente = None + # Cliente para quem a NFS-e será emitida + cliente = None + # Optante Simples Nacional + simples = int() # 1-Sim; 2-Não + # Incentivo Fiscal + incentivo = int() # 1-Sim; 2-Não + + def __init__(self, *args, **kwargs): + + super(NotaFiscalServico, self).__init__(*args, **kwargs) + + def __str__(self): + return ' '.join([str(self.identificador)]) + diff --git a/pynfe/entidades/servico.py b/pynfe/entidades/servico.py new file mode 100644 index 0000000..e9679bb --- /dev/null +++ b/pynfe/entidades/servico.py @@ -0,0 +1,21 @@ +""" + @author: Junior Tada, Leonardo Tada +""" + +from .base import Entidade +from decimal import Decimal + +class Servico(Entidade): + + valor_servico = Decimal() + iss_retido = Decimal() + """ http://www1.receita.fazenda.gov.br/sistemas/nfse/tabelas-de-codigos.htm + Lista com códigos dos serviços + """ + item_lista = str() + discriminacao = str() + exigibilidade = int() + codigo_municipio = str() + + def __str__(self): + return self.discriminacao \ No newline at end of file diff --git a/pynfe/processamento/__init__.py b/pynfe/processamento/__init__.py index a28647d..e63097d 100644 --- a/pynfe/processamento/__init__.py +++ b/pynfe/processamento/__init__.py @@ -1,4 +1,5 @@ from .serializacao import SerializacaoXML +from .serializacao import SerializacaoNfse from .validacao import Validacao from .assinatura import AssinaturaA1 from .comunicacao import ComunicacaoSefaz diff --git a/pynfe/processamento/assinatura.py b/pynfe/processamento/assinatura.py index 2b16130..9cd702b 100644 --- a/pynfe/processamento/assinatura.py +++ b/pynfe/processamento/assinatura.py @@ -62,4 +62,42 @@ class AssinaturaA1(Assinatura): return xml except Exception as e: raise e + + def assinarNfse(self, xml, retorna_string=False): + try: + # No raiz do XML de saida + tag = 'InfDeclaracaoPrestacaoServico'; # tag que será assinada + raiz = etree.Element('Signature', xmlns='http://www.w3.org/2000/09/xmldsig#') + siginfo = etree.SubElement(raiz, 'SignedInfo') + etree.SubElement(siginfo, 'CanonicalizationMethod', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') + etree.SubElement(siginfo, 'SignatureMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1') + # Tenta achar a tag infNFe + + ref = etree.SubElement(siginfo, 'Reference', URI='#'+xml.xpath('Rps/InfDeclaracaoPrestacaoServico')[0].attrib['Id']) + + trans = etree.SubElement(ref, 'Transforms') + etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/2000/09/xmldsig#enveloped-signature') + etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') + etree.SubElement(ref, 'DigestMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#sha1') + etree.SubElement(ref, 'DigestValue') + etree.SubElement(raiz, 'SignatureValue') + keyinfo = etree.SubElement(raiz, 'KeyInfo') + etree.SubElement(keyinfo, 'X509Data') + + rps = xml.xpath('Rps')[0] + rps.append(raiz) + + # Escreve no arquivo depois de remover caracteres especiais e parse string + with open('nfse.xml', 'w') as arquivo: + arquivo.write(remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False))) + + subprocess.call(['xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd', self.senha, '--crypto', 'openssl', '--output', 'funfa.xml', '--id-attr:Id', tag, 'nfse.xml']) + xml = etree.parse('funfa.xml').getroot() + + if retorna_string: + return etree.tostring(xml, encoding="unicode", pretty_print=False) + else: + return xml + except Exception as e: + raise e diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py index 5073e7a..462d54d 100644 --- a/pynfe/processamento/serializacao.py +++ b/pynfe/processamento/serializacao.py @@ -6,7 +6,7 @@ from pynfe.entidades import NotaFiscal from pynfe.utils import etree, so_numeros, obter_municipio_por_codigo, \ obter_pais_por_codigo, obter_municipio_e_codigo, \ formatar_decimal, remover_acentos, obter_uf_por_codigo, obter_codigo_por_municipio -from pynfe.utils.flags import CODIGOS_ESTADOS, VERSAO_PADRAO, NAMESPACE_NFE +from pynfe.utils.flags import CODIGOS_ESTADOS, VERSAO_PADRAO, NAMESPACE_NFE, NAMESPACE_BETHA class Serializacao(object): """Classe abstrata responsavel por fornecer as funcionalidades basicas para @@ -576,6 +576,99 @@ class SerializacaoXML(Serializacao): else: return raiz +class SerializacaoNfse(Serializacao): + + def exportar(self): + pass + + def importar(self): + pass + + def _serializar_emitente(self, emitente, tag_raiz='Prestador', retorna_string=True): + raiz = etree.Element(tag_raiz) + documento = etree.SubElement(raiz, 'CpfCnpj') + etree.SubElement(documento, 'Cnpj').text = emitente.cnpj + etree.SubElement(raiz, 'InscricaoMunicipal').text = emitente.inscricao_municipal + + if retorna_string: + return etree.tostring(raiz, encoding="unicode", pretty_print=True) + else: + return raiz + + def _serializar_cliente(self, cliente, tag_raiz='Tomador', retorna_string=True): + raiz = etree.Element(tag_raiz) + identificacao = etree.SubElement(raiz, 'IdentificacaoTomador') + documento = etree.SubElement(identificacao, 'CpfCnpj') + etree.SubElement(documento, cliente.tipo_documento).text = cliente.numero_documento # Apenas Cnpj ?? + etree.SubElement(identificacao, 'InscricaoMunicipal').text = cliente.inscricao_municipal # obrigatório?? + etree.SubElement(raiz, 'RazaoSocial').text = cliente.razao_social + endereco = etree.SubElement(raiz, 'Endereco') + etree.SubElement(endereco, 'Endereco').text = cliente.endereco_logradouro + etree.SubElement(endereco, 'Numero').text = cliente.endereco_numero + if cliente.endereco_complemento: + etree.SubElement(endereco, 'Complemento').text = cliente.endereco_complemento + etree.SubElement(endereco, 'Bairro').text = cliente.endereco_bairro + etree.SubElement(endereco, 'CodigoMunicipio').text = obter_codigo_por_municipio( + cliente.endereco_municipio, cliente.endereco_uf) + etree.SubElement(endereco, 'Uf').text = cliente.endereco_uf + etree.SubElement(endereco, 'CodigoPais').text = cliente.endereco_pais + etree.SubElement(endereco, 'Cep').text = so_numeros(cliente.endereco_cep) + contato = etree.SubElement(raiz, 'Contato') + etree.SubElement(contato, 'Telefone').text = cliente.endereco_telefone + etree.SubElement(contato, 'Email').text = cliente.email + + if retorna_string: + return etree.tostring(raiz, encoding="unicode", pretty_print=True) + else: + return raiz + + def _serializar_servico(self, servico, tag_raiz='Servico', retorna_string=True): + raiz = etree.Element(tag_raiz) + valores = etree.SubElement(raiz, 'Valores') + etree.SubElement(valores, 'ValorServicos').text = str('{:.2f}').format(servico.valor_servico) + etree.SubElement(raiz, 'IssRetido').text = str('{:.2f}').format(servico.iss_retido) + #etree.SubElement(raiz, 'ResponsavelRetencao').text = '' + etree.SubElement(raiz, 'ItemListaServico').text = servico.item_lista + #etree.SubElement(raiz, 'CodigoCnae').text = '' + #etree.SubElement(raiz, 'CodigoTributacaoMunicipio').text = '' + etree.SubElement(raiz, 'Discriminacao').text = servico.discriminacao + etree.SubElement(raiz, 'CodigoMunicipio').text = servico.codigo_municipio + #etree.SubElement(raiz, 'CodigoPais').text = '' + etree.SubElement(raiz, 'ExigibilidadeISS').text = str(servico.exigibilidade) + etree.SubElement(raiz, 'MunicipioIncidencia').text = servico.codigo_municipio + #etree.SubElement(raiz, 'NumeroProcesso').text = '' + + if retorna_string: + return etree.tostring(raiz, encoding="unicode", pretty_print=True) + else: + return raiz + + def _serializar_gerar(self, nfse, tag_raiz='GerarNfseEnvio', retorna_string=False): + + if nfse.autorizador == 'betha': + raiz = etree.Element(tag_raiz, xmlns=NAMESPACE_BETHA) + # TODO - implementar outros sistemas autorizadores + else: + raiz = etree.Element(tag_raiz) + rps = etree.SubElement(raiz, 'Rps') + info = etree.SubElement(rps, 'InfDeclaracaoPrestacaoServico', Id=nfse.identificador) + etree.SubElement(info, 'Competencia').text = nfse.data_emissao.strftime('%Y-%m-%d') + + # Servico + info.append(self._serializar_servico(nfse.servico, retorna_string=False)) + # Emitente/Prestador + info.append(self._serializar_emitente(nfse.emitente, retorna_string=False)) + # Cliente/Tomador + info.append(self._serializar_cliente(nfse.cliente, retorna_string=False)) + + etree.SubElement(info, 'OptanteSimplesNacional').text = str(nfse.simples) # 1-Sim; 2-Não + etree.SubElement(info, 'IncentivoFiscal').text = str(nfse.incentivo) # 1-Sim; 2-Não + + if retorna_string: + return etree.tostring(raiz, encoding="unicode", pretty_print=True) + else: + return raiz + class SerializacaoPipes(Serializacao): """Serialização utilizada pela SEFAZ-SP para a importação de notas.""" diff --git a/pynfe/utils/flags.py b/pynfe/utils/flags.py index 4ca34db..f1bb65d 100644 --- a/pynfe/utils/flags.py +++ b/pynfe/utils/flags.py @@ -7,6 +7,8 @@ NAMESPACE_XSI = 'http://www.w3.org/2001/XMLSchema-instance' NAMESPACE_XSD = 'http://www.w3.org/2001/XMLSchema' NAMESPACE_METODO = 'http://www.portalfiscal.inf.br/nfe/wsdl/' +NAMESPACE_BETHA = 'http://www.betha.com.br/e-nota-contribuinte-ws' + VERSAO_PADRAO = '3.10' VERSAO_QRCODE = '100' diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py index 00af8a1..453ee7b 100644 --- a/pynfe/utils/webservices.py +++ b/pynfe/utils/webservices.py @@ -420,4 +420,34 @@ NFE = { 'HTTPS': 'https://nfe.', 'HOMOLOGACAO': 'https://nfe-homologacao.' }, +} + +# Nfs-e +NFSE = { + # + 'BETHA': { + 'STATUS':'', + 'AUTORIZACAO':'GerarNfse', + 'CANCELAR':'CancelarNfse', + 'CONSULTA_RPS':'ConsultarNfsePorRps', + 'CONSULTA_FAIXA':'ConsultarNfseFaixa', + 'CONSULTA_SERVICO':'ConsultarNfseServicoPrestado', + 'CONSULTA_SERVICO_TOMADO':'ConsultarNfseServicoTomado', + 'SUBSTITUIR':'SubstituirNfse', + 'HTTPS':'http://e-gov.betha.com.br/e-nota-contribuinte-ws/nfseWS?wsdl', + 'HOMOLOGACAO':'http://e-gov.betha.com.br/e-nota-contribuinte-test-ws/nfseWS?wsdl' + }, + # + 'GINFES':{ + 'STATUS':'', + 'AUTORIZACAO':'GerarNfse', + 'CANCELAR':'CancelarNfse', + 'CONSULTA_RPS':'ConsultarNfsePorRps', + 'CONSULTA_FAIXA':'ConsultarNfseFaixa', + 'CONSULTA_SERVICO':'ConsultarNfseServicoPrestado', + 'CONSULTA_SERVICO_TOMADO':'ConsultarNfseServicoTomado', + 'SUBSTITUIR':'SubstituirNfse', + 'HTTPS':'https://producao.ginfes.com.br/ServiceGinfesImpl?wsdl', + 'HOMOLOGACAO':'https://homologacao.ginfes.com.br/ServiceGinfesImpl?wsdl' + } } \ No newline at end of file From f299be3660a1bd023f293afbbf925b984a036b32 Mon Sep 17 00:00:00 2001 From: Junior Tada Date: Wed, 11 Nov 2015 12:45:33 -0200 Subject: [PATCH 6/6] =?UTF-8?q?Xml=20soap=20para=20emiss=C3=A3o=20de=20NFS?= =?UTF-8?q?-e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pynfe/processamento/comunicacao.py | 65 +++++++++++++++++++++++++++++++++++-- pynfe/processamento/serializacao.py | 2 +- pynfe/utils/flags.py | 1 + pynfe/utils/webservices.py | 3 +- 4 files changed, 66 insertions(+), 5 deletions(-) diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py index b50907c..5894a9d 100644 --- a/pynfe/processamento/comunicacao.py +++ b/pynfe/processamento/comunicacao.py @@ -3,8 +3,9 @@ import datetime import time import requests from pynfe.utils import etree, so_numeros -from pynfe.utils.flags import NAMESPACE_NFE, NAMESPACE_SOAP, NAMESPACE_XSI, NAMESPACE_XSD, NAMESPACE_METODO, VERSAO_PADRAO, CODIGOS_ESTADOS -from pynfe.utils.webservices import NFCE, NFE +from pynfe.utils.flags import NAMESPACE_NFE, NAMESPACE_SOAP, NAMESPACE_XSI, NAMESPACE_XSD, NAMESPACE_METODO, VERSAO_PADRAO, CODIGOS_ESTADOS, \ +NAMESPACE_SOAP_NFSE, NAMESPACE_BETHA +from pynfe.utils.webservices import NFCE, NFE, NFSE from .assinatura import AssinaturaA1 from pynfe.entidades.certificado import CertificadoA1 @@ -349,4 +350,62 @@ class ComunicacaoSefaz(Comunicacao): except requests.exceptions.ConnectionError as e: raise e finally: - certificadoA1.excluir() \ No newline at end of file + certificadoA1.excluir() + + +class ComunicacaoNfse(Comunicacao): + """ Classe de comunicação que segue o padrão definido para as SEFAZ dos Municípios. """ + + _versao = '' + + def autorizacao(self, autorizador, nota): + # url do serviço + url = self._get_url(autorizador) + NFSE[autorizador.upper()]['AUTORIZACAO'] + # gerar + raiz = etree.Element('GerarNfse') + # cabecalho + raiz.append(self._cabecalho_soap(autorizador)) + dados = etree.SubElement(raiz, 'nfseDadosMsg') + dados.append(nota) + # xml soap + xml = self._construir_xml(raiz) + + print (url) + print (etree.tostring(xml, encoding='unicode').replace(':ns0','').replace('ns0:','')) + + + def _cabecalho_soap(self, autorizador): + u"""Monta o XML do cabeçalho da requisição SOAP""" + if autorizador.upper() == 'BETHA': + namespace = NAMESPACE_BETHA + versao = '2.02' + + raiz = etree.Element('nfseCabecMsg') + cabecalho = etree.SubElement(raiz, 'cabecalho', xmlns=namespace, versao=versao) + etree.SubElement(cabecalho, 'versaoDados').text = versao + return raiz + + def _construir_xml(self, dados): + """Mota o XML para o envio via SOAP""" + + raiz = etree.Element('{%s}Envelope'%NAMESPACE_SOAP, nsmap={'soapenv': NAMESPACE_SOAP_NFSE}) + etree.SubElement(raiz, '{%s}Header'%NAMESPACE_SOAP) + body = etree.SubElement(raiz, '{%s}Body'%NAMESPACE_SOAP) + body.append(dados) + return raiz + + + def _get_url(self, autorizador): + """ Retorna a url para comunicação com o webservice """ + if self._ambiente == 1: + ambiente = 'HTTPS' + else: + ambiente = 'HOMOLOGACAO' + if autorizador.upper() in NFSE: + self.url = NFSE[autorizador.upper()][ambiente] + else: + raise Exception('Autorizador nao encontrado!') + return self.url + + def _post(self, url): + pass \ No newline at end of file diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py index 462d54d..8fa14e6 100644 --- a/pynfe/processamento/serializacao.py +++ b/pynfe/processamento/serializacao.py @@ -645,7 +645,7 @@ class SerializacaoNfse(Serializacao): def _serializar_gerar(self, nfse, tag_raiz='GerarNfseEnvio', retorna_string=False): - if nfse.autorizador == 'betha': + if nfse.autorizador.upper() == 'BETHA': raiz = etree.Element(tag_raiz, xmlns=NAMESPACE_BETHA) # TODO - implementar outros sistemas autorizadores else: diff --git a/pynfe/utils/flags.py b/pynfe/utils/flags.py index f1bb65d..8a65863 100644 --- a/pynfe/utils/flags.py +++ b/pynfe/utils/flags.py @@ -7,6 +7,7 @@ NAMESPACE_XSI = 'http://www.w3.org/2001/XMLSchema-instance' NAMESPACE_XSD = 'http://www.w3.org/2001/XMLSchema' NAMESPACE_METODO = 'http://www.portalfiscal.inf.br/nfe/wsdl/' +NAMESPACE_SOAP_NFSE = 'http://schemas.xmlsoap.org/soap/envelope/' NAMESPACE_BETHA = 'http://www.betha.com.br/e-nota-contribuinte-ws' VERSAO_PADRAO = '3.10' diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py index 453ee7b..f0674bf 100644 --- a/pynfe/utils/webservices.py +++ b/pynfe/utils/webservices.py @@ -435,7 +435,8 @@ NFSE = { 'CONSULTA_SERVICO_TOMADO':'ConsultarNfseServicoTomado', 'SUBSTITUIR':'SubstituirNfse', 'HTTPS':'http://e-gov.betha.com.br/e-nota-contribuinte-ws/nfseWS?wsdl', - 'HOMOLOGACAO':'http://e-gov.betha.com.br/e-nota-contribuinte-test-ws/nfseWS?wsdl' + 'HOMOLOGACAO':'http://e-gov.betha.com.br/e-nota-contribuinte-test-ws/nfseWS?' + #'HOMOLOGACAO':'http://e-gov.betha.com.br/e-nota-contribuinte-test-ws/nfseWS?wsdl' }, # 'GINFES':{