From 36c6843ce0cd8b1dbd5c9d70e3cd2bf23f402626 Mon Sep 17 00:00:00 2001 From: Junior Tada Date: Fri, 17 Jul 2015 19:12:18 -0300 Subject: [PATCH] ajuste xml soap --- pynfe/entidades/cliente.py | 6 +++++ pynfe/processamento/comunicacao.py | 53 ++++++++++++++++++++----------------- pynfe/processamento/serializacao.py | 26 ++++++++++++++---- pynfe/utils/flags.py | 3 +++ 4 files changed, 58 insertions(+), 30 deletions(-) diff --git a/pynfe/entidades/cliente.py b/pynfe/entidades/cliente.py index 01bb669..57bbfea 100644 --- a/pynfe/entidades/cliente.py +++ b/pynfe/entidades/cliente.py @@ -17,9 +17,15 @@ class Cliente(Entidade): # - Numero do Documento (obrigatorio) numero_documento = str() + # - Indicador da IE do destinatário: 1 – Contribuinte ICMSpagamento à vista; 2 – Contribuinte isento de inscrição; 9 – Não Contribuinte + indicador_ie = int() + # - Inscricao Estadual inscricao_estadual = str() + # - Inscricao Municial + inscricao_municipal = str() + # - Inscricao SUFRAMA inscricao_suframa = str() diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py index d08c1ee..9b34087 100644 --- a/pynfe/processamento/comunicacao.py +++ b/pynfe/processamento/comunicacao.py @@ -3,7 +3,7 @@ import datetime import time import requests from pynfe.utils import etree, so_numeros -from pynfe.utils.flags import NAMESPACE_NFE, NAMESPACE_SOAP, VERSAO_PADRAO, CODIGOS_ESTADOS +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 @@ -42,10 +42,10 @@ class ComunicacaoSefaz(Comunicacao): elem = etree.XML(etree.tostring(raiz, encoding='unicode'), parser=parser) dados = etree.tostring(elem, encoding="unicode") # BUG < retorna caracteres ASCII # Monta XML para envio da requisição - xml = self._construir_xml_status_pr(cabecalho=self._cabecalho_soap(), dados=dados) - xml = str(xml).replace('lt;','<').replace('gt;','>').replace('&','').replace('ds:','') - #print (xml) - return self._post(url, xml) + 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) def cancelar(self, modelo, xml): """ Envia um evento de cancelamento de nota fiscal """ @@ -64,7 +64,7 @@ class ComunicacaoSefaz(Comunicacao): etree.SubElement(evento, 'versao').text = '1' # versao do leiaute do evento (cancelamento = 1) etree.SubElement(raiz, 'infEvento').text = xml # Evento, um lote pode conter até 20 eventos dados = etree.tostring(raiz, encoding="unicode") - xml = self._construir_xml_status_pr(cabecalho=self._cabecalho_soap(), dados=dados, url=url) + xml = self._construir_xml_status_pr(cabecalho=self._cabecalho_soap(metodo='RecepcaoEvento'), metodo='RecepcaoEvento', dados=dados) xml = str(xml).replace('&','').replace('lt;','<').replace('gt;','>').replace('&','') return xml #return self._post(url, xml) @@ -87,11 +87,12 @@ class ComunicacaoSefaz(Comunicacao): 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(), dados=dados) + 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='nfeRecepcao2', tag_metodo='nfeStatusServicoNF2', dados=dados) - xml = str(xml).replace('<', '<').replace('>', '>').replace('\'', '"').replace('\n', '') + xml = self._construir_xml_soap(cabecalho=self._cabecalho_soap(metodo='NfeStatusServico3'), metodo='NfeStatusServico3', dados=dados) + xml = str(xml).replace('<', '<').replace('>', '>').replace('\\\'', '"').replace('\\n', '') # Chama método que efetua a requisição POST no servidor SOAP + #print (xml) return self._post(url, xml) def consultar_cadastro(self, instancia): @@ -100,6 +101,7 @@ class ComunicacaoSefaz(Comunicacao): def inutilizar_faixa_numeracao(self, numero_inicial, numero_final, emitente, certificado, senha, ano=None, serie='1', justificativa=''): post = '/nfeweb/services/nfestatusservico.asmx' + metodo = 'NfeInutilizacao2' # Valores default ano = str(ano or datetime.date.today().year)[-2:] @@ -169,39 +171,34 @@ class ComunicacaoSefaz(Comunicacao): pass return url - def _cabecalho_soap(self): + def _cabecalho_soap(self, metodo): u"""Monta o XML do cabeçalho da requisição SOAP""" - raiz = etree.Element('nfeCabecMsg') - etree.SubElement(raiz, 'cUF').text = str(41) + raiz = etree.Element('nfeCabecMsg', xmlns=NAMESPACE_METODO+metodo) + etree.SubElement(raiz, 'cUF').text = CODIGOS_ESTADOS[self.uf.upper()] etree.SubElement(raiz, 'versaoDados').text = VERSAO_PADRAO return etree.tostring(raiz, encoding="unicode") - def _construir_xml_soap(self, cabecalho, metodo, tag_metodo, dados): + def _construir_xml_soap(self, cabecalho, metodo, dados): """Mota o XML para o envio via SOAP""" - raiz = etree.Element('{%s}Envelope'%NAMESPACE_SOAP, nsmap={'soap': NAMESPACE_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 body = etree.SubElement(raiz, '{%s}Body'%NAMESPACE_SOAP) - met = etree.SubElement( - body, tag_metodo, xmlns=metodo, - ) - - etree.SubElement(met, 'nfeCabecMsg').text = cabecalho - etree.SubElement(met, 'nfeDadosMsg').text = dados + etree.SubElement(body, 'nfeDadosMsg', xmlns=NAMESPACE_METODO+metodo).text = dados return etree.tostring(raiz, encoding="utf-8", xml_declaration=True) - def _construir_xml_status_pr(self, cabecalho, dados): + 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={'soap': NAMESPACE_SOAP}, xmlns=NAMESPACE_NFE) + 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').text = dados + etree.SubElement(body, 'nfeDadosMsg', xmlns=NAMESPACE_METODO+metodo).text = dados - return etree.tostring(raiz, encoding='unicode') + return etree.tostring(raiz, encoding="utf-8", xml_declaration=True) def _post_header(self): u"""Retorna um dicionário com os atributos para o cabeçalho da requisição HTTP""" @@ -229,8 +226,14 @@ class ComunicacaoSefaz(Comunicacao): 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 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/processamento/serializacao.py b/pynfe/processamento/serializacao.py index 3e1a401..13849ce 100644 --- a/pynfe/processamento/serializacao.py +++ b/pynfe/processamento/serializacao.py @@ -105,10 +105,6 @@ class SerializacaoXML(Serializacao): # Dados do cliente (distinatario) etree.SubElement(raiz, cliente.tipo_documento).text = so_numeros(cliente.numero_documento) etree.SubElement(raiz, 'xNome').text = cliente.razao_social - # nfc-e nao possui IE mesmo que seja uma empresa - if modelo == 55: - etree.SubElement(raiz, 'IE').text = cliente.inscricao_estadual - # Endereço endereco = etree.SubElement(raiz, 'enderDest') etree.SubElement(endereco, 'xLgr').text = cliente.endereco_logradouro etree.SubElement(endereco, 'nro').text = cliente.endereco_numero @@ -122,7 +118,24 @@ class SerializacaoXML(Serializacao): etree.SubElement(endereco, 'cPais').text = cliente.endereco_pais etree.SubElement(endereco, 'xPais').text = obter_pais_por_codigo(cliente.endereco_pais) etree.SubElement(endereco, 'fone').text = cliente.endereco_telefone - + #Indicador da IE do destinatário: 1 – Contribuinte ICMSpagamento à vista; 2 – Contribuinte isento de inscrição; 9 – Não Contribuinte + if cliente.isento_icms or cliente.inscricao_estadual.upper() == 'ISENTO': + etree.SubElement(raiz, 'indIEDest').text = str(2) + etree.SubElement(raiz, 'IE').text = 'ISENTO' + elif cliente.indicador_ie == 9: + # 9 – Não Contribuinte + etree.SubElement(raiz, 'indIEDest').text = str(9) + else: + # Indicador da IE do destinatário: 1 – Contribuinte ICMSpagamento à vista; + etree.SubElement(raiz, 'indIEDest').text = cliente.indicador_ie + etree.SubElement(raiz, 'IE').text = cliente.inscricao_estadual + # Suframa + if cliente.inscricao_suframa: + etree.SubElement(raiz, 'ISUF').text = cliente.inscricao_suframa + # Inscrição Municipal do tomador do serviço + if cliente.inscricao_municipal: + etree.SubElement(raiz, 'IM').text = cliente.inscricao_municipal + etree.SubElement(raiz, 'email').text = cliente.email if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: @@ -179,6 +192,9 @@ class SerializacaoXML(Serializacao): etree.SubElement(prod, 'cProd').text = str(produto_servico.codigo) etree.SubElement(prod, 'cEAN').text = produto_servico.ean etree.SubElement(prod, 'xProd').text = produto_servico.descricao + etree.SubElement(prod, 'NCM').text = produto_servico.ncm + # Codificação opcional que detalha alguns NCM. Formato: duas letras maiúsculas e 4 algarismos. Se a mercadoria se enquadrar em mais de uma codificação, informar até 8 codificações principais. + #etree.SubElement(prod, 'NVE').text = '' etree.SubElement(prod, 'CFOP').text = produto_servico.cfop etree.SubElement(prod, 'uCom').text = produto_servico.unidade_comercial etree.SubElement(prod, 'qCom').text = str(produto_servico.quantidade_comercial or 0) diff --git a/pynfe/utils/flags.py b/pynfe/utils/flags.py index 024cbf0..301d22e 100644 --- a/pynfe/utils/flags.py +++ b/pynfe/utils/flags.py @@ -3,6 +3,9 @@ NAMESPACE_NFE = 'http://www.portalfiscal.inf.br/nfe' 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/' VERSAO_PADRAO = '3.10'