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 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 _serializar_evento(self, evento, tag_raiz="evento", retorna_string=False): # timezone Brasília -03:00 tz = time.strftime("%z") tz = "{}:{}".format(tz[:-2], tz[-2:]) # import ipdb # ipdb.set_trace() raiz = etree.Element(tag_raiz, versao="1.00", xmlns=NAMESPACE_NFE) e = etree.SubElement(raiz, "infEvento", Id=evento.identificador) etree.SubElement(e, "cOrgao").text = CODIGOS_ESTADOS[evento.uf.upper()] etree.SubElement(e, "tpAmb").text = str(self._ambiente) etree.SubElement(e, "CNPJ").text = evento.cnpj # Empresas somente terão CNPJ # etree.SubElement(e, 'CPF').text = '' etree.SubElement(e, "chNFe").text = evento.chave etree.SubElement(e, "dhEvento").text = evento.data_emissao.strftime("%Y-%m-%dT%H:%M:%S") + tz etree.SubElement(e, "tpEvento").text = evento.tp_evento etree.SubElement(e, "nSeqEvento").text = str(evento.n_seq_evento) etree.SubElement(e, "verEvento").text = "1.00" det = etree.SubElement(e, "detEvento", versao="1.00") etree.SubElement(det, "descEvento").text = evento.descricao etree.SubElement(det, "nProt").text = evento.protocolo etree.SubElement(det, "xJust").text = evento.justificativa if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
def _serializar_emitente(self, emitente, tag_raiz="emit", retorna_string=True): raiz = etree.Element(tag_raiz) # Dados do emitente etree.SubElement(raiz, "CNPJ").text = so_numeros(emitente.cnpj) etree.SubElement(raiz, "xNome").text = emitente.razao_social etree.SubElement(raiz, "xFant").text = emitente.nome_fantasia etree.SubElement(raiz, "IE").text = emitente.inscricao_estadual # Endereço endereco = etree.SubElement(raiz, "enderEmit") etree.SubElement(endereco, "xLgr").text = emitente.endereco_logradouro etree.SubElement(endereco, "nro").text = emitente.endereco_numero etree.SubElement(endereco, "xCpl").text = emitente.endereco_complemento etree.SubElement(endereco, "xBairro").text = emitente.endereco_bairro etree.SubElement(endereco, "cMun").text = emitente.endereco_municipio etree.SubElement(endereco, "xMun").text = obter_municipio_por_codigo( emitente.endereco_municipio, emitente.endereco_uf ) etree.SubElement(endereco, "UF").text = emitente.endereco_uf etree.SubElement(endereco, "CEP").text = so_numeros(emitente.endereco_cep) etree.SubElement(endereco, "cPais").text = emitente.endereco_pais etree.SubElement(endereco, "xPais").text = obter_pais_por_codigo(emitente.endereco_pais) etree.SubElement(endereco, "fone").text = emitente.endereco_telefone if retorna_string: return etree.tostring(raiz, pretty_print=True) else: return raiz
def _serializar_consulta(self, consulta, tag_raiz='Consulta', retorna_string=True): raiz = etree.Element(tag_raiz) etree.SubElement(raiz, 'ModeloDocumento').text = 'NFCe' etree.SubElement(raiz, 'Versao').text = self._versao etree.SubElement(raiz, 'tpAmb').text = str(self._ambiente) etree.SubElement(raiz, 'CnpjEmpresa').text = so_numeros(consulta.cnpj) etree.SubElement(raiz, 'CnpjEmissor').text = so_numeros(consulta.cnpj) if consulta.numero_inicial: etree.SubElement(raiz, 'NumeroInicial').text = str(consulta.numero_inicial) if consulta.numero_final: etree.SubElement(raiz, 'NumeroFinal').text = str(consulta.numero_final) etree.SubElement(raiz, 'Serie').text = str(consulta.serie) if consulta.chave_acesso: etree.SubElement(raiz, 'ChaveAcesso').text = str(consulta.chave_acesso) if consulta.data_inicial and consulta.data_final: etree.SubElement( raiz, 'DataEmissaoInicial').text = consulta.data_inicial.strftime("%Y-%m-%d") etree.SubElement( raiz, 'DataEmissaoFinal').text = consulta.data_final.strftime("%Y-%m-%d") if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
def _serializar_permissoes(tag_raiz='Permissoes', retorna_string=True): raiz = etree.Element(tag_raiz) # Permissões referente ao módulo NFC-e p_nfce = etree.SubElement(raiz, 'PermissaoNFCe') etree.SubElement(p_nfce, 'Visualizar').text = "S" etree.SubElement(p_nfce, 'Baixar').text = "S" # Permissões gerais da aplicação p_geral = etree.SubElement(raiz, 'PermissoesGerais') etree.SubElement(p_geral, 'ImportarDocumentos').text = "N" etree.SubElement(p_geral, 'AlterarDadosDoUsuario').text = "S" etree.SubElement(p_geral, 'AlterarDadosDaEmpresa').text = "N" etree.SubElement(p_geral, 'AlterarMarcasDaEmpresa').text = "N" etree.SubElement(p_geral, 'AlterarCertificadosDaEmpresa').text = "S" etree.SubElement(p_geral, 'AlterarConfiguracoesParametros').text = "N" etree.SubElement(p_geral, 'CadastrarEmpresas').text = "N" etree.SubElement(p_geral, 'AlterarCaixasDeEmail').text = "S" etree.SubElement(p_geral, 'AlterarPermissoesDeUsuario').text = "S" etree.SubElement(p_geral, 'AdicionarNovosUsuarios').text = "S" etree.SubElement(p_geral, 'VisualizarChaveAcesso').text = "N" etree.SubElement(p_geral, 'VisualizarAcoesDeUsuarios').text = "S" etree.SubElement(p_geral, 'VisualizarQuantidadesEmitidas').text = "S" etree.SubElement(p_geral, 'VisualizarLicencas').text = "S" etree.SubElement(p_geral, 'ConfiguracaoSenha').text = "N" etree.SubElement(p_geral, 'GerarRelatorios').text = "S" etree.SubElement(p_geral, 'InutilizarDocumentos').text = "S" etree.SubElement(p_geral, 'FerramentasIntegracao').text = "N" if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
def _serializar_parametros_nfce(tag_raiz='NFCe', retorna_string=True): def _serializar_contingencia(tag_raiz='OrdemContingencia', retorna_string=True): raiz = etree.Element(tag_raiz) orderm = etree.SubElement(raiz, 'OrdemContingenciaItem') etree.SubElement(orderm, 'OrdemContingenciaNFCe').text = '0' if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz # Parâmetros referente ao módulo NFC-e raiz = etree.Element(tag_raiz) etree.SubElement( raiz, 'InutilizarAutomaticamenteDocumentosRejeitados').text = 'N' etree.SubElement(raiz, 'InutilizarPulosNumeracao').text = 'N' etree.SubElement(raiz, 'FormaRetornoPDFIntegracao').text = '3' etree.SubElement(raiz, 'FormaRetornoXMLIntegracao').text = '3' etree.SubElement(raiz, 'UltimoNSU').text = '000000000000000' etree.SubElement(raiz, 'IDTokenCscSEFAZ').text = empresa.token etree.SubElement(raiz, 'CscSEFAZ').text = empresa.csc etree.SubElement(raiz, 'PossuiLeituraX').text = 'S' etree.SubElement(raiz, 'PossuiGeracaoRelatorios').text = 'S' raiz.append(_serializar_contingencia(retorna_string=False)) if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
def _serializar_evento(self, evento, tag_raiz='evento', retorna_string=False): # timezone Brasília -03:00 tz = time.strftime("%z") tz = "{}:{}".format(tz[:-2], tz[-2:]) raiz = etree.Element(tag_raiz, versao='1.00', xmlns=NAMESPACE_NFE) e = etree.SubElement(raiz, 'infEvento', Id=evento.identificador) etree.SubElement(e, 'cOrgao').text = CODIGOS_ESTADOS[evento.uf.upper()] etree.SubElement(e, 'tpAmb').text = str(self._ambiente) etree.SubElement(e, 'CNPJ').text = evento.cnpj # Empresas somente terão CNPJ #etree.SubElement(evento, 'CPF').text = '' etree.SubElement(e, 'chNFe').text = evento.chave etree.SubElement(e, 'dhEvento').text = evento.data_emissao.strftime('%Y-%m-%dT%H:%M:%S') + tz etree.SubElement(e, 'tpEvento').text = evento.tp_evento etree.SubElement(e, 'nSeqEvento').text = str(evento.n_seq_evento) etree.SubElement(e, 'verEvento').text = '1.00' det = etree.SubElement(e, 'detEvento', versao='1.00') etree.SubElement(det, 'descEvento').text = evento.descricao etree.SubElement(det, 'nProt').text = evento.protocolo etree.SubElement(det, 'xJust').text = evento.justificativa if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
def _serializar_evento(self, evento, tag_raiz='EnvioEvento', retorna_string=True): raiz = etree.Element(tag_raiz) etree.SubElement(raiz, 'ModeloDocumento').text = 'NFCe' etree.SubElement(raiz, 'Versao').text = self._versao # timezone Brasília -03:00 tz = time.strftime("%z") event = etree.SubElement(raiz, 'Evento') etree.SubElement(event, 'NtfCnpjEmissor').text = so_numeros(evento.cnpj) etree.SubElement(event, 'NtfNumero').text = evento.numero etree.SubElement(event, 'NtfSerie').text = evento.serie etree.SubElement(event, 'tpAmb').text = str(self._ambiente) eve_info = etree.SubElement(event, 'EveInf') etree.SubElement(eve_info, 'EveDh').text = evento.data_emissao.strftime( '%Y-%m-%dT%H:%M:%S') etree.SubElement(eve_info, 'EveFusoHorario').text = "{}:{}".format( tz[:-2], tz[-2:]) etree.SubElement(eve_info, 'EveTp').text = evento.tp_evento etree.SubElement(eve_info, 'EvenSeq').text = str(evento.n_seq_evento) eve_det = etree.SubElement(eve_info, 'Evedet') etree.SubElement(eve_det, 'EveDesc').text = evento.descricao etree.SubElement(eve_det, 'EvenProt').text = evento.protocolo etree.SubElement(eve_det, 'EvexJust').text = evento.justificativa if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
def exportar(self, destino=None, retorna_string=False, limpar=True, **kwargs): """Gera o(s) arquivo(s) de Nota Fiscal eletronica no padrao oficial da SEFAZ e Receita Federal, para ser(em) enviado(s) para o webservice ou para ser(em) armazenado(s) em cache local. @param destino - @param retorna_string - Retorna uma string para debug. @param limpar - Limpa a fonte de dados para não gerar xml com dados duplicados. """ try: # No raiz do XML de saida raiz = etree.Element("NFe", xmlns=NAMESPACE_NFE) # Carrega lista de Notas Fiscais notas_fiscais = self._fonte_dados.obter_lista(_classe=NotaFiscal, **kwargs) for nf in notas_fiscais: raiz.append(self._serializar_nota_fiscal(nf, retorna_string=False)) # Grupo de informaçoes suplementares NT2015.002 # Somente para NFC-e # if nf.modelo == 65: # info = etree.Element('infNFeSupl') # etree.SubElement(info, 'qrCode').text = '' # raiz.append(info) if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=False) else: return raiz except Exception as e: raise e finally: if limpar: self._fonte_dados.limpar_dados()
def _serializar_cliente(self, cliente, tag_raiz='dest', retorna_string=True): raiz = etree.Element(tag_raiz) # Dados do cliente etree.SubElement(raiz, cliente.tipo_documento).text = so_numeros(cliente.numero_documento) etree.SubElement(raiz, 'xNome').text = cliente.razao_social etree.SubElement(raiz, 'IE').text = cliente.inscricao_estadual # Endereço endereco = etree.SubElement(raiz, 'enderDest') etree.SubElement(endereco, 'xLgr').text = cliente.endereco_logradouro etree.SubElement(endereco, 'nro').text = cliente.endereco_numero etree.SubElement(endereco, 'xCpl').text = cliente.endereco_complemento etree.SubElement(endereco, 'xBairro').text = cliente.endereco_bairro etree.SubElement(endereco, 'cMun').text = cliente.endereco_municipio etree.SubElement(endereco, 'xMun').text = obter_municipio_por_codigo( cliente.endereco_municipio, cliente.endereco_uf, ) etree.SubElement(endereco, 'UF').text = cliente.endereco_uf etree.SubElement(endereco, 'CEP').text = so_numeros(cliente.endereco_cep) etree.SubElement(endereco, 'cPais').text = cliente.endereco_pais etree.SubElement(endereco, 'xPais').text = obter_pais_por_codigo(cliente.endereco_pais) etree.SubElement(endereco, 'fone').text = cliente.endereco_telefone if retorna_string: return etree.tostring(raiz, pretty_print=True) else: return raiz
def _serializar_emitente(self, emitente, tag_raiz='emit', retorna_string=True): raiz = etree.Element(tag_raiz) # Dados do emitente etree.SubElement(raiz, 'CNPJ').text = so_numeros(emitente.cnpj) etree.SubElement(raiz, 'xNome').text = emitente.razao_social etree.SubElement(raiz, 'xFant').text = emitente.nome_fantasia etree.SubElement(raiz, 'IE').text = emitente.inscricao_estadual # Endereço endereco = etree.SubElement(raiz, 'enderEmit') etree.SubElement(endereco, 'xLgr').text = emitente.endereco_logradouro etree.SubElement(endereco, 'nro').text = emitente.endereco_numero etree.SubElement(endereco, 'xCpl').text = emitente.endereco_complemento etree.SubElement(endereco, 'xBairro').text = emitente.endereco_bairro etree.SubElement(endereco, 'cMun').text = obter_codigo_por_municipio( emitente.endereco_municipio, emitente.endereco_uf) etree.SubElement(endereco, 'xMun').text = emitente.endereco_municipio etree.SubElement(endereco, 'UF').text = emitente.endereco_uf etree.SubElement(endereco, 'CEP').text = so_numeros(emitente.endereco_cep) etree.SubElement(endereco, 'cPais').text = emitente.endereco_pais etree.SubElement(endereco, 'xPais').text = obter_pais_por_codigo(emitente.endereco_pais) etree.SubElement(endereco, 'fone').text = emitente.endereco_telefone if retorna_string: return etree.tostring(raiz, pretty_print=True) else: return raiz
def _cabecalho_soap(self): u"""Monta o XML do cabeçalho da requisição SOAP""" raiz = etree.Element('cabecMsg', xmlns=NAMESPACE_NFE, versao="1.02") etree.SubElement(raiz, 'versaoDados').text = self._versao return etree.tostring(raiz, encoding='utf-8', xml_declaration=True)
def exportar(self, destino=None, retorna_string=False, limpar=True, **kwargs): """Gera o(s) arquivo(s) de Cancelamento Nota Fiscal eletronica no padrao oficial da migrate, invocity @param destino - @param retorna_string - Retorna uma string para debug. @param limpar - Limpa a fonte de dados para não gerar xml com dados duplicados. """ try: # Carrega lista de Notas Fiscais eventos = self._fonte_dados.obter_lista(_classe=EventoCancelarNotaMigrate, **kwargs) for evento in eventos: raiz = self._serializar_evento(evento, retorna_string=False) if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=False) else: return raiz except Exception as e: raise e finally: if limpar: self._fonte_dados.limpar_dados()
def _antes_de_assinar_ou_verificar(self, raiz): # Converte etree para string xml = etree.tostring(raiz, xml_declaration=True, encoding='utf-8') # Ativa funções criptográficas self._ativar_funcoes_criptograficas() # Colocamos o texto no avaliador XML FIXME: descobrir forma de evitar o uso do libxml2 neste processo doc_xml = libxml2.parseMemory(xml, len(xml)) # Cria o contexto para manipulação do XML via sintaxe XPATH ctxt = doc_xml.xpathNewContext() ctxt.xpathRegisterNs(u'sig', NAMESPACE_SIG) # Separa o nó da assinatura noh_assinatura = ctxt.xpathEval(u'//*/sig:Signature')[0] # Buscamos a chave no arquivo do certificado chave = xmlsec.cryptoAppKeyLoad( filename=str(self.certificado.caminho_arquivo), format=xmlsec.KeyDataFormatPkcs12, pwd=str(self.senha), pwdCallback=None, pwdCallbackCtx=None, ) # Cria a variável de chamada (callable) da função de assinatura assinador = xmlsec.DSigCtx() # Atribui a chave ao assinador assinador.signKey = chave return doc_xml, ctxt, noh_assinatura, assinador
def exportar(self, destino=None, retorna_string=False, limpar=True, **kwargs): """Gera o(s) arquivo(s) de Nota Fiscal eletronica no padrao oficial da SEFAZ e Receita Federal, para ser(em) enviado(s) para o webservice ou para ser(em) armazenado(s) em cache local. @param destino - @param retorna_string - Retorna uma string para debug. @param limpar - Limpa a fonte de dados para não gerar xml com dados duplicados. """ try: # Carrega lista de Notas Fiscais notas_fiscais = self._fonte_dados.obter_lista(_classe=NotaFiscal, **kwargs) for nf in notas_fiscais: raiz = self._serializar_nota_fiscal(nf, retorna_string=False) if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=False) else: return raiz except Exception: raise finally: if limpar: self._fonte_dados.limpar_dados()
def exportar(self, destino=None, retorna_string=False, limpar=True, **kwargs): """Gera o(s) arquivo(s) de Consulta Nota Fiscal eletronica no padrao oficial da migrate, invocity @param destino - @param retorna_string - Retorna uma string para debug. @param limpar - Limpa a fonte de dados para não gerar xml com dados duplicados. """ try: # Carrega lista de Notas Fiscais consultas = self._fonte_dados.obter_lista(_classe=ConsultaPuloNumeracao, **kwargs) for consulta in consultas: raiz = self._serializar_pulo(consulta, retorna_string=False) if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=False) else: return raiz except: raise finally: if limpar: self._fonte_dados.limpar_dados()
def _serializar_parametros(self, empresa, tag_raiz='Parametros', retorna_string=True): def _serializar_parametros_nfce(tag_raiz='NFCe', retorna_string=True): def _serializar_contingencia(tag_raiz='OrdemContingencia', retorna_string=True): raiz = etree.Element(tag_raiz) orderm = etree.SubElement(raiz, 'OrdemContingenciaItem') etree.SubElement(orderm, 'OrdemContingenciaNFCe').text = '0' if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz # Parâmetros referente ao módulo NFC-e raiz = etree.Element(tag_raiz) etree.SubElement( raiz, 'InutilizarAutomaticamenteDocumentosRejeitados').text = 'N' etree.SubElement(raiz, 'InutilizarPulosNumeracao').text = 'N' etree.SubElement(raiz, 'FormaRetornoPDFIntegracao').text = '3' etree.SubElement(raiz, 'FormaRetornoXMLIntegracao').text = '3' etree.SubElement(raiz, 'UltimoNSU').text = '000000000000000' etree.SubElement(raiz, 'IDTokenCscSEFAZ').text = empresa.token etree.SubElement(raiz, 'CscSEFAZ').text = empresa.csc etree.SubElement(raiz, 'PossuiLeituraX').text = 'S' etree.SubElement(raiz, 'PossuiGeracaoRelatorios').text = 'S' raiz.append(_serializar_contingencia(retorna_string=False)) if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz raiz = etree.Element(tag_raiz) etree.SubElement(raiz, 'OrientDANFE').text = '1' etree.SubElement(raiz, 'InfCplVerso').text = 'N' etree.SubElement(raiz, 'DhImpressao').text = 'S' etree.SubElement(raiz, 'ImpTributos').text = '3' etree.SubElement(raiz, 'DescICMS').text = 'N' etree.SubElement(raiz, 'EnviarPDFEmail').text = 'N' etree.SubElement(raiz, 'EnviarXMLEmail').text = 'N' etree.SubElement(raiz, 'ReaprovDocsRejeitados').text = 'N' etree.SubElement(raiz, 'InutPulosNumeracao').text = 'N' etree.SubElement(raiz, 'IdTokenNFCe').text = empresa.token etree.SubElement(raiz, 'CSCNFCe').text = empresa.csc # NFC-e raiz.append(_serializar_parametros_nfce(retorna_string=False)) if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
def nfeInutilizacaoNF(self, raiz): data_hora = datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S') ret = etree.Element('retInutNFe') etree.SubElement(ret, 'versao').text = '1.00' # FIXME xml_dados = raiz.getroot().getchildren()[0].getchildren()[0].getchildren()[1].text xml = etree.tostring(ret, encoding='utf-8', xml_declaration=True) self.write(xml)
def autorizacao(self, nota): # url do serviço url = self._get_url() if self.autorizador == 'BETHA': # xml xml = etree.tostring(nota, encoding='unicode', pretty_print=False) # comunica via wsdl return self._post(url, xml, 'gerar') else: raise Exception('Este método só esta implementado no autorizador betha.')
def _serializar_url_qrcode(self, nota_fiscal, tag_raiz='infNFeSupl', retorna_string=True): raiz = etree.Element(tag_raiz) data = base64.b16encode(nota_fiscal.data_emissao.isoformat()).decode() digest = base64.b16encode(digest).decode() try: cpf = nota_fiscal.emitente.numero_documento except: cpf = None if cpf is None: url = 'chNFe={}&nVersao={}&tpAmb={}&dhEmi={}&vNF={}&vICMS={}&digVal={}&cIdToken={}'.format( nota_fiscal.nota_fiscal.identificador_unico.replace('NFe', ''), VERSAO_QRCODE, self._ambiente, data.lower(), nota_fiscal.valor_total_nota, nota_fiscal.valor_icms, digest.lower(), nota_fiscal.emitente.token) else: url = 'chNFe={}&nVersao={}&tpAmb={}&cDest={}&dhEmi={}&vNF={}&vICMS={}&digVal={}&cIdToken={}'.format( nota_fiscal.nota_fiscal.identificador_unico.replace('NFe', ''), VERSAO_QRCODE, self._ambiente, cpf, data.lower(), nota_fiscal.totais_icms_total_nota, nota_fiscal.totais_icms_total, digest.lower(), nota_fiscal.emitente.token) url_hash = hashlib.sha1(url.encode()+nota_fiscal.emitente.csc.encode()).digest() url_hash = base64.b16encode(url_hash).decode() url = url + '&cHashQRCode=' + url_hash.upper() if nota_fiscal.uf.upper() == 'PR': url_qrcode = NFCE[nota_fiscal.uf.upper()]['QR'] + url else: if self._homologacao: url_qrcode = NFCE[nota_fiscal.uf.upper()]['HOMOLOGACAO'] +\ NFCE[nota_fiscal.uf.upper()]['QR'] + url else: url_qrcode = NFCE[nota_fiscal.uf.upper()]['HTTPS'] +\ NFCE[nota_fiscal.uf.upper()]['QR'] + url print url_qrcode etree.SubElement(raiz, 'qrCode').text = "<![CDATA[%s]]>" % (url_qrcode) if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
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 _serializar_contingencia(tag_raiz='OrdemContingencia', retorna_string=True): raiz = etree.Element(tag_raiz) orderm = etree.SubElement(raiz, 'OrdemContingenciaItem') etree.SubElement(orderm, 'OrdemContingenciaNFCe').text = '0' if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
def _serializar_certificado(self, empresa, tag_raiz='Certificado', retorna_string=True): raiz = etree.Element(tag_raiz) etree.SubElement(raiz, 'ArquivoPFX').text = empresa.certificado_pfx etree.SubElement(raiz, 'Senha').text = empresa.senha_certificado if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
def _serializar_licenciamento(self, empresa, tag_raiz='Licenciamento', retorna_string=True): raiz = etree.Element(tag_raiz) item = etree.SubElement(raiz, 'LicenciamentoItem') etree.SubElement(item, 'Modulo').text = 'NFCe' etree.SubElement(item, 'Modelo').text = '2' if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
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 _serializar_usuario(self, usuario, tag_raiz='Usuarios', retorna_string=True): def _serializar_permissoes(tag_raiz='Permissoes', retorna_string=True): raiz = etree.Element(tag_raiz) # Permissões referente ao módulo NFC-e p_nfce = etree.SubElement(raiz, 'PermissaoNFCe') etree.SubElement(p_nfce, 'Visualizar').text = "S" etree.SubElement(p_nfce, 'Baixar').text = "S" # Permissões gerais da aplicação p_geral = etree.SubElement(raiz, 'PermissoesGerais') etree.SubElement(p_geral, 'ImportarDocumentos').text = "N" etree.SubElement(p_geral, 'AlterarDadosDoUsuario').text = "S" etree.SubElement(p_geral, 'AlterarDadosDaEmpresa').text = "N" etree.SubElement(p_geral, 'AlterarMarcasDaEmpresa').text = "N" etree.SubElement(p_geral, 'AlterarCertificadosDaEmpresa').text = "S" etree.SubElement(p_geral, 'AlterarConfiguracoesParametros').text = "N" etree.SubElement(p_geral, 'CadastrarEmpresas').text = "N" etree.SubElement(p_geral, 'AlterarCaixasDeEmail').text = "S" etree.SubElement(p_geral, 'AlterarPermissoesDeUsuario').text = "S" etree.SubElement(p_geral, 'AdicionarNovosUsuarios').text = "S" etree.SubElement(p_geral, 'VisualizarChaveAcesso').text = "N" etree.SubElement(p_geral, 'VisualizarAcoesDeUsuarios').text = "S" etree.SubElement(p_geral, 'VisualizarQuantidadesEmitidas').text = "S" etree.SubElement(p_geral, 'VisualizarLicencas').text = "S" etree.SubElement(p_geral, 'ConfiguracaoSenha').text = "N" etree.SubElement(p_geral, 'GerarRelatorios').text = "S" etree.SubElement(p_geral, 'InutilizarDocumentos').text = "S" etree.SubElement(p_geral, 'FerramentasIntegracao').text = "N" if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz raiz = etree.Element(tag_raiz) # Dados do usuario item = etree.SubElement(raiz, 'UsuariosItem') etree.SubElement(item, 'UsrNome').text = usuario.user_root_nome etree.SubElement(item, 'UsrEmail').text = usuario.user_root_email etree.SubElement(item, 'UsrSenha').text = usuario.user_root_senha # 1 - Gerente; 2 - Digitador; 3 - Nenhum etree.SubElement(item, 'GrupoUsuario').text = '3' # Permissoes item.append(_serializar_permissoes(retorna_string=False)) if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
def _serializar_empresa(self, empresa, tag_raiz='CadastroEmpresa', retorna_string=True): raiz = etree.Element(tag_raiz) # Dados do empresa etree.SubElement(raiz, 'EmpCNPJ').text = so_numeros(empresa.cnpj) etree.SubElement(raiz, 'EmpRazSocial').text = empresa.razao_social etree.SubElement(raiz, 'EmpNomFantasia').text = empresa.nome_fantasia etree.SubElement(raiz, 'EmpApelido').text = empresa.apelido etree.SubElement(raiz, 'EmpIE').text = empresa.inscricao_estadual # Inscricao Municipal if empresa.inscricao_municipal: etree.SubElement(raiz, 'EmpIM').text = so_numeros(empresa.inscricao_municipal) # Endereço etree.SubElement(raiz, 'EmpEndereco').text = empresa.endereco_logradouro etree.SubElement(raiz, 'EmpNumero').text = empresa.endereco_numero if empresa.endereco_complemento: etree.SubElement(raiz, 'EmpComplemento').text = empresa.endereco_complemento etree.SubElement(raiz, 'EmpBairro').text = empresa.endereco_bairro etree.SubElement(raiz, 'MunCodigo').text = obter_codigo_por_municipio( empresa.endereco_municipio, empresa.endereco_uf) etree.SubElement(raiz, 'EmpCEP').text = so_numeros(empresa.endereco_cep) if empresa.endereco_telefone: etree.SubElement(raiz, 'EmpTelefone').text = empresa.endereco_telefone etree.SubElement(raiz, 'EmpCNAE').text = empresa.cnae_fiscal etree.SubElement(raiz, 'EmpCRT').text = empresa.codigo_de_regime_tributario etree.SubElement(raiz, 'EmpIEST').text = '' etree.SubElement(raiz, 'EmpMarca').text = '' etree.SubElement(raiz, 'EmpMarcaExtensao').text = '' etree.SubElement(raiz, 'EmpEmail').text = empresa.email etree.SubElement(raiz, 'EmpTpoEndereco').text = empresa.tipo_endereco # Certificado raiz.append(self._serializar_certificado(empresa, retorna_string=False)) # Usuarios raiz.append(self._serializar_usuario(empresa, retorna_string=False)) # Parametros raiz.append(self._serializar_parametros(empresa, retorna_string=False)) # Licenciamento raiz.append(self._serializar_licenciamento(empresa, retorna_string=False)) if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
def assinar(self, xml, retorna_string=False): try: # No raiz do XML de saida tag = 'infNFe' # 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') # Tenta achar a tag infNFe try: ref = etree.SubElement(siginfo, 'Reference', URI='#'+xml.findall('infNFe')[0].attrib['Id']) # Caso nao tenha a tag infNFe, procura a tag infEvento except IndexError: tag = 'infEvento' ref = etree.SubElement(siginfo, 'Reference', URI='#'+xml.findall('infEvento')[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') xml.append(raiz) # Escreve no arquivo depois de remover caracteres especiais e parse string with open('testes.xml', 'w') as arquivo: arquivo.write(remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False))) subprocess.call(['xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd', self.senha, '--crypto', 'openssl', '--output', 'funfa.xml', '--id-attr:Id', tag, 'testes.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 _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 _post(self, url, xml): certificado_a1 = CertificadoA1(self.certificado) chave, cert = certificado_a1.separar_arquivo(self.certificado_senha, caminho=True) chave_cert = (cert, chave) # Abre a conexão HTTPS try: xml_declaration = '<?xml version="1.0" encoding="UTF-8"?>' # limpa xml com caracteres bugados para infMDFeSupl em NFC-e xml = re.sub( '<qrCodMDFe>(.*?)</qrCodMDFe>', lambda x: x.group(0).replace( '<', '<').replace('>', '>').replace('amp;', ''), etree.tostring(xml, encoding='unicode').replace('\n', '')) xml = xml_declaration + xml xml = xml.encode( 'utf8') # necessário para o evento "CONSULTAR NÃO ENCERRADOS" print(xml) print('-' * 20) # Faz o request com o servidor result = requests.post(url, xml, headers=self._post_header(), cert=chave_cert, verify=False, timeout=50) result.encoding = 'utf-8' return result except requests.exceptions.Timeout as e: raise e except requests.exceptions.RequestException as e: raise e finally: certificado_a1.excluir()
def _cabecalho(self, retorna_string=True): """ Monta o XML do cabeçalho da requisição wsdl Namespaces padrão homologação (Ginfes) """ xml_declaration = '<?xml version="1.0" encoding="UTF-8"?>' # cabecalho = '<ns2:cabecalho versao="3" xmlns:ns2="http://www.ginfes.com.br/cabecalho_v03.xsd" # xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><versaoDados>3</versaoDados></ns2:cabecalho>' # cabecalho raiz = etree.Element('{%s}cabecalho' % self._namespace, nsmap={ 'ns2': self._namespace, 'xsi': NAMESPACE_XSI }, versao=self._versao) etree.SubElement(raiz, 'versaoDados').text = self._versao if retorna_string: cabecalho = etree.tostring(raiz, encoding='unicode', pretty_print=False).replace('\n', '') cabecalho = xml_declaration + cabecalho return cabecalho else: return raiz
def _serializar_produto_servico(self, produto_servico, tag_raiz='det', retorna_string=True): raiz = etree.Element(tag_raiz) # Produto prod = etree.SubElement(raiz, 'prod') etree.SubElement(prod, 'cProd').text = str(produto_servico.codigo) etree.SubElement(prod, 'cEAN').text = produto_servico.ean etree.SubElement(prod, 'xProd').text = produto_servico.descricao etree.SubElement(prod, 'CFOP').text = produto_servico.cfop etree.SubElement(prod, 'uCom').text = produto_servico.unidade_comercial etree.SubElement(prod, 'qCom').text = str( produto_servico.quantidade_comercial or 0) etree.SubElement(prod, 'vUnCom').text = str( produto_servico.valor_unitario_comercial or 0) etree.SubElement(prod, 'vProd').text = str(produto_servico.valor_total_bruto or 0) etree.SubElement(prod, 'cEANTrib').text = produto_servico.ean_tributavel etree.SubElement(prod, 'uTrib').text = produto_servico.unidade_tributavel etree.SubElement(prod, 'qTrib').text = str( produto_servico.quantidade_tributavel) etree.SubElement(prod, 'vUnTrib').text = str( produto_servico.valor_unitario_tributavel) # Imposto imposto = etree.SubElement(raiz, 'imposto') icms = etree.SubElement(imposto, 'ICMS') icms_item = etree.SubElement( icms, 'ICMS' + produto_servico.icms_situacao_tributaria) etree.SubElement(icms_item, 'orig').text = str(produto_servico.icms_origem) etree.SubElement(icms_item, 'CST').text = produto_servico.icms_situacao_tributaria etree.SubElement(icms_item, 'modBC').text = str( produto_servico.icms_modalidade_determinacao_bc) etree.SubElement(icms_item, 'vBC').text = str( produto_servico.icms_valor_base_calculo) etree.SubElement(icms_item, 'pICMS').text = str(produto_servico.icms_aliquota) etree.SubElement(icms_item, 'vICMS').text = str(produto_servico.icms_valor) pis = etree.SubElement(imposto, 'PIS') pis_item = etree.SubElement(pis, 'PISAliq') etree.SubElement(pis_item, 'CST').text = str( produto_servico.pis_situacao_tributaria) etree.SubElement(pis_item, 'vBC').text = str( produto_servico.pis_valor_base_calculo) etree.SubElement(pis_item, 'pPIS').text = str( produto_servico.pis_aliquota_percentual) etree.SubElement(pis_item, 'vPIS').text = str(produto_servico.pis_valor) cofins = etree.SubElement(imposto, 'COFINS') cofins_item = etree.SubElement(cofins, 'COFINSAliq') etree.SubElement(cofins_item, 'CST').text = str( produto_servico.cofins_situacao_tributaria) etree.SubElement(cofins_item, 'vBC').text = str( produto_servico.cofins_valor_base_calculo) etree.SubElement(cofins_item, 'pCOFINS').text = str( produto_servico.cofins_aliquota_percentual) etree.SubElement(cofins_item, 'vCOFINS').text = str(produto_servico.cofins_valor) if retorna_string: return etree.tostring(raiz, pretty_print=True) else: return raiz
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 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_etree(self, raiz, retorna_xml=False): # Extrai a tag do elemento raiz tipo = extrair_tag(raiz.getroot()) # doctype compatível com o tipo da tag raiz if tipo == u'NFe': doctype = u'<!DOCTYPE NFe [<!ATTLIST infNFe Id ID #IMPLIED>]>' elif tipo == u'inutNFe': doctype = u'<!DOCTYPE inutNFe [<!ATTLIST infInut Id ID #IMPLIED>]>' elif tipo == u'cancNFe': doctype = u'<!DOCTYPE cancNFe [<!ATTLIST infCanc Id ID #IMPLIED>]>' elif tipo == u'DPEC': doctype = u'<!DOCTYPE DPEC [<!ATTLIST infDPEC Id ID #IMPLIED>]>' # Tag de assinatura if raiz.getroot().find('Signature') is None: signature = etree.Element( '{%s}Signature' % NAMESPACE_SIG, URI=raiz.getroot().getchildren()[0].attrib['Id'], nsmap={'sig': NAMESPACE_SIG}, ) signed_info = etree.SubElement(signature, '{%s}SignedInfo' % NAMESPACE_SIG) etree.SubElement( signed_info, 'CanonicalizationMethod', Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315") etree.SubElement( signed_info, 'SignatureMethod', Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1") reference = etree.SubElement( signed_info, '{%s}Reference' % NAMESPACE_SIG, URI=raiz.getroot().getchildren()[0].attrib['Id']) transforms = etree.SubElement( reference, 'Transforms', URI=raiz.getroot().getchildren()[0].attrib['Id']) etree.SubElement( transforms, 'Transform', Algorithm= "http://www.w3.org/2000/09/xmldsig#enveloped-signature") etree.SubElement( transforms, 'Transform', Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315") etree.SubElement( reference, '{%s}DigestMethod' % NAMESPACE_SIG, Algorithm="http://www.w3.org/2000/09/xmldsig#sha1") digest_value = etree.SubElement(reference, '{%s}DigestValue' % NAMESPACE_SIG) signature_value = etree.SubElement( signature, '{%s}SignatureValue' % NAMESPACE_SIG) key_info = etree.SubElement(signature, '{%s}KeyInfo' % NAMESPACE_SIG) x509_data = etree.SubElement(key_info, '{%s}X509Data' % NAMESPACE_SIG) x509_certificate = etree.SubElement( x509_data, '{%s}X509Certificate' % NAMESPACE_SIG) raiz.getroot().insert(0, signature) # Acrescenta a tag de doctype (como o lxml nao suporta alteracao do doctype, # converte para string para faze-lo) xml = etree.tostring(raiz, xml_declaration=True, encoding='utf-8') if xml.find('<!DOCTYPE ') == -1: pos = xml.find('>') + 1 xml = xml[:pos] + doctype + xml[pos:] #raiz = etree.parse(StringIO(xml)) doc_xml, ctxt, noh_assinatura, assinador = self._antes_de_assinar_ou_verificar( raiz) # Realiza a assinatura assinador.sign(noh_assinatura) # Coloca na instância Signature os valores calculados digest_value.text = ctxt.xpathEval( u'//sig:DigestValue')[0].content.replace(u'\n', u'') signature_value.text = ctxt.xpathEval( u'//sig:SignatureValue')[0].content.replace(u'\n', u'') # Provavelmente retornarão vários certificados, já que o xmlsec inclui a cadeia inteira certificados = ctxt.xpathEval(u'//sig:X509Data/sig:X509Certificate') x509_certificate.text = certificados[len(certificados) - 1].content.replace(u'\n', u'') resultado = assinador.status == xmlsec.DSigStatusSucceeded # Gera o XML para retornar xml = doc_xml.serialize() # Limpa objetos da memoria e desativa funções criptográficas self._depois_de_assinar_ou_verificar(doc_xml, ctxt, assinador) if retorna_xml: return xml else: return etree.parse(StringIO(xml))
def _serializar_produto_servico(self, produto_servico, modelo, tag_raiz='det', retorna_string=True): raiz = etree.Element(tag_raiz) # Produto prod = etree.SubElement(raiz, 'prod') etree.SubElement(prod, 'cProd').text = str(produto_servico.codigo) etree.SubElement(prod, 'cEAN').text = produto_servico.ean etree.SubElement(prod, 'xProd').text = produto_servico.descricao etree.SubElement(prod, 'NCM').text = produto_servico.ncm # Codificação opcional que detalha alguns NCM. Formato: duas letras maiúsculas e 4 algarismos. Se a mercadoria se enquadrar em mais de uma codificação, informar até 8 codificações principais. #etree.SubElement(prod, 'NVE').text = '' etree.SubElement(prod, 'CFOP').text = produto_servico.cfop etree.SubElement(prod, 'uCom').text = produto_servico.unidade_comercial etree.SubElement(prod, 'qCom').text = str( produto_servico.quantidade_comercial or 0) etree.SubElement(prod, 'vUnCom').text = str('{:.2f}').format( produto_servico.valor_unitario_comercial or 0) etree.SubElement(prod, 'vProd').text = str('{:.2f}').format( produto_servico.valor_total_bruto or 0) etree.SubElement(prod, 'cEANTrib').text = produto_servico.ean_tributavel etree.SubElement(prod, 'uTrib').text = produto_servico.unidade_tributavel etree.SubElement(prod, 'qTrib').text = str( produto_servico.quantidade_tributavel) etree.SubElement(prod, 'vUnTrib').text = str('{:.2f}').format( produto_servico.valor_unitario_tributavel) """ Indica se valor do Item (vProd) entra no valor total da NF-e (vProd) 0=Valor do item (vProd) não compõe o valor total da NF-e 1=Valor do item (vProd) compõe o valor total da NF-e (vProd) (v2.0) """ etree.SubElement(prod, 'indTot').text = str(produto_servico.ind_total) # Imposto imposto = etree.SubElement(raiz, 'imposto') # Lei da transparencia # Tributos aprox por item if produto_servico.valor_tributos_aprox: etree.SubElement( imposto, 'vTotTrib').text = produto_servico.valor_tributos_aprox ### ICMS icms = etree.SubElement(imposto, 'ICMS') icms_csosn = ('102', '103', '300', '400') if produto_servico.icms_modalidade in icms_csosn: icms_item = etree.SubElement( icms, 'ICMSSN' + produto_servico.icms_modalidade) etree.SubElement(icms_item, 'orig').text = str(produto_servico.icms_origem) etree.SubElement(icms_item, 'CSOSN').text = produto_servico.icms_csosn elif produto_servico.icms_modalidade == '101': icms_item = etree.SubElement( icms, 'ICMS' + produto_servico.icms_modalidade) etree.SubElement(icms_item, 'orig').text = str(produto_servico.icms_origem) etree.SubElement(icms_item, 'CSOSN').text = produto_servico.icms_csosn etree.SubElement( icms_item, 'pCredSN' ).text = '' # Alíquota aplicável de cálculo do crédito (Simples Nacional). etree.SubElement( icms_item, 'vCredICMSSN' ).text = '' # Valor crédito do ICMS que pode ser aproveitado nos termos do art. 23 da LC 123 (Simples Nacional) elif produto_servico.icms_modalidade == 'ST': icms_item = etree.SubElement( icms, 'ICMS' + produto_servico.icms_modalidade) etree.SubElement(icms_item, 'orig').text = str(produto_servico.icms_origem) etree.SubElement(icms_item, 'CST').text = '41' # Nao tributado etree.SubElement( icms_item, 'vBCSTRet' ).text = '' # Informar o valor da BC do ICMS ST retido na UF remetente etree.SubElement( icms_item, 'vICMSSTRet' ).text = '' # Informar o valor do ICMS ST retido na UF remetente etree.SubElement( icms_item, 'vBCSTDest' ).text = '' # Informar o valor da BC do ICMS ST da UF destino etree.SubElement( icms_item, 'vICMSSTDest' ).text = '' # Informar o valor do ICMS ST da UF destino else: # FIXME ### OUTROS TIPOS DE ICMS etree.SubElement(icms_item, 'modBC').text = str( produto_servico.icms_modalidade_determinacao_bc) etree.SubElement(icms_item, 'vBC').text = str( produto_servico.icms_valor_base_calculo) etree.SubElement(icms_item, 'pICMS').text = str(produto_servico.icms_aliquota) etree.SubElement(icms_item, 'vICMS').text = str(produto_servico.icms_valor) # apenas nfe pisnt = ('04', '05', '06', '07', '08', '09') if modelo == 55: ## PIS pis = etree.SubElement(imposto, 'PIS') if produto_servico.pis_modalidade in pisnt: pis_item = etree.SubElement(pis, 'PISNT') etree.SubElement(pis_item, 'CST').text = produto_servico.pis_modalidade elif produto_servico.pis_modalidade == '01' or produto_servico.pis_modalidade == '02': pis_item = etree.SubElement(pis, 'PISAliq') etree.SubElement(pis_item, 'CST').text = produto_servico.pis_modalidade etree.SubElement( pis_item, 'vBC').text = produto_servico.pis_valor_base_calculo etree.SubElement( pis_item, 'pPIS').text = produto_servico.pis_aliquota_percentual etree.SubElement(pis_item, 'vPIS').text = produto_servico.pis_valor elif produto_servico.pis_modalidade == '03': pis_item = etree.SubElement(pis, 'PISQtde') etree.SubElement(pis_item, 'CST').text = produto_servico.pis_modalidade etree.SubElement( pis_item, 'qBCProd').text = produto_servico.quantidade_comercial etree.SubElement( pis_item, 'vAliqProd').text = produto_servico.pis_aliquota_percentual etree.SubElement( pis_item, 'vPIS').text = produto_servico.pis_valor_base_calculo else: pis_item = etree.SubElement(pis, 'PISOutr') etree.SubElement(pis_item, 'CST').text = produto_servico.pis_modalidade etree.SubElement( pis_item, 'vBC').text = produto_servico.pis_valor_base_calculo etree.SubElement( pis_item, 'pPIS').text = produto_servico.pis_aliquota_percentual etree.SubElement( pis_item, 'qBCProd').text = produto_servico.quantidade_comercial etree.SubElement( pis_item, 'vAliqProd').text = produto_servico.pis_aliquota_percentual etree.SubElement( pis_item, 'vPIS').text = produto_servico.pis_valor_base_calculo ## PISST # pis_item = etree.SubElement(pis, 'PISST') # etree.SubElement(pis_item, 'vBC').text = produto_servico.pis_valor_base_calculo # etree.SubElement(pis_item, 'pPIS').text = produto_servico.pis_aliquota_percentual # etree.SubElement(pis_item, 'qBCProd').text = produto_servico.quantidade_comercial # etree.SubElement(pis_item, 'vAliqProd').text = produto_servico.pis_aliquota_percentual # etree.SubElement(pis_item, 'vPIS').text = produto_servico.pis_valor_base_calculo cofinsnt = ('04', '05', '06', '07', '08', '09') ## COFINS cofins = etree.SubElement(imposto, 'COFINS') if produto_servico.cofins_modalidade in cofinsnt: cofins_item = etree.SubElement(cofins, 'COFINSNT') etree.SubElement( cofins_item, 'CST').text = produto_servico.cofins_modalidade elif produto_servico.cofins_modalidade == '01' or produto_servico.cofins_modalidade == '02': cofins_item = etree.SubElement(cofins, 'COFINSAliq') etree.SubElement( cofins_item, 'CST').text = produto_servico.cofins_modalidade etree.SubElement( cofins_item, 'vBC').text = produto_servico.cofins_valor_base_calculo etree.SubElement( cofins_item, 'pCOFINS' ).text = produto_servico.cofins_aliquota_percentual etree.SubElement(cofins_item, 'vCOFINS').text = produto_servico.cofins_valor elif produto_servico.cofins_modalidade == '03': cofins_item = etree.SubElement(cofins, 'COFINSQtde') etree.SubElement( cofins_item, 'CST').text = produto_servico.cofins_modalidade etree.SubElement( cofins_item, 'qBCProd').text = produto_servico.quantidade_comercial etree.SubElement( cofins_item, 'vAliqProd' ).text = produto_servico.cofins_aliquota_percentual etree.SubElement(cofins_item, 'vCOFINS').text = produto_servico.cofins_valor else: cofins_item = etree.SubElement(cofins, 'COFINSOutr') etree.SubElement( cofins_item, 'CST').text = produto_servico.cofins_modalidade etree.SubElement( cofins_item, 'vBC').text = produto_servico.cofins_valor_base_calculo etree.SubElement( cofins_item, 'pCOFINS' ).text = produto_servico.cofins_aliquota_percentual etree.SubElement( cofins_item, 'vAliqProd' ).text = produto_servico.cofins_aliquota_percentual etree.SubElement(cofins_item, 'vCOFINS').text = produto_servico.cofins_valor ## COFINSST # cofins_item = etree.SubElement(cofins, 'COFINSOutr') # etree.SubElement(cofins_item, 'vBC').text = produto_servico.cofins_valor_base_calculo # etree.SubElement(cofins_item, 'pCOFINS').text = produto_servico.cofins_aliquota_percentual # etree.SubElement(cofins_item, 'qBCProd').text = produto_servico.quantidade_comercial # etree.SubElement(cofins_item, 'vAliqProd').text = produto_servico.cofins_aliquota_percentual # etree.SubElement(cofins_item, 'vCOFINS').text = produto_servico.cofins_valor if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
def _serializar_nota_fiscal(self, nota_fiscal, tag_raiz='infNFe', retorna_string=True): #raiz = etree.Element('NFe', xmlns='http://www.portalfiscal.inf.br/nfe') raiz = etree.Element(tag_raiz, versao=self._versao) # 'Id' da tag raiz # Ex.: NFe35080599999090910270550010000000011518005123 raiz.attrib['Id'] = nota_fiscal.identificador_unico # timezone Brasília -03:00 tz = time.strftime("%z") tz = "{}:{}".format(tz[:-2], tz[-2:]) # Dados da Nota Fiscal ide = etree.SubElement(raiz, 'ide') etree.SubElement(ide, 'cUF').text = CODIGOS_ESTADOS[nota_fiscal.uf] etree.SubElement(ide, 'cNF').text = nota_fiscal.codigo_numerico_aleatorio etree.SubElement(ide, 'natOp').text = nota_fiscal.natureza_operacao etree.SubElement(ide, 'indPag').text = str(nota_fiscal.forma_pagamento) etree.SubElement(ide, 'mod').text = str(nota_fiscal.modelo) etree.SubElement(ide, 'serie').text = nota_fiscal.serie etree.SubElement(ide, 'nNF').text = str(nota_fiscal.numero_nf) etree.SubElement( ide, 'dhEmi' ).text = nota_fiscal.data_emissao.strftime('%Y-%m-%dT%H:%M:%S') + tz #etree.SubElement(ide, 'dhSaiEnt').text = nota_fiscal.data_saida_entrada.strftime('%Y-%m-%dT%H:%M:%S') + tz """dhCont Data e Hora da entrada em contingência E B01 D 0-1 Formato AAAA-MM-DDThh:mm:ssTZD (UTC - Universal Coordinated Time) Exemplo: no formato UTC para os campos de Data-Hora, "TZD" pode ser -02:00 (Fernando de Noronha), -03:00 (Brasília) ou -04:00 (Manaus), no horário de verão serão -01:00, -02:00 e -03:00. Exemplo: "2010-08-19T13:00:15-03:00". """ etree.SubElement(ide, 'tpNF').text = str( nota_fiscal.tipo_documento) # 0=entrada 1=saida """ nfce suporta apenas operação interna Identificador de local de destino da operação 1=Operação interna;2=Operação interestadual;3=Operação com exterior. """ if nota_fiscal.modelo == 65: etree.SubElement(ide, 'idDest').text = str(1) else: etree.SubElement(ide, 'idDest').text = str( nota_fiscal.indicador_destino) etree.SubElement(ide, 'cMunFG').text = nota_fiscal.municipio etree.SubElement(ide, 'tpImp').text = str(nota_fiscal.tipo_impressao_danfe) """ ### CONTINGENCIA ### 1=Emissão normal (não em contingência); 2=Contingência FS-IA, com impressão do DANFE em formulário de segurança; 3=Contingência SCAN (Sistema de Contingência do Ambiente Nacional); 4=Contingência DPEC (Declaração Prévia da Emissão em Contingência); 5=Contingência FS-DA, com impressão do DANFE em formulário de segurança; 6=Contingência SVC-AN (SEFAZ Virtual de Contingência do AN); 7=Contingência SVC-RS (SEFAZ Virtual de Contingência do RS); 9=Contingência off-line da NFC-e (as demais opções de contingência são válidas também para a NFC-e). Para a NFC-e somente estão disponíveis e são válidas as opções de contingência 5 e 9. """ if self._contingencia != None: if nota_fiscal.forma_emissao == '1': nota_fiscal.forma_emissao = '9' etree.SubElement(ide, 'tpEmis').text = str(nota_fiscal.forma_emissao) etree.SubElement(ide, 'cDV').text = nota_fiscal.dv_codigo_numerico_aleatorio etree.SubElement(ide, 'tpAmb').text = str(self._ambiente) etree.SubElement(ide, 'finNFe').text = str(nota_fiscal.finalidade_emissao) if nota_fiscal.modelo == 65: etree.SubElement(ide, 'indFinal').text = str(1) etree.SubElement(ide, 'indPres').text = str(1) else: etree.SubElement(ide, 'indFinal').text = str(nota_fiscal.cliente_final) etree.SubElement(ide, 'indPres').text = str( nota_fiscal.indicador_presencial) etree.SubElement(ide, 'procEmi').text = str(nota_fiscal.processo_emissao) etree.SubElement( ide, 'verProc').text = '%s %s' % (self._nome_aplicacao, nota_fiscal.versao_processo_emissao) ### CONTINGENCIA ### if self._contingencia != None: etree.SubElement( ide, 'dhCont' ).text = nota_fiscal.data_emissao.strftime( '%Y-%m-%dT%H:%M:%S' ) + tz # Data e Hora da entrada em contingência AAAA-MM-DDThh:mm:ssTZD etree.SubElement( ide, 'xJust' ).text = nota_fiscal.self._contingencia # Justificativa da entrada em contingência (min 20, max 256 caracteres) # Emitente raiz.append( self._serializar_emitente(nota_fiscal.emitente, retorna_string=False)) # Destinatário try: raiz.append( self._serializar_cliente(nota_fiscal.cliente, modelo=nota_fiscal.modelo, retorna_string=False)) except AttributeError as e: # NFC-e pode ser gerada sem destinatário if nota_fiscal.modelo == 65: pass else: raise e # Retirada if nota_fiscal.retirada: raiz.append( self._serializar_entrega_retirada( nota_fiscal.retirada, retorna_string=False, tag_raiz='retirada', )) # Entrega if nota_fiscal.entrega: raiz.append( self._serializar_entrega_retirada( nota_fiscal.entrega, retorna_string=False, tag_raiz='entrega', )) # Itens for num, item in enumerate(nota_fiscal.produtos_e_servicos): det = self._serializar_produto_servico(item, modelo=nota_fiscal.modelo, retorna_string=False) det.attrib['nItem'] = str(num + 1) raiz.append(det) # Totais total = etree.SubElement(raiz, 'total') icms_total = etree.SubElement(total, 'ICMSTot') #etree.SubElement(icms_total, 'vBC').text = str(nota_fiscal.totais_icms_base_calculo) etree.SubElement(icms_total, 'vBC').text = str('{:.2f}').format( nota_fiscal.totais_icms_base_calculo) etree.SubElement(icms_total, 'vICMS').text = str('{:.2f}').format( nota_fiscal.totais_icms_total) etree.SubElement(icms_total, 'vICMSDeson').text = str('{:.2f}').format( nota_fiscal.totais_icms_desonerado ) # Valor Total do ICMS desonerado etree.SubElement(icms_total, 'vBCST').text = str('{:.2f}').format( nota_fiscal.totais_icms_st_base_calculo) etree.SubElement(icms_total, 'vST').text = str('{:.2f}').format( nota_fiscal.totais_icms_st_total) etree.SubElement(icms_total, 'vProd').text = str('{:.2f}').format( nota_fiscal.totais_icms_total_produtos_e_servicos) etree.SubElement(icms_total, 'vFrete').text = str('{:.2f}').format( nota_fiscal.totais_icms_total_frete) etree.SubElement(icms_total, 'vSeg').text = str('{:.2f}').format( nota_fiscal.totais_icms_total_seguro) etree.SubElement(icms_total, 'vDesc').text = str('{:.2f}').format( nota_fiscal.totais_icms_total_desconto) # Tributos etree.SubElement(icms_total, 'vII').text = str('{:.2f}').format( nota_fiscal.totais_icms_total_ii) etree.SubElement(icms_total, 'vIPI').text = str('{:.2f}').format( nota_fiscal.totais_icms_total_ipi) etree.SubElement(icms_total, 'vPIS').text = str('{:.2f}').format( nota_fiscal.totais_icms_pis) etree.SubElement(icms_total, 'vCOFINS').text = str('{:.2f}').format( nota_fiscal.totais_icms_cofins) etree.SubElement(icms_total, 'vOutro').text = str('{:.2f}').format( nota_fiscal.totais_icms_outras_despesas_acessorias) etree.SubElement(icms_total, 'vNF').text = str('{:.2f}').format( nota_fiscal.totais_icms_total_nota) if nota_fiscal.totais_tributos_aproximado: etree.SubElement(icms_total, 'vTotTrib').text = str('{:.2f}').format( nota_fiscal.totais_tributos_aproximado) # Apenas NF-e if nota_fiscal.modelo == 55: # Transporte transp = etree.SubElement(raiz, 'transp') etree.SubElement(transp, 'modFrete').text = str( nota_fiscal.transporte_modalidade_frete) # Transportadora if nota_fiscal.transporte_transportadora: transp.append( self._serializar_transportadora( nota_fiscal.transporte_transportadora, retorna_string=False, )) # Veículo veiculo = etree.SubElement(transp, 'veicTransp') etree.SubElement( veiculo, 'placa' ).text = nota_fiscal.transporte_veiculo_placa # Obrigatório EX: XXX9999 etree.SubElement(veiculo, 'UF').text = nota_fiscal.transporte_veiculo_uf etree.SubElement( veiculo, 'RNTC').text = nota_fiscal.transporte_veiculo_rntc # Reboque reboque = etree.SubElement(transp, 'reboque') etree.SubElement( reboque, 'placa').text = nota_fiscal.transporte_reboque_placa etree.SubElement(reboque, 'UF').text = nota_fiscal.transporte_reboque_uf etree.SubElement( reboque, 'RNTC').text = nota_fiscal.transporte_reboque_rntc # Volumes for volume in nota_fiscal.transporte_volumes: vol = etree.SubElement(transp, 'vol') etree.SubElement(vol, 'qVol').text = str(volume.quantidade) etree.SubElement(vol, 'esp').text = volume.especie etree.SubElement(vol, 'marca').text = volume.marca etree.SubElement(vol, 'nVol').text = volume.numeracao etree.SubElement(vol, 'pesoL').text = str(volume.peso_liquido) etree.SubElement(vol, 'pesoB').text = str(volume.peso_bruto) # Lacres lacres = etree.SubElement(vol, 'lacres') for lacre in volume.lacres: etree.SubElement(lacres, 'nLacre').text = lacre.numero_lacre # Somente NFC-e if nota_fiscal.modelo == 65: # Transporte transp = etree.SubElement(raiz, 'transp') etree.SubElement(transp, 'modFrete').text = str(9) # Pagamento pag = etree.SubElement(raiz, 'pag') etree.SubElement(pag, 'tPag').text = str( nota_fiscal.tipo_pagamento ).zfill( 2 ) # 01=Dinheiro 02=Cheque 03=Cartão de Crédito 04=Cartão de Débito 05=Crédito Loja 10=Vale Alimentação 11=Vale Refeição 12=Vale Presente 13=Vale Combustível 99=Outros etree.SubElement(pag, 'vPag').text = str('{:.2f}').format( nota_fiscal.totais_icms_total_nota) #etree.SubElement(pag, 'card').text = '' #etree.SubElement(pag, 'CNPJ').text = '' # Informar o CNPJ da Credenciadora de cartão de crédito / débito #etree.SubElement(pag, 'tBand').text = '' # 01=Visa 02=Mastercard 03=American Express 04=Sorocred 99=Outros #etree.SubElement(pag, 'cAut').text = '' # Identifica o número da autorização da transação da operação com cartão de crédito e/ou débito # Informações adicionais if nota_fiscal.informacoes_adicionais_interesse_fisco or nota_fiscal.informacoes_complementares_interesse_contribuinte: info_ad = etree.SubElement(raiz, 'infAdic') if nota_fiscal.informacoes_adicionais_interesse_fisco: etree.SubElement( info_ad, 'infAdFisco' ).text = nota_fiscal.informacoes_adicionais_interesse_fisco if nota_fiscal.informacoes_complementares_interesse_contribuinte: etree.SubElement( info_ad, 'infCpl' ).text = nota_fiscal.informacoes_complementares_interesse_contribuinte if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
f.close() #a1 = AssinaturaA1(certificado, "1234") #xml = a1.assinar(xml) res = post(xml, url) f = open("file.txt", "w") a = str(res.content) f.write(a) f.close() print(a) ''' #''' certificado_a1 = CertificadoA1(certificado) chave, cert = certificado_a1.separar_arquivo(senha, caminho=True) chave_cert = (cert, chave) f = open("xmlfuncional.xml", "r") a1 = AssinaturaA1(certificado, senha) xml = etree.XML(f.read()) xml = a1.assinar(xml) print(etree.tostring(xml)) #a1 = AssinaturaA1(certificado, "1234") #xml = a1.assinar(xml) #print(etree.tostring(xml)) res = mdfe.post(xml, url, chave_cert) f = open("file.txt", "w") a = str(res.content) f.write(a) f.close() print(a) #'''
def _serializar_cliente(self, cliente, modelo, tag_raiz='dest', retorna_string=True): raiz = etree.Element(tag_raiz) # Dados do cliente (distinatario) etree.SubElement(raiz, cliente.tipo_documento).text = so_numeros( cliente.numero_documento) if cliente.razao_social: etree.SubElement(raiz, 'xNome').text = cliente.razao_social if not self._so_cpf: endereco = etree.SubElement(raiz, 'enderDest') etree.SubElement(endereco, 'xLgr').text = cliente.endereco_logradouro etree.SubElement(endereco, 'nro').text = cliente.endereco_numero if cliente.endereco_complemento: etree.SubElement(endereco, 'xCpl').text = cliente.endereco_complemento etree.SubElement(endereco, 'xBairro').text = cliente.endereco_bairro etree.SubElement(endereco, 'cMun').text = obter_codigo_por_municipio( cliente.endereco_municipio, cliente.endereco_uf) etree.SubElement(endereco, 'xMun').text = cliente.endereco_municipio etree.SubElement(endereco, 'UF').text = cliente.endereco_uf etree.SubElement(endereco, 'CEP').text = so_numeros(cliente.endereco_cep) etree.SubElement(endereco, 'cPais').text = cliente.endereco_pais etree.SubElement(endereco, 'xPais').text = obter_pais_por_codigo( cliente.endereco_pais) if cliente.endereco_telefone: etree.SubElement(endereco, 'fone').text = cliente.endereco_telefone #Indicador da IE do destinatário: 1 – Contribuinte ICMSpagamento à vista; 2 – Contribuinte isento de inscrição; 9 – Não Contribuinte if cliente.isento_icms or cliente.inscricao_estadual.upper( ) == 'ISENTO': etree.SubElement(raiz, 'indIEDest').text = str(2) etree.SubElement(raiz, 'IE').text = 'ISENTO' elif cliente.indicador_ie == 9: # 9 – Não Contribuinte etree.SubElement(raiz, 'indIEDest').text = str(9) else: # Indicador da IE do destinatário: 1 – Contribuinte ICMSpagamento à vista; etree.SubElement(raiz, 'indIEDest').text = cliente.indicador_ie etree.SubElement(raiz, 'IE').text = cliente.inscricao_estadual # Suframa if cliente.inscricao_suframa: etree.SubElement(raiz, 'ISUF').text = cliente.inscricao_suframa # Inscrição Municipal do tomador do serviço if cliente.inscricao_municipal: etree.SubElement(raiz, 'IM').text = cliente.inscricao_municipal # E-mail if cliente.email: etree.SubElement(raiz, 'email').text = cliente.email if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
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 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 _serializar_produto_servico(self, produto_servico, modelo, tag_raiz='det', retorna_string=True): raiz = etree.Element(tag_raiz) # Produto prod = etree.SubElement(raiz, 'prod') etree.SubElement(prod, 'cProd').text = str(produto_servico.codigo) etree.SubElement(prod, 'cEAN').text = produto_servico.ean etree.SubElement(prod, 'xProd').text = produto_servico.descricao etree.SubElement(prod, 'NCM').text = produto_servico.ncm # Codificação opcional que detalha alguns NCM. Formato: duas letras maiúsculas e 4 algarismos. # Se a mercadoria se enquadrar em mais de uma codificação, informar até 8 codificações principais. #etree.SubElement(prod, 'NVE').text = '' etree.SubElement(prod, 'CFOP').text = produto_servico.cfop etree.SubElement(prod, 'uCom').text = produto_servico.unidade_comercial etree.SubElement(prod, 'qCom').text = str(produto_servico.quantidade_comercial or 0) etree.SubElement(prod, 'vUnCom').text = str('{:.4f}').format(produto_servico.valor_unitario_comercial or 0) """ Código Especificador da Substituição Tributária – CEST, que estabelece a sistemática de uniformização e identificação das mercadorias e bens passíveis de sujeição aos regimes de substituição tributária e de antecipação de recolhimento do ICMS. """ #if produto_servico.cest: # etree.SubElement(prod, 'CEST').text = produto_servico.cest etree.SubElement(prod, 'vProd').text = str('{:.2f}').format(produto_servico.valor_total_bruto or 0) etree.SubElement(prod, 'cEANTrib').text = produto_servico.ean_tributavel etree.SubElement(prod, 'uTrib').text = produto_servico.unidade_tributavel etree.SubElement(prod, 'qTrib').text = str(produto_servico.quantidade_tributavel) etree.SubElement(prod, 'vUnTrib').text = '{:.4f}'.format(produto_servico.valor_unitario_tributavel or 0) """ Indica se valor do Item (vProd) entra no valor total da NF-e (vProd) 0=Valor do item (vProd) não compõe o valor total da NF-e 1=Valor do item (vProd) compõe o valor total da NF-e (vProd) (v2.0) """ etree.SubElement(prod, 'indTot').text = str(produto_servico.ind_total) """ Informação de interesse do emissor para controle do B2B.(v2.0) """ # Número do Pedido de Compra. Tam 1-15 if produto_servico.numero_pedido: etree.SubElement(prod, 'xPed').text = str(produto_servico.numero_pedido) # Item do Pedido de Compra. Tam 6 if produto_servico.numero_item: etree.SubElement(prod, 'nItemPed').text = str(produto_servico.numero_item) # Imposto imposto = etree.SubElement(raiz, 'imposto') # Lei da transparencia # Tributos aprox por item if produto_servico.valor_tributos_aprox: etree.SubElement(imposto, 'vTotTrib').text = produto_servico.valor_tributos_aprox ### ICMS icms = etree.SubElement(imposto, 'ICMS') icms_csosn = ('102', '103', '300', '400') if produto_servico.icms_modalidade in icms_csosn: icms_item = etree.SubElement(icms, 'ICMSSN'+produto_servico.icms_modalidade) etree.SubElement(icms_item, 'orig').text = str(produto_servico.icms_origem) etree.SubElement(icms_item, 'CSOSN').text = produto_servico.icms_csosn elif produto_servico.icms_modalidade == '101': icms_item = etree.SubElement(icms, 'ICMSSN'+produto_servico.icms_modalidade) etree.SubElement(icms_item, 'orig').text = str(produto_servico.icms_origem) etree.SubElement(icms_item, 'CSOSN').text = produto_servico.icms_csosn etree.SubElement(icms_item, 'pCredSN').text = str(produto_servico.icms_aliquota) # Alíquota aplicável de cálculo do crédito (Simples Nacional). etree.SubElement(icms_item, 'vCredICMSSN').text = str(produto_servico.icms_credito) # Valor crédito do ICMS que pode ser aproveitado nos termos do art. 23 da LC 123 (Simples Nacional) elif produto_servico.icms_modalidade == 'ST': icms_item = etree.SubElement(icms, 'ICMS'+produto_servico.icms_modalidade) etree.SubElement(icms_item, 'orig').text = str(produto_servico.icms_origem) etree.SubElement(icms_item, 'CST').text = '41' # Nao tributado etree.SubElement(icms_item, 'vBCSTRet').text = '' # Informar o valor da BC do ICMS ST retido na UF remetente etree.SubElement(icms_item, 'vICMSSTRet').text = '' # Informar o valor do ICMS ST retido na UF remetente etree.SubElement(icms_item, 'vBCSTDest').text = '' # Informar o valor da BC do ICMS ST da UF destino etree.SubElement(icms_item, 'vICMSSTDest').text = '' # Informar o valor do ICMS ST da UF destino else: ### OUTROS TIPOS DE ICMS (00,10,20) icms_item = etree.SubElement(icms, 'ICMS'+produto_servico.icms_modalidade) etree.SubElement(icms_item, 'orig').text = str(produto_servico.icms_origem) etree.SubElement(icms_item, 'CST').text = produto_servico.icms_modalidade # Modalidade de determinação da BC do ICMS: 0=Margem Valor Agregado (%); 1=Pauta (Valor); 2=Preço Tabelado Máx. (valor); 3=Valor da operação. etree.SubElement(icms_item, 'modBC').text = str(produto_servico.icms_modalidade_determinacao_bc) # 00=Tributada integralmente. if produto_servico.icms_modalidade == '00': etree.SubElement(icms_item, 'vBC').text = str(produto_servico.icms_valor_base_calculo) # Valor da BC do ICMS etree.SubElement(icms_item, 'pICMS').text = str(produto_servico.icms_aliquota) # Alíquota do imposto etree.SubElement(icms_item, 'vICMS').text = '{:.2f}'.format(produto_servico.icms_valor or 0) # Valor do ICMS # 10=Tributada e com cobrança do ICMS por substituição tributária elif produto_servico.icms_modalidade == '10': etree.SubElement(icms_item, 'vBC').text = str(produto_servico.icms_valor_base_calculo) # Valor da BC do ICMS etree.SubElement(icms_item, 'pICMS').text = str(produto_servico.icms_aliquota) # Alíquota do imposto etree.SubElement(icms_item, 'vICMS').text = '{:.2f}'.format(produto_servico.icms_valor or 0) # Valor do ICMS # Modalidade de determinação da BC do ICMS ST # 0=Preço tabelado ou máximo sugerido; 1=Lista Negativa (valor);2=Lista Positiva (valor);3=Lista Neutra (valor);4=Margem Valor Agregado (%);5=Pauta (valor); etree.SubElement(icms_item, 'modBCST').text = str(produto_servico.icms_st_modalidade_determinacao_bc) etree.SubElement(icms_item, 'pMVAST').text = str(produto_servico.icms_st_percentual_adicional) # Percentual da margem de valor Adicionado do ICMS ST etree.SubElement(icms_item, 'pRedBCST').text = str(produto_servico.icms_st_percentual_reducao_bc) # APercentual da Redução de BC do ICMS ST etree.SubElement(icms_item, 'vBCST ').text = str(produto_servico.icms_st_valor_base_calculo) etree.SubElement(icms_item, 'pICMSST ').text = str(produto_servico.icms_st_aliquota) etree.SubElement(icms_item, 'vICMSST ').text = str(produto_servico.icms_st_valor) # 20=Com redução de base de cálculo elif produto_servico.icms_modalidade == '20': etree.SubElement(icms_item, 'pRedBC').text = str(produto_servico.icms_percentual_reducao_bc) # Percentual da Redução de BC etree.SubElement(icms_item, 'vBC').text = '{:.2f}'.format(produto_servico.icms_valor_base_calculo or 0) # Valor da BC do ICMS etree.SubElement(icms_item, 'pICMS').text = str(produto_servico.icms_aliquota) # Alíquota do imposto etree.SubElement(icms_item, 'vICMS').text = '{:.2f}'.format(produto_servico.icms_valor or 0) # Valor do ICMS # Impostos não implementados else: raise NotImplementedError # ipi # ipi = etree.SubElement(imposto, 'IPI') # etree.SubElement(ipi, 'clEnq') = produto_servico.ipi_classe_enquadramento # Preenchimento conforme Atos Normativos editados pela Receita Federal (Observação 2) # ipint = etree.SubElement(ipi, 'IPINT') # # 01=Entrada tributada com alíquota zero 02=Entrada isenta 03=Entrada não-tributada 04=Entrada imune 05=Entrada com suspensão # # 51=Saída tributada com alíquota zero 52=Saída isenta 53=Saída não-tributada 54=Saída imune 55=Saída com suspensão # etree.SubElement(ipint, 'CST') = produto_servico.ipi_codigo_enquadramento # apenas nfe if modelo == 55: ## PIS pisnt = ('04','05','06','07','08','09') pis = etree.SubElement(imposto, 'PIS') if produto_servico.pis_modalidade in pisnt: pis_item = etree.SubElement(pis, 'PISNT') etree.SubElement(pis_item, 'CST').text = produto_servico.pis_modalidade elif produto_servico.pis_modalidade == '01' or produto_servico.pis_modalidade == '02': pis_item = etree.SubElement(pis, 'PISAliq') etree.SubElement(pis_item, 'CST').text = produto_servico.pis_modalidade etree.SubElement(pis_item, 'vBC').text = produto_servico.pis_valor_base_calculo etree.SubElement(pis_item, 'pPIS').text = produto_servico.pis_aliquota_percentual etree.SubElement(pis_item, 'vPIS').text = produto_servico.pis_valor elif produto_servico.pis_modalidade == '03': pis_item = etree.SubElement(pis, 'PISQtde') etree.SubElement(pis_item, 'CST').text = produto_servico.pis_modalidade etree.SubElement(pis_item, 'qBCProd').text = produto_servico.quantidade_comercial etree.SubElement(pis_item, 'vAliqProd').text = produto_servico.pis_aliquota_percentual etree.SubElement(pis_item, 'vPIS').text = produto_servico.pis_valor_base_calculo else: pis_item = etree.SubElement(pis, 'PISOutr') etree.SubElement(pis_item, 'CST').text = produto_servico.pis_modalidade etree.SubElement(pis_item, 'vBC').text = produto_servico.pis_valor_base_calculo etree.SubElement(pis_item, 'pPIS').text = produto_servico.pis_aliquota_percentual if produto_servico.pis_modalidade is not '99': etree.SubElement(pis_item, 'qBCProd').text = produto_servico.quantidade_comercial etree.SubElement(pis_item, 'vAliqProd').text = produto_servico.pis_aliquota_percentual etree.SubElement(pis_item, 'vPIS').text = produto_servico.pis_valor_base_calculo ## PISST # pis_item = etree.SubElement(pis, 'PISST') # etree.SubElement(pis_item, 'vBC').text = produto_servico.pis_valor_base_calculo # etree.SubElement(pis_item, 'pPIS').text = produto_servico.pis_aliquota_percentual # etree.SubElement(pis_item, 'qBCProd').text = produto_servico.quantidade_comercial # etree.SubElement(pis_item, 'vAliqProd').text = produto_servico.pis_aliquota_percentual # etree.SubElement(pis_item, 'vPIS').text = produto_servico.pis_valor_base_calculo cofinsnt = ('04','05','06','07','08','09') ## COFINS cofins = etree.SubElement(imposto, 'COFINS') if produto_servico.cofins_modalidade in cofinsnt: cofins_item = etree.SubElement(cofins, 'COFINSNT') etree.SubElement(cofins_item, 'CST').text = produto_servico.cofins_modalidade elif produto_servico.cofins_modalidade == '01' or produto_servico.cofins_modalidade == '02': cofins_item = etree.SubElement(cofins, 'COFINSAliq') etree.SubElement(cofins_item, 'CST').text = produto_servico.cofins_modalidade etree.SubElement(cofins_item, 'vBC').text = produto_servico.cofins_valor_base_calculo etree.SubElement(cofins_item, 'pCOFINS').text = produto_servico.cofins_aliquota_percentual etree.SubElement(cofins_item, 'vCOFINS').text = produto_servico.cofins_valor elif produto_servico.cofins_modalidade == '03': cofins_item = etree.SubElement(cofins, 'COFINSQtde') etree.SubElement(cofins_item, 'CST').text = produto_servico.cofins_modalidade etree.SubElement(cofins_item, 'qBCProd').text = produto_servico.quantidade_comercial etree.SubElement(cofins_item, 'vAliqProd').text = produto_servico.cofins_aliquota_percentual etree.SubElement(cofins_item, 'vCOFINS').text = produto_servico.cofins_valor else: cofins_item = etree.SubElement(cofins, 'COFINSOutr') etree.SubElement(cofins_item, 'CST').text = produto_servico.cofins_modalidade etree.SubElement(cofins_item, 'vBC').text = produto_servico.cofins_valor_base_calculo etree.SubElement(cofins_item, 'pCOFINS').text = produto_servico.cofins_aliquota_percentual if produto_servico.cofins_modalidade is not '99': etree.SubElement(cofins_item, 'vAliqProd').text = produto_servico.cofins_aliquota_percentual etree.SubElement(cofins_item, 'vCOFINS').text = produto_servico.cofins_valor ## COFINSST # cofins_item = etree.SubElement(cofins, 'COFINSOutr') # etree.SubElement(cofins_item, 'vBC').text = produto_servico.cofins_valor_base_calculo # etree.SubElement(cofins_item, 'pCOFINS').text = produto_servico.cofins_aliquota_percentual # etree.SubElement(cofins_item, 'qBCProd').text = produto_servico.quantidade_comercial # etree.SubElement(cofins_item, 'vAliqProd').text = produto_servico.cofins_aliquota_percentual # etree.SubElement(cofins_item, 'vCOFINS').text = produto_servico.cofins_valor if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
def _serializar_nota_fiscal(self, nota_fiscal, tag_raiz='infNFe', retorna_string=True): raiz = etree.Element(tag_raiz, versao=self._versao) # 'Id' da tag raiz # Ex.: NFe35080599999090910270550010000000011518005123 raiz.attrib['Id'] = nota_fiscal.identificador_unico tz = datetime.now().astimezone().strftime('%z') tz = "{}:{}".format(tz[:-2], tz[-2:]) # Dados da Nota Fiscal ide = etree.SubElement(raiz, 'ide') etree.SubElement(ide, 'cUF').text = CODIGOS_ESTADOS[nota_fiscal.uf] etree.SubElement(ide, 'cNF').text = nota_fiscal.codigo_numerico_aleatorio etree.SubElement(ide, 'natOp').text = nota_fiscal.natureza_operacao etree.SubElement(ide, 'mod').text = str(nota_fiscal.modelo) etree.SubElement(ide, 'serie').text = nota_fiscal.serie etree.SubElement(ide, 'nNF').text = str(nota_fiscal.numero_nf) etree.SubElement(ide, 'dhEmi').text = nota_fiscal.data_emissao.strftime('%Y-%m-%dT%H:%M:%S') + tz """dhCont Data e Hora da entrada em contingência E B01 D 0-1 Formato AAAA-MM-DDThh:mm:ssTZD (UTC - Universal Coordinated Time) Exemplo: no formato UTC para os campos de Data-Hora, "TZD" pode ser -02:00 (Fernando de Noronha), -03:00 (Brasília) ou -04:00 (Manaus), no horário de verão serão -01:00, -02:00 e -03:00. Exemplo: "2010-08-19T13:00:15-03:00". """ etree.SubElement(ide, 'tpNF').text = str(nota_fiscal.tipo_documento) # 0=entrada 1=saida """ nfce suporta apenas operação interna Identificador de local de destino da operação 1=Operação interna;2=Operação interestadual;3=Operação com exterior. """ if nota_fiscal.modelo == 65: etree.SubElement(ide, 'idDest').text = str(1) else: etree.SubElement(ide, 'idDest').text = str(nota_fiscal.indicador_destino) etree.SubElement(ide, 'cMunFG').text = nota_fiscal.municipio etree.SubElement(ide, 'tpImp').text = str(nota_fiscal.tipo_impressao_danfe) """ ### CONTINGENCIA ### 1=Emissão normal (não em contingência); 2=Contingência FS-IA, com impressão do DANFE em formulário de segurança; 3=Contingência SCAN (Sistema de Contingência do Ambiente Nacional); 4=Contingência DPEC (Declaração Prévia da Emissão em Contingência); 5=Contingência FS-DA, com impressão do DANFE em formulário de segurança; 6=Contingência SVC-AN (SEFAZ Virtual de Contingência do AN); 7=Contingência SVC-RS (SEFAZ Virtual de Contingência do RS); 9=Contingência off-line da NFC-e (as demais opções de contingência são válidas também para a NFC-e). Para a NFC-e somente estão disponíveis e são válidas as opções de contingência 5 e 9. """ if self._contingencia != None: if nota_fiscal.forma_emissao == '1': nota_fiscal.forma_emissao = '9' etree.SubElement(ide, 'tpEmis').text = str(nota_fiscal.forma_emissao) etree.SubElement(ide, 'cDV').text = nota_fiscal.dv_codigo_numerico_aleatorio etree.SubElement(ide, 'tpAmb').text = str(self._ambiente) etree.SubElement(ide, 'finNFe').text = str(nota_fiscal.finalidade_emissao) if nota_fiscal.modelo == 65: etree.SubElement(ide, 'indFinal').text = str(1) etree.SubElement(ide, 'indPres').text = str(1) else: etree.SubElement(ide, 'indFinal').text = str(nota_fiscal.cliente_final) etree.SubElement(ide, 'indPres').text = str(nota_fiscal.indicador_presencial) etree.SubElement(ide, 'procEmi').text = str(nota_fiscal.processo_emissao) etree.SubElement(ide, 'verProc').text = '%s %s'%(self._nome_aplicacao, nota_fiscal.versao_processo_emissao) ### NF-e referenciada (utilizado em casos de devolução/garantia) ### # Apenas NF-e if nota_fiscal.modelo == 55: if nota_fiscal.notas_fiscais_referenciadas: nfref = etree.SubElement(ide, 'NFref') for refNFe in nota_fiscal.notas_fiscais_referenciadas: etree.SubElement(nfref, 'refNFe').text = refNFe.chave_acesso ### CONTINGENCIA ### if self._contingencia != None: etree.SubElement(ide, 'dhCont').text = nota_fiscal.data_emissao.strftime('%Y-%m-%dT%H:%M:%S') + tz # Data e Hora da entrada em contingência AAAA-MM-DDThh:mm:ssTZD etree.SubElement(ide, 'xJust').text = nota_fiscal.self._contingencia # Justificativa da entrada em contingência (min 20, max 256 caracteres) # Emitente raiz.append(self._serializar_emitente(nota_fiscal.emitente, retorna_string=False)) # Destinatário try: raiz.append(self._serializar_cliente(nota_fiscal.cliente, modelo=nota_fiscal.modelo, retorna_string=False)) except AttributeError as e: # NFC-e pode ser gerada sem destinatário if nota_fiscal.modelo == 65: pass else: raise e # Retirada if nota_fiscal.retirada: raiz.append(self._serializar_entrega_retirada( nota_fiscal.retirada, retorna_string=False, tag_raiz='retirada', )) # Entrega if nota_fiscal.entrega: raiz.append(self._serializar_entrega_retirada( nota_fiscal.entrega, retorna_string=False, tag_raiz='entrega', )) # Itens for num, item in enumerate(nota_fiscal.produtos_e_servicos): det = self._serializar_produto_servico(item, modelo=nota_fiscal.modelo, retorna_string=False) det.attrib['nItem'] = str(num+1) raiz.append(det) # Totais total = etree.SubElement(raiz, 'total') icms_total = etree.SubElement(total, 'ICMSTot') etree.SubElement(icms_total, 'vBC').text = '{:.2f}'.format(nota_fiscal.totais_icms_base_calculo) etree.SubElement(icms_total, 'vICMS').text = '{:.2f}'.format(nota_fiscal.totais_icms_total) etree.SubElement(icms_total, 'vICMSDeson').text = '{:.2f}'.format(nota_fiscal.totais_icms_desonerado) # Valor Total do ICMS desonerado if nota_fiscal.totais_fcp_destino: etree.SubElement(icms_total, 'vFCPUFDest').text = '{:.2f}'.format(nota_fiscal.totais_fcp_destino) if nota_fiscal.totais_icms_inter_destino: etree.SubElement(icms_total, 'vICMSUFDest').text = '{:.2f}'.format(nota_fiscal.totais_icms_inter_destino) if nota_fiscal.totais_icms_inter_remetente: etree.SubElement(icms_total, 'vICMSUFRemet').text = '{:.2f}'.format(nota_fiscal.totais_icms_remetente) etree.SubElement(icms_total, 'vFCP').text = '{:.2f}'.format(nota_fiscal.totais_fcp) etree.SubElement(icms_total, 'vBCST').text = '{:.2f}'.format(nota_fiscal.totais_icms_st_base_calculo) etree.SubElement(icms_total, 'vST').text = '{:.2f}'.format(nota_fiscal.totais_icms_st_total) etree.SubElement(icms_total, 'vFCPST').text = '{:.2f}'.format(nota_fiscal.totais_fcp_st) etree.SubElement(icms_total, 'vFCPSTRet').text = '{:.2f}'.format(nota_fiscal.totais_fcp_st_ret) etree.SubElement(icms_total, 'vProd').text = str(nota_fiscal.totais_icms_total_produtos_e_servicos) etree.SubElement(icms_total, 'vFrete').text = '{:.2f}'.format(nota_fiscal.totais_icms_total_frete) etree.SubElement(icms_total, 'vSeg').text = '{:.2f}'.format(nota_fiscal.totais_icms_total_seguro) etree.SubElement(icms_total, 'vDesc').text = '{:.2f}'.format(nota_fiscal.totais_icms_total_desconto) # Tributos etree.SubElement(icms_total, 'vII').text = '{:.2f}'.format(nota_fiscal.totais_icms_total_ii) etree.SubElement(icms_total, 'vIPI').text = '{:.2f}'.format(nota_fiscal.totais_icms_total_ipi) etree.SubElement(icms_total, 'vIPIDevol').text = '{:.2f}'.format(nota_fiscal.totais_icms_total_ipi_dev) etree.SubElement(icms_total, 'vPIS').text = '{:.2f}'.format(nota_fiscal.totais_icms_pis) etree.SubElement(icms_total, 'vCOFINS').text = '{:.2f}'.format(nota_fiscal.totais_icms_cofins) etree.SubElement(icms_total, 'vOutro').text = '{:.2f}'.format(nota_fiscal.totais_icms_outras_despesas_acessorias) etree.SubElement(icms_total, 'vNF').text = str(nota_fiscal.totais_icms_total_nota) if nota_fiscal.totais_tributos_aproximado: etree.SubElement(icms_total, 'vTotTrib').text = '{:.2f}'.format(nota_fiscal.totais_tributos_aproximado) # Transporte transp = etree.SubElement(raiz, 'transp') etree.SubElement(transp, 'modFrete').text = str(nota_fiscal.transporte_modalidade_frete) # Apenas NF-e if nota_fiscal.modelo == 55: # Transportadora if nota_fiscal.transporte_transportadora: transp.append(self._serializar_transportadora( nota_fiscal.transporte_transportadora, retorna_string=False, )) # Veículo if nota_fiscal.transporte_veiculo_placa and nota_fiscal.transporte_veiculo_uf: veiculo = etree.SubElement(transp, 'veicTransp') etree.SubElement(veiculo, 'placa').text = nota_fiscal.transporte_veiculo_placa # Obrigatório EX: XXX9999 etree.SubElement(veiculo, 'UF').text = nota_fiscal.transporte_veiculo_uf # Registro Nacional de Transportador de Carga (ANTT) if nota_fiscal.transporte_veiculo_rntc: etree.SubElement(veiculo, 'RNTC').text = nota_fiscal.transporte_veiculo_rntc # Reboque if nota_fiscal.transporte_reboque_placa and nota_fiscal.transporte_reboque_uf: reboque = etree.SubElement(transp, 'reboque') etree.SubElement(reboque, 'placa').text = nota_fiscal.transporte_reboque_placa etree.SubElement(reboque, 'UF').text = nota_fiscal.transporte_reboque_uf # Registro Nacional de Transportador de Carga (ANTT) if nota_fiscal.transporte_reboque_rntc: etree.SubElement(reboque, 'RNTC').text = nota_fiscal.transporte_reboque_rntc # Volumes if nota_fiscal.transporte_volumes: for volume in nota_fiscal.transporte_volumes: vol = etree.SubElement(transp, 'vol') if volume.quantidade: etree.SubElement(vol, 'qVol').text = str(volume.quantidade) etree.SubElement(vol, 'esp').text = volume.especie if volume.marca: etree.SubElement(vol, 'marca').text = volume.marca if volume.numeracao: etree.SubElement(vol, 'nVol').text = volume.numeracao etree.SubElement(vol, 'pesoL').text = str(volume.peso_liquido) etree.SubElement(vol, 'pesoB').text = str(volume.peso_bruto) # Lacres if volume.lacres: lacres = etree.SubElement(vol, 'lacres') for lacre in volume.lacres: etree.SubElement(lacres, 'nLacre').text = lacre.numero_lacre # Pagamento """ Obrigatório o preenchimento do Grupo Informações de Pagamento para NF-e e NFC-e. Para as notas com finalidade de Ajuste ou Devolução o campo Forma de Pagamento deve ser preenchido com 90=Sem Pagamento. """ pag = etree.SubElement(raiz, 'pag') detpag = etree.SubElement(pag, 'detPag') if nota_fiscal.finalidade_emissao == '3' or nota_fiscal.finalidade_emissao == '4': etree.SubElement(detpag, 'tPag').text = '90' etree.SubElement(detpag, 'vPag').text = '{:.2f}'.format(0) else: etree.SubElement(detpag, 'tPag').text = str(nota_fiscal.tipo_pagamento).zfill(2) etree.SubElement(detpag, 'vPag').text = '{:.2f}'.format(nota_fiscal.totais_icms_total_nota) if nota_fiscal.tipo_pagamento == 3 or nota_fiscal.tipo_pagamento == 4: cartao = etree.SubElement(detpag, 'card') """ Tipo de Integração do processo de pagamento com o sistema de automação da empresa: 1=Pagamento integrado com o sistema de automação da empresa (Ex.: equipamento TEF, Comércio Eletrônico); 2= Pagamento não integrado com o sistema de automação da empresa (Ex.: equipamento POS); """ etree.SubElement(cartao, 'tpIntegra').text = '2' #etree.SubElement(cartao, 'CNPJ').text = '' # Informar o CNPJ da Credenciadora de cartão de crédito / débito #etree.SubElement(cartao, 'tBand').text = '' # 01=Visa 02=Mastercard 03=American Express 04=Sorocred 05=Diners Club 06=Elo 07=Hipercard 08=Aura 09=Caba 99=Outros #etree.SubElement(cartao, 'cAut').text = '' # Identifica o número da autorização da transação da operação com cartão de crédito e/ou débito # troco # etree.SubElement(pag, 'vTroco').text = str('') # Informações adicionais if nota_fiscal.informacoes_adicionais_interesse_fisco or nota_fiscal.informacoes_complementares_interesse_contribuinte: info_ad = etree.SubElement(raiz, 'infAdic') if nota_fiscal.informacoes_adicionais_interesse_fisco: etree.SubElement(info_ad, 'infAdFisco').text = nota_fiscal.informacoes_adicionais_interesse_fisco if nota_fiscal.informacoes_complementares_interesse_contribuinte: etree.SubElement(info_ad, 'infCpl').text = nota_fiscal.informacoes_complementares_interesse_contribuinte # Responsavel Tecnico NT2018/003 if nota_fiscal.responsavel_tecnico: raiz.append(self._serializar_responsavel_tecnico( nota_fiscal.responsavel_tecnico[0], retorna_string=False)) if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
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 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 assinar(self, xml, retorna_string=False): try: # No raiz do XML de saida tag = 'infNFe' # 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') # Tenta achar a tag infNFe try: if len(xml.nsmap.items()) == 0: # não tem namespace ref = etree.SubElement( siginfo, 'Reference', URI='#' + xml.findall('infNFe')[0].attrib['Id']) else: ns = {'ns': 'http://www.portalfiscal.inf.br/nfe'} ref = etree.SubElement( siginfo, 'Reference', URI='#' + xml.findall('ns:infNFe', namespaces=ns)[0].attrib['Id']) # Caso nao tenha a tag infNFe, procura a tag infEvento except IndexError: try: tag = 'infEvento' ref = etree.SubElement( siginfo, 'Reference', URI='#' + xml.findall('infEvento')[0].attrib['Id']) # Caso nao tenha a tag infNFe, procura a tag inutNFe except IndexError: tag = 'infInut' ref = etree.SubElement( siginfo, 'Reference', URI='#' + xml.findall('infInut')[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') xml.append(raiz) # Escreve no arquivo depois de remover caracteres especiais e parse string with open('testes.xml', 'w') as arquivo: arquivo.write( remover_acentos( etree.tostring(xml, encoding="unicode", pretty_print=False))) subprocess.check_call([ 'xmlsec1', '--sign', '--pkcs12', self.certificado, '--pwd', self.senha, '--crypto', 'openssl', '--output', 'funfa.xml', '--id-attr:Id', tag, 'testes.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 _serializar_notas_fiscal(self, nota_fiscal, tag_raiz='infNFe', retorna_string=True): raiz = etree.Element(tag_raiz, versao=self._versao) # Dados da Nota Fiscal ide = etree.SubElement(raiz, 'ide') etree.SubElement(ide, 'cUF').text = CODIGOS_ESTADOS[nota_fiscal.uf] etree.SubElement(ide, 'cNF').text = nota_fiscal.codigo_numerico_aleatorio etree.SubElement(ide, 'natOp').text = nota_fiscal.natureza_operacao etree.SubElement(ide, 'indPag').text = str(nota_fiscal.forma_pagamento) etree.SubElement(ide, 'mod').text = str(nota_fiscal.modelo) etree.SubElement(ide, 'serie').text = nota_fiscal.serie etree.SubElement(ide, 'nNF').text = str(nota_fiscal.numero_nf) etree.SubElement( ide, 'dEmi').text = nota_fiscal.data_emissao.strftime('%Y-%m-%d') etree.SubElement( ide, 'dSaiEnt').text = nota_fiscal.data_saida_entrada.strftime( '%Y-%m-%d') etree.SubElement(ide, 'tpNF').text = str(nota_fiscal.tipo_documento) etree.SubElement(ide, 'cMunFG').text = nota_fiscal.municipio etree.SubElement(ide, 'tpImp').text = str(nota_fiscal.tipo_impressao_danfe) etree.SubElement(ide, 'tpEmis').text = str(nota_fiscal.forma_emissao) etree.SubElement(ide, 'cDV').text = nota_fiscal.dv_codigo_numerico_aleatorio etree.SubElement(ide, 'tpAmb').text = str(self._ambiente) etree.SubElement(ide, 'finNFe').text = str(nota_fiscal.finalidade_emissao) etree.SubElement(ide, 'procEmi').text = str(nota_fiscal.processo_emissao) etree.SubElement( ide, 'verProc').text = '%s %s' % (self._nome_aplicacao, nota_fiscal.versao_processo_emissao) # Emitente raiz.append( self._serializar_emitente(nota_fiscal.emitente, retorna_string=False)) # Destinatário raiz.append( self._serializar_cliente(nota_fiscal.cliente, retorna_string=False)) # Retirada if nota_fiscal.retirada: raiz.append( self._serializar_entrega_retirada( nota_fiscal.retirada, retorna_string=False, tag_raiz='retirada', )) # Entrega if nota_fiscal.entrega: raiz.append( self._serializar_entrega_retirada( nota_fiscal.entrega, retorna_string=False, tag_raiz='entrega', )) # Itens for num, item in enumerate(nota_fiscal.produtos_e_servicos): det = self._serializar_produto_servico(item, retorna_string=False) det.attrib['nItem'] = str(num + 1) raiz.append(det) # Totais total = etree.SubElement(raiz, 'total') icms_total = etree.SubElement(total, 'ICMSTot') etree.SubElement(icms_total, 'vBC').text = str( nota_fiscal.totais_icms_base_calculo) etree.SubElement(icms_total, 'vICMS').text = str(nota_fiscal.totais_icms_total) etree.SubElement(icms_total, 'vBCST').text = str( nota_fiscal.totais_icms_st_base_calculo) etree.SubElement(icms_total, 'vST').text = str(nota_fiscal.totais_icms_st_total) etree.SubElement(icms_total, 'vProd').text = str( nota_fiscal.totais_icms_total_produtos_e_servicos) etree.SubElement(icms_total, 'vFrete').text = str( nota_fiscal.totais_icms_total_frete) etree.SubElement(icms_total, 'vSeg').text = str( nota_fiscal.totais_icms_total_seguro) etree.SubElement(icms_total, 'vDesc').text = str( nota_fiscal.totais_icms_total_desconto) etree.SubElement(icms_total, 'vII').text = str(nota_fiscal.totais_icms_total_ii) etree.SubElement(icms_total, 'vIPI').text = str(nota_fiscal.totais_icms_total_ipi) etree.SubElement(icms_total, 'vPIS').text = str(nota_fiscal.totais_icms_pis) etree.SubElement(icms_total, 'vCOFINS').text = str(nota_fiscal.totais_icms_cofins) etree.SubElement(icms_total, 'vOutro').text = str( nota_fiscal.totais_icms_outras_despesas_acessorias) etree.SubElement(icms_total, 'vNF').text = str(nota_fiscal.totais_icms_total_nota) # Transporte transp = etree.SubElement(raiz, 'transp') etree.SubElement(transp, 'modFrete').text = str( nota_fiscal.transporte_modalidade_frete) # Transportadora transp.append( self._serializar_transportadora( nota_fiscal.transporte_transportadora, retorna_string=False, )) # Veículo veiculo = etree.SubElement(transp, 'veicTransp') etree.SubElement(veiculo, 'placa').text = nota_fiscal.transporte_veiculo_placa etree.SubElement(veiculo, 'UF').text = nota_fiscal.transporte_veiculo_uf etree.SubElement(veiculo, 'RNTC').text = nota_fiscal.transporte_veiculo_rntc # Reboque reboque = etree.SubElement(transp, 'reboque') etree.SubElement(reboque, 'placa').text = nota_fiscal.transporte_reboque_placa etree.SubElement(reboque, 'UF').text = nota_fiscal.transporte_reboque_uf etree.SubElement(reboque, 'RNTC').text = nota_fiscal.transporte_reboque_rntc # Volumes for volume in nota_fiscal.transporte_volumes: vol = etree.SubElement(transp, 'vol') etree.SubElement(vol, 'qVol').text = str(volume.quantidade) etree.SubElement(vol, 'esp').text = volume.especie etree.SubElement(vol, 'marca').text = volume.marca etree.SubElement(vol, 'nVol').text = volume.numeracao etree.SubElement(vol, 'pesoL').text = str(volume.peso_liquido) etree.SubElement(vol, 'pesoB').text = str(volume.peso_bruto) # Lacres lacres = etree.SubElement(vol, 'lacres') for lacre in volume.lacres: etree.SubElement(lacres, 'nLacre').text = lacre.numero_lacre # Informações adicionais info_ad = etree.SubElement(raiz, 'infAdic') etree.SubElement( info_ad, 'infAdFisco' ).text = nota_fiscal.informacoes_adicionais_interesse_fisco etree.SubElement( info_ad, 'infCpl' ).text = nota_fiscal.informacoes_complementares_interesse_contribuinte # 'Id' da tag raiz # Ex.: NFe35080599999090910270550010000000011518005123 raiz.attrib['Id'] = nota_fiscal.identificador_unico if retorna_string: return etree.tostring(raiz, pretty_print=True) else: return raiz
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