def validar(self, xml, nome_xsd = None): '''Função que valida um XML usando lxml do Python via arquivo XSD no diretório xsd/<pacote>/<nó_xml>.xsd''' # Realiza o parser sobre o xml, identificado como string se iniciar por '<', senão é identificado como nome de arquivo if type(xml) == str: if xml[0] == '<': xml = PoleXML.importar(xml) else: xml = PoleXML.importar(open(xml).read()) # Para este sistema com lxml funcionar foi preciso trocar em tiposBasico_v1.03.xsd {0,} por * # Obeter a versão do primeiro ou segundo nó versao = xml('', 1)['versao'] or xml('', 1)('', 1)['versao'] # O padrão de nome de arquivos xsd é iniciar com letras minúsculas, # mantendo maiúsuclas iniciais de palavras, assim foi preciso desse # trecho de código para passar para músculas iniciais maiúsculas if nome_xsd is None: nome = '' temp = xml('', 1)._XML__nome for i in range(len(temp)): if temp[i].isupper(): nome += temp[i].lower() else: break nome += temp[i:] else: nome = nome_xsd # Caminho do arquivo XSD #print nome_xsd, self.__raiz , '/xsd/' , self.__pacote , '/' , nome , '_v' , versao , '.xsd' arquivo_xsd = os.path.join(self.__raiz, 'xsd', self.__pacote, nome + '_v' + versao + '.xsd') # Verifica a validade do xml self.erros = PoleXML.validar(xml, arquivo_xsd) return len(self.erros) == 0
def validar(self, xml, nome_xsd=None): '''Função que valida um XML usando lxml do Python via arquivo XSD no diretório xsd/<pacote>/<nó_xml>.xsd''' # Realiza o parser sobre o xml, identificado como string se iniciar por '<', senão é identificado como nome de arquivo if type(xml) == str: if xml[0] == '<': xml = PoleXML.importar(xml) else: xml = PoleXML.importar(open(xml).read()) # Para este sistema com lxml funcionar foi preciso trocar em tiposBasico_v1.03.xsd {0,} por * # Obeter a versão do primeiro ou segundo nó versao = xml('', 1)['versao'] or xml('', 1)('', 1)['versao'] # O padrão de nome de arquivos xsd é iniciar com letras minúsculas, # mantendo maiúsuclas iniciais de palavras, assim foi preciso desse # trecho de código para passar para músculas iniciais maiúsculas if nome_xsd is None: nome = '' temp = xml('', 1)._XML__nome for i in range(len(temp)): if temp[i].isupper(): nome += temp[i].lower() else: break nome += temp[i:] else: nome = nome_xsd # Caminho do arquivo XSD #print nome_xsd, self.__raiz , '/xsd/' , self.__pacote , '/' , nome , '_v' , versao , '.xsd' arquivo_xsd = os.path.join(self.__raiz, 'xsd', self.__pacote, nome + '_v' + versao + '.xsd') # Verifica a validade do xml self.erros = PoleXML.validar(xml, arquivo_xsd) return len(self.erros) == 0
def servico(self, nome_wsdl, xml, nome_xsd = None): # Validar xml para envio if not self.validar(xml, nome_xsd): erros = "Erro(s) no XML: " for erro in self.erros: erros += erro['type_name'] + ': ' + erro['message'] raise ValueError(erros) # Criar meio de transporte criptografado transporte = suds.transport.http.HttpTransport() transporte.urlopener = urllib2.build_opener(https_ssl(key_file = self.__chave, cert_file = self.__certificado, ca_file = self.__certificadoras)) # Carrega o wsdl da estrutura de arquivos <raiz>/wsdl/<uf>/<nome_wsdl>.wsdl arquivo_wsdl = 'file://' + self.__raiz + '/wsdl/' + self.__sefaz + '/' + self.__str_ambiente + '/' + str(nome_wsdl) + '.wsdl' wsdl = suds.client.Client(arquivo_wsdl, transport = transporte) # Configurar o ambiente do SOAP wsdl.options.cache.clear() ns_anterior = suds.bindings.binding.envns suds.bindings.binding.envns = ('SOAP-ENV', 'http://www.w3.org/2003/05/soap-envelope') # Cria uma função do primeiro serviço, primeira URL (port) e primeiro método, visto que são únicos funcao = suds.client.Method(wsdl, wsdl.wsdl.services[0].ports[0].methods.values()[0]) # Configura o cabeçalho e retorno em XML - Na versão do servidor não tem o parâmetro prettyxml, então tem que comentá-lo para rodar lá wsdl.set_options(soapheaders = self.__cabecalho(wsdl, xml('', 1)['versao']), retxml = True, prettyxml = True) # Executa a função e coleta o resultado em XML resultado = funcao(suds.sax.parser.Parser().parse(string = PoleXML.serializar(xml)).root()) #resultado = funcao(PoleXML.exportar(xml, -1)) #print repr(PoleXML.importar(resultado)) # Voltando o ambiente do SOAP suds.bindings.binding.envns = ns_anterior # Retornar o resultado na forma da classe XML, somente o corpo do envelope Soap return PoleXML.importar(resultado).Envelope.Body('', 1)
def consultar_distribuicao_dfe(self, ultimo_nsu=0, nsu=None, chave=None): # Usar sefaz = 'AN' (ambiente nacional) if self.__sefaz == 'AN': ws = self else: ws = Webservice(self.__cnpj, self.__ambiente, self.__uf, 'AN', self.__raiz, self.__pacote, self.__contingencia) requisicao = PoleXML.XML() distDFeInt = requisicao.nfeDadosMsg.distDFeInt distDFeInt['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' distDFeInt['versao'] = '1.01' if chave else '1.35' distDFeInt.tpAmb = self.__ambiente distDFeInt.cUFAutor = UFS_IBGE[self.__uf] distDFeInt.CNPJ = self.__cnpj if chave: distDFeInt.consChNFe.chNFe = chave elif nsu: distDFeInt.consNSU.NSU = "%015i" % nsu else: distDFeInt.distNSU.ultNSU = "%015i" % ultimo_nsu retorno = ws.servico('NfeDistribuicaoDFe', requisicao, versao_wsdl='1.00') lote = retorno.nfeDistDFeInteresseResult.retDistDFeInt.loteDistDFeInt for num_doc in range(1, lote('docZip', 0) + 1): doc = PoleXML.importar( zlib.decompress(str(lote.docZip(num_doc)).decode('base64'), 16 + zlib.MAX_WBITS)) # for gZip header lote.docZip = None, num_doc lote.docZip += doc, num_doc return retorno
def servico(self, nome_wsdl, xml, nome_xsd=None, versao_wsdl=None): # Validar xml para envio if not self.validar(xml, nome_xsd): erros = "Erro(s) no XML: " for erro in self.erros: erros += erro['type_name'] + ': ' + erro['message'] raise ValueError(erros) # Versões do XML e do WSDL versao_xml = xml('', 1)['versao'] or xml('', 1)('', 1)['versao'] if not versao_wsdl: versao_wsdl = versao_xml # Carrega o wsdl da estrutura de arquivos pela versão do WSDL # <raiz>/wsdl/<sefaz>/<ambiente>/<versao>/<nome_wsdl>.wsdl arquivo_wsdl = os.path.join(self.__raiz, 'wsdl', self.__sefaz, self.__str_ambiente, versao_wsdl, nome_wsdl + '.wsdl') # Se não encontrou pela versão do WSDL especificada, vai pela do XML if not os.path.exists(arquivo_wsdl): arquivo_wsdl = os.path.join( self.__raiz, 'wsdl', self.__sefaz, self.__str_ambiente, versao_xml, nome_wsdl + '.wsdl') arquivo_wsdl = 'file://' + arquivo_wsdl # Criar meio de transporte criptografado transporte = suds.transport.http.HttpTransport() transporte_ssl = (https_ssl_mt if (self.__sefaz == 'MT' or (sys.version_info.major == 2 and sys.version_info.minor < 7)) else https_ssl) transporte.urlopener = urllib2.build_opener( transporte_ssl(key_file=self.__chave, cert_file=self.__certificado, ca_file=self.__certificadoras)) wsdl = suds.client.Client(arquivo_wsdl, transport=transporte) # Configurar o ambiente do SOAP 1.2 wsdl.options.cache.clear() ns_anterior = suds.bindings.binding.envns suds.bindings.binding.envns = ( 'soap12', 'http://www.w3.org/2003/05/soap-envelope') # Cria uma função do primeiro serviço, primeira URL (port) # e primeiro método, visto que são únicos funcao = suds.client.Method(wsdl, wsdl.wsdl. services[0].ports[0].methods.values()[0]) # Configura os headers http para SOAP 1.2, o cabeçalho e retorno em XML wsdl.set_options(soapheaders=self.__cabecalho(wsdl, versao_xml), headers={'Content-Type': 'application/soap+xml; charset=utf-8'}, retxml=True) # Na versão do servidor não tem o parâmetro prettyxml, # então tem que comentá-lo para rodar lá if sys.version_info.major > 2 or sys.version_info.minor > 6: wsdl.set_options(prettyxml=True) # Executa a função e coleta o resultado em XML resultado = funcao(suds.sax.parser.Parser().parse( string=PoleXML.serializar(xml)).root()) # Voltando o ambiente do SOAP suds.bindings.binding.envns = ns_anterior # Retornar o resultado na forma da classe XML, # somente o corpo do envelope Soap return PoleXML.importar(resultado).Envelope.Body('', 1)
def servico(self, nome_wsdl, xml, nome_xsd=None, versao_wsdl=None): # Validar xml para envio if not self.validar(xml, nome_xsd): erros = "Erro(s) no XML: " for erro in self.erros: erros += erro['type_name'] + ': ' + erro['message'] raise ValueError(erros) # Versões do XML e do WSDL versao_xml = xml('', 1)['versao'] or xml('', 1)('', 1)['versao'] if not versao_wsdl: versao_wsdl = versao_xml # Carrega o wsdl da estrutura de arquivos pela versão do WSDL # <raiz>/wsdl/<sefaz>/<ambiente>/<versao>/<nome_wsdl>.wsdl arquivo_wsdl = os.path.join(self.__raiz, 'wsdl', self.__sefaz, self.__str_ambiente, versao_wsdl, nome_wsdl + '.wsdl') # Se não encontrou pela versão do WSDL especificada, vai pela do XML if not os.path.exists(arquivo_wsdl): arquivo_wsdl = os.path.join(self.__raiz, 'wsdl', self.__sefaz, self.__str_ambiente, versao_xml, nome_wsdl + '.wsdl') arquivo_wsdl = 'file://' + arquivo_wsdl # Criar meio de transporte criptografado transporte = suds.transport.http.HttpTransport() transporte_ssl = (https_ssl_mt if (self.__sefaz == 'MT' or (sys.version_info.major == 2 and sys.version_info.minor < 7)) else https_ssl) transporte.urlopener = urllib2.build_opener( transporte_ssl(key_file=self.__chave, cert_file=self.__certificado, ca_file=self.__certificadoras)) wsdl = suds.client.Client(arquivo_wsdl, transport=transporte) # Configurar o ambiente do SOAP 1.2 wsdl.options.cache.clear() ns_anterior = suds.bindings.binding.envns suds.bindings.binding.envns = ( 'soap12', 'http://www.w3.org/2003/05/soap-envelope') # Cria uma função do primeiro serviço, primeira URL (port) # e primeiro método, visto que são únicos funcao = suds.client.Method( wsdl, wsdl.wsdl.services[0].ports[0].methods.values()[0]) # Configura os headers http para SOAP 1.2, o cabeçalho e retorno em XML wsdl.set_options( soapheaders=self.__cabecalho(wsdl, versao_xml), headers={'Content-Type': 'application/soap+xml; charset=utf-8'}, retxml=True) # Na versão do servidor não tem o parâmetro prettyxml, # então tem que comentá-lo para rodar lá if sys.version_info.major > 2 or sys.version_info.minor > 6: wsdl.set_options(prettyxml=True) # Executa a função e coleta o resultado em XML resultado = funcao(suds.sax.parser.Parser().parse( string=PoleXML.serializar(xml)).root()) # Voltando o ambiente do SOAP suds.bindings.binding.envns = ns_anterior # Retornar o resultado na forma da classe XML, # somente o corpo do envelope Soap return PoleXML.importar(resultado).Envelope.Body('', 1)
def enviar_envento(self, descr_evento, chave_nfe, data_hora_evento, qtd_mesmo_evento, xml_adicional): cod, xsd_evento, ev_maiusculo, xsd_envio, uf = EVENTOS[descr_evento] if not uf: uf = self.__uf if uf == self.__uf: ws_envio = self else: ws_envio = Webservice(self.__cnpj, self.__ambiente, uf, None, self.__raiz, self.__pacote, self.__contingencia) dh = cf(data_hora_evento, datetime.datetime)[0] dh = PoleUtil.tz.localize(dh).strftime('%Y-%m-%dT%H:%M:%S%z') dh = dh[:-2] + ':' + dh[-2:] evento = PoleXML.XML() ev = evento.Evento if ev_maiusculo else evento.evento ev['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' ev['versao'] = '1.00' ev.infEvento['Id'] = 'ID%s%s%02i' % (cod, chave_nfe, qtd_mesmo_evento) ev.infEvento.cOrgao = UFS_IBGE[uf] ev.infEvento.tpAmb = self.__ambiente ev.infEvento.CNPJ = self.__cnpj ev.infEvento.chNFe = chave_nfe ev.infEvento.dhEvento = dh ev.infEvento.tpEvento = cod ev.infEvento.nSeqEvento = qtd_mesmo_evento ev.infEvento.verEvento = '1.00' ev.infEvento.detEvento['versao'] = '1.00' ev.infEvento.detEvento.descEvento = descr_evento ev.infEvento.detEvento += xml_adicional self.assinar(ev.infEvento) # Validar xml da evento if not self.validar(evento, xsd_evento): erros = "Erro(s) no XML: " for erro in self.erros: erros += erro['type_name'] + ': ' + erro['message'] raise ValueError(erros) # Lote para envio envio = PoleXML.XML() envio.envEvento['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' envio.envEvento['versao'] = '1.00' # idLote = microsegundo/10 do envio - 15 dígitos no máximo envio.envEvento.idLote = str(int(time.time() * 100000)) envio.envEvento.evento = ev(1) recibo = ws_envio.servico('RecepcaoEvento', envio, xsd_envio, '4.00') retorno = PoleXML.XML() retorno.procEventoNFe['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' retorno.procEventoNFe['versao'] = '1.00' retorno.procEventoNFe.evento = ev(1) if recibo.retEnvEvento('retEvento'): retorno.procEventoNFe.retEvento = recibo.retEnvEvento.retEvento else: retorno.procEventoNFe.retEnvEvento = recibo.retEnvEvento if uf != self.__uf: del ws_envio return retorno
def enviar_envento(self, descr_evento, chave_nfe, data_hora_evento, qtd_mesmo_evento, xml_adicional): dh = cf(data_hora_evento, datetime.datetime)[0] cod_evento, xsd_evento, ev_maiusculo, xsd_envio = EVENTOS[descr_evento] #tz = time.altzone if time.daylight else time.timezone #tz = '%c%02i:%02i' % ('-' if tz > 0 else '+', tz/3600, tz/60%60) #dh = dh.strftime('%Y-%m-%dT%H:%M:%S') + tz tz = pytz.timezone(open('/etc/timezone').read().strip()) dh = tz.localize(dh).strftime('%Y-%m-%dT%H:%M:%S%z') dh = dh[:-2] + ':' + dh[-2:] evento = PoleXML.XML() ev = evento.Evento if ev_maiusculo else evento.evento ev['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' ev['versao'] = '1.00' ev.infEvento[ 'Id'] = 'ID' + cod_evento + chave_nfe + "%02i" % qtd_mesmo_evento ev.infEvento.cOrgao = UFS_IBGE[self.__uf] ev.infEvento.tpAmb = self.__ambiente ev.infEvento.CNPJ = self.__cnpj ev.infEvento.chNFe = chave_nfe ev.infEvento.dhEvento = dh ev.infEvento.tpEvento = cod_evento ev.infEvento.nSeqEvento = qtd_mesmo_evento ev.infEvento.verEvento = '1.00' ev.infEvento.detEvento['versao'] = '1.00' ev.infEvento.detEvento.descEvento = descr_evento ev.infEvento.detEvento += xml_adicional self.assinar(ev.infEvento) # Validar xml da evento if not self.validar(evento, xsd_evento): erros = "Erro(s) no XML: " for erro in self.erros: erros += erro['type_name'] + ': ' + erro['message'] raise ValueError(erros) # Lote para envio envio = PoleXML.XML() envio.envEvento['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' envio.envEvento['versao'] = '1.00' envio.envEvento.idLote = str( int(time.time() * 100000)) # microsegundo/10 do envio - 15 dígitos no máximo envio.envEvento.evento = ev(1) recibo = self.servico('RecepcaoEvento', envio, xsd_envio) retorno = PoleXML.XML() retorno.procEventoNFe['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' retorno.procEventoNFe['versao'] = '1.00' retorno.procEventoNFe.evento = ev(1) if recibo.retEnvEvento('retEvento'): retorno.procEventoNFe.retEvento = recibo.retEnvEvento.retEvento else: retorno.procEventoNFe.retEnvEvento = recibo.retEnvEvento return retorno
def lista_eventos(self, chave): xml_eventos = self.consultar_chave(chave) eventos = PoleXML.procurar(xml_eventos, 'procEventoNFe') retorno = [] for ev in eventos: ev.evento["xmlns"] = "http://www.portalfiscal.inf.br/nfe" ev.retEvento["xmlns"] = "http://www.portalfiscal.inf.br/nfe" rev = PoleXML.XML() rev.procEventoNFe["xmlns"] = "http://www.portalfiscal.inf.br/nfe" rev.procEventoNFe["versao"] = ev["versao"] rev.procEventoNFe.evento = ev.evento rev.procEventoNFe.retEvento = ev.retEvento retorno.append(rev) return retorno
def inutilizar(self, justificativa, ano, numero_inicial, numero_final=None, serie=1): if numero_final is None: numero_final = numero_inicial inutilizacao = PoleXML.XML() inutilizacao.inutNFe['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' inutilizacao.inutNFe['versao'] = '2.00' # Id = Código da UF + Ano (2 posições) + CNPJ + modelo + série + nro inicial e nro final, precedida do literal “ID” inutilizacao.inutNFe.infInut['Id'] = 'ID' + UFS_IBGE[self.__uf] + str( int(ano) % 100) + self.__cnpj + '55' + ("%03i" % int(serie)) + ( "%09i" % int(numero_inicial)) + ("%09i" % int(numero_final)) inutilizacao.inutNFe.infInut.tpAmb = self.__ambiente inutilizacao.inutNFe.infInut.xServ = 'INUTILIZAR' inutilizacao.inutNFe.infInut.cUF = UFS_IBGE[self.__uf] inutilizacao.inutNFe.infInut.ano = int(ano) % 100 inutilizacao.inutNFe.infInut.CNPJ = self.__cnpj inutilizacao.inutNFe.infInut.mod = 55 inutilizacao.inutNFe.infInut.serie = serie inutilizacao.inutNFe.infInut.nNFIni = numero_inicial inutilizacao.inutNFe.infInut.nNFFin = numero_final inutilizacao.inutNFe.infInut.xJust = justificativa self.assinar(inutilizacao, inutilizacao.inutNFe.infInut) return self.servico('NfeInutilizacao2', inutilizacao)
def enviar_carta_correcao(self, qtd_carta_correcao, correcao, chave_nfe, data_hora_evento): carta = PoleXML.XML() carta.xCorrecao = correcao carta.xCondUso = 'A Carta de Correcao e disciplinada pelo paragrafo 1o-A do art. 7o do Convenio S/N, de 15 de dezembro de 1970 e pode ser utilizada para regularizacao de erro ocorrido na emissao de documento fiscal, desde que o erro nao esteja relacionado com: I - as variaveis que determinam o valor do imposto tais como: base de calculo, aliquota, diferenca de preco, quantidade, valor da operacao ou da prestacao; II - a correcao de dados cadastrais que implique mudanca do remetente ou do destinatario; III - a data de emissao ou de saida.' return self.enviar_envento('Carta de Correcao', chave_nfe, data_hora_evento, qtd_carta_correcao, carta)
def consultar_cadastro(self, CNPJ=None, IE=None, CPF=None): sefaz = self.__sefaz self.__sefaz = SEFAZ_CONSULTA[self.__uf] consulta = PoleXML.XML() consulta.ConsCad['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' consulta.ConsCad['versao'] = '3.10' if self.__uf == 'MS' else '2.00' consulta.ConsCad.infCons.xServ = 'CONS-CAD' consulta.ConsCad.infCons.UF = self.__uf if CNPJ is not None: consulta.ConsCad.infCons.CNPJ = CNPJ elif IE is not None: consulta.ConsCad.infCons.IE = IE elif CPF is not None: consulta.ConsCad.infCons.CPF = CPF # Para cSit = Situação do contribuinte: # 0 - não habilitado # 1 - habilitado # Para indCredNFe e indCredCTe: # 0 - Não credenciado para emissão # 1 - Credenciado # 2 - Credenciado com obrigatoriedade para todas operações # 3 - Credenciado com obrigatoriedade parcial # 4 - a SEFAZ não fornece a informação # Especificar a versão, pois no XML é 2.00 e o wsdl é 3.10 retorno = self.servico('NfeConsultaCadastro', consulta, versao_wsdl='3.10') self.__sefaz = sefaz return retorno
def enviar_nfe_e_consultar_recibo(self, xml, tentativas=30, aviso_processamento=True): retorno = self.enviar_nfe(xml) if str(retorno.retEnviNFe.cStat ) != '103': # 103 = Lote recebido com sucesso return retorno recibo = str(retorno.retEnviNFe.infRec.nRec) consulta = PoleXML.XML() consulta.consReciNFe['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' consulta.consReciNFe['versao'] = '2.00' consulta.consReciNFe.tpAmb = self.__ambiente consulta.consReciNFe.nRec = recibo cStat = '105' # 105 = Lote em processamento tentativa = 1 while cStat == '105' and tentativa <= tentativas: time.sleep(1) retorno = self.servico('NfeRetRecepcao2', consulta) cStat = str(retorno.retConsReciNFe.cStat) if aviso_processamento: print 'Tentativa ' + str(tentativa) + ': ' + str( retorno.retConsReciNFe.cStat) + ' - ' + str( retorno.retConsReciNFe.xMotivo) if cStat == '105': print 'Consultando novamente...' tentativa += 1 # Retorna o resultado da consulta do recibo if aviso_processamento: print 'Tentativa ' + str(tentativa - 1) + ': ' + str( retorno.retConsReciNFe.protNFe.infProt.cStat) + ' - ' + str( retorno.retConsReciNFe.protNFe.infProt.xMotivo) return retorno
def cancelar_chave(self, justificativa, chave_nfe, protocolo=None): if not protocolo: consulta = self.consultar_chave(chave_nfe) protocolo = str(consulta.retConsSitNFe.protNFe.infProt.nProt) cancelamento = PoleXML.XML() #cancelamento.cancNFe['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' #cancelamento.cancNFe['versao'] = '2.00' #cancelamento.cancNFe.infCanc['Id'] = 'ID' + chave_nfe #cancelamento.cancNFe.infCanc.tpAmb = self.__ambiente #cancelamento.cancNFe.infCanc.xServ = 'CANCELAR' #cancelamento.cancNFe.infCanc.chNFe = chave_nfe #cancelamento.cancNFe.infCanc.nProt = protocolo #cancelamento.cancNFe.infCanc.xJust = justificativa #self.assinar(cancelamento, cancelamento.cancNFe.infCanc) #recibo = self.servico('NfeCancelamento2', cancelamento) #retorno = PoleXML.XML() #retorno.procCancNFe['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' #retorno.procCancNFe['versao'] = '2.00' #retorno.procCancNFe.cancNFe = cancelamento.cancNFe #retorno.procCancNFe.retCancNFe = recibo.retCancNFe #return retorno cancelamento.nProt = protocolo cancelamento.xJust = justificativa return self.enviar_envento('Cancelamento', chave_nfe, datetime.datetime.now(), 1, cancelamento)
def enviar_nfe_e_consultar_recibo(self, xml, tentativas=30, espera_em_segundos=5, aviso_processamento=True): retorno = self.enviar_nfe(xml) # se o lote não foi recebido com sucesso (103), retorna este recibo if str(retorno.retEnviNFe.cStat) != '103': return retorno recibo = str(retorno.retEnviNFe.infRec.nRec) consulta = PoleXML.XML() consulta.consReciNFe['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' consulta.consReciNFe['versao'] = '3.10' consulta.consReciNFe.tpAmb = self.__ambiente consulta.consReciNFe.nRec = recibo cStat = '105' # 105 = Lote em processamento tentativa = 1 while cStat == '105' and tentativa <= tentativas: time.sleep(espera_em_segundos) retorno = self.servico('NfeRetAutorizacao', consulta) cStat = str(retorno.retConsReciNFe.cStat) if aviso_processamento: print('Tentativa %i: %s - %s' % (tentativa, str(retorno.retConsReciNFe.cStat), str(retorno.retConsReciNFe.xMotivo))) if cStat == '105': print 'Consultando novamente...' tentativa += 1 # Retorna o resultado da consulta do recibo if aviso_processamento: print('Tentativa %i: %s - %s' % (tentativa - 1, str(retorno.retConsReciNFe.protNFe.infProt.cStat), str(retorno.retConsReciNFe.protNFe.infProt.xMotivo))) return retorno
def consultar_recibo(self, recibo): # Cria a estrutra consulta pelo número do recibo e faz a consulta consulta = PoleXML.XML() consulta.consReciNFe['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' consulta.consReciNFe['versao'] = '2.00' consulta.consReciNFe.tpAmb = self.__ambiente consulta.consReciNFe.nRec = recibo return self.servico('NfeRetRecepcao2', consulta)
def consultar_chave(self, chave): consulta = PoleXML.XML() consulta.consSitNFe['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' consulta.consSitNFe['versao'] = '2.01' consulta.consSitNFe.tpAmb = self.__ambiente consulta.consSitNFe.xServ = 'CONSULTAR' consulta.consSitNFe.chNFe = chave return self.servico('NfeConsulta2', consulta)
def download_nfe(self, chave): ret = self.consultar_distribuicao_dfe(chave=chave) doc = ret.nfeDistDFeInteresseResult.retDistDFeInt.loteDistDFeInt.docZip if doc('', PoleXML.FILHOS) == 0: return None nfe = PoleXML.XML() nfe += doc return nfe
def status(self): consulta = PoleXML.XML() consulta.consStatServ['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' consulta.consStatServ['versao'] = '2.00' consulta.consStatServ.tpAmb = self.__ambiente consulta.consStatServ.cUF = UFS_IBGE[self.__uf] consulta.consStatServ.xServ = 'STATUS' return self.servico('NfeStatusServico2', consulta)
def download_nfe(self, chave): # usar uf = 'AN' (ambiente nacional) requisicao = PoleXML.XML() requisicao.downloadNFe['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' requisicao.downloadNFe['versao'] = '1.00' requisicao.downloadNFe.tpAmb = self.__ambiente requisicao.downloadNFe.xServ = 'DOWNLOAD NFE' requisicao.downloadNFe.CNPJ = self.__cnpj requisicao.downloadNFe.chNFe = chave return self.servico('NfeDownloadNF', requisicao)
def download_nfe(self, chave): # usar uf = 'AN' (ambiente nacional) requisicao = PoleXML.XML() requisicao.downloadNFe['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' requisicao.downloadNFe['versao'] = '1.00' requisicao.downloadNFe.tpAmb = self.__ambiente requisicao.downloadNFe.xServ = 'DOWNLOAD NFE' requisicao.downloadNFe.CNPJ = self.__cnpj requisicao.downloadNFe.chNFe = chave xml_download = self.servico('NfeDownloadNF', requisicao) nfeProc = xml_download.retDownloadNFe.retNFe.procNFe.nfeProc nfeProc.NFe["xmlns"] = "http://www.portalfiscal.inf.br/nfe" nfeProc.protNFe["xmlns"] = "http://www.portalfiscal.inf.br/nfe" procnfe = PoleXML.XML() procnfe.nfeProc["xmlns"] = "http://www.portalfiscal.inf.br/nfe" procnfe.nfeProc["versao"] = nfeProc["versao"] procnfe.nfeProc.NFe = nfeProc.NFe procnfe.nfeProc.protNFe = nfeProc.protNFe return procnfe
def enviar_nfe(self, xml): # Realiza o parser sobre nfe, identificada como string se iniciar por '<', senão é identificada como nome de arquivo if type(xml) == str: if xml[0] == '<': xml = PoleXML.importar(xml) else: xml = PoleXML.importar(open(xml).read()) if not isinstance(xml, PoleXML.XML): raise TypeError('A NFe em XML precisa ser passada como string XML, string com o nome do arquivo com o XML ou instância de PoleXML.XML!') # Assina a NFe self.assinar(xml.NFe.infNFe) # Cria envelope de lote para a NFe lote_nfe = PoleXML.XML() lote_nfe.enviNFe['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' lote_nfe.enviNFe['versao'] = '2.00' lote_nfe.enviNFe.idLote = datetime.datetime.now().strftime('%y%m%d%H%M%S%f')[:15] lote_nfe.enviNFe += xml # Envia a NFe return self.servico('NfeRecepcao2', lote_nfe)
def enviar_nfe(self, xml): # Realiza o parser sobre nfe, identificada como string se iniciar por '<', senão é identificada como nome de arquivo if type(xml) == str: if xml[0] == '<': xml = PoleXML.importar(xml) else: xml = PoleXML.importar(open(xml).read()) if not isinstance(xml, PoleXML.XML): raise TypeError( 'A NFe em XML precisa ser passada como string XML, string com o nome do arquivo com o XML ou instância de PoleXML.XML!' ) # Assina a NFe self.assinar(xml.NFe.infNFe) # Cria envelope de lote para a NFe lote_nfe = PoleXML.XML() lote_nfe.enviNFe['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' lote_nfe.enviNFe['versao'] = '2.00' lote_nfe.enviNFe.idLote = datetime.datetime.now().strftime( '%y%m%d%H%M%S%f')[:15] lote_nfe.enviNFe += xml # Envia a NFe return self.servico('NfeRecepcao2', lote_nfe)
def servico(self, nome_wsdl, xml, nome_xsd=None): # Validar xml para envio if not self.validar(xml, nome_xsd): erros = "Erro(s) no XML: " for erro in self.erros: erros += erro['type_name'] + ': ' + erro['message'] raise ValueError(erros) # Criar meio de transporte criptografado transporte = suds.transport.http.HttpTransport() transporte.urlopener = urllib2.build_opener( https_ssl(key_file=self.__chave, cert_file=self.__certificado, ca_file=self.__certificadoras)) # Carrega o wsdl da estrutura de arquivos <raiz>/wsdl/<uf>/<nome_wsdl>.wsdl arquivo_wsdl = 'file://' + self.__raiz + '/wsdl/' + self.__sefaz + '/' + self.__str_ambiente + '/' + str( nome_wsdl) + '.wsdl' wsdl = suds.client.Client(arquivo_wsdl, transport=transporte) # Configurar o ambiente do SOAP wsdl.options.cache.clear() ns_anterior = suds.bindings.binding.envns suds.bindings.binding.envns = ( 'SOAP-ENV', 'http://www.w3.org/2003/05/soap-envelope') # Cria uma função do primeiro serviço, primeira URL (port) e primeiro método, visto que são únicos funcao = suds.client.Method( wsdl, wsdl.wsdl.services[0].ports[0].methods.values()[0]) # Configura o cabeçalho e retorno em XML - Na versão do servidor não tem o parâmetro prettyxml, então tem que comentá-lo para rodar lá wsdl.set_options(soapheaders=self.__cabecalho(wsdl, xml('', 1)['versao']), retxml=True, prettyxml=True) # Executa a função e coleta o resultado em XML resultado = funcao(suds.sax.parser.Parser().parse( string=PoleXML.serializar(xml)).root()) #resultado = funcao(PoleXML.exportar(xml, -1)) #print repr(PoleXML.importar(resultado)) # Voltando o ambiente do SOAP suds.bindings.binding.envns = ns_anterior # Retornar o resultado na forma da classe XML, somente o corpo do envelope Soap return PoleXML.importar(resultado).Envelope.Body('', 1)
def consultar_chave(self, chave): if chave[:2] == UFS_IBGE[self.__uf]: ws_consulta = self else: uf_consulta = dict([x[::-1] for x in UFS_IBGE.items()])[chave[:2]] ws_consulta = Webservice(self.__cnpj, self.__ambiente, uf_consulta, uf_consulta, self.__raiz, self.__pacote) consulta = PoleXML.XML() consulta.consSitNFe['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' consulta.consSitNFe['versao'] = '3.10' consulta.consSitNFe.tpAmb = self.__ambiente consulta.consSitNFe.xServ = 'CONSULTAR' consulta.consSitNFe.chNFe = chave return ws_consulta.servico('NfeConsultaProtocolo', consulta)
def download_eventos(self, chave): xml_eventos = self.consultar_chave(chave) eventos = PoleXML.procurar(xml_eventos, 'procEventoNFe') retorno = [] for ev in eventos: ev.evento["xmlns"] = "http://www.portalfiscal.inf.br/nfe" ev.retEvento["xmlns"] = "http://www.portalfiscal.inf.br/nfe" rev = PoleXML.XML() rev.procEventoNFe["xmlns"] = "http://www.portalfiscal.inf.br/nfe" rev.procEventoNFe["versao"] = ev["versao"] rev.procEventoNFe.evento = ev.evento rev.procEventoNFe.retEvento = ev.retEvento retorno.append(rev) return retorno
def consultar_nfes_destinadas(self, consultar=TODAS, sem_cnpj_base=False, ultimo_nsu=0): consulta = PoleXML.XML() consulta.consNFeDest['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' consulta.consNFeDest['versao'] = '1.01' consulta.consNFeDest.tpAmb = self.__ambiente consulta.consNFeDest.xServ = 'CONSULTAR NFE DEST' consulta.consNFeDest.CNPJ = self.__cnpj consulta.consNFeDest.indNFe = consultar consulta.consNFeDest.indEmi = +sem_cnpj_base consulta.consNFeDest.ultNSU = ultimo_nsu retorno = self.servico('NfeConsultaDest', consulta) while (retorno.retConsNFeDest.cStat == '138' and retorno.retConsNFeDest.indCont == '1'): consulta.consNFeDest.ultNSU = retorno.consNFeDest.ultNSU retorno += self.servico('NfeConsultaDest', consulta) return retorno
def consultar_cadastro(self, CNPJ=None, IE=None, CPF=None): consulta = PoleXML.XML() consulta.ConsCad['xmlns'] = 'http://www.portalfiscal.inf.br/nfe' consulta.ConsCad['versao'] = '2.00' consulta.ConsCad.infCons.xServ = 'CONS-CAD' consulta.ConsCad.infCons.UF = self.__uf if CNPJ is not None: consulta.ConsCad.infCons.CNPJ = CNPJ elif IE is not None: consulta.ConsCad.infCons.IE = IE elif CPF is not None: consulta.ConsCad.infCons.CPF = CPF # Para cSit = Situação do contribuinte: # 0 - não habilitado # 1 - habilitado # Para indCredNFe e indCredCTe: # 0 - Não credenciado para emissão # 1 - Credenciado # 2 - Credenciado com obrigatoriedade para todas operações # 3 - Credenciado com obrigatoriedade parcial # 4 - a SEFAZ não fornece a informação return self.servico('CadConsultaCadastro2', consulta)
def assinar(self, filho_id): return PoleXML.assinar(filho_id, 'Id', self.__chave, self.__certificado)
def verificar_assinatura(self, filho_id): return PoleXML.verificar_assinatura(filho_id, "Id", raiz + "/certificadoras/v1_v2_v3.crt")
def verificar_assinatura(self, filho_id): return PoleXML.verificar_assinatura( filho_id, 'Id', raiz + '/certificadoras/v1_v2_v3.crt')
def manifestar(self, manifestacao, chave_nfe, justificativa=None): manifesto = PoleXML.XML() if justificativa: manifesto.xJust = justificativa return self.enviar_envento(manifestacao, chave_nfe, datetime.datetime.now(), 1, manifesto)
def verificar_assinatura(self, filho_id): return PoleXML.verificar_assinatura(filho_id, 'Id', raiz + '/certificadoras/v1_v2_v3.crt')