diff --git a/pytrustnfe/nfe/__init__.py b/pytrustnfe/nfe/__init__.py index 1a5b9c0..0268634 100644 --- a/pytrustnfe/nfe/__init__.py +++ b/pytrustnfe/nfe/__init__.py @@ -1,8 +1,7 @@ # -*- coding: utf-8 -*- # © 2016 Danimar Ribeiro, Trustcode # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - - +import hashlib import os import requests from lxml import etree @@ -11,10 +10,9 @@ from .assinatura import Assinatura from pytrustnfe.xml import render_xml, sanitize_response from pytrustnfe.utils import gerar_chave, ChaveNFe from pytrustnfe.Servidores import localizar_url +from pytrustnfe.urls import url_qrcode, url_qrcode_exibicao from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key from requests.packages.urllib3.exceptions import InsecureRequestWarning - - # Zeep from requests import Session from zeep import Client @@ -42,6 +40,12 @@ def _generate_nfe_id(**kwargs): def _render(certificado, method, sign, **kwargs): path = os.path.join(os.path.dirname(__file__), 'templates') + if sign and kwargs['NFes'][0]['ide']['mod'] == '65': + kwargs['NFes'][0]['qrCode'] = 1 if 'qrCode' not in kwargs else \ + kwargs['NFes'][0]['qrCode'] + kwargs['NFes'][0]['urlChave'] = 1 \ + if 'urlChave' not in kwargs['NFes'][0] else \ + kwargs['NFes'][0]['urlChave'] xmlElem_send = render_xml(path, '%s.xml' % method, True, **kwargs) modelo = xmlElem_send.find(".//{http://www.portalfiscal.inf.br/nfe}mod") @@ -53,7 +57,85 @@ def _render(certificado, method, sign, **kwargs): xml_send = signer.assina_xml(xmlElem_send, kwargs['obj']['id']) if method == 'NfeAutorizacao': xml_send = signer.assina_xml( - xmlElem_send, kwargs['NFes'][0]['infNFe']['Id']) + xmlElem_send, kwargs['NFes'][0]['infNFe']['Id'], True) + if modelo == '65' and 'urlChave' not in kwargs['NFes'][0] and \ + 'qrCode' not in kwargs['NFes'][0]: + if kwargs['NFes'][0]['ide']['tpEmis'] != 1: + digest_value = xmlElem_send.find( + ".//{http://www.w3.org/2000/09/xmldsig#}DigestValue") + c_hash_qr_code = \ + "{ch_acesso}|{versao}|{tp_amb}|{dh_emi}|" \ + "{v_nf}|{dig_val}|{id_csc}|{csc}".format( + ch_acesso=kwargs['NFes'][0]['NFe']['infNFe']['Id']. + replace('NFe', ''), + versao=2, + tp_amb=kwargs['NFes'][0]['ide']['tpAmb'], + dh_emi=kwargs['NFes'][0]['ide']['dhEmi'].split("-")[2]. + split("T")[0], + v_nf=kwargs['NFes'][0]['total']['vNF'], + dig_val=digest_value.text, + id_csc=int(kwargs['NFes'][0]['id_csc']), + csc=kwargs['NFes'][0]['csc'] + ) + c_hash_qr_code = hashlib.sha1(c_hash_qr_code.encode()). \ + hexdigest() + qr_code_url = 'p={ch_acesso}|{versao}|{tp_amb}|{dh_emi}|" \ + "{v_nf}|{dig_val}|{id_csc}|{hash}'.format( + ch_acesso=kwargs['NFes'][0]['NFe']['infNFe']['Id']. + replace('NFe', ''), + versao=2, + tp_amb=kwargs['NFes'][0]['ide']['tpAmb'], + dh_emi=kwargs['NFes'][0]['ide']['dhEmi'].split("-")[2]. + split("T")[0], + v_nf=kwargs['NFes'][0]['total']['vNF'], + dig_val=digest_value.text, + id_csc=int(kwargs['NFes'][0]['id_csc']), + hash=c_hash_qr_code + ) + qrcode = url_qrcode( + kwargs['NFes'][0]['emit']['enderEmit']['UF'], + str(kwargs['NFes'][0]['ide']['tpAmb']) + ) + qr_code_url + url_consulta = url_qrcode_exibicao( + kwargs['NFes'][0]['emit']['enderEmit']['UF'], + str(kwargs['NFes'][0]['ide']['tpAmb']) + ) + else: + c_hash_qr_code = \ + "{ch_acesso}|{versao}|{tp_amb}|{id_csc}|{csc}".format( + ch_acesso=kwargs['NFe']['infNFe']['Id']. + replace('NFe', ''), + versao=2, + tp_amb=kwargs['ide']['tpAmb'], + id_csc=int(kwargs['id_csc']), + csc=kwargs['csc'] + ) + c_hash_qr_code = hashlib.sha1( + c_hash_qr_code.encode()).hexdigest() + qr_code_url = "p={ch_acesso}|{versao}|{tp_amb}|{id_csc}|" \ + "{hash}".format( + ch_acesso=kwargs['NFe']['infNFe']['Id'] + .replace('NFe', ''), + versao=2, + tp_amb=kwargs['ide']['tpAmb'], + id_csc=int(kwargs['id_csc']), + hash=c_hash_qr_code + ) + qrcode = url_qrcode( + kwargs['emit']['enderEmit']['UF'], + str(kwargs['ide']['tpAmb']) + ) + qr_code_url + url_consulta = url_qrcode_exibicao( + kwargs['emit']['enderEmit']['UF'], + str(kwargs['ide']['tpAmb']) + ) + qrCode = xml_send.find( + './/{http://www.portalfiscal.inf.br/nfe}qrCode').text = \ + qrcode + urlChave = xml_send.find( + './/{http://www.portalfiscal.inf.br/nfe}urlChave').text = \ + url_consulta + xml_send = etree.tostring(xmlElem_send, encoding=str) elif method == 'RecepcaoEvento': xml_send = signer.assina_xml( xmlElem_send, kwargs['eventos'][0]['Id']) diff --git a/pytrustnfe/nfe/assinatura.py b/pytrustnfe/nfe/assinatura.py index 34df54a..8e088e3 100644 --- a/pytrustnfe/nfe/assinatura.py +++ b/pytrustnfe/nfe/assinatura.py @@ -14,7 +14,7 @@ class Assinatura(object): self.arquivo = arquivo self.senha = senha - def assina_xml(self, xml_element, reference): + def assina_xml(self, xml_element, reference, return_element_etree=False): cert, key = extract_cert_and_key_from_pfx(self.arquivo, self.senha) for element in xml_element.iter("*"): @@ -42,4 +42,6 @@ class Assinatura(object): if element_signed is not None and signature is not None: parent = element_signed.getparent() parent.append(signature) + if return_element_etree is True: + return signed_root return etree.tostring(signed_root, encoding=str) diff --git a/pytrustnfe/nfe/templates/NfeAutorizacao.xml b/pytrustnfe/nfe/templates/NfeAutorizacao.xml index 0efd5cd..ce72360 100644 --- a/pytrustnfe/nfe/templates/NfeAutorizacao.xml +++ b/pytrustnfe/nfe/templates/NfeAutorizacao.xml @@ -28,6 +28,10 @@ {{ ide.indPres }} {{ ide.procEmi }} {{ ide.verProc }} + {% if ide.tpEmis != 1 %} + {{ ide.dhCont }} + {{ ide.xJust }} + {% endif %} {% if ide.NFref is defined -%} {% for ref in ide.NFref %} diff --git a/setup.py b/setup.py index 73e2fb8..6ecb618 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,6 @@ # coding=utf-8 from setuptools import setup, find_packages - VERSION = "1.0.44"