def autorizacao(self, modelo, nota_fiscal, id_lote=1, ind_sinc=1): """ Método para realizar autorização da nota de acordo com o modelo :param modelo: Modelo :param nota_fiscal: XML assinado :param id_lote: Id do lote - numero autoincremental gerado pelo sistema :param ind_sinc: Indicador de sincrono e assincrono, 0 para assincrono, 1 para sincrono :return: Uma tupla que em caso de sucesso, retorna xml com nfe e protocolo de autorização. Caso contrário, envia todo o soap de resposta da Sefaz para decisão do usuário. """ # url do serviço url = self._get_url(modelo=modelo, consulta='AUTORIZACAO') # Monta XML do corpo da requisição raiz = etree.Element('enviNFe', xmlns=NAMESPACE_NFE, versao=VERSAO_PADRAO) etree.SubElement(raiz, 'idLote').text = str(id_lote) # numero autoincremental gerado pelo sistema etree.SubElement(raiz, 'indSinc').text = str(ind_sinc) # 0 para assincrono, 1 para sincrono raiz.append(nota_fiscal) # Monta XML para envio da requisição xml = self._construir_xml_soap('NFeAutorizacao4', raiz) # Faz request no Servidor da Sefaz retorno = self._post(url, xml) # Em caso de sucesso, retorna xml com nfe e protocolo de autorização. # Caso contrário, envia todo o soap de resposta da Sefaz para decisão do usuário. if retorno.status_code == 200: if ind_sinc == 1: # Procuta status no xml ns = {'ns': 'http://www.portalfiscal.inf.br/nfe'} # namespace try: prot = etree.fromstring(retorno.text) except ValueError: # em SP retorno.text apresenta erro prot = etree.fromstring(retorno.content) try: # Protocolo com envio OK inf_prot = prot[1][0][0][6] # root protNFe status = inf_prot.xpath("ns:infProt/ns:cStat", namespaces=ns)[0].text except IndexError: # Protocolo com algum erro no Envio ret_envi = prot[1][0][0] # root retEnvi status = ret_envi.xpath("ns:cStat", namespaces=ns)[0].text if status == '100': raiz = etree.Element('nfeProc', xmlns=NAMESPACE_NFE, versao=VERSAO_PADRAO) raiz.append(nota_fiscal) raiz.append(inf_prot) return 0, raiz else: # Retorna id do protocolo para posterior consulta em caso de sucesso. ns = {'ns': 'http://www.portalfiscal.inf.br/nfe'} # namespace rec = etree.fromstring(retorno.text) rec = rec[1][0][0] status = rec.xpath("ns:cStat", namespaces=ns)[0].text # Lote Recebido com Sucesso! if status == '103': nrec = rec.xpath("ns:infRec/ns:nRec", namespaces=ns)[0].text return 0, nrec, nota_fiscal return 1, retorno, nota_fiscal
def autorizacao(self, modelo, nota_fiscal, idlote=1, indSinc=1): # url do serviço url = self._get_url(modelo=modelo, consulta='AUTORIZACAO') # Monta XML do corpo da requisição raiz = etree.Element('enviNFe', xmlns=NAMESPACE_NFE, versao=VERSAO_PADRAO) etree.SubElement(raiz, 'idLote').text = str(idlote) # numero autoincremental gerado pelo sistema etree.SubElement(raiz, 'indSinc').text = str(indSinc) # 0 para assincrono, 1 para sincrono 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=raiz) # Faz request no Servidor da Sefaz retorno = self._post(url, xml) # Em caso de sucesso, retorna xml com nfe e protocolo de autorização. # Caso contrário, envia todo o soap de resposta da Sefaz para decisão do usuário. if retorno.status_code == 200: if indSinc == 1: # Procuta status no xml ns = {'ns':'http://www.portalfiscal.inf.br/nfe'} # namespace try: prot = etree.fromstring(retorno.text) except ValueError: #em SP retorno.text apresenta erro prot = etree.fromstring(retorno.content) try: # Protocolo com envio OK infProt = prot[1][0][0][6] # root protNFe status = infProt.xpath("ns:infProt/ns:cStat", namespaces=ns)[0].text except IndexError: # Protocolo com algum erro no Envio retEnvi = prot[1][0][0] # root retEnvi status = retEnvi.xpath("ns:cStat", namespaces=ns)[0].text if status == '100': raiz = etree.Element('nfeProc', xmlns=NAMESPACE_NFE, versao=VERSAO_PADRAO) raiz.append(nota_fiscal) raiz.append(infProt) return 0, raiz else: # Retorna id do protocolo para posterior consulta em caso de sucesso. ns = {'ns':'http://www.portalfiscal.inf.br/nfe'} # namespace rec = etree.fromstring(retorno.text) rec = rec[1][0][0] status = rec.xpath("ns:cStat", namespaces=ns)[0].text # Lote Recebido com Sucesso! if status == '103': nrec = rec.xpath("ns:infRec/ns:nRec", namespaces=ns)[0].text return 0, nrec, nota_fiscal return 1, retorno, nota_fiscal
def assinar(self, xml, retorna_string=False): # busca tag que tem id(reference_uri), logo nao importa se tem namespace reference = xml.find(".//*[@Id]").attrib['Id'] # retira acentos xml_str = remover_acentos( etree.tostring(xml, encoding="unicode", pretty_print=False)) xml = etree.fromstring(xml_str) signer = XMLSigner( method=signxml.methods.enveloped, signature_algorithm="rsa-sha1", digest_algorithm='sha1', c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') ns = {None: signer.namespaces['ds']} signer.namespaces = ns ref_uri = ('#%s' % reference) if reference else None signed_root = signer.sign(xml, key=self.key, cert=self.cert, reference_uri=ref_uri) ns = {'ns': NAMESPACE_SIG} # coloca o certificado na tag X509Data/X509Certificate tagX509Data = signed_root.find('.//ns:X509Data', namespaces=ns) etree.SubElement(tagX509Data, 'X509Certificate').text = self.cert if retorna_string: return etree.tostring(signed_root, encoding="unicode", pretty_print=False) else: return signed_root
def assinar(self, xml, retorna_string=False): # busca tag que tem id(reference_uri), logo nao importa se tem namespace reference = xml.find(".//*[@Id]").attrib['Id'] #print('Referencia: ',reference) # retira acentos xml_str = remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False)) xml = etree.fromstring(xml_str) signer = XMLSigner( method=signxml.methods.enveloped, signature_algorithm="rsa-sha1", digest_algorithm='sha1', c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') ns = {None: signer.namespaces['ds']} signer.namespaces = ns #print('Chave......: ',self.key) #print('*',200) #print('Certificado: ',self.cert) ref_uri = ('#%s' % reference) if reference else None signed_root = signer.sign( xml, key=self.key, cert=self.cert, reference_uri=ref_uri) ns = {'ns': NAMESPACE_SIG} # coloca o certificado na tag X509Data/X509Certificate tagX509Data = signed_root.find('.//ns:X509Data', namespaces=ns) etree.SubElement(tagX509Data, 'X509Certificate').text = self.cert #print('Assinatura: ',etree.tostring(signed_root, encoding="unicode", pretty_print=False) ) if retorna_string: return etree.tostring(signed_root, encoding="unicode", pretty_print=False) else: return signed_root
def assinarNfse(self, xml, retorna_string=True): "Assina NFS-e" try: # define variaveis de acordo com autorizador if self.autorizador == 'ginfes': xpath = './/ns2:InfRps' tag = 'InfRps' elif self.autorizador == 'betha': xpath = './/ns1:InfDeclaracaoPrestacaoServico' tag = 'InfDeclaracaoPrestacaoServico' else: raise Exception('Autorizador não encontrado!') xml = etree.fromstring(xml) # define namespaces, pega do proprio xml namespaces = xml.nsmap # No raiz do XML de saida raiz = etree.Element('Signature', xmlns='http://www.w3.org/2000/09/xmldsig#') siginfo = etree.SubElement(raiz, 'SignedInfo') etree.SubElement(siginfo, 'CanonicalizationMethod', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement(siginfo, 'SignatureMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1') # Tenta achar a tag ref = etree.SubElement(siginfo, 'Reference', URI='#' + xml.xpath(xpath, namespaces=namespaces)[0].attrib['Id']) trans = etree.SubElement(ref, 'Transforms') etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/2000/09/xmldsig#enveloped-signature') etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement(ref, 'DigestMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#sha1') etree.SubElement(ref, 'DigestValue') etree.SubElement(raiz, 'SignatureValue') keyinfo = etree.SubElement(raiz, 'KeyInfo') etree.SubElement(keyinfo, 'X509Data') rps = xml.xpath(xpath+'/..', namespaces=namespaces)[0] rps.append(raiz) # Escreve no arquivo depois de remover caracteres especiais e parse string with open('nfse.xml', 'w') as arquivo: texto = remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False)) # se for tag do Betha if tag == 'InfDeclaracaoPrestacaoServico': texto = texto.replace('ns1:', '').replace(':ns1', '') arquivo.write(texto) subprocess.call(['xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd', self.senha, '--crypto', 'openssl', '--output', 'nfse.xml', '--id-attr:Id', tag, 'nfse.xml']) if retorna_string: return open('nfse.xml', 'r').read() else: return etree.parse('nfse.xml').getroot() except Exception as e: raise e
def assinarCancelar(self, xml, retorna_string=True): """ Método que assina o xml para cancelamento de NFS-e """ try: if self.autorizador == 'ginfes': xpath = 'CancelarNfseEnvio' tag = 'CancelarNfseEnvio' namespaces = {'ns1': 'http://www.ginfes.com.br/servico_cancelar_nfse_envio', 'ns2':'http://www.ginfes.com.br/tipos'} elif self.autorizador == 'betha': xpath = '/CancelarNfseEnvio/ns1:Pedido' tag = 'InfPedidoCancelamento' namespaces = {'ns1': 'http://www.betha.com.br/e-nota-contribuinte-ws'} else: raise Exception('Autorizador não encontrado!') xml = etree.fromstring(xml) # No raiz do XML de saida raiz = etree.Element('Signature', xmlns='http://www.w3.org/2000/09/xmldsig#') siginfo = etree.SubElement(raiz, 'SignedInfo') etree.SubElement(siginfo, 'CanonicalizationMethod', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement(siginfo, 'SignatureMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1') # Tenta achar a tag informada no xpath if tag == 'InfPedidoCancelamento': ref = etree.SubElement(siginfo, 'Reference', URI='#'+xml.xpath('.//ns1:'+tag, namespaces=namespaces)[0].attrib['Id']) # ginfes não tem id no cancelamento v2 else: ref = etree.SubElement(siginfo, 'Reference', URI='') trans = etree.SubElement(ref, 'Transforms') etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/2000/09/xmldsig#enveloped-signature') etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement(ref, 'DigestMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#sha1') etree.SubElement(ref, 'DigestValue') etree.SubElement(raiz, 'SignatureValue') keyinfo = etree.SubElement(raiz, 'KeyInfo') etree.SubElement(keyinfo, 'X509Data') if tag == 'InfPedidoCancelamento': xml = xml.xpath(xpath, namespaces=namespaces)[0] # ginfes só possui a tag root else: xml.append(raiz) # Escreve no arquivo depois de remover caracteres especiais e parse string with open('nfse.xml', 'w') as arquivo: arquivo.write(remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False).replace('\n',''))) subprocess.call(['xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd', self.senha, '--crypto', 'openssl', '--output', 'funfa.xml', '--id-attr:Id', tag, 'nfse.xml']) if retorna_string: return open('funfa.xml', 'r').read() else: return etree.parse('funfa.xml').getroot() except Exception as e: raise e
def assinarLote(self, xml, retorna_string=True): "Assina nfse e lote" try: xml = self.assinarNfse(xml, retorna_string=False) xpath = './/ns1:LoteRps' tag = 'LoteRps' # define namespaces, pega do proprio xml namespaces = xml.nsmap # No raiz do XML de saida raiz = etree.Element('Signature', xmlns='http://www.w3.org/2000/09/xmldsig#') siginfo = etree.SubElement(raiz, 'SignedInfo') etree.SubElement(siginfo, 'CanonicalizationMethod', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement(siginfo, 'SignatureMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1') # Tenta achar a tag ref = etree.SubElement(siginfo, 'Reference', URI='#' + xml.xpath(xpath, namespaces=namespaces)[0].attrib['Id']) trans = etree.SubElement(ref, 'Transforms') etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/2000/09/xmldsig#enveloped-signature') etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement(ref, 'DigestMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#sha1') etree.SubElement(ref, 'DigestValue') etree.SubElement(raiz, 'SignatureValue') keyinfo = etree.SubElement(raiz, 'KeyInfo') etree.SubElement(keyinfo, 'X509Data') # posiciona tag Signature antes do LoteRps para assinar base = xml.xpath(xpath+'/..', namespaces=namespaces)[0] base.insert(0, raiz) # Escreve no arquivo depois de remover caracteres especiais with open('nfse.xml', 'w') as arquivo: texto = remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False)) arquivo.write(texto) # assina lote subprocess.call(['xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd', self.senha, '--crypto', 'openssl', '--output', 'nfse.xml', '--id-attr:Id', tag, 'nfse.xml']) # Reposiciona tag Signature apos LoteRps xml = etree.fromstring(open('nfse.xml', 'r').read()) namespaces = xml.nsmap sig = xml.find('{http://www.w3.org/2000/09/xmldsig#}Signature') sig.getparent().remove(sig) xml.append(sig) if retorna_string: return etree.tostring(xml, encoding="unicode", pretty_print=False) else: return xml except Exception as e: raise e
def _post_soap(self, classe, ws_metodo, raiz_xml, str_xml=False): url, webservice, metodo = self._get_url_webservice_metodo(ws_metodo) if not str_xml: xml = self._construir_xml_soap(webservice, self._construir_etree_ds(raiz_xml)) else: etree_ds = self._construir_etree_ds(raiz_xml) etree_ds.append(etree.fromstring(str_xml)) xml = self._construir_xml_soap(webservice, etree_ds) retorno = self._post(url, xml, soap_webservice_method=webservice + b'/' + metodo) return analisar_retorno(ws_metodo, retorno, classe)
def analisar_retorno(webservice, retorno, classe_resposta): # retorno.raise_for_status() # print(retorno.text) match = re.search('<soap:Body>(.*?)</soap:Body>', retorno.text) if match: resultado = etree.tostring(etree.fromstring(match.group(1))[0]) # classe_resposta.Validate_simpletypes_ = False # resposta = classe_resposta.parseString(resultado) resposta = resultado # resposta = retorno.text return RetornoSoap(webservice, retorno, resposta)
def consulta_nota_assinada(self, xml, modelo, chave_assinatura): """ Este método oferece a consulta da situação da NF-e/NFC-e na Base de Dados do Portal da Secretaria de Fazenda Estadual. :param xml: XML da nota :param modelo: Modelo da nota :param chave_assinatura: Tupla (certificado, chave) A3 :return: """ if type(xml) == str: xml = etree.fromstring(xml) # url do serviço url = self._get_url(modelo=modelo, consulta='CHAVE') return self._post(url, xml, chave_assinatura)
def _assinar(self, xml, tag, retorna_string=True): """ Método para assinar xml de NFS-e com tags sem ID Consulta de Lote e Consulta por RPS @param tag - raiz do xml que será assinado """ try: xml = etree.fromstring(xml) # No raiz do XML de saida raiz = etree.Element('Signature', xmlns='http://www.w3.org/2000/09/xmldsig#') siginfo = etree.SubElement(raiz, 'SignedInfo') etree.SubElement(siginfo, 'CanonicalizationMethod', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement(siginfo, 'SignatureMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1') # Consulta nao tem id ref = etree.SubElement(siginfo, 'Reference', URI='') trans = etree.SubElement(ref, 'Transforms') etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/2000/09/xmldsig#enveloped-signature') etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement(ref, 'DigestMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#sha1') etree.SubElement(ref, 'DigestValue') etree.SubElement(raiz, 'SignatureValue') keyinfo = etree.SubElement(raiz, 'KeyInfo') etree.SubElement(keyinfo, 'X509Data') xml.append(raiz) # Escreve no arquivo depois de remover caracteres especiais e parse string with open('nfse.xml', 'w') as arquivo: arquivo.write(remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False).replace('\n',''))) subprocess.call(['xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd', self.senha, '--crypto', 'openssl', '--output', 'funfa.xml', '--id-attr:Id', tag, 'nfse.xml']) xml = etree.parse('funfa.xml').getroot() if retorna_string: return etree.tostring(xml, encoding="unicode", pretty_print=False).replace('\n','') else: return xml except Exception as e: raise e
def assinarConsulta(self, xml, retorna_string=True): try: xml = etree.fromstring(xml) # No raiz do XML de saida tag = 'ns1:ConsultarNfseEnvio' # tag que será assinada raiz = etree.Element('Signature', xmlns='http://www.w3.org/2000/09/xmldsig#') siginfo = etree.SubElement(raiz, 'SignedInfo') etree.SubElement(siginfo, 'CanonicalizationMethod', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement(siginfo, 'SignatureMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1') # Consulta nao tem id ref = etree.SubElement(siginfo, 'Reference', URI='') trans = etree.SubElement(ref, 'Transforms') etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/2000/09/xmldsig#enveloped-signature') etree.SubElement(trans, 'Transform', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement(ref, 'DigestMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#sha1') etree.SubElement(ref, 'DigestValue') etree.SubElement(raiz, 'SignatureValue') keyinfo = etree.SubElement(raiz, 'KeyInfo') etree.SubElement(keyinfo, 'X509Data') consulta = xml.xpath('/ns1:ConsultarNfseEnvio', namespaces={'ns1': 'http://www.ginfes.com.br/servico_consultar_nfse_envio_v03.xsd', 'ns2':'http://www.ginfes.com.br/tipos_v03.xsd'})[0] consulta.append(raiz) # Escreve no arquivo depois de remover caracteres especiais e parse string with open('nfse.xml', 'w') as arquivo: arquivo.write(remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False).replace('\n',''))) subprocess.call(['xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd', self.senha, '--crypto', 'openssl', '--output', 'funfa.xml', '--id-attr:Id', tag, 'nfse.xml']) xml = etree.parse('funfa.xml').getroot() if retorna_string: return etree.tostring(xml, encoding="unicode", pretty_print=False) else: return xml except Exception as e: raise e
def assinarLote(self, xml, retorna_string=True): "Assina nfse e lote" try: xml = self.assinarNfse(xml, retorna_string=False) xpath = './/ns1:LoteRps' tag = 'LoteRps' # define namespaces, pega do proprio xml namespaces = xml.nsmap # No raiz do XML de saida raiz = etree.Element('Signature', xmlns='http://www.w3.org/2000/09/xmldsig#') siginfo = etree.SubElement(raiz, 'SignedInfo') etree.SubElement( siginfo, 'CanonicalizationMethod', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement( siginfo, 'SignatureMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1') # Tenta achar a tag ref = etree.SubElement( siginfo, 'Reference', URI='#' + xml.xpath(xpath, namespaces=namespaces)[0].attrib['Id']) trans = etree.SubElement(ref, 'Transforms') etree.SubElement( trans, 'Transform', Algorithm= 'http://www.w3.org/2000/09/xmldsig#enveloped-signature') etree.SubElement( trans, 'Transform', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement( ref, 'DigestMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#sha1') etree.SubElement(ref, 'DigestValue') etree.SubElement(raiz, 'SignatureValue') keyinfo = etree.SubElement(raiz, 'KeyInfo') etree.SubElement(keyinfo, 'X509Data') # posiciona tag Signature antes do LoteRps para assinar base = xml.xpath(xpath + '/..', namespaces=namespaces)[0] base.insert(0, raiz) # Escreve no arquivo depois de remover caracteres especiais with open('nfse.xml', 'w') as arquivo: texto = remover_acentos( etree.tostring(xml, encoding="unicode", pretty_print=False)) arquivo.write(texto) # assina lote subprocess.check_call([ 'xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd', self.senha, '--crypto', 'openssl', '--output', 'nfse.xml', '--id-attr:Id', tag, 'nfse.xml' ]) # Reposiciona tag Signature apos LoteRps xml = etree.fromstring(open('nfse.xml', 'r').read()) namespaces = xml.nsmap sig = xml.find('{http://www.w3.org/2000/09/xmldsig#}Signature') sig.getparent().remove(sig) xml.append(sig) if retorna_string: return etree.tostring(xml, encoding="unicode", pretty_print=False) else: return xml except Exception as e: raise e
def gerar_qrcode(self, token, csc, xml, return_qr=False, online=True): """ Classe para gerar url do qrcode da NFC-e """ # Procura atributos no xml ns = {'ns':NAMESPACE_NFE} sig = {'sig':NAMESPACE_SIG} # Tag Raiz NFe Ex: <NFe> nfe = xml chave = nfe[0].attrib['Id'].replace('NFe','') data = nfe.xpath('ns:infNFe/ns:ide/ns:dhEmi/text()', namespaces=ns)[0].encode() tpamb = nfe.xpath('ns:infNFe/ns:ide/ns:tpAmb/text()', namespaces=ns)[0] cuf = nfe.xpath('ns:infNFe/ns:ide/ns:cUF/text()', namespaces=ns)[0] uf = [key for key, value in CODIGOS_ESTADOS.items() if value == cuf][0] # tenta encontrar a tag cpf try: cpf = nfe.xpath('ns:infNFe/ns:dest/ns:CPF/text()', namespaces=ns)[0] except IndexError: # em caso de erro tenta procurar a tag cnpj try: cpf = nfe.xpath('ns:infNFe/ns:dest/ns:CNPJ/text()', namespaces=ns)[0] except IndexError: cpf = None total = nfe.xpath('ns:infNFe/ns:total/ns:ICMSTot/ns:vNF/text()', namespaces=ns)[0] # icms = nfe.xpath('ns:infNFe/ns:total/ns:ICMSTot/ns:vICMS/text()', namespaces=ns)[0] digest = nfe.xpath('sig:Signature/sig:SignedInfo/sig:Reference/sig:DigestValue/text()', namespaces=sig)[0].encode() lista_dia = re.findall("-\d{2}", str(data)) dia = str(lista_dia[1]) dia = dia[1:] replacements = {'0': ''} token = re.sub('([0])', lambda m: replacements[m.group()], token) #VERSAO_QRCODE =2 if online: #versão online url = '{}|{}|{}|{}'.format(chave,VERSAO_QRCODE, tpamb, token) else: #versão offline digest = digest.lower() digest = digest.hex() url = '{}|{}|{}|{}|{}|{}|{}'.format( chave,VERSAO_QRCODE,tpamb,dia,total,digest,token ) url_complementar = url + csc url_hash = hashlib.sha1(url_complementar.encode()).digest() url_hash = base64.b16encode(url_hash).decode() url = 'p={}|{}'.format(url, url_hash) # url_chave - Texto com a URL de consulta por chave de acesso a ser impressa no DANFE NFC-e. # Informar a URL da “Consulta por chave de acesso da NFC-e”. # A mesma URL que deve estar informada no DANFE NFC-e para consulta por chave de acesso lista_uf_padrao = ['PR', 'CE', 'RS', 'RJ', 'RO', 'DF'] if uf.upper() in lista_uf_padrao: qrcode = NFCE[uf.upper()]['QR'] + url url_chave = NFCE[uf.upper()]['URL'] elif uf.upper() == 'SP': if tpamb == '1': qrcode = NFCE[uf.upper()]['HTTPS'] + 'www.' + NFCE[uf.upper()]['QR'] + url url_chave = NFCE[uf.upper()]['HTTPS'] + 'www.' + NFCE[uf.upper()]['URL'] else: qrcode = NFCE[uf.upper()]['HTTPS'] + 'www.homologacao.' + NFCE[uf.upper()]['QR'] + url url_chave = NFCE[uf.upper()]['HTTPS'] + 'www.homologacao.' + NFCE[uf.upper()]['URL'] # BA tem comportamento distindo para qrcode e url elif uf.upper() == 'BA': if tpamb == '1': qrcode = NFCE[uf.upper()]['HTTPS'] + NFCE[uf.upper()]['QR'] + url else: qrcode = NFCE[uf.upper()]['HOMOLOGACAO'] + NFCE[uf.upper()]['QR'] + url url_chave = url_chave = NFCE[uf.upper()]['URL'] # AC, AM, RR, PA, else: if tpamb == '1': qrcode = NFCE[uf.upper()]['HTTPS'] + NFCE[uf.upper()]['QR'] + url url_chave = NFCE[uf.upper()]['HTTPS'] + NFCE[uf.upper()]['URL'] else: qrcode = NFCE[uf.upper()]['HOMOLOGACAO'] + NFCE[uf.upper()]['QR'] + url url_chave = NFCE[uf.upper()]['HOMOLOGACAO'] + NFCE[uf.upper()]['URL'] # adicionta tag infNFeSupl com qrcode info = etree.Element('infNFeSupl') etree.SubElement(info, 'qrCode').text = '<![CDATA['+ qrcode.strip() + ']]>' etree.SubElement(info, 'urlChave').text = url_chave nfe.insert(1, info) # correção da tag qrCode, retira caracteres pois e CDATA tnfe = etree.tostring(nfe, encoding='unicode') etree.tostring(nfe.find(".//qrCode"), encoding='unicode') \ .replace('\n','').replace('<','<').replace('>','>').replace('amp;','') nfe = etree.fromstring(tnfe) # retorna nfe com o qrcode incluido NT2015/002 e qrcode if return_qr: return nfe, qrcode.strip() # retorna apenas nfe com o qrcode incluido NT2015/002 else: return nfe
def autorizacao(self, manifesto, id_lote=1, ind_sinc=1): """ Método para realizar autorização do manifesto :param manifesto: XML assinado :param id_lote: Id do lote - numero autoincremental gerado pelo sistema :param ind_sinc: Indicador de sincrono e assincrono, 0 para assincrono, 1 para sincrono :return: Uma tupla que em caso de sucesso, retorna xml com manifesto e protocolo de autorização. Caso contrário, envia todo o soap de resposta da Sefaz para decisão do usuário. """ # url do serviço if ind_sinc == 0: url = self._get_url(consulta='RECEPCAO') elif ind_sinc == 1: url = self._get_url(consulta='RECEPCAO_SINC') else: raise f'ind_sinc deve ser 0=assincrono ou 1=sincrono' # Monta XML do corpo da requisição raiz = etree.Element('enviMDFe', xmlns=NAMESPACE_MDFE, versao=VERSAO_MDFE) etree.SubElement(raiz, 'idLote').text = str( id_lote) # numero autoincremental gerado pelo sistema #etree.SubElement(raiz, 'indSinc').text = str(ind_sinc) # 0 para assincrono, 1 para sincrono raiz.append(manifesto) # Monta XML para envio da requisição if ind_sinc == 0: xml = self._construir_xml_soap('MDFeRecepcao', raiz) elif ind_sinc == 1: xml = self._construir_xml_soap('MDFeRecepcaoSinc', raiz) # Faz request no Servidor da Sefaz retorno = self._post(url, xml) # Em caso de sucesso, retorna xml com o mdfe e protocolo de autorização. # Caso contrário, envia todo o soap de resposta da Sefaz para decisão do usuário. if retorno.status_code == 200: # namespace ns = {'ns': NAMESPACE_MDFE} # Procuta status no xml try: prot = etree.fromstring(retorno.text) except ValueError: # em SP retorno.text apresenta erro prot = etree.fromstring(retorno.content) if ind_sinc == 1: try: # Protocolo com envio OK inf_prot = prot[1][0] lote_status = inf_prot.xpath("ns:retEnviMDFe/ns:cStat", namespaces=ns)[0].text # Lote processado if lote_status == self._edoc_situacao_lote_processado: prot_mdfe = inf_prot.xpath( "ns:retEnviMDFe/ns:protMDFe", namespaces=ns)[0] status = prot_mdfe.xpath('ns:infProt/ns:cStat', namespaces=ns)[0].text # autorizado uso do MDF-e # retorna xml final (protMDFe + MDFe) if status in self._edoc_situacao_ja_enviado: # if status == '100': raiz = etree.Element('mdfeProc', xmlns=NAMESPACE_MDFE, versao=VERSAO_MDFE) raiz.append(manifesto) raiz.append(prot_mdfe) return 0, raiz except IndexError: # Protocolo com algum erro no Envio return 1, retorno, manifesto else: # Retorna id do protocolo para posterior consulta em caso de sucesso. rec = prot[1][0] status = rec.xpath("ns:retEnviMDFe/ns:cStat", namespaces=ns)[0].text # Lote Recebido com Sucesso! if status == self._edoc_situacao_arquivo_recebido_com_sucesso: nrec = rec.xpath("ns:retEnviMDFe/ns:infRec/ns:nRec", namespaces=ns)[0].text return 0, nrec, manifesto return 1, retorno, manifesto
def gerar_qrcode(self, token, csc, xml, return_qr=False): """ Classe para gerar url do qrcode da NFC-e """ # Procura atributos no xml ns = {'ns':'http://www.portalfiscal.inf.br/nfe'} sig = {'sig':'http://www.w3.org/2000/09/xmldsig#'} # Tag Raiz NFe Ex: <NFe> nfe = xml chave = nfe[0].attrib['Id'].replace('NFe','') data = nfe.xpath('ns:infNFe/ns:ide/ns:dhEmi/text()', namespaces=ns)[0].encode() tpamb = nfe.xpath('ns:infNFe/ns:ide/ns:tpAmb/text()', namespaces=ns)[0] cuf = nfe.xpath('ns:infNFe/ns:ide/ns:cUF/text()', namespaces=ns)[0] uf = [key for key, value in CODIGOS_ESTADOS.items() if value == cuf][0] # tenta encontrar a tag cpf try: cpf = nfe.xpath('ns:infNFe/ns:dest/ns:CPF/text()', namespaces=ns)[0] except IndexError: # em caso de erro tenta procurar a tag cnpj try: cpf = nfe.xpath('ns:infNFe/ns:dest/ns:CNPJ/text()', namespaces=ns)[0] except IndexError: cpf = None total = nfe.xpath('ns:infNFe/ns:total/ns:ICMSTot/ns:vNF/text()', namespaces=ns)[0] icms = nfe.xpath('ns:infNFe/ns:total/ns:ICMSTot/ns:vICMS/text()', namespaces=ns)[0] digest = nfe.xpath('sig:Signature/sig:SignedInfo/sig:Reference/sig:DigestValue/text()', namespaces=sig)[0].encode() data = base64.b16encode(data).decode() digest = base64.b16encode(digest).decode() if cpf is None: url = 'chNFe={}&nVersao={}&tpAmb={}&dhEmi={}&vNF={}&vICMS={}&digVal={}&cIdToken={}'.format( chave, VERSAO_QRCODE, tpamb, data.lower(), total, icms, digest.lower(), token) else: url = 'chNFe={}&nVersao={}&tpAmb={}&cDest={}&dhEmi={}&vNF={}&vICMS={}&digVal={}&cIdToken={}'.format( chave, VERSAO_QRCODE, tpamb, cpf, data.lower(), total, icms, digest.lower(), token) url_hash = hashlib.sha1(url.encode()+csc.encode()).digest() url_hash = base64.b16encode(url_hash).decode() url = url + '&cHashQRCode=' + url_hash.upper() if uf.upper() == 'PR': qrcode = NFCE[uf.upper()]['QR'] + url else: if tpamb == '1': qrcode = NFCE[uf.upper()]['HTTPS'] + NFCE[uf.upper()]['QR'] + url else: qrcode = NFCE[uf.upper()]['HOMOLOGACAO'] + NFCE[uf.upper()]['QR'] + url # adicionta tag infNFeSupl com qrcode info = etree.Element('infNFeSupl') etree.SubElement(info, 'qrCode').text = '<![CDATA['+ qrcode.strip() + ']]>' nfe.insert(1, info) # correção da tag qrCode, retira caracteres pois e CDATA tnfe = etree.tostring(nfe, encoding='unicode') etree.tostring(nfe.find(".//qrCode"), encoding='unicode') \ .replace('\n','').replace('<','<').replace('>','>').replace('amp;','') nfe = etree.fromstring(tnfe) # retorna nfe com o qrcode incluido NT2015/002 e qrcode if return_qr: return nfe, qrcode.strip() # retorna apenas nfe com o qrcode incluido NT2015/002 else: return nfe
def gerar_qrcode(self, token, csc, xml, return_qr=False): """ Classe para gerar url do qrcode da NFC-e """ # Procura atributos no xml ns = {'ns':'http://www.portalfiscal.inf.br/nfe'} sig = {'sig':'http://www.w3.org/2000/09/xmldsig#'} # Tag Raiz NFe Ex: <NFe> nfe = xml chave = nfe[0].attrib['Id'].replace('NFe','') data = nfe.xpath('ns:infNFe/ns:ide/ns:dhEmi/text()', namespaces=ns)[0].encode() tpamb = nfe.xpath('ns:infNFe/ns:ide/ns:tpAmb/text()', namespaces=ns)[0] cuf = nfe.xpath('ns:infNFe/ns:ide/ns:cUF/text()', namespaces=ns)[0] uf = [key for key, value in CODIGOS_ESTADOS.items() if value == cuf][0] # tenta encontrar a tag cpf try: cpf = nfe.xpath('ns:infNFe/ns:dest/ns:CPF/text()', namespaces=ns)[0] except IndexError: # em caso de erro tenta procurar a tag cnpj try: cpf = nfe.xpath('ns:infNFe/ns:dest/ns:CNPJ/text()', namespaces=ns)[0] except IndexError: cpf = None total = nfe.xpath('ns:infNFe/ns:total/ns:ICMSTot/ns:vNF/text()', namespaces=ns)[0] icms = nfe.xpath('ns:infNFe/ns:total/ns:ICMSTot/ns:vICMS/text()', namespaces=ns)[0] digest = nfe.xpath('sig:Signature/sig:SignedInfo/sig:Reference/sig:DigestValue/text()', namespaces=sig)[0].encode() data = base64.b16encode(data).decode() digest = base64.b16encode(digest).decode() if cpf is None: url = 'chNFe={}&nVersao={}&tpAmb={}&dhEmi={}&vNF={}&vICMS={}&digVal={}&cIdToken={}'.format( chave, VERSAO_QRCODE, tpamb, data.lower(), total, icms, digest.lower(), token) else: url = 'chNFe={}&nVersao={}&tpAmb={}&cDest={}&dhEmi={}&vNF={}&vICMS={}&digVal={}&cIdToken={}'.format( chave, VERSAO_QRCODE, tpamb, cpf, data.lower(), total, icms, digest.lower(), token) url_hash = hashlib.sha1(url.encode()+csc.encode()).digest() url_hash = base64.b16encode(url_hash).decode() url = url + '&cHashQRCode=' + url_hash.upper() # url_chave - Texto com a URL de consulta por chave de acesso a ser impressa no DANFE NFC-e. # Informar a URL da “Consulta por chave de acesso da NFC-e”. # A mesma URL que deve estar informada no DANFE NFC-e para consulta por chave de acesso lista_uf_padrao = ['PR', 'CE', 'RS', 'RJ', 'RO'] if uf.upper() in lista_uf_padrao: qrcode = NFCE[uf.upper()]['QR'] + url url_chave = NFCE[uf.upper()]['URL'] elif uf.upper() == 'SP': if tpamb == '1': qrcode = NFCE[uf.upper()]['HTTPS'] + 'www.' + NFCE[uf.upper()]['QR'] + url url_chave = NFCE[uf.upper()]['HTTPS'] + 'www.' + NFCE[uf.upper()]['URL'] + url else: qrcode = NFCE[uf.upper()]['HTTPS'] + 'www.homologacao.' + NFCE[uf.upper()]['QR'] + url url_chave = NFCE[uf.upper()]['HTTPS'] + 'www.homologacao.' + NFCE[uf.upper()]['URL'] + url # AC, AM, RR, PA, else: if tpamb == '1': qrcode = NFCE[uf.upper()]['HTTPS'] + NFCE[uf.upper()]['QR'] + url url_chave = NFCE[uf.upper()]['HTTPS'] + NFCE[uf.upper()]['URL'] + url else: qrcode = NFCE[uf.upper()]['HOMOLOGACAO'] + NFCE[uf.upper()]['QR'] + url url_chave = NFCE[uf.upper()]['HOMOLOGACAO'] + NFCE[uf.upper()]['URL'] + url # adicionta tag infNFeSupl com qrcode info = etree.Element('infNFeSupl') etree.SubElement(info, 'qrCode').text = '<![CDATA['+ qrcode.strip() + ']]>' etree.SubElement(info, 'urlChave').text = url_chave nfe.insert(1, info) # correção da tag qrCode, retira caracteres pois e CDATA tnfe = etree.tostring(nfe, encoding='unicode') etree.tostring(nfe.find(".//qrCode"), encoding='unicode') \ .replace('\n','').replace('<','<').replace('>','>').replace('amp;','') nfe = etree.fromstring(tnfe) # retorna nfe com o qrcode incluido NT2015/002 e qrcode if return_qr: return nfe, qrcode.strip() # retorna apenas nfe com o qrcode incluido NT2015/002 else: return nfe
def assinarNfse(self, xml, retorna_string=True): "Assina NFS-e" try: # define variaveis de acordo com autorizador if self.autorizador == 'ginfes': xpath = './/ns2:InfRps' tag = 'InfRps' elif self.autorizador == 'betha': xpath = './/ns1:InfDeclaracaoPrestacaoServico' tag = 'InfDeclaracaoPrestacaoServico' else: raise Exception('Autorizador não encontrado!') xml = etree.fromstring(xml) # define namespaces, pega do proprio xml namespaces = xml.nsmap # No raiz do XML de saida raiz = etree.Element('Signature', xmlns='http://www.w3.org/2000/09/xmldsig#') siginfo = etree.SubElement(raiz, 'SignedInfo') etree.SubElement( siginfo, 'CanonicalizationMethod', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement( siginfo, 'SignatureMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1') # Tenta achar a tag ref = etree.SubElement( siginfo, 'Reference', URI='#' + xml.xpath(xpath, namespaces=namespaces)[0].attrib['Id']) trans = etree.SubElement(ref, 'Transforms') etree.SubElement( trans, 'Transform', Algorithm= 'http://www.w3.org/2000/09/xmldsig#enveloped-signature') etree.SubElement( trans, 'Transform', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement( ref, 'DigestMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#sha1') etree.SubElement(ref, 'DigestValue') etree.SubElement(raiz, 'SignatureValue') keyinfo = etree.SubElement(raiz, 'KeyInfo') etree.SubElement(keyinfo, 'X509Data') rps = xml.xpath(xpath + '/..', namespaces=namespaces)[0] rps.append(raiz) # Escreve no arquivo depois de remover caracteres especiais e parse string with open('nfse.xml', 'w') as arquivo: texto = remover_acentos( etree.tostring(xml, encoding="unicode", pretty_print=False)) # se for tag do Betha if tag == 'InfDeclaracaoPrestacaoServico': texto = texto.replace('ns1:', '').replace(':ns1', '') arquivo.write(texto) subprocess.check_call([ 'xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd', self.senha, '--crypto', 'openssl', '--output', 'nfse.xml', '--id-attr:Id', tag, 'nfse.xml' ]) if retorna_string: return open('nfse.xml', 'r').read() else: return etree.parse('nfse.xml').getroot() except Exception as e: raise e
def _assinar(self, xml, tag, retorna_string=True): """ Método para assinar xml de NFS-e com tags sem ID Consulta de Lote e Consulta por RPS @param tag - raiz do xml que será assinado """ try: xml = etree.fromstring(xml) # No raiz do XML de saida raiz = etree.Element('Signature', xmlns='http://www.w3.org/2000/09/xmldsig#') siginfo = etree.SubElement(raiz, 'SignedInfo') etree.SubElement( siginfo, 'CanonicalizationMethod', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement( siginfo, 'SignatureMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1') # Consulta nao tem id ref = etree.SubElement(siginfo, 'Reference', URI='') trans = etree.SubElement(ref, 'Transforms') etree.SubElement( trans, 'Transform', Algorithm= 'http://www.w3.org/2000/09/xmldsig#enveloped-signature') etree.SubElement( trans, 'Transform', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement( ref, 'DigestMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#sha1') etree.SubElement(ref, 'DigestValue') etree.SubElement(raiz, 'SignatureValue') keyinfo = etree.SubElement(raiz, 'KeyInfo') etree.SubElement(keyinfo, 'X509Data') xml.append(raiz) # Escreve no arquivo depois de remover caracteres especiais e parse string with open('nfse.xml', 'w') as arquivo: arquivo.write( remover_acentos( etree.tostring(xml, encoding="unicode", pretty_print=False).replace('\n', ''))) subprocess.check_call([ 'xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd', self.senha, '--crypto', 'openssl', '--output', 'funfa.xml', '--id-attr:Id', tag, 'nfse.xml' ]) xml = etree.parse('funfa.xml').getroot() if retorna_string: return etree.tostring(xml, encoding="unicode", pretty_print=False).replace('\n', '') else: return xml except Exception as e: raise e
def assinarConsulta(self, xml, retorna_string=True): try: xml = etree.fromstring(xml) # No raiz do XML de saida tag = 'ns1:ConsultarNfseEnvio' # tag que será assinada raiz = etree.Element('Signature', xmlns='http://www.w3.org/2000/09/xmldsig#') siginfo = etree.SubElement(raiz, 'SignedInfo') etree.SubElement( siginfo, 'CanonicalizationMethod', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement( siginfo, 'SignatureMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1') # Consulta nao tem id ref = etree.SubElement(siginfo, 'Reference', URI='') trans = etree.SubElement(ref, 'Transforms') etree.SubElement( trans, 'Transform', Algorithm= 'http://www.w3.org/2000/09/xmldsig#enveloped-signature') etree.SubElement( trans, 'Transform', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement( ref, 'DigestMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#sha1') etree.SubElement(ref, 'DigestValue') etree.SubElement(raiz, 'SignatureValue') keyinfo = etree.SubElement(raiz, 'KeyInfo') etree.SubElement(keyinfo, 'X509Data') consulta = xml.xpath( '/ns1:ConsultarNfseEnvio', namespaces={ 'ns1': 'http://www.ginfes.com.br/servico_consultar_nfse_envio_v03.xsd', 'ns2': 'http://www.ginfes.com.br/tipos_v03.xsd' })[0] consulta.append(raiz) # Escreve no arquivo depois de remover caracteres especiais e parse string with open('nfse.xml', 'w') as arquivo: arquivo.write( remover_acentos( etree.tostring(xml, encoding="unicode", pretty_print=False).replace('\n', ''))) subprocess.check_call([ 'xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd', self.senha, '--crypto', 'openssl', '--output', 'funfa.xml', '--id-attr:Id', tag, 'nfse.xml' ]) xml = etree.parse('funfa.xml').getroot() if retorna_string: return etree.tostring(xml, encoding="unicode", pretty_print=False) else: return xml except Exception as e: raise e
def assinarCancelar(self, xml, retorna_string=True): """ Método que assina o xml para cancelamento de NFS-e """ try: if self.autorizador == 'ginfes': xpath = 'CancelarNfseEnvio' tag = 'CancelarNfseEnvio' namespaces = { 'ns1': 'http://www.ginfes.com.br/servico_cancelar_nfse_envio', 'ns2': 'http://www.ginfes.com.br/tipos' } elif self.autorizador == 'betha': xpath = '/CancelarNfseEnvio/ns1:Pedido' tag = 'InfPedidoCancelamento' namespaces = { 'ns1': 'http://www.betha.com.br/e-nota-contribuinte-ws' } else: raise Exception('Autorizador não encontrado!') xml = etree.fromstring(xml) # No raiz do XML de saida raiz = etree.Element('Signature', xmlns='http://www.w3.org/2000/09/xmldsig#') siginfo = etree.SubElement(raiz, 'SignedInfo') etree.SubElement( siginfo, 'CanonicalizationMethod', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement( siginfo, 'SignatureMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1') # Tenta achar a tag informada no xpath if tag == 'InfPedidoCancelamento': ref = etree.SubElement( siginfo, 'Reference', URI='#' + xml.xpath('.//ns1:' + tag, namespaces=namespaces)[0].attrib['Id']) # ginfes não tem id no cancelamento v2 else: ref = etree.SubElement(siginfo, 'Reference', URI='') trans = etree.SubElement(ref, 'Transforms') etree.SubElement( trans, 'Transform', Algorithm= 'http://www.w3.org/2000/09/xmldsig#enveloped-signature') etree.SubElement( trans, 'Transform', Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') etree.SubElement( ref, 'DigestMethod', Algorithm='http://www.w3.org/2000/09/xmldsig#sha1') etree.SubElement(ref, 'DigestValue') etree.SubElement(raiz, 'SignatureValue') keyinfo = etree.SubElement(raiz, 'KeyInfo') etree.SubElement(keyinfo, 'X509Data') if tag == 'InfPedidoCancelamento': xml = xml.xpath(xpath, namespaces=namespaces)[0] # ginfes só possui a tag root else: xml.append(raiz) # Escreve no arquivo depois de remover caracteres especiais e parse string with open('nfse.xml', 'w') as arquivo: arquivo.write( remover_acentos( etree.tostring(xml, encoding="unicode", pretty_print=False).replace('\n', ''))) subprocess.check_call([ 'xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd', self.senha, '--crypto', 'openssl', '--output', 'funfa.xml', '--id-attr:Id', tag, 'nfse.xml' ]) if retorna_string: return open('funfa.xml', 'r').read() else: return etree.parse('funfa.xml').getroot() except Exception as e: raise e
def autorizacao(self, modelo, nota_fiscal, id_lote=1, ind_sinc=1): """ Método para realizar autorização da nota de acordo com o modelo :param modelo: Modelo :param nota_fiscal: XML assinado :param id_lote: Id do lote - numero autoincremental gerado pelo sistema :param ind_sinc: Indicador de sincrono e assincrono, 0 para assincrono, 1 para sincrono :return: Uma tupla que em caso de sucesso, retorna xml com nfe e protocolo de autorização. Caso contrário, envia todo o soap de resposta da Sefaz para decisão do usuário. """ # url do serviço url = self._get_url(modelo=modelo, consulta='AUTORIZACAO') # Monta XML do corpo da requisição raiz = etree.Element('enviNFe', xmlns=NAMESPACE_NFE, versao=VERSAO_PADRAO) etree.SubElement(raiz, 'idLote').text = str( id_lote) # numero autoincremental gerado pelo sistema etree.SubElement(raiz, 'indSinc').text = str( ind_sinc) # 0 para assincrono, 1 para sincrono raiz.append(nota_fiscal) # Monta XML para envio da requisição xml = self._construir_xml_soap('NFeAutorizacao4', raiz) # Faz request no Servidor da Sefaz retorno = self._post(url, xml) # Em caso de sucesso, retorna xml com nfe e protocolo de autorização. # Caso contrário, envia todo o soap de resposta da Sefaz para decisão do usuário. if retorno.status_code == 200: # namespace ns = {'ns': NAMESPACE_NFE} # Procuta status no xml try: prot = etree.fromstring(retorno.text) except ValueError: # em SP retorno.text apresenta erro prot = etree.fromstring(retorno.content) if ind_sinc == 1: try: # Protocolo com envio OK try: inf_prot = prot[0][0] # root protNFe except IndexError: # Estados como GO vem com a tag header inf_prot = prot[1][0] lote_status = inf_prot.xpath("ns:retEnviNFe/ns:cStat", namespaces=ns)[0].text # Lote processado if lote_status == '104': prot_nfe = inf_prot.xpath("ns:retEnviNFe/ns:protNFe", namespaces=ns)[0] status = prot_nfe.xpath('ns:infProt/ns:cStat', namespaces=ns)[0].text # autorizado usa da NF-e # retorna xml final (protNFe+NFe) if status == '100': raiz = etree.Element('nfeProc', xmlns=NAMESPACE_NFE, versao=VERSAO_PADRAO) raiz.append(nota_fiscal) raiz.append(prot_nfe) return 0, raiz # denegado o uso da NF-e # 110 = Uso Denegado # 301 = Uso Denegado: Irregularidade fiscal do emitente # 302 = Uso Denegado: Irregularidade fiscal do destinatário # 303 = Uso Denegado: Destinatário não habilitado a operar na UF elif status in ["110", "301", "302", "303"]: raiz = etree.Element('nfeProc', xmlns=NAMESPACE_NFE, versao=VERSAO_PADRAO) raiz.append(nota_fiscal) raiz.append(prot_nfe) return 2, raiz except IndexError: # Protocolo com algum erro no Envio return 1, retorno, nota_fiscal else: # Retorna id do protocolo para posterior consulta em caso de sucesso. rec = prot[0][0] status = rec.xpath("ns:retEnviNFe/ns:cStat", namespaces=ns)[0].text # Lote Recebido com Sucesso! if status == '103': nrec = rec.xpath("ns:retEnviNFe/ns:infRec/ns:nRec", namespaces=ns)[0].text return 0, nrec, nota_fiscal return 1, retorno, nota_fiscal