From 223fd7bc3cf930f51f4147f84064a8a209aea333 Mon Sep 17 00:00:00 2001 From: Junior Tada Date: Tue, 21 Jul 2015 14:11:41 -0300 Subject: [PATCH] =?UTF-8?q?Remo=C3=A7=C3=A3o=20de=20.tostring=20na=20const?= =?UTF-8?q?ru=C3=A7=C3=A3o=20do=20soap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pynfe/entidades/certificado.py | 2 +- pynfe/processamento/assinatura.py | 2 +- pynfe/processamento/comunicacao.py | 82 ++++++++++++++------------------------ pynfe/utils/flags.py | 2 +- 4 files changed, 33 insertions(+), 55 deletions(-) diff --git a/pynfe/entidades/certificado.py b/pynfe/entidades/certificado.py index ddb24b2..a2406b4 100644 --- a/pynfe/entidades/certificado.py +++ b/pynfe/entidades/certificado.py @@ -27,7 +27,7 @@ class CertificadoA1(Certificado): def __init__(self, caminho_arquivo=None): self.caminho_arquivo = caminho_arquivo - def separar_arquivo(self, senha, caminho_chave=None, caminho_cert=None): + def separar_arquivo(self, senha): """Separa o arquivo de certificado em dois: de chave e de certificado, e retorna a string.""" diff --git a/pynfe/processamento/assinatura.py b/pynfe/processamento/assinatura.py index f1a85f0..187ab58 100644 --- a/pynfe/processamento/assinatura.py +++ b/pynfe/processamento/assinatura.py @@ -28,7 +28,7 @@ class AssinaturaA1(Assinatura): def assinar(self, xml, retona_string=True): arquivo_cert = CertificadoA1(self.certificado) - chave, cert = arquivo_cert.separar_arquivo(self.senha) + chave, cert = arquivo_cert.separar_arquivo(self.senha, caminho=True) #root = etree.parse(xml).getroot() # caminho root = etree.fromstring(xml) # string diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py index 9b34087..f4942a2 100644 --- a/pynfe/processamento/comunicacao.py +++ b/pynfe/processamento/comunicacao.py @@ -6,6 +6,7 @@ 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 .assinatura import AssinaturaA1 +from pynfe.entidades.certificado import CertificadoA1 class Comunicacao(object): u"""Classe abstrata responsavel por definir os metodos e logica das classes @@ -15,6 +16,7 @@ class Comunicacao(object): uf = None certificado = None certificado_senha = None + url = None def __init__(self, uf, certificado, certificado_senha, homologacao=False): self.uf = uf @@ -31,21 +33,17 @@ class ComunicacaoSefaz(Comunicacao): def autorizacao(self, modelo, nota_fiscal): # url do serviço url = self._get_url(modelo=modelo, consulta='AUTORIZACAO') - parser = etree.XMLParser(remove_blank_text=True) # Monta XML do corpo da requisição raiz = etree.Element('enviNFe', versao=VERSAO_PADRAO) #etree.SubElement(raiz, 'versao').text = self._versao etree.SubElement(raiz, 'idLote').text = str(1) # numero autoincremental gerado pelo sistema etree.SubElement(raiz, 'indSinc').text = str(1) # 0 para assincrono, 1 para sincrono #etree.SubElement(raiz, 'NFe').text = nota_fiscal # conjunto de nfe tramistidas (max 50) - raiz.append(etree.fromstring(nota_fiscal)) - elem = etree.XML(etree.tostring(raiz, encoding='unicode'), parser=parser) - dados = etree.tostring(elem, encoding="unicode") # BUG < retorna caracteres ASCII + raiz.append(nota_fiscal) # Monta XML para envio da requisição - xml = self._construir_xml_status_pr(cabecalho=self._cabecalho_soap(metodo='NfeAutorizacao'), metodo='NfeAutorizacao', dados=dados) - xml = str(xml).replace('lt;','<').replace('gt;','>').replace('&','').replace('ds:','').replace('\\\'','"').replace('\\n','') - print (xml) - #return self._post(url, xml) + xml = self._construir_xml_status_pr(cabecalho=self._cabecalho_soap(metodo='NfeAutorizacao'), metodo='NfeAutorizacao', dados=raiz) + #print (xml) + return self._post(url, xml) def cancelar(self, modelo, xml): """ Envia um evento de cancelamento de nota fiscal """ @@ -74,7 +72,7 @@ class ComunicacaoSefaz(Comunicacao): def status_servico(self, modelo): """ Verifica status do servidor da receita. """ - """ tipo é a string com tipo de serviço que deseja consultar + """ modelo é a string com tipo de serviço que deseja consultar Ex: nfe ou nfce """ url = self._get_url(modelo=modelo, consulta='STATUS') @@ -84,15 +82,9 @@ class ComunicacaoSefaz(Comunicacao): etree.SubElement(raiz, 'tpAmb').text = str(self._ambiente) etree.SubElement(raiz, 'cUF').text = CODIGOS_ESTADOS[self.uf.upper()] etree.SubElement(raiz, 'xServ').text = 'STATUS' - dados = etree.tostring(raiz, encoding="utf-8").decode('utf-8') # Monta XML para envio da requisição - if self.uf.upper() == 'PR': - xml = self._construir_xml_status_pr(cabecalho=self._cabecalho_soap(metodo='NfeStatusServico3'), metodo='NfeStatusServico3', dados=dados) - else: - xml = self._construir_xml_soap(cabecalho=self._cabecalho_soap(metodo='NfeStatusServico3'), metodo='NfeStatusServico3', dados=dados) - xml = str(xml).replace('<', '<').replace('>', '>').replace('\\\'', '"').replace('\\n', '') + xml = self._construir_xml_status_pr(cabecalho=self._cabecalho_soap(metodo='NfeStatusServico2'), metodo='NfeStatusServico2', dados=raiz) # Chama método que efetua a requisição POST no servidor SOAP - #print (xml) return self._post(url, xml) def consultar_cadastro(self, instancia): @@ -162,23 +154,22 @@ class ComunicacaoSefaz(Comunicacao): ambiente = 'https://homologacao.' if modelo == 'nfe': # nfe Ex: https://nfe.fazenda.pr.gov.br/nfe/NFeStatusServico3 - url = ambiente + NFE[self.uf.upper()][consulta] + self.url = ambiente + NFE[self.uf.upper()][consulta] elif modelo == 'nfce': # nfce Ex: https://homologacao.nfce.fazenda.pr.gov.br/nfce/NFeStatusServico3 - url = ambiente + NFCE[self.uf.upper()][consulta] + self.url = ambiente + NFCE[self.uf.upper()][consulta] else: # TODO implementar outros tipos de notas como NFS-e pass - return url + return self.url def _cabecalho_soap(self, metodo): u"""Monta o XML do cabeçalho da requisição SOAP""" - raiz = etree.Element('nfeCabecMsg', xmlns=NAMESPACE_METODO+metodo) + raiz = etree.Element('nfeCabecMsg') etree.SubElement(raiz, 'cUF').text = CODIGOS_ESTADOS[self.uf.upper()] etree.SubElement(raiz, 'versaoDados').text = VERSAO_PADRAO - - return etree.tostring(raiz, encoding="unicode") + return raiz def _construir_xml_soap(self, cabecalho, metodo, dados): """Mota o XML para o envio via SOAP""" @@ -186,54 +177,41 @@ class ComunicacaoSefaz(Comunicacao): raiz = etree.Element('{%s}Envelope'%NAMESPACE_SOAP, nsmap={'xsi': NAMESPACE_XSI, 'xsd': NAMESPACE_XSD, 'soap12': NAMESPACE_SOAP}) etree.SubElement(raiz, '{%s}Header'%NAMESPACE_SOAP).text = cabecalho body = etree.SubElement(raiz, '{%s}Body'%NAMESPACE_SOAP) - etree.SubElement(body, 'nfeDadosMsg', xmlns=NAMESPACE_METODO+metodo).text = dados - - return etree.tostring(raiz, encoding="utf-8", xml_declaration=True) + etree.SubElement(body, 'nfeDadosMsg').text = dados + return raiz def _construir_xml_status_pr(self, cabecalho, metodo, dados): u"""Mota o XML para o envio via SOAP""" - raiz = etree.Element('{%s}Envelope'%NAMESPACE_SOAP, nsmap={'xsi': NAMESPACE_XSI, 'xsd': NAMESPACE_XSD, 'soap12': NAMESPACE_SOAP}) - etree.SubElement(raiz, '{%s}Header'%NAMESPACE_SOAP).text = cabecalho + raiz = etree.Element('{%s}Envelope'%NAMESPACE_SOAP, nsmap={'soap': NAMESPACE_SOAP}, xmlns=NAMESPACE_METODO+metodo) + c = etree.SubElement(raiz, '{%s}Header'%NAMESPACE_SOAP) + c.append(cabecalho) body = etree.SubElement(raiz, '{%s}Body'%NAMESPACE_SOAP) - etree.SubElement(body, 'nfeDadosMsg', xmlns=NAMESPACE_METODO+metodo).text = dados - - return etree.tostring(raiz, encoding="utf-8", xml_declaration=True) + a = etree.SubElement(body, 'nfeDadosMsg', xmlns=NAMESPACE_METODO+metodo) + a.append(dados) + return raiz def _post_header(self): u"""Retorna um dicionário com os atributos para o cabeçalho da requisição HTTP""" return { - u'content-type': u'application/soap+xml; charset=utf-8', - #u'content-type': u'text/xml; charset=utf-8', - #u'Accept': u'text/xml; charset=utf-8', - u'Accept': u'application/soap+xml; charset=utf-8', + u'content-type': u'application/soap+xml; charset=utf-8;', + u'Accept': u'application/soap+xml; charset=utf-8;', } def _post(self, url, xml): - # Separa arquivos de certificado para chave e certificado (sozinho) - #caminho_chave, caminho_cert = self.certificado.separar_arquivo(senha=self.certificado_senha) - #caminho_chave = 'key.pem' - #caminho_cert = 'cert.pem' - caminho_chave = '/home/junior/Documentos/Certificados/key.pem' - caminho_cert = '/home/junior/Documentos/Certificados/cert.pem' - + certificadoA1 = CertificadoA1(self.certificado) + chave, cert = certificadoA1.separar_arquivo(self.certificado_senha, caminho=True) + cert = (cert, chave) # Abre a conexão HTTPS - cert = (caminho_cert, caminho_chave) - #headers = {'content-type': 'text/xml'} - try: - print (url) + # Passa o lxml.etree para string + xml = etree.tostring(xml, encoding='unicode', pretty_print=False) + # Faz o request com o servidor result = requests.post(url, xml, headers=self._post_header(), cert=cert, verify=False) - print (result.content) if result == 200: result.encoding='utf-8' - print (result) - print (result.content) - return result.text + return result else: return result - print (result) - print (result.content) - print (result.text) except requests.exceptions.ConnectionError as e: raise e \ No newline at end of file diff --git a/pynfe/utils/flags.py b/pynfe/utils/flags.py index 301d22e..6e75243 100644 --- a/pynfe/utils/flags.py +++ b/pynfe/utils/flags.py @@ -5,7 +5,7 @@ NAMESPACE_SIG = 'http://www.w3.org/2000/09/xmldsig#' NAMESPACE_SOAP = 'http://www.w3.org/2003/05/soap-envelope' NAMESPACE_XSI = 'http://www.w3.org/2001/XMLSchema-instance' NAMESPACE_XSD = 'http://www.w3.org/2001/XMLSchema' -NAMESPACE_METODO = 'http://www.portalfiscal.inf.br/sce/wsdl/' +NAMESPACE_METODO = 'http://www.portalfiscal.inf.br/nfe/wsdl/' VERSAO_PADRAO = '3.10'