diff --git a/pytrustnfe/HttpClient.py b/pytrustnfe/HttpClient.py deleted file mode 100644 index a2ee8fe..0000000 --- a/pytrustnfe/HttpClient.py +++ /dev/null @@ -1,31 +0,0 @@ -# coding=utf-8 -''' -Created on Jun 16, 2015 - -@author: danimar -''' -import requests - - -class HttpClient(object): - - def __init__(self, url, cert_path, key_path): - self.url = url - self.cert_path = cert_path - self.key_path = key_path - - def _headers(self): - return { - u'Content-type': u'application/soap+xml; charset=utf-8; action="http://www.portalfiscal.inf.br/nfe/wsdl/NfeAutorizacao/nfeAutorizacaoLote', - u'Accept': u'application/soap+xml; charset=utf-8' - } - - def post_xml(self, post, xml): - try: - url = 'https://nfe-homologacao.sefazrs.rs.gov.br/ws/NfeAutorizacao/NFeAutorizacao.asmx' - res = requests.post(url, data=xml, cert=(self.cert_path, self.key_path), - verify=False, headers=self._headers()) - return res.text - except Exception as e: - print(str(e)) - diff --git a/pytrustnfe/Servidores.py b/pytrustnfe/Servidores.py index 5b2b763..01ba675 100644 --- a/pytrustnfe/Servidores.py +++ b/pytrustnfe/Servidores.py @@ -1,8 +1,26 @@ -''' -Created on 26/06/2015 +# -*- coding: utf-8 -*- +# © 2016 Danimar Ribeiro +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +WS_NFE_AUTORIZACAO = 0 +WS_NFE_CONSULTA_AUTORIZACAO = 1 +WS_NFE_CANCELAMENTO = 2 +WS_NFE_INUTILIZACAO = 3 +WS_NFE_CONSULTA = 4 +WS_NFE_SITUACAO = 5 +WS_NFE_CONSULTA_CADASTRO = 6 + +WS_DPEC_RECEPCAO = 7 +WS_DPEC_CONSULTA = 8 + +WS_NFE_RECEPCAO_EVENTO = 9 +WS_NFE_DOWNLOAD = 10 +WS_NFE_CONSULTA_DESTINADAS = 11 +WS_DFE_DISTRIBUICAO = 12 + +NFE_AMBIENTE_PRODUCAO = 1 +NFE_AMBIENTE_HOMOLOGACAO = 2 -@author: danimar -''' def localizar_url(servico, estado): return ESTADO_WS[estado]['servidor'], ESTADO_WS[estado][servico] @@ -279,17 +297,8 @@ UFGO = { } } -#UFMA = { - #NFE_AMBIENTE_PRODUCAO: { - #'servidor': 'sistemas.sefaz.ma.gov.br', - #WS_NFE_CONSULTA_CADASTRO: 'wscadastro/CadConsultaCadastro2', - #} -#} UFMT = { -#NFeAutorizacao 3.10 https://nfe.sefaz.mt.gov.br/nfews/v2/services/NfeAutorizacao?wsdl -#NFeRetAutorizacao 3.10 https://nfe.sefaz.mt.gov.br/nfews/v2/services/NfeRetAutorizacao?wsdl - NFE_AMBIENTE_PRODUCAO: { 'servidor' : 'nfe.sefaz.mt.gov.br', WS_NFE_AUTORIZACAO : 'nfews/v2/services/NfeAutorizacao', diff --git a/pytrustnfe/certificado.py b/pytrustnfe/certificado.py index b385a03..724912d 100644 --- a/pytrustnfe/certificado.py +++ b/pytrustnfe/certificado.py @@ -1,9 +1,8 @@ -# coding=utf-8 -''' -Created on Jun 16, 2015 +# -*- coding: utf-8 -*- +# © 2016 Danimar Ribeiro, Trustcode +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + -@author: danimar -''' from uuid import uuid4 import os.path from OpenSSL import crypto @@ -15,22 +14,18 @@ class Certificado(object): self.password = password -def converte_pfx_pem(pfx_stream, senha): - try: - certificado = crypto.load_pkcs12(pfx_stream, senha) - - cert = crypto.dump_certificate(crypto.FILETYPE_PEM, - certificado.get_certificate()) - key = crypto.dump_privatekey(crypto.FILETYPE_PEM, - certificado.get_privatekey()) - except Exception as e: - if len(e.message) == 1 and len(e.message[0]) == 3 and \ - e.message[0][2] == 'mac verify failure': - raise Exception('Senha inválida') - raise +def extract_cert_and_key_from_pfx(pfx, password): + pfx = crypto.load_pkcs12(pfx, password) + # PEM formatted private key + key = crypto.dump_privatekey(crypto.FILETYPE_PEM, + pfx.get_privatekey()) + # PEM formatted certificate + cert = crypto.dump_certificate(crypto.FILETYPE_PEM, + pfx.get_certificate()) return cert, key + def save_cert_key(cert, key): cert_temp = '/tmp/' + uuid4().hex key_temp = '/tmp/' + uuid4().hex diff --git a/pytrustnfe/client.py b/pytrustnfe/client.py index 6bd130b..0867982 100644 --- a/pytrustnfe/client.py +++ b/pytrustnfe/client.py @@ -1,3 +1,6 @@ +# -*- coding: utf-8 -*- +# © 2016 Danimar Ribeiro, Trustcode +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). import requests import suds.client @@ -28,3 +31,23 @@ def get_client(base_url): cache=cache, transport=suds_requests.RequestsTransport(session) ) + + +class HttpClient(object): + + def __init__(self, url, cert_path, key_path): + self.url = url + self.cert_path = cert_path + self.key_path = key_path + + def _headers(self, action): + return { + u'Content-type': u'application/soap+xml; charset=utf-8; action="http://www.portalfiscal.inf.br/nfe/wsdl/%s' % action, + u'Accept': u'application/soap+xml; charset=utf-8' + } + + def post_soap(self, xml_soap, action): + res = requests.post(self.url, data=xml_soap, + cert=(self.cert_path, self.key_path), + verify=False, headers=self._headers(action)) + return res.text diff --git a/pytrustnfe/nfe/__init__.py b/pytrustnfe/nfe/__init__.py new file mode 100644 index 0000000..2a9ccf5 --- /dev/null +++ b/pytrustnfe/nfe/__init__.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# © 2016 Danimar Ribeiro, Trustcode +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + + +import os +from lxml import etree +from .comunicacao import Comunicacao +from .assinatura import assinar, Assinatura +from pytrustnfe import utils +from pytrustnfe.xml import render_xml + + +class NFe(Comunicacao): + + def __init__(self, cert, key): + Comunicacao.__init__(self, cert, key) + + def consultar_cadastro(self, cadastro, estado): + self.url = 'https://cad.sefazrs.rs.gov.br/ws/cadconsultacadastro/cadconsultacadastro2.asmx' + self.metodo = 'NfeConsultaCadastro' + + path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'xml') + xml = render_xml(path, 'consultar_cadastro.xml', **cadastro) + + xml_response, obj = self._executar_consulta(xml) + + return { + 'sent_xml': xml, + 'received_xml': xml_response, + 'object': obj.Body.nfeAutorizacaoLoteResult + } + + + def autorizar_nfe(self, nfe, nfe_id): + self.url = 'https://nfe-homologacao.sefazrs.rs.gov.br/ws/NfeAutorizacao/NFeAutorizacao.asmx' + self.metodo = 'NfeAutorizacao/nfeAutorizacaoLote' + + path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'xml') + xml = render_xml(path, 'nfeEnv.xml', **nfe) + + xmlElem = etree.fromstring(xml) + xml_signed = assinar(xmlElem, self.cert, self.key, '#%s' % nfe_id) + + xml_response, obj = self._executar_consulta(xml_signed) + + return { + 'sent_xml': xml_signed, + 'received_xml': xml_response, + 'object': obj.Body.nfeAutorizacaoLoteResult + } diff --git a/pytrustnfe/nfe/assinatura.py b/pytrustnfe/nfe/assinatura.py new file mode 100644 index 0000000..7754ab2 --- /dev/null +++ b/pytrustnfe/nfe/assinatura.py @@ -0,0 +1,130 @@ +# -*- coding: utf-8 -*- +# © 2016 Danimar Ribeiro, Trustcode +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import xmlsec +import libxml2 +import os.path + +from signxml import XMLSigner +from signxml import methods +from lxml import etree +from OpenSSL import crypto + +NAMESPACE_SIG = 'http://www.w3.org/2000/09/xmldsig#' + + +def extract_cert_and_key_from_pfx(pfx, password): + pfx = crypto.load_pkcs12(pfx, password) + # PEM formatted private key + key = crypto.dump_privatekey(crypto.FILETYPE_PEM, + pfx.get_privatekey()) + # PEM formatted certificate + cert = crypto.dump_certificate(crypto.FILETYPE_PEM, + pfx.get_certificate()) + return cert, key + + +def recursively_empty(e): + if e.text: + return False + return all((recursively_empty(c) for c in e.iterchildren())) + + +def assinar(xml, cert, key, reference): + context = etree.iterwalk(xml) + for dummy, elem in context: + parent = elem.getparent() + if recursively_empty(elem): + parent.remove(elem) + + element = xml.find('{' + xml.nsmap[None] + '}NFe') + signer = XMLSigner(digest_algorithm=u'sha1',signature_algorithm="rsa-sha1", + method=methods.enveloped, + c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') + ns = {} + ns[None] = signer.namespaces['ds'] + signer.namespaces = ns + signed_root = signer.sign(element, key=str(key), cert=cert, reference_uri=reference) + + xml.remove(element) + xml.append(signed_root) + return etree.tostring(xml) + + +class Assinatura(object): + + def __init__(self, arquivo, senha): + self.arquivo = arquivo + self.senha = senha + + def _checar_certificado(self): + if not os.path.isfile(self.arquivo): + raise Exception('Caminho do certificado não existe.') + + def _inicializar_cripto(self): + libxml2.initParser() + libxml2.substituteEntitiesDefault(1) + + xmlsec.init() + xmlsec.cryptoAppInit(None) + xmlsec.cryptoInit() + + def _finalizar_cripto(self): + xmlsec.cryptoShutdown() + xmlsec.cryptoAppShutdown() + xmlsec.shutdown() + + libxml2.cleanupParser() + + def assina_xml(self, xml, reference): + self._checar_certificado() + self._inicializar_cripto() + try: + doc_xml = libxml2.parseMemory( + xml.encode('utf-8'), len(xml.encode('utf-8'))) + + signNode = xmlsec.TmplSignature(doc_xml, xmlsec.transformInclC14NId(), + xmlsec.transformRsaSha1Id(), None) + + doc_xml.getLastChild().addChild(signNode) + refNode = signNode.addReference(xmlsec.transformSha1Id(), + None, reference, None) + + refNode.addTransform(xmlsec.transformEnvelopedId()) + refNode.addTransform(xmlsec.transformInclC14NId()) + keyInfoNode = signNode.ensureKeyInfo() + keyInfoNode.addX509Data() + + dsig_ctx = xmlsec.DSigCtx() + chave = xmlsec.cryptoAppKeyLoad(filename=str(self.arquivo), + format=xmlsec.KeyDataFormatPkcs12, + pwd=str(self.senha), + pwdCallback=None, + pwdCallbackCtx=None) + + dsig_ctx.signKey = chave + dsig_ctx.sign(signNode) + + status = dsig_ctx.status + dsig_ctx.destroy() + + if status != xmlsec.DSigStatusSucceeded: + raise RuntimeError( + 'Erro ao realizar a assinatura do arquivo; status: "' + + str(status) + + '"') + + xpath = doc_xml.xpathNewContext() + xpath.xpathRegisterNs('sig', NAMESPACE_SIG) + certificados = xpath.xpathEval( + '//sig:X509Data/sig:X509Certificate') + for i in range(len(certificados) - 1): + certificados[i].unlinkNode() + certificados[i].freeNode() + + xml = doc_xml.serialize() + return xml + finally: + doc_xml.freeDoc() + self._finalizar_cripto() diff --git a/pytrustnfe/servicos/comunicacao.py b/pytrustnfe/nfe/comunicacao.py similarity index 86% rename from pytrustnfe/servicos/comunicacao.py rename to pytrustnfe/nfe/comunicacao.py index a987214..f767873 100644 --- a/pytrustnfe/servicos/comunicacao.py +++ b/pytrustnfe/nfe/comunicacao.py @@ -1,13 +1,8 @@ -# coding=utf-8 -''' -Created on Jun 14, 2015 +# -*- coding: utf-8 -*- +# © 2016 Danimar Ribeiro, Trustcode +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -@author: danimar -''' -import suds.client -import suds_requests -import requests from lxml import objectify from uuid import uuid4 from pytrustnfe.HttpClient import HttpClient @@ -57,14 +52,9 @@ class Comunicacao(object): def _validar_dados(self): assert self.url != '', "Url servidor não configurada" - assert self.web_service != '', "Web service não especificado" assert self.metodo != '', "Método não configurado" - def _validar_nfe(self, obj): - if not isinstance(obj, dict): - raise u"Objeto deve ser um dicionário de valores" - def _executar_consulta(self, xmlEnviar): self._validar_dados() cert_path, key_path = self._preparar_temp_pem() diff --git a/pytrustnfe/servicos/NFeDistribuicaoDFe.py b/pytrustnfe/servicos/NFeDistribuicaoDFe.py deleted file mode 100644 index 59a70cf..0000000 --- a/pytrustnfe/servicos/NFeDistribuicaoDFe.py +++ /dev/null @@ -1,21 +0,0 @@ -#coding=utf-8 -''' -Created on 21/06/2015 - -@author: danimar -''' -from pytrustnfe.servicos.Comunicacao import Comunicacao -from pytrustnfe.xml import DynamicXml - - -class NfeDistribuicaoDFe(Comunicacao): - - def distribuicao(self, dfe): - xml = self._validar_xml(recibo) - - self.metodo = 'NFeDistribuicaoDFe' - self.tag_retorno = 'retDistDFeInt' - self.web_service = 'NFeDistribuicaoDFe/NFeDistribuicaoDFe.asmx' - self.url = 'www1.nfe.fazenda.gov.br' - - return self._executar_consulta(xml) \ No newline at end of file diff --git a/pytrustnfe/servicos/NFeRetAutorizacao.py b/pytrustnfe/servicos/NFeRetAutorizacao.py deleted file mode 100644 index 82cc39e..0000000 --- a/pytrustnfe/servicos/NFeRetAutorizacao.py +++ /dev/null @@ -1,21 +0,0 @@ -#coding=utf-8 -''' -Created on 21/06/2015 - -@author: danimar -''' -from pytrustnfe.servicos.Comunicacao import Comunicacao -from pytrustnfe.xml import DynamicXml - - -class NfeRetAutorizacao(Comunicacao): - - def consulta_autorizacao(self, recibo): - xml = self._validar_xml(recibo) - - self.metodo = 'NFeRetAutorizacao' - self.tag_retorno = 'retConsReciNFe' - self.web_service = 'ws/NfeRetAutorizacao/NFeRetAutorizacao.asmx' - self.url = 'nfe.sefazrs.rs.gov.br' - - return self._executar_consulta(xml) \ No newline at end of file diff --git a/pytrustnfe/servicos/NfeConsultaCadastro.py b/pytrustnfe/servicos/NfeConsultaCadastro.py deleted file mode 100644 index e1bd79f..0000000 --- a/pytrustnfe/servicos/NfeConsultaCadastro.py +++ /dev/null @@ -1,25 +0,0 @@ -#coding=utf-8 -''' -Created on 21/06/2015 - -@author: danimar -''' -from pytrustnfe.servicos.Comunicacao import Comunicacao -from pytrustnfe.xml.DynamicXml import DynamicXml - - -class NfeConsultaCadastro(Comunicacao): - - def __init__(self, certificado, senha): - super(NfeConsultaCadastro, self).__init__(certificado, senha) - self.metodo = 'CadConsultaCadastro2' - self.tag_retorno = 'retConsCad' - - - def consultar_cadastro(self, cadastro, estado): - xml = self._validar_xml(cadastro) - - self.web_service = '/ws/cadconsultacadastro/cadconsultacadastro2.asmx' - self.url = 'cad.svrs.rs.gov.br' - - return self._executar_consulta(xml) \ No newline at end of file diff --git a/pytrustnfe/servicos/NfeConsultaProtocolo.py b/pytrustnfe/servicos/NfeConsultaProtocolo.py deleted file mode 100644 index 7ae759c..0000000 --- a/pytrustnfe/servicos/NfeConsultaProtocolo.py +++ /dev/null @@ -1,21 +0,0 @@ -#coding=utf-8 -''' -Created on 21/06/2015 - -@author: danimar -''' -from pytrustnfe.servicos.Comunicacao import Comunicacao -from pytrustnfe.xml import DynamicXml - - -class NfeConsultaProtocolo(Comunicacao): - - def consultar_protocolo(self, recibo): - xml = self._validar_xml(recibo) - - self.metodo = 'NfeConsulta2' - self.tag_retorno = 'retConsSitNFe' - self.web_service = 'ws/NfeConsulta/NfeConsulta2.asmx' - self.url = 'nfe.sefazrs.rs.gov.br' - - return self._executar_consulta(xml) \ No newline at end of file diff --git a/pytrustnfe/servicos/NfeInutilizacao.py b/pytrustnfe/servicos/NfeInutilizacao.py deleted file mode 100644 index 558ecc8..0000000 --- a/pytrustnfe/servicos/NfeInutilizacao.py +++ /dev/null @@ -1,21 +0,0 @@ -#coding=utf-8 -''' -Created on 21/06/2015 - -@author: danimar -''' -from pytrustnfe.servicos.Comunicacao import Comunicacao -from pytrustnfe.xml import DynamicXml - - -class NfeInutilizacao(Comunicacao): - - def inutilizar(self, inutilizacao): - xml = self._validar_xml(recibo) - - self.metodo = 'nfeinutilizacao2' - self.tag_retorno = 'retInutNFe' - self.web_service = 'ws/nfeinutilizacao/nfeinutilizacao2.asmx' - self.url = 'nfe.sefazrs.rs.gov.br' - - return self._executar_consulta(xml) \ No newline at end of file diff --git a/pytrustnfe/servicos/NfeStatusServico.py b/pytrustnfe/servicos/NfeStatusServico.py deleted file mode 100644 index a88839a..0000000 --- a/pytrustnfe/servicos/NfeStatusServico.py +++ /dev/null @@ -1,19 +0,0 @@ -# coding=utf-8 -''' -Created on 21/06/2015 - -@author: danimar -''' -from pytrustnfe.servicos.comunicacao import Comunicacao - -class NfeStatusServico(Comunicacao): - - def status(self, consulta): - xml = self._validar_xml(recibo) - - self.metodo = 'NfeStatusServico2' - self.tag_retorno = 'retConsStatServ' - self.web_service = 'ws/NfeStatusServico/NfeStatusServico2.asmx' - self.url = 'nfe.sefazrs.rs.gov.br' - - return self._executar_consulta(xml) diff --git a/pytrustnfe/servicos/RecepcaoEvento.py b/pytrustnfe/servicos/RecepcaoEvento.py deleted file mode 100644 index 7ea125e..0000000 --- a/pytrustnfe/servicos/RecepcaoEvento.py +++ /dev/null @@ -1,20 +0,0 @@ -#coding=utf-8 -''' -Created on 21/06/2015 - -@author: danimar -''' -from pytrustnfe.servicos.Comunicacao import Comunicacao - - -class RecepcaoEvento(Comunicacao): - - def registrar_evento(self, evento): - xml = self._validar_xml(recibo) - - self.metodo = 'RecepcaoEvento' - self.tag_retorno = 'retEnvEvento' - self.web_service = 'ws/recepcaoevento/recepcaoevento.asmx' - self.url = 'nfe.sefazrs.rs.gov.br' - - return self._executar_consulta(xml) diff --git a/pytrustnfe/servicos/Validacao.py b/pytrustnfe/servicos/Validacao.py deleted file mode 100644 index ce5ecdb..0000000 --- a/pytrustnfe/servicos/Validacao.py +++ /dev/null @@ -1,15 +0,0 @@ -''' -Created on 24/06/2015 - -@author: danimar -''' - -def validar_schema(): - arquivo_esquema = '' - xml = tira_abertura(self.xml).encode('utf-8') - - esquema = etree.XMLSchema(etree.parse(arquivo_esquema)) - esquema.validate(etree.fromstring(xml)) - - namespace = '{http://www.portalfiscal.inf.br/nfe}' - return "\n".join([x.message.replace(namespace, '') for x in esquema.error_log]) diff --git a/pytrustnfe/servicos/assinatura.py b/pytrustnfe/servicos/assinatura.py deleted file mode 100644 index 7b29e6f..0000000 --- a/pytrustnfe/servicos/assinatura.py +++ /dev/null @@ -1,48 +0,0 @@ -# coding=utf-8 -''' -Created on Jun 14, 2015 - -@author: danimar -''' - -from signxml import XMLSigner -from signxml import methods -from lxml import etree -from OpenSSL import crypto - - -def extract_cert_and_key_from_pfx(pfx, password): - pfx = crypto.load_pkcs12(pfx, password) - # PEM formatted private key - key = crypto.dump_privatekey(crypto.FILETYPE_PEM, - pfx.get_privatekey()) - # PEM formatted certificate - cert = crypto.dump_certificate(crypto.FILETYPE_PEM, - pfx.get_certificate()) - return cert, key - - -def recursively_empty(e): - if e.text: - return False - return all((recursively_empty(c) for c in e.iterchildren())) - - -def assinar(xml, cert, key, reference): - context = etree.iterwalk(xml) - for action, elem in context: - parent = elem.getparent() - if recursively_empty(elem): - parent.remove(elem) - - # element = xml.find('{' + xml.nsmap[None] + '}NFe') - signer = XMLSigner(digest_algorithm=u'sha1',signature_algorithm="rsa-sha1", - method=methods.enveloped, - c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') - ns = {} - ns[None] = signer.namespaces['ds'] - signer.namespaces = ns - signed_root = signer.sign(xml, key=str(key), cert=cert, reference_uri=reference) - - # XMLSigner(signed_root, digest_algorithm=u'sha1').verify(x509_cert=cert) - return etree.tostring(signed_root) diff --git a/pytrustnfe/servicos/nfe_autorizacao.py b/pytrustnfe/servicos/nfe_autorizacao.py deleted file mode 100644 index 78331ba..0000000 --- a/pytrustnfe/servicos/nfe_autorizacao.py +++ /dev/null @@ -1,41 +0,0 @@ -# coding=utf-8 -''' -Created on 21/06/2015 - -@author: danimar -''' -import os -from lxml import etree -from suds.sax.element import Element -from suds.sax.text import Raw -from suds.sax.parser import Parser -from pytrustnfe.servicos.comunicacao import Comunicacao -from pytrustnfe import utils -from pytrustnfe.xml import render_xml -from pytrustnfe.servicos.assinatura import assinar - - -class NfeAutorizacao(Comunicacao): - - def __init__(self, cert, key): - Comunicacao.__init__(self, cert, key) - - def autorizar_nfe(self, nfe, id): - self.url = 'nfe-homologacao.sefazrs.rs.gov.br' - self.web_service = '/ws/NfeAutorizacao/NFeAutorizacao.asmx' - self.metodo = 'nfeAutorizacaoLote' - - self._validar_nfe(nfe) - path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'xml') - xml = render_xml(path, 'nfeEnv.xml', **nfe) - - #xmlElem = etree.fromstring(xml) TODO Assinar - #xml_signed = assinar(xmlElem, self.cert, self.key, '#%s' % id) - print xml - xml_response, obj = self._executar_consulta(xml) - - return { - 'sent_xml': xml, - 'received_xml': xml_response, - 'object': obj.Body.nfeAutorizacaoLoteResult - } diff --git a/pytrustnfe/utils.py b/pytrustnfe/utils.py index 264e658..d6b5f4c 100644 --- a/pytrustnfe/utils.py +++ b/pytrustnfe/utils.py @@ -1,11 +1,32 @@ -# coding=utf-8 -''' -Created on 22/06/2015 +# -*- coding: utf-8 -*- +# © 2016 Danimar Ribeiro, Trustcode +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + -@author: danimar -''' from datetime import date, datetime -from pytrustnfe.ChaveNFe import ChaveNFe + + +class ChaveNFe(object): + + def __init__(self, **kwargs): + self.cnpj = kwargs.pop('cnpj', '') + self.estado = kwargs.pop('estado', '') + self.emissao = kwargs.pop('emissao', '') + self.modelo = kwargs.pop('modelo', '') + self.serie = kwargs.pop('serie', '') + self.numero = kwargs.pop('numero', '') + self.tipo = kwargs.pop('tipo', '') + self.codigo = kwargs.pop('codigo', '') + + def validar(self): + assert self.cnpj != '', 'CNPJ necessário para criar chave NF-e' + assert self.estado != '', 'Estado necessário para criar chave NF-e' + assert self.emissao != '', 'Emissão necessário para criar chave NF-e' + assert self.modelo != '', 'Modelo necessário para criar chave NF-e' + assert self.serie != '', 'Série necessária para criar chave NF-e' + assert self.numero != '', 'Número necessário para criar chave NF-e' + assert self.tipo != '', 'Tipo necessário para criar chave NF-e' + assert self.codigo != '', 'Código necessário para criar chave NF-e' def date_tostring(data): diff --git a/pytrustnfe/xml/__init__.py b/pytrustnfe/xml/__init__.py index 145731f..792bc21 100644 --- a/pytrustnfe/xml/__init__.py +++ b/pytrustnfe/xml/__init__.py @@ -1,3 +1,7 @@ +# -*- coding: utf-8 -*- +# © 2016 Danimar Ribeiro, Trustcode +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + import os.path import unicodedata from lxml import etree diff --git a/pytrustnfe/servicos/__init__.py b/pytrustnfe/xml/consultar_cadastro.xml similarity index 100% rename from pytrustnfe/servicos/__init__.py rename to pytrustnfe/xml/consultar_cadastro.xml diff --git a/pytrustnfe/xml/nfeEnv.xml b/pytrustnfe/xml/nfeEnv.xml index e1a21e2..2ca11ad 100644 --- a/pytrustnfe/xml/nfeEnv.xml +++ b/pytrustnfe/xml/nfeEnv.xml @@ -31,7 +31,12 @@ {% with emit = NFe.infNFe.emit %} - {{ emit.CNPJ }} + {% if emit.tipo == 'person' -%} + {{ emit.cnpj_cpf }} + {% endif %} + {% if emit.tipo == 'company' -%} + {{ emit.cnpj_cpf }} + {% endif %} {{ emit.xNome }} {{ emit.xFant }} @@ -52,8 +57,12 @@ {% with dest = NFe.infNFe.dest %} - {{ dest.CNPJ }} - {{ dest.CPF }} + {% if dest.tipo == 'person' -%} + {{ dest.cnpj_cpf }} + {% endif %} + {% if dest.tipo == 'company' -%} + {{ dest.cnpj_cpf }} + {% endif %} {{ dest.xNome }} {{ dest.enderDest.xLgr }} @@ -68,7 +77,7 @@ {{ dest.enderDest.fone }} {{ dest.indIEDest }} - {{ dest.IE }} + {% if dest.IE != '' -%}{{ dest.IE }}{% endif %} {% endwith %} {% for det in NFe.infNFe.detalhes %} @@ -169,7 +178,6 @@ {{ NFe.infNFe.infAdic.infCpl }} - {% endfor %}