def __init__(self): self.ambiente = 2 self.estado = 'SP' self.versao = '2.00' self.certificado = Certificado() self.caminho = '' self.salvar_arquivos = True self.contingencia_SCAN = False self.gerar_danfe = True self.danfe = DANFE() self.caminho_temporario = '' self.maximo_tentativas_consulta_recibo = 5 self._servidor = '' self._url = '' self._soap_envio = None self._soap_retorno = None
def _obter_dados_do_certificado(self, certificado, senha): self._certificado = Certificado() self._certificado.arquivo = certificado self._certificado.senha = senha self._certificado.prepara_certificado_arquivo_pfx()
class ProcessadorBase(object): def __init__(self, servidor, endereco, certificado, senha, caminho=''): self.servidor = servidor self.endereco = endereco self.versao = u'1.00' self.caminho = caminho self._destino = None self._obter_dados_do_certificado(certificado, senha) self.NS = 'http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd' NS_SCHEMA = 'http://www.w3.org/2001/XMLSchema-instance' self.namespace = 'xmlns="{}" xmlns:xsi="{}"'.format(self.NS, NS_SCHEMA) def _obter_dados_do_certificado(self, certificado, senha): self._certificado = Certificado() self._certificado.arquivo = certificado self._certificado.senha = senha self._certificado.prepara_certificado_arquivo_pfx() def _remover_encode(self, xml): aberturas = ('<?xml version="1.0" encoding="utf-8"?>', '<?xml version="1.0" encoding="utf-8" ?>', '<?xml version="1.0" encoding="UTF-8"?>', '<?xml version="1.0" encoding="UTF-8" ?>') for a in aberturas: xml = xml.replace(a, '') return xml def _validar_xml(self, xml, xsd=None): xml = self._remover_encode(xml) curdir = os.getcwd() try: xsd_path = os.path.join(os.path.dirname(__file__), 'nfse.xsd') esquema = etree.XMLSchema(etree.parse(xsd_path)) finally: os.chdir(curdir) esquema.assertValid(etree.fromstring(xml)) return xml def _conectar_servidor(self, xml, servico, xsd_retorno): caminho_temporario = u'/tmp/' nome_arq_chave = caminho_temporario + uuid4().hex arq_tmp = open(nome_arq_chave, 'w') arq_tmp.write(self._certificado.chave) arq_tmp.close() nome_arq_certificado = caminho_temporario + uuid4().hex arq_tmp = open(nome_arq_certificado, 'w') arq_tmp.write(self._certificado.certificado) arq_tmp.close() xml = self._soap(xml, servico) con = HTTPSConnection(self.servidor, key_file=nome_arq_chave, cert_file=nome_arq_certificado) con.request( u'POST', self.endereco, xml, { u'Content-Type': u'application/soap+xml; charset=utf-8', u'Content-Length': len(xml), }) if self._destino: arq = open(self._destino + '-env.xml', 'w') arq.write(xml.encode(u'utf-8')) arq.close() resposta = con.getresponse() if resposta.status != 200: raise CommunicationError(resposta.status, resposta.reason) resp_xml_str = resposta.read() resp_xml = ET.fromstring(resp_xml_str) result_str = resp_xml.find(".//{%s}RetornoXML" % self.NS).text xsd_retorno.ExternalEncoding = 'utf-8' result = xsd_retorno.parseString(result_str.encode('utf-8')) nos_erro = result.Erro nos_alerta = result.Alerta sucesso = result.Cabecalho.Sucesso alertas = {} for n in nos_alerta: codigo = n.Codigo descricao = n.Descricao chave_rps = n.ChaveRPS if chave_rps: chave = chave_rps else: chave = n.ChaveNFe try: alertas[chave].append((codigo, descricao)) except KeyError: alertas[chave] = [(codigo, descricao)] erros = {} for n in nos_erro: codigo = n.Codigo descricao = n.Descricao if n.ChaveRPS: chave = n.ChaveRPS else: chave = n.ChaveNFe try: erros[chave].append((codigo, descricao)) except KeyError: erros[chave] = [(codigo, descricao)] if self._destino: arq = open(self._destino + '-rec.xml', 'w') arq.write(resp_xml_str.encode(u'utf-8')) arq.close() os.remove(nome_arq_chave) os.remove(nome_arq_certificado) con.close() return (sucesso, result, alertas, erros) def _soap(self, xml, servico): return '''<?xml version="1.0" encoding="utf-8"?> <soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"> <soap12:Body> <{servico} xmlns="http://www.e-governeapps2.com.br/"> {xml} </{servico}> </soap12:Body> </soap12:Envelope> '''.format(servico=servico, xml=xml).encode(u'utf-8') def _obter_xml_da_funcao(self, funcao, assinar=False, xsd=None): tmp_dir = u'/tmp/' tmp_file_path = tmp_dir + uuid4().hex tmp_file = open(tmp_file_path, 'w+') funcao.export(tmp_file, 0, namespacedef_=self.namespace) tmp_file.seek(0) xml = tmp_file.read() tmp_file.close() if assinar: xml = self._certificado.assina_xml(xml) return self._validar_xml(xml, xsd) def _remove_accents(self, data): return ''.join(x for x in unicodedata.normalize('NFKD', unicode(data))\ if x in string.ascii_letters + ' ').lower() # FIXME: Verificar utilidade dos dois métodos abaixo def RemoveSoap(self, xml): for x in ('RecepcionarLoteRpsResponse', 'ConsultarLoteRpsResponse', 'CancelarNfseResponse'): xml = xml.replace( '<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><%s xmlns="http://www.e-governeapps2.com.br/">' % x, '') xml = xml.replace('</%s></soap:Body></soap:Envelope>' % x, '') return xml def Destino(self, emissao=None, serie=None, rps=None, arquivo=None): self._destino = None if arquivo is not None: destino = ('%s/%s/%03d-%09d' % (os.path.join( self.caminho, 'producao' if self.ambiente == 1 else 'homologacao'), emissao.strftime('%Y-%m'), serie, rps)) if not os.path.exists(destino): os.makedirs(destino) self._destino = os.path.join(destino, arquivo) return self._destino
class ProcessadorBase(object): def __init__(self, servidor, endereco, certificado, senha, caminho='', servidor_homologacao=''): self.servidor = servidor self.servidor_homologacao = servidor_homologacao self.endereco = endereco self.versao = u'1.00' self.caminho = caminho self._destino = None self._obter_dados_do_certificado(certificado, senha) self.NS = 'http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd' self.NS_SCHEMA = 'http://www.w3.org/2001/XMLSchema-instance' self.namespace = 'xmlns="{}" xmlns:xsi="{}"'.format(self.NS, self.NS_SCHEMA) def _obter_dados_do_certificado(self, certificado, senha): self._certificado = Certificado() self._certificado.arquivo = certificado self._certificado.senha = senha self._certificado.prepara_certificado_arquivo_pfx() def _remover_encode(self, xml): aberturas = ('<?xml version="1.0" encoding="utf-8"?>', '<?xml version="1.0" encoding="utf-8" ?>', '<?xml version="1.0" encoding="UTF-8"?>', '<?xml version="1.0" encoding="UTF-8" ?>') for a in aberturas: xml = xml.replace(a, '') return xml def _validar_xml(self, xml, xsd=None): xml = self._remover_encode(xml) curdir = os.getcwd() try: xsd_path = os.path.join(os.path.dirname(__file__), 'nfse.xsd') esquema = etree.XMLSchema(etree.parse(xsd_path)) finally: os.chdir(curdir) esquema.assertValid(etree.fromstring(xml)) return xml def _soap_post(self, connection, xml, xsd_retorno, servico=None): connection.request(u'POST', self.endereco, xml, { u'Content-Type': u'application/soap+xml; charset=utf-8', u'Content-Length': len(xml), }) if self._destino: arq = open(self._destino + '-env.xml', 'w') arq.write(xml.encode(u'utf-8')) arq.close() resposta = connection.getresponse() if resposta.status != 200: raise CommunicationError(resposta.status, resposta.reason) resp_xml_str = resposta.read() resp_xml = ET.fromstring(resp_xml_str) result_str = resp_xml.find(".//{%s}RetornoXML" % self.NS).text xsd_retorno.ExternalEncoding = 'utf-8' result = xsd_retorno.parseString(result_str.encode('utf-8')) return result def _parse_result(self, result): nos_erro = result.Erro nos_alerta = result.Alerta sucesso = result.Cabecalho.Sucesso alertas = {} for n in nos_alerta: codigo = n.Codigo descricao = n.Descricao chave_rps = n.ChaveRPS if chave_rps: chave = chave_rps else: chave = n.ChaveNFe #TODO a chave esta vindo como None, estou setando para o codigo indice, desta forma nao sera possivel enviar em lote. try: alertas[codigo].append((descricao)) except KeyError: alertas[codigo] = [(descricao)] erros = {} for n in nos_erro: codigo = n.Codigo descricao = n.Descricao if n.ChaveRPS: chave = n.ChaveRPS else: chave = n.ChaveNFe #TODO a chave esta vindo como None, estou setando para o codigo indice, desta forma nao sera possivel enviar em lote. try: erros[codigo].append((descricao)) except KeyError: erros[codigo] = [(descricao)] return (sucesso, erros, alertas) def _conectar_servidor(self, xml, service, xsd_retorno, test=False): server = test and self.servidor_homologacao or self.servidor caminho_temporario = u'/tmp/' key_file = caminho_temporario + uuid4().hex arq_tmp = open(key_file, 'w') arq_tmp.write(self._certificado.chave) arq_tmp.close() cert_file = caminho_temporario + uuid4().hex arq_tmp = open(cert_file, 'w') arq_tmp.write(self._certificado.certificado) arq_tmp.close() xml = self._soap(xml, service) connection = HTTPSConnection(server, key_file=key_file, cert_file=cert_file) result = self._soap_post(connection, xml, xsd_retorno, service) sucesso, erros, alertas = self._parse_result(result) if self._destino: arq = open(self._destino + '-rec.xml', 'w') arq.write(resp_xml_str.encode(u'utf-8')) arq.close() os.remove(key_file) os.remove(cert_file) connection.close() return (sucesso, result, alertas, erros) def _soap(self, xml, servico): return '''<?xml version="1.0" encoding="utf-8"?> <soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"> <soap12:Body> <{servico} xmlns="http://www.e-governeapps2.com.br/"> {xml} </{servico}> </soap12:Body> </soap12:Envelope> '''.format(servico=servico, xml=xml).encode(u'utf-8') def _obter_xml_da_funcao(self, funcao, assinar=False, xsd=None): tmp_dir = u'/tmp/' tmp_file_path = tmp_dir + uuid4().hex tmp_file = open(tmp_file_path, 'w+') funcao.export(tmp_file, 0, namespacedef_=self.namespace) tmp_file.seek(0) xml = tmp_file.read() tmp_file.close() if assinar: xml = self._certificado.assina_xml(xml) return self._validar_xml(xml, xsd) def _remove_accents(self, data): return ''.join(x for x in unicodedata.normalize('NFKD', unicode(data))\ if x in string.ascii_letters + ' ').lower() # FIXME: Verificar utilidade dos dois métodos abaixo def RemoveSoap(self, xml): for x in ('RecepcionarLoteRpsResponse', 'ConsultarLoteRpsResponse', 'CancelarNfseResponse'): xml = xml.replace('<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><%s xmlns="http://www.e-governeapps2.com.br/">' % x, '') xml = xml.replace('</%s></soap:Body></soap:Envelope>' % x, '') return xml def Destino(self, emissao=None, serie=None, rps=None, arquivo=None): self._destino = None if arquivo is not None: destino = ('%s/%s/%03d-%09d' % (os.path.join(self.caminho, 'producao' if self.ambiente == 1 else 'homologacao'), emissao.strftime('%Y-%m'), serie, rps)) if not os.path.exists(destino): os.makedirs(destino) self._destino = os.path.join(destino, arquivo) return self._destino
class ProcessadorNFe(object): def __init__(self): self.ambiente = 2 self.estado = 'SP' self.versao = '2.00' self.certificado = Certificado() self.caminho = '' self.salvar_arquivos = True self.contingencia_SCAN = False self.gerar_danfe = True self.danfe = DANFE() self.caminho_temporario = '' self.maximo_tentativas_consulta_recibo = 5 self._servidor = '' self._url = '' self._soap_envio = None self._soap_retorno = None def _conectar_servico(self, servico, envio, resposta, ambiente=None, somente_ambiente_nacional=False): if ambiente is None: ambiente = self.ambiente if self.versao == u'1.10': metodo_ws = webservices_1.METODO_WS self._soap_envio = SOAPEnvio_110() self._soap_retorno = SOAPRetorno_110() if self.contingencia_SCAN: self._servidor = webservices_1.SCAN[ambiente]['servidor'] self._url = webservices_1.SCAN[ambiente][servico] else: self._servidor = webservices_1.ESTADO_WS[self.estado][ambiente]['servidor'] self._url = webservices_1.ESTADO_WS[self.estado][ambiente][servico] elif self.versao == u'2.00': metodo_ws = webservices_2.METODO_WS self._soap_envio = SOAPEnvio_200() self._soap_retorno = SOAPRetorno_200() self._soap_envio.cUF = UF_CODIGO[self.estado] if somente_ambiente_nacional: self._servidor = webservices_2.AN[ambiente]['servidor'] self._url = webservices_2.AN[ambiente][servico] elif servico == WS_NFE_DOWNLOAD: self._servidor = webservices_2.SVAN[ambiente]['servidor'] self._url = webservices_2.SVAN[ambiente][servico] elif self.contingencia_SCAN: self._servidor = webservices_2.SCAN[ambiente]['servidor'] self._url = webservices_2.SCAN[ambiente][servico] else: # # Testa a opção de um estado, para determinado serviço, usar o WS # de outro estado # if type(webservices_2.ESTADO_WS[self.estado][ambiente][servico]) == dict: ws_a_usar = webservices_2.ESTADO_WS[self.estado][ambiente][servico] else: ws_a_usar = webservices_2.ESTADO_WS[self.estado] self._servidor = ws_a_usar[ambiente]['servidor'] self._url = ws_a_usar[ambiente][servico] self._soap_envio.webservice = metodo_ws[servico]['webservice'] self._soap_envio.metodo = metodo_ws[servico]['metodo'] self._soap_envio.envio = envio self._soap_retorno.webservice = self._soap_envio.webservice self._soap_retorno.metodo = self._soap_envio.metodo self._soap_retorno.resposta = resposta #try: self.certificado.prepara_certificado_arquivo_pfx() # # Salva o certificado e a chave privada para uso na conexão HTTPS # Salvamos como um arquivo de nome aleatório para evitar o conflito # de uso de vários certificados e chaves diferentes na mesma máquina # ao mesmo tempo # self.caminho_temporario = self.caminho_temporario or '/tmp/' nome_arq_chave = self.caminho_temporario + uuid4().hex arq_tmp = open(nome_arq_chave, 'w') arq_tmp.write(self.certificado.chave) arq_tmp.close() nome_arq_certificado = self.caminho_temporario + uuid4().hex arq_tmp = open(nome_arq_certificado, 'w') arq_tmp.write(self.certificado.certificado) arq_tmp.close() #con = HTTPSConnection(self._servidor, key_file=nome_arq_chave, cert_file=nome_arq_certificado) con = ConexaoHTTPS(self._servidor, key_file=nome_arq_chave, cert_file=nome_arq_certificado) #con.request('POST', '/' + self._url, self._soap_envio.xml.decode('utf-8'), self._soap_envio.header) # # É preciso definir o POST abaixo como bytestring, já que importamos # os unicode_literals... Dá um pau com xml com acentos sem isso... # con.request(b'POST', b'/' + self._url.encode('utf-8'), self._soap_envio.xml.encode('utf-8'), self._soap_envio.header) resp = con.getresponse() # # Apagamos os arquivos do certificado e o da chave privada, para evitar # um potencial risco de segurança; muito embora o uso da chave privada # para assinatura exija o uso da senha, pode haver serviços que exijam # apenas o uso do certificado para validar a identidade, independente # da existência de assinatura digital # os.remove(nome_arq_chave) os.remove(nome_arq_certificado) # Dados do envelope de envio salvos para possível debug envio.original = self._soap_envio.xml # Dados da resposta salvos para possível debug self._soap_retorno.resposta.version = resp.version self._soap_retorno.resposta.status = resp.status self._soap_retorno.resposta.reason = unicode(resp.reason.decode('utf-8')) self._soap_retorno.resposta.msg = resp.msg self._soap_retorno.resposta.original = unicode(resp.read().decode('utf-8')) # Tudo certo! if self._soap_retorno.resposta.status == 200: self._soap_retorno.xml = self._soap_retorno.resposta.original #except Exception, e: #raise e #else: con.close() def enviar_lote(self, numero_lote=None, lista_nfes=[]): if self.versao == u'1.10': envio = EnviNFe_110() resposta = RetEnviNFe_110() elif self.versao == u'2.00': envio = EnviNFe_200() resposta = RetEnviNFe_200() if self.ambiente == 2: # Homologação tem detalhes especificos desde a NT2011_002 for nfe in lista_nfes: nfe.infNFe.dest.CNPJ.valor = '99999999000191' nfe.infNFe.dest.xNome.valor = 'NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL' nfe.infNFe.dest.IE.valor = '' processo = ProcessoNFe(webservice=WS_NFE_ENVIO_LOTE, envio=envio, resposta=resposta) # # Vamos assinar e validar todas as NF-e antes da transmissão, evitando # rejeição na SEFAZ por incorreção no schema dos arquivos # for nfe in lista_nfes: self.certificado.assina_xmlnfe(nfe) nfe.validar() envio.NFe = lista_nfes if numero_lote is None: numero_lote = datetime.now().strftime('%Y%m%d%H%M%S') envio.idLote.valor = numero_lote envio.validar() if self.salvar_arquivos: for n in lista_nfes: n.monta_chave() arq = open(self.caminho + n.chave + '-nfe.xml', 'w') arq.write(n.xml.encode('utf-8')) arq.close arq = open(self.caminho + unicode(envio.idLote.valor).strip().rjust(15, '0') + '-env-lot.xml', 'w') arq.write(envio.xml.encode('utf-8')) arq.close() self._conectar_servico(WS_NFE_ENVIO_LOTE, envio, resposta) #resposta.validar() if self.salvar_arquivos: nome_arq = self.caminho + unicode(envio.idLote.valor).strip().rjust(15, '0') + '-rec' if resposta.cStat.valor != '103': nome_arq += '-rej.xml' else: nome_arq += '.xml' arq = open(nome_arq, 'w') arq.write(resposta.xml.encode('utf-8')) arq.close() return processo def consultar_recibo(self, ambiente=None, numero_recibo=None): if self.versao == u'1.10': envio = ConsReciNFe_110() resposta = RetConsReciNFe_110() elif self.versao == u'2.00': envio = ConsReciNFe_200() resposta = RetConsReciNFe_200() processo = ProcessoNFe(webservice=WS_NFE_CONSULTA_RECIBO, envio=envio, resposta=resposta) if ambiente is None: ambiente = self.ambiente envio.tpAmb.valor = ambiente envio.nRec.valor = numero_recibo envio.validar() if self.salvar_arquivos: arq = open(self.caminho + unicode(envio.nRec.valor).strip().rjust(15, '0') + '-ped-rec.xml', 'w') arq.write(envio.xml.encode('utf-8')) arq.close() self._conectar_servico(WS_NFE_CONSULTA_RECIBO, envio, resposta, ambiente) #resposta.validar() if self.salvar_arquivos: nome_arq = self.caminho + unicode(envio.nRec.valor).strip().rjust(15, '0') + '-pro-rec' if resposta.cStat.valor != '104': nome_arq += '-rej.xml' else: nome_arq += '.xml' arq = open(nome_arq, 'w') arq.write(resposta.xml.encode('utf-8')) arq.close() # # Salvar os resultados dos processamentos # for pn in resposta.protNFe: nome_arq = self.caminho + unicode(pn.infProt.chNFe.valor).strip().rjust(44, '0') + '-pro-nfe-' # NF-e autorizada if pn.infProt.cStat.valor == '100': nome_arq += 'aut.xml' # NF-e denegada elif pn.infProt.cStat.valor in ('110', '301', '302'): nome_arq += 'den.xml' # NF-e rejeitada else: nome_arq += 'rej.xml' arq = open(nome_arq, 'w') arq.write(pn.xml.encode('utf-8')) arq.close() return processo def cancelar_nota(self, ambiente=None, chave_nfe=None, numero_protocolo=None, justificativa=None): if self.versao == u'1.10': envio = CancNFe_107() resposta = RetCancNFe_107() elif self.versao == u'2.00': envio = CancNFe_200() resposta = RetCancNFe_200() processo = ProcessoNFe(webservice=WS_NFE_CANCELAMENTO, envio=envio, resposta=resposta) if ambiente is None: ambiente = self.ambiente self.caminho = self.monta_caminho_nfe(ambiente=ambiente, chave_nfe=chave_nfe) envio.infCanc.tpAmb.valor = ambiente envio.infCanc.chNFe.valor = chave_nfe envio.infCanc.nProt.valor = numero_protocolo envio.infCanc.xJust.valor = justificativa self.certificado.assina_xmlnfe(envio) envio.validar() if self.salvar_arquivos: arq = open(self.caminho + unicode(envio.infCanc.chNFe.valor).strip().rjust(44, '0') + '-ped-can.xml', 'w') arq.write(envio.xml.encode('utf-8')) arq.close() self._conectar_servico(WS_NFE_CANCELAMENTO, envio, resposta, ambiente) #resposta.validar() # # Se for autorizado, monta o processo de cancelamento # 101 - cancelado dentro do prazo # 151 - cancelado fora do prazo # if resposta.infCanc.cStat.valor in ('101', '151'): if self.versao == u'1.10': processo_cancelamento_nfe = ProcCancNFe_107() elif self.versao == u'2.00': processo_cancelamento_nfe = ProcCancNFe_200() nome_arq = self.caminho + unicode(envio.infCanc.chNFe.valor).strip().rjust(44, '0') + '-proc-canc-nfe.xml' processo_cancelamento_nfe.cancNFe = envio processo_cancelamento_nfe.retCancNFe = resposta processo_cancelamento_nfe.validar() processo.processo_cancelamento_nfe = processo_cancelamento_nfe if self.salvar_arquivos: nome_arq = self.caminho + unicode(envio.infCanc.chNFe.valor).strip().rjust(44, '0') + '-pro-can-' # Cancelamento autorizado if resposta.infCanc.cStat.valor == '101': nome_arq += 'aut.xml' else: nome_arq += 'rej.xml' arq = open(nome_arq, 'w') arq.write(resposta.xml.encode('utf-8')) arq.close() # Se for autorizado, monta o processo de cancelamento if resposta.infCanc.cStat.valor == '101': nome_arq = self.caminho + unicode(envio.infCanc.chNFe.valor).strip().rjust(44, '0') + '-proc-canc-nfe.xml' arq = open(nome_arq, 'w') arq.write(processo_cancelamento_nfe.xml.encode('utf-8')) arq.close() # Estranhamente, o nome desse arquivo, pelo manual, deve ser chave-can.xml nome_arq = self.caminho + unicode(envio.infCanc.chNFe.valor).strip().rjust(44, '0') + '-can.xml' arq = open(nome_arq, 'w') arq.write(processo_cancelamento_nfe.xml.encode('utf-8')) arq.close() return processo def inutilizar_nota(self, ambiente=None, codigo_estado=None, ano=None, cnpj=None, serie=None, numero_inicial=None, numero_final=None, justificativa=None): if self.versao == u'1.10': envio = InutNFe_107() resposta = RetInutNFe_107() elif self.versao == u'2.00': envio = InutNFe_200() resposta = RetInutNFe_200() processo = ProcessoNFe(webservice=WS_NFE_INUTILIZACAO, envio=envio, resposta=resposta) if ambiente is None: ambiente = self.ambiente if codigo_estado is None: codigo_estado = UF_CODIGO[self.estado] if ano is None: ano = datetime.now().strftime('%y') if numero_final is None: numero_final = numero_inicial self.caminho = self.monta_caminho_inutilizacao(ambiente=ambiente, serie=serie, numero_inicial=numero_inicial, numero_final=numero_final) envio.infInut.tpAmb.valor = ambiente envio.infInut.cUF.valor = codigo_estado envio.infInut.ano.valor = ano envio.infInut.CNPJ.valor = cnpj #envio.infInut.mod.valor = 55 envio.infInut.serie.valor = serie envio.infInut.nNFIni.valor = numero_inicial envio.infInut.nNFFin.valor = numero_final envio.infInut.xJust.valor = justificativa envio.gera_nova_chave() self.certificado.assina_xmlnfe(envio) envio.validar() if self.salvar_arquivos: arq = open(self.caminho + unicode(envio.chave).strip().rjust(41, '0') + '-ped-inu.xml', 'w') arq.write(envio.xml.encode('utf-8')) arq.close() self._conectar_servico(WS_NFE_INUTILIZACAO, envio, resposta, ambiente) #resposta.validar() # Se for autorizada, monta o processo de inutilização if resposta.infInut.cStat.valor == '102': if self.versao == u'1.10': processo_inutilizacao_nfe = ProcInutNFe_107() elif self.versao == u'2.00': processo_inutilizacao_nfe = ProcInutNFe_200() processo_inutilizacao_nfe.inutNFe = envio processo_inutilizacao_nfe.retInutNFe = resposta processo_inutilizacao_nfe.validar() processo.processo_inutilizacao_nfe = processo_inutilizacao_nfe if self.salvar_arquivos: nome_arq = self.caminho + unicode(envio.chave).strip().rjust(41, '0') + '-pro-inu-' # Inutilização autorizada if resposta.infInut.cStat.valor == '102': nome_arq += 'aut.xml' else: nome_arq += 'rej.xml' arq = open(nome_arq, 'w') arq.write(resposta.xml.encode('utf-8')) arq.close() # Se for autorizada, monta o processo de inutilização if resposta.infInut.cStat.valor == '102': nome_arq = self.caminho + unicode(envio.chave).strip().rjust(41, '0') + '-proc-inut-nfe.xml' arq = open(nome_arq, 'w') arq.write(processo_inutilizacao_nfe.xml.encode('utf-8')) arq.close() # Estranhamente, o nome desse arquivo, pelo manual, deve ser chave-inu.xml nome_arq = self.caminho + unicode(envio.chave).strip().rjust(41, '0') + '-inu.xml' arq = open(nome_arq, 'w') arq.write(processo_inutilizacao_nfe.xml.encode('utf-8')) arq.close() return processo def consultar_nota(self, ambiente=None, chave_nfe=None, nfe=None): if self.versao == u'1.10': envio = ConsSitNFe_107() resposta = RetConsSitNFe_107() elif self.versao == u'2.00': envio = ConsSitNFe_201() resposta = RetConsSitNFe_201() processo = ProcessoNFe(webservice=WS_NFE_CONSULTA, envio=envio, resposta=resposta) if ambiente is None: ambiente = self.ambiente caminho_original = self.caminho self.caminho = self.monta_caminho_nfe(ambiente, chave_nfe) envio.tpAmb.valor = ambiente envio.chNFe.valor = chave_nfe envio.validar() if self.salvar_arquivos: arq = open(self.caminho + unicode(chave_nfe).strip().rjust(44, '0') + '-ped-sit.xml', 'w') arq.write(envio.xml.encode('utf-8')) arq.close() self._conectar_servico(WS_NFE_CONSULTA, envio, resposta, ambiente) #resposta.validar() if self.salvar_arquivos: nome_arq = self.caminho + unicode(chave_nfe).strip().rjust(44, '0') + '-sit.xml' arq = open(nome_arq, 'w') arq.write(resposta.xml.encode('utf-8')) arq.close() self.caminho = caminho_original # # Se a NF-e tiver sido informada, montar o processo da NF-e # if nfe: nfe.procNFe = self.montar_processo_uma_nota(nfe, protnfe_recibo=resposta.protNFe) return processo def consultar_servico(self, ambiente=None, codigo_estado=None): if self.versao == u'1.10': envio = ConsStatServ_107() resposta = RetConsStatServ_107() elif self.versao == u'2.00': envio = ConsStatServ_200() resposta = RetConsStatServ_200() processo = ProcessoNFe(webservice=WS_NFE_SITUACAO, envio=envio, resposta=resposta) if ambiente is None: ambiente = self.ambiente if codigo_estado is None: codigo_estado = UF_CODIGO[self.estado] envio.tpAmb.valor = ambiente envio.cUF.valor = codigo_estado envio.data = datetime.now() envio.validar() if self.salvar_arquivos: arq = open(self.caminho + envio.data.strftime('%Y%m%dT%H%M%S') + '-ped-sta.xml', 'w') arq.write(envio.xml.encode('utf-8')) arq.close() self._conectar_servico(WS_NFE_SITUACAO, envio, resposta, ambiente) #resposta.validar() if self.salvar_arquivos: arq = open(self.caminho + envio.data.strftime('%Y%m%dT%H%M%S') + '-sta.xml', 'w') arq.write(resposta.xml.encode('utf-8')) arq.close() return processo def processar_notas(self, lista_nfes): # # Definir o caminho geral baseado na 1ª NF-e # caminho_original = self.caminho nfe = lista_nfes[0] nfe.monta_chave() self.caminho = caminho_original ambiente = nfe.infNFe.ide.tpAmb.valor self.caminho = self.monta_caminho_nfe(ambiente=nfe.infNFe.ide.tpAmb.valor, chave_nfe=nfe.chave) proc_servico = self.consultar_servico(ambiente=ambiente) yield proc_servico # # Serviço em operação? # if proc_servico.resposta.cStat.valor == '107': # # Verificar se as notas já não foram emitadas antes # for nfe in lista_nfes: nfe.monta_chave() self.caminho = caminho_original proc_consulta = self.consultar_nota(ambiente=nfe.infNFe.ide.tpAmb.valor, chave_nfe=nfe.chave) yield proc_consulta # # Nenhuma das notas estava já enviada, enviá-las então # nfe = lista_nfes[0] nfe.monta_chave() self.caminho = caminho_original self.caminho = self.monta_caminho_nfe(ambiente=nfe.infNFe.ide.tpAmb.valor, chave_nfe=nfe.chave) proc_envio = self.enviar_lote(lista_nfes=lista_nfes) yield proc_envio ret_envi_nfe = proc_envio.resposta # # Deu certo? # if ret_envi_nfe.cStat.valor == '103': # # Aguarda o tempo do processamento antes da consulta # time.sleep(ret_envi_nfe.infRec.tMed.valor * 1.3) proc_recibo = self.consultar_recibo(ambiente=ret_envi_nfe.tpAmb.valor, numero_recibo=ret_envi_nfe.infRec.nRec.valor) # # Tenta receber o resultado do processamento do lote # tentativa = 0 while proc_recibo.resposta.cStat.valor == '105' and tentativa < self.maximo_tentativas_consulta_recibo: time.sleep(ret_envi_nfe.infRec.tMed.valor * 1.5) tentativa += 1 proc_recibo = self.consultar_recibo(ambiente=ret_envi_nfe.tpAmb.valor, numero_recibo=ret_envi_nfe.infRec.nRec.valor) # Montar os processos das NF-es dic_protNFe = proc_recibo.resposta.dic_protNFe dic_procNFe = proc_recibo.resposta.dic_procNFe self.caminho = caminho_original self.montar_processo_lista_notas(lista_nfes, dic_protNFe, dic_procNFe) yield proc_recibo def montar_processo_lista_notas(self, lista_nfes, dic_protNFe, dic_procNFe): for nfe in lista_nfes: if nfe.chave in dic_protNFe: protocolo = dic_protNFe[nfe.chave] processo = self.montar_processo_uma_nota(nfe, protnfe_recibo=protocolo) if processo is not None: dic_procNFe[nfe.chave] = processo def montar_processo_uma_nota(self, nfe, protnfe_recibo=None, protnfe_consulta_110=None, retcancnfe=None): # # Somente para a versão 1.10 # Caso processarmos o protocolo vindo de uma consulta, # temos que converter esse protocolo no formato # do protocolo que retorna quando o recibo do lote é consultado. # # Sim, as informações são as mesmas, mas o leiaute não... # Vai entender... # if protnfe_consulta_110 is not None: protnfe_recibo = ProtNFe_110() protnfe_recibo.infProt.tpAmb.valor = protnfe_consulta_110.infProt.tpAmb.valor protnfe_recibo.infProt.verAplic.valor = protnfe_consulta_110.infProt.verAplic.valor protnfe_recibo.infProt.chNFe.valor = protnfe_consulta_110.infProt.chNFe.valor protnfe_recibo.infProt.dhRecbto.valor = protnfe_consulta_110.infProt.dhRecbto.valor protnfe_recibo.infProt.cStat.valor = protnfe_consulta_110.infProt.cStat.valor protnfe_recibo.infProt.xMotivo.valor = protnfe_consulta_110.infProt.xMotivo.valor protnfe_recibo.infProt.nProt.valor = protnfe_consulta_110.infProt.nProt.valor protnfe_recibo.infProt.digVal.valor = protnfe_consulta_110.infProt.digVal.valor caminho_original = self.caminho self.caminho = self.monta_caminho_nfe(ambiente=nfe.infNFe.ide.tpAmb.valor, chave_nfe=nfe.chave) processo = None # # Se nota foi autorizada ou denegada # 100 - autorizada # 150 - autorizada fora do prazo # 110 - denegada # 301 - denegada por irregularidade do emitente # 302 - denegada por irregularidade do destinatário # if protnfe_recibo.infProt.cStat.valor in ('100', '104', '150', '110', '301', '302', '204'): if self.versao == u'1.10': processo = ProcNFe_110() elif self.versao == u'2.00': processo = ProcNFe_200() processo.NFe = nfe processo.protNFe = protnfe_recibo if self.gerar_danfe: self.danfe.NFe = nfe self.danfe.protNFe = protnfe_recibo self.danfe.salvar_arquivo = self.salvar_arquivos self.danfe.gerar_danfe() processo.danfe_pdf = self.danfe.conteudo_pdf if self.salvar_arquivos: nome_arq = self.caminho + unicode(nfe.chave).strip().rjust(44, '0') + '-proc-nfe.xml' arq = open(nome_arq, 'w') arq.write(processo.xml.encode('utf-8')) arq.close() # Estranhamente, o nome desse arquivo, pelo manual, deve ser chave-nfe.xml ou chave-den.xml # para notas denegadas if protnfe_recibo.infProt.cStat.valor in ('100', '150'): nome_arq = self.caminho + unicode(nfe.chave).strip().rjust(44, '0') + '-nfe.xml' else: nome_arq = self.caminho + unicode(nfe.chave).strip().rjust(44, '0') + '-den.xml' arq = open(nome_arq, 'w') arq.write(processo.xml.encode('utf-8')) arq.close() if self.gerar_danfe: nome_arq = self.caminho + unicode(nfe.chave).strip().rjust(44, '0') + '.pdf' arq = open(nome_arq, 'w') arq.write(processo.danfe_pdf) arq.close() self.caminho = caminho_original return processo def monta_caminho_nfe(self, ambiente, chave_nfe): caminho = self.caminho if ambiente == 1: caminho = os.path.join(caminho, 'producao/') else: caminho = os.path.join(caminho, 'homologacao/') data = '20' + chave_nfe[2:4] + '-' + chave_nfe[4:6] serie = chave_nfe[22:25] numero = chave_nfe[25:34] caminho = os.path.join(caminho, data + '/') caminho = os.path.join(caminho, serie + '-' + numero + '/') try: os.makedirs(caminho) except: pass return caminho def monta_caminho_inutilizacao(self, ambiente=None, data=None, serie=None, numero_inicial=None, numero_final=None): caminho = self.caminho if ambiente == 1: caminho = os.path.join(caminho, 'producao/') else: caminho = os.path.join(caminho, 'homologacao/') if data is None: data = datetime.now() caminho = os.path.join(caminho, data.strftime('%Y-%m') + '/') serie = unicode(serie).strip().rjust(3, '0') numero_inicial = unicode(numero_inicial).strip().rjust(9, '0') numero_final = unicode(numero_final).strip().rjust(9, '0') caminho = os.path.join(caminho, serie + '-' + numero_inicial + '-' + numero_final + '/') try: os.makedirs(caminho) except: pass return caminho def montar_processo_lista_eventos(self, lista_eventos, dic_retEvento, dic_procEvento, classe_procEvento): for evento in lista_eventos: chave = evento.infEvento.chNFe.valor if chave in dic_retEvento: retorno = dic_retEvento[chave] processo = classe_procEvento() processo.evento = evento processo.retEvento = retorno dic_procEvento[chave] = processo def _enviar_lote_evento(self, tipo_evento, numero_lote=None, lista_eventos=[]): # # Determina o tipo do evento # if tipo_evento == 'cce': classe_evento = ProcEventoCCe_100 envio = EnvEventoCCe_100() resposta = RetEnvEventoCCe_100() elif tipo_evento == 'can': classe_evento = ProcEventoCancNFe_100 envio = EnvEventoCancNFe_100() resposta = RetEnvEventoCancNFe_100() elif tipo_evento == 'confrec': classe_evento = ProcEventoConfRecebimento_100 envio = EnvEventoConfRecebimento_100() resposta = RetEnvEventoConfRecebimento_100() processo = ProcessoNFe(webservice=WS_NFE_RECEPCAO_EVENTO, envio=envio, resposta=resposta) # # Vamos assinar e validar todas os Eventos antes da transmissão, evitando # rejeição na SEFAZ por incorreção no schema dos arquivos # for evento in lista_eventos: # # No caso de eventos de confirmação de recebimento, só é possível o # envio para o ambiente nacional, então é preciso forçar o cOrgao # nos eventos # if tipo_evento == 'confrec': evento.infEvento.cOrgao.valor = UF_CODIGO['RFB'] self.certificado.assina_xmlnfe(evento) #evento.validar() envio.evento = lista_eventos if numero_lote is None: numero_lote = datetime.now().strftime('%Y%m%d%H%M%S') envio.idLote.valor = numero_lote envio.validar() if self.salvar_arquivos: for evento in lista_eventos: chave = evento.infEvento.chNFe.valor ambiente = evento.infEvento.tpAmb.valor caminho = self.monta_caminho_nfe(ambiente=ambiente, chave_nfe=chave) numero_sequencia = evento.infEvento.nSeqEvento.valor nome_arq = caminho + chave + '-' + unicode(numero_sequencia).zfill(2) arq = open(nome_arq + '-' + tipo_evento + '.xml', 'w') arq.write(evento.xml.encode('utf-8')) arq.close arq = open(caminho + unicode(envio.idLote.valor).strip().rjust(15, '0') + '-env-' + tipo_evento + '.xml', 'w') arq.write(envio.xml.encode('utf-8')) arq.close() self._conectar_servico(WS_NFE_RECEPCAO_EVENTO, envio, resposta, somente_ambiente_nacional=tipo_evento=='confrec') #resposta.validar() if self.salvar_arquivos: nome_arq = caminho + unicode(envio.idLote.valor).strip().rjust(15, '0') + '-rec-' + tipo_evento if resposta.cStat.valor != '129': nome_arq += '-rej.xml' else: nome_arq += '.xml' arq = open(nome_arq, 'w') arq.write(resposta.xml.encode('utf-8')) arq.close() self.montar_processo_lista_eventos(lista_eventos, processo.resposta.dic_retEvento, processo.resposta.dic_procEvento, classe_evento) # # Salva o processamento de cada arquivo # for ret in resposta.retEvento: chave = ret.infEvento.chNFe.valor ambiente = ret.infEvento.tpAmb.valor caminho = self.monta_caminho_nfe(ambiente=ambiente, chave_nfe=chave) nome_arq = caminho + ret.infEvento.chNFe.valor + '-' + unicode(ret.infEvento.nSeqEvento.valor).zfill(2) # # O evento foi aceito e vinculado à NF-e # if ret.infEvento.cStat.valor == '135': arq = open(nome_arq + '-ret-' + tipo_evento + '.xml', 'w') arq.write(ret.xml.encode('utf-8')) arq.close # # Salva o processo do evento # arq = open(nome_arq + '-proc-' + tipo_evento + '.xml', 'w') arq.write(processo.resposta.dic_procEvento[chave].xml.encode('utf-8')) arq.close # # O evento foi aceito, mas não foi vinculado à NF-e # elif ret.infEvento.cStat.valor == '136': arq = open(nome_arq + '-ret-' + tipo_evento + '-sv.xml', 'w') # -sv = sem vínculo arq.write(ret.xml.encode('utf-8')) arq.close # # Salva o processo do evento # arq = open(nome_arq + '-proc-' + tipo_evento + '.xml', 'w') arq.write(processo.resposta.dic_procEvento[chave].xml.encode('utf-8')) arq.close # # O evento foi aceito e vinculado à NF-e, é um cancelamento for do prazo # elif ret.infEvento.cStat.valor == '155': arq = open(nome_arq + '-ret-' + tipo_evento + '.xml', 'w') arq.write(ret.xml.encode('utf-8')) arq.close # # Salva o processo do evento # arq = open(nome_arq + '-proc-' + tipo_evento + '.xml', 'w') arq.write(processo.resposta.dic_procEvento[chave].xml.encode('utf-8')) arq.close # # O evento foi rejeitado # else: arq = open(nome_arq + '-ret-' + tipo_evento + '-rej.xml', 'w') arq.write(ret.xml.encode('utf-8')) arq.close return processo def enviar_lote_cce(self, numero_lote=None, lista_eventos=[]): return self._enviar_lote_evento('cce', numero_lote, lista_eventos) def enviar_lote_cancelamento(self, numero_lote=None, lista_eventos=[]): return self._enviar_lote_evento('can', numero_lote, lista_eventos) def enviar_lote_confirmacao_recebimento(self, numero_lote=None, lista_eventos=[]): return self._enviar_lote_evento('confrec', numero_lote, lista_eventos) def consultar_notas_destinadas(self, ambiente=None, cnpj=None, ultimo_nsu='0', tipo_emissao='0', tipo_nfe='0'): envio = ConsNFeDest_101() resposta = RetConsNFeDest_101() envio.tpAmb.valor = ambiente or self.ambiente envio.CNPJ.valor = cnpj envio.ultNSU.valor = ultimo_nsu envio.indNFe.valor = tipo_nfe envio.indEmi.valor = tipo_emissao processo = ProcessoNFe(webservice=WS_NFE_CONSULTA_DESTINADAS, envio=envio, resposta=resposta) numero_lote = datetime.now().strftime('%Y%m%d%H%M%S') envio.validar() if self.salvar_arquivos: arq = open(self.caminho + unicode(numero_lote).strip().rjust(15, '0') + '-consnfedest.xml', 'w') arq.write(envio.xml.encode('utf-8')) arq.close() self._conectar_servico(WS_NFE_CONSULTA_DESTINADAS, envio, resposta, somente_ambiente_nacional=True) #resposta.validar() if self.salvar_arquivos: arq = open(self.caminho + unicode(numero_lote).strip().rjust(15, '0') + '-consnfedest-resp.xml', 'w') arq.write(resposta.original.encode('utf-8')) arq.close() return processo def baixar_notas_destinadas(self, ambiente=None, cnpj=None, lista_chaves=[]): envio = DownloadNFe_100() resposta = RetDownloadNFe_100() envio.tpAmb.valor = ambiente or self.ambiente envio.CNPJ.valor = cnpj envio.chNFe = [TagChNFe_100(valor=ch) for ch in lista_chaves] processo = ProcessoNFe(webservice=WS_NFE_DOWNLOAD, envio=envio, resposta=resposta) numero_lote = datetime.now().strftime('%Y%m%d%H%M%S') envio.validar() if self.salvar_arquivos: arq = open(self.caminho + unicode(numero_lote).strip().rjust(15, '0') + '-downloadnfe.xml', 'w') arq.write(envio.xml.encode('utf-8')) arq.close() self._conectar_servico(WS_NFE_DOWNLOAD, envio, resposta) #resposta.validar() if self.salvar_arquivos: arq = open(self.caminho + unicode(numero_lote).strip().rjust(15, '0') + '-downloadnfe-resp.xml', 'w') arq.write(resposta.original.encode('utf-8')) arq.close() return processo def cancelar_nota_evento(self, ambiente=None, chave_nfe=None, numero_protocolo=None, justificativa=None): evento = EventoCancNFe_100() evento.infEvento.tpAmb.valor = ambiente or self.ambiente evento.infEvento.cOrgao.valor = UF_CODIGO[self.estado] evento.infEvento.CNPJ.valor = chave_nfe[6:20] # Extrai o CNPJ da própria chave da NF-e evento.infEvento.chNFe.valor = chave_nfe evento.infEvento.dhEvento.valor = datetime.now() evento.infEvento.detEvento.nProt.valor = numero_protocolo evento.infEvento.detEvento.xJust.valor = justificativa processo = self.enviar_lote_cancelamento(lista_eventos=[evento]) return processo def corrigir_nota_evento(self, ambiente=None, chave_nfe=None, numero_sequencia=None, correcao=None): evento = EventoCCe_100() evento.infEvento.tpAmb.valor = ambiente or self.ambiente evento.infEvento.cOrgao.valor = UF_CODIGO[self.estado] evento.infEvento.CNPJ.valor = chave_nfe[6:20] # Extrai o CNPJ da própria chave da NF-e evento.infEvento.chNFe.valor = chave_nfe evento.infEvento.dhEvento.valor = datetime.now() evento.infEvento.detEvento.xCorrecao.valor = correcao evento.infEvento.nSeqEvento.valor = numero_sequencia or 1 processo = self.enviar_lote_cce(lista_eventos=[evento]) return processo def confirmar_operacao_evento(self, ambiente=None, chave_nfe=None, cnpj=None): evento = EventoConfRecebimento_100() evento.infEvento.tpAmb.valor = ambiente or self.ambiente evento.infEvento.cOrgao.valor = UF_CODIGO[self.estado] evento.infEvento.CNPJ.valor = cnpj evento.infEvento.chNFe.valor = chave_nfe evento.infEvento.dhEvento.valor = datetime.now() evento.infEvento.tpEvento.valor = CONF_RECEBIMENTO_CONFIRMAR_OPERACAO evento.infEvento.detEvento.descEvento.valor = DESCEVENTO_CONF_RECEBIMENTO[evento.infEvento.tpEvento.valor] processo = self.enviar_lote_confirmacao_recebimento(lista_eventos=[evento]) return processo def conhecer_operacao_evento(self, ambiente=None, chave_nfe=None, cnpj=None): evento = EventoConfRecebimento_100() evento.infEvento.tpAmb.valor = ambiente or self.ambiente evento.infEvento.cOrgao.valor = UF_CODIGO[self.estado] evento.infEvento.CNPJ.valor = cnpj evento.infEvento.chNFe.valor = chave_nfe evento.infEvento.dhEvento.valor = datetime.now() evento.infEvento.tpEvento.valor = CONF_RECEBIMENTO_CIENCIA_OPERACAO evento.infEvento.detEvento.descEvento.valor = DESCEVENTO_CONF_RECEBIMENTO[evento.infEvento.tpEvento.valor] processo = self.enviar_lote_confirmacao_recebimento(lista_eventos=[evento]) return processo def desconhecer_operacao_evento(self, ambiente=None, chave_nfe=None, cnpj=None): evento = EventoConfRecebimento_100() evento.infEvento.tpAmb.valor = ambiente or self.ambiente evento.infEvento.cOrgao.valor = UF_CODIGO[self.estado] evento.infEvento.CNPJ.valor = cnpj evento.infEvento.chNFe.valor = chave_nfe evento.infEvento.dhEvento.valor = datetime.now() evento.infEvento.tpEvento.valor = CONF_RECEBIMENTO_DESCONHECIMENTO_OPERACAO evento.infEvento.detEvento.descEvento.valor = DESCEVENTO_CONF_RECEBIMENTO[evento.infEvento.tpEvento.valor] processo = self.enviar_lote_confirmacao_recebimento(lista_eventos=[evento]) return processo def nao_realizar_operacao_evento(self, ambiente=None, chave_nfe=None, cnpj=None, justificativa=None): evento = EventoConfRecebimento_100() evento.infEvento.tpAmb.valor = ambiente or self.ambiente evento.infEvento.cOrgao.valor = UF_CODIGO[self.estado] evento.infEvento.CNPJ.valor = cnpj evento.infEvento.chNFe.valor = chave_nfe evento.infEvento.dhEvento.valor = datetime.now() evento.infEvento.tpEvento.valor = CONF_RECEBIMENTO_OPERACAO_NAO_REALIZADA evento.infEvento.detEvento.descEvento.valor = DESCEVENTO_CONF_RECEBIMENTO[evento.infEvento.tpEvento.valor] evento.infEvento.detEvento.xJust.valor = justificativa processo = self.enviar_lote_confirmacao_recebimento(lista_eventos=[evento]) return processo def consultar_cadastro(self, estado=None, ie=None, cnpj_cpf=None): if self.versao == '1.10': envio = ConsCad_101() resposta = RetConsCad_101() elif self.versao == '2.00': envio = ConsCad_200() resposta = RetConsCad_200() processo = ProcessoNFe(webservice=WS_NFE_CONSULTA_CADASTRO, envio=envio, resposta=resposta) if estado is None: estado = self.estado envio.infCons.UF.valor = estado if ie is not None: envio.infCons.IE.valor = ie nome = 'IE_' + ie elif cnpj_cpf is not None: if len(cnpj_cpf) == 11: envio.infCons.CPF.valor = cnpj_cpf nome = 'CPF_' + cnpj_cpf else: envio.infCons.CNPJ.valor = cnpj_cpf nome = 'CNPJ_' + cnpj_cpf envio.validar() if self.salvar_arquivos: arq = open(self.caminho + nome + '-cons-cad.xml', 'w') arq.write(envio.xml.encode('utf-8')) arq.close() # Consulta de cadastro é sempre feita em ambiente de produção self._conectar_servico(WS_NFE_CONSULTA_CADASTRO, envio, resposta, 1) #resposta.validar() if self.salvar_arquivos: arq = open(self.caminho + nome + '-cad.xml', 'w') arq.write(resposta.xml.encode('utf-8')) arq.close() return processo