Browse Source

Removendo arquivos extras

Assinatura através do signxml sendo chamada corretamente
tags/0.1.5
Danimar 9 years ago
parent
commit
35359531e2
  1. 31
      pytrustnfe/HttpClient.py
  2. 35
      pytrustnfe/Servidores.py
  3. 31
      pytrustnfe/certificado.py
  4. 23
      pytrustnfe/client.py
  5. 51
      pytrustnfe/nfe/__init__.py
  6. 130
      pytrustnfe/nfe/assinatura.py
  7. 16
      pytrustnfe/nfe/comunicacao.py
  8. 21
      pytrustnfe/servicos/NFeDistribuicaoDFe.py
  9. 21
      pytrustnfe/servicos/NFeRetAutorizacao.py
  10. 25
      pytrustnfe/servicos/NfeConsultaCadastro.py
  11. 21
      pytrustnfe/servicos/NfeConsultaProtocolo.py
  12. 21
      pytrustnfe/servicos/NfeInutilizacao.py
  13. 19
      pytrustnfe/servicos/NfeStatusServico.py
  14. 20
      pytrustnfe/servicos/RecepcaoEvento.py
  15. 15
      pytrustnfe/servicos/Validacao.py
  16. 48
      pytrustnfe/servicos/assinatura.py
  17. 41
      pytrustnfe/servicos/nfe_autorizacao.py
  18. 33
      pytrustnfe/utils.py
  19. 4
      pytrustnfe/xml/__init__.py
  20. 0
      pytrustnfe/xml/consultar_cadastro.xml
  21. 18
      pytrustnfe/xml/nfeEnv.xml

31
pytrustnfe/HttpClient.py

@ -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))

35
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',

31
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

23
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

51
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
}

130
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()

16
pytrustnfe/servicos/comunicacao.py → 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()

21
pytrustnfe/servicos/NFeDistribuicaoDFe.py

@ -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)

21
pytrustnfe/servicos/NFeRetAutorizacao.py

@ -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)

25
pytrustnfe/servicos/NfeConsultaCadastro.py

@ -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)

21
pytrustnfe/servicos/NfeConsultaProtocolo.py

@ -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)

21
pytrustnfe/servicos/NfeInutilizacao.py

@ -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)

19
pytrustnfe/servicos/NfeStatusServico.py

@ -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)

20
pytrustnfe/servicos/RecepcaoEvento.py

@ -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)

15
pytrustnfe/servicos/Validacao.py

@ -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])

48
pytrustnfe/servicos/assinatura.py

@ -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)

41
pytrustnfe/servicos/nfe_autorizacao.py

@ -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
}

33
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):

4
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

0
pytrustnfe/servicos/__init__.py → pytrustnfe/xml/consultar_cadastro.xml

18
pytrustnfe/xml/nfeEnv.xml

@ -31,7 +31,12 @@
</ide>
<emit>
{% with emit = NFe.infNFe.emit %}
<CNPJ>{{ emit.CNPJ }}</CNPJ>
{% if emit.tipo == 'person' -%}
<CPF>{{ emit.cnpj_cpf }}</CPF>
{% endif %}
{% if emit.tipo == 'company' -%}
<CNPJ>{{ emit.cnpj_cpf }}</CNPJ>
{% endif %}
<xNome>{{ emit.xNome }}</xNome>
<xFant>{{ emit.xFant }}</xFant>
<enderEmit>
@ -52,8 +57,12 @@
</emit>
<dest>
{% with dest = NFe.infNFe.dest %}
<CNPJ>{{ dest.CNPJ }}</CNPJ>
<CPF>{{ dest.CPF }}</CPF>
{% if dest.tipo == 'person' -%}
<CPF>{{ dest.cnpj_cpf }}</CPF>
{% endif %}
{% if dest.tipo == 'company' -%}
<CNPJ>{{ dest.cnpj_cpf }}</CNPJ>
{% endif %}
<xNome>{{ dest.xNome }}</xNome>
<enderDest>
<xLgr>{{ dest.enderDest.xLgr }}</xLgr>
@ -68,7 +77,7 @@
<fone>{{ dest.enderDest.fone }}</fone>
</enderDest>
<indIEDest>{{ dest.indIEDest }}</indIEDest>
<IE>{{ dest.IE }}</IE>
{% if dest.IE != '' -%}<IE>{{ dest.IE }}</IE>{% endif %}
{% endwith %}
</dest>
{% for det in NFe.infNFe.detalhes %}
@ -169,7 +178,6 @@
<infCpl>{{ NFe.infNFe.infAdic.infCpl }}</infCpl>
</infAdic>
</infNFe>
<Signature Id="placeholder"></Signature>
</NFe>
{% endfor %}
</enviNFe>
Loading…
Cancel
Save