14 changed files with 496 additions and 274 deletions
-
4pytrustnfe/servicos/NfeStatusServico.py
-
5pytrustnfe/servicos/RecepcaoEvento.py
-
4pytrustnfe/servicos/Validacao.py
-
54pytrustnfe/servicos/assinatura.py
-
22pytrustnfe/servicos/comunicacao.py
-
23pytrustnfe/servicos/nfe_autorizacao.py
-
1pytrustnfe/utils.py
-
76pytrustnfe/xml/DynamicXml.py
-
22pytrustnfe/xml/__init__.py
-
58pytrustnfe/xml/filters.py
-
174pytrustnfe/xml/nfeEnv.xml
-
1setup.py
@ -1,76 +0,0 @@ |
|||||
# coding=utf-8 |
|
||||
''' |
|
||||
Created on Jun 17, 2015 |
|
||||
|
|
||||
@author: danimar |
|
||||
''' |
|
||||
|
|
||||
import xml.etree.ElementTree as ET |
|
||||
from lxml.etree import Element, tostring |
|
||||
from __builtin__ import str |
|
||||
|
|
||||
|
|
||||
class DynamicXml(object): |
|
||||
|
|
||||
def __getattr__(self, name): |
|
||||
try: |
|
||||
return object.__getattribute__(self, name) |
|
||||
except: |
|
||||
self.__setattr__(name, None) |
|
||||
return object.__getattribute__(self, name) |
|
||||
|
|
||||
def __setattr__(self, obj, val): |
|
||||
if(obj == "value" or obj == "atributos" or obj == "_indice"): |
|
||||
object.__setattr__(self, obj, val) |
|
||||
else: |
|
||||
self._indice = self._indice + 1 |
|
||||
object.__setattr__(self, obj, DynamicXml(val, self._indice)) |
|
||||
|
|
||||
def __init__(self, value, indice=0): |
|
||||
self.value = unicode(value, 'utf-8') if isinstance(value, |
|
||||
str) else value |
|
||||
self.atributos = {} |
|
||||
self._indice = indice |
|
||||
|
|
||||
def __str__(self): |
|
||||
return unicode(self.value) |
|
||||
|
|
||||
def __call__(self, *args, **kw): |
|
||||
if(len(kw) > 0): |
|
||||
self.atributos = kw |
|
||||
if(len(args) > 0): |
|
||||
self.value = args[0] |
|
||||
else: |
|
||||
return self.value |
|
||||
|
|
||||
def __getitem__(self, i): |
|
||||
if not isinstance(self.value, list): |
|
||||
self.value = [] |
|
||||
if(i + 1 > len(self.value)): |
|
||||
self.value.append(DynamicXml(None)) |
|
||||
return self.value[i] |
|
||||
|
|
||||
def render(self, pretty_print=False): |
|
||||
root = Element(self.value) |
|
||||
self._gerar_xml(root, self) |
|
||||
return tostring(root, pretty_print=pretty_print) |
|
||||
|
|
||||
def _gerar_xml(self, xml, objeto): |
|
||||
items = sorted( |
|
||||
objeto.__dict__.items(), |
|
||||
key=lambda x: x[1]._indice if isinstance(x[1], DynamicXml) else 0 |
|
||||
) |
|
||||
for attr, value in items: |
|
||||
if(attr != "value" and attr != "atributos" and attr != "_indice"): |
|
||||
if isinstance(value(), list): |
|
||||
for item in value(): |
|
||||
sub = ET.SubElement(xml, attr) |
|
||||
self._gerar_xml(sub, item) |
|
||||
else: |
|
||||
sub = ET.SubElement(xml, attr) |
|
||||
if(unicode(value) != u"None"): |
|
||||
sub.text = unicode(value) |
|
||||
self._gerar_xml(sub, value) |
|
||||
elif(attr == "atributos"): |
|
||||
for atr, val in value.items(): |
|
||||
xml.set(atr.replace("__", ":"), str(val)) |
|
||||
@ -0,0 +1,22 @@ |
|||||
|
import os.path |
||||
|
from lxml import etree |
||||
|
from jinja2 import Environment, FileSystemLoader |
||||
|
from . import filters |
||||
|
|
||||
|
|
||||
|
def render_xml(template_name, **nfe): |
||||
|
path = os.path.dirname(__file__) |
||||
|
env = Environment( |
||||
|
loader=FileSystemLoader(path), extensions=['jinja2.ext.with_']) |
||||
|
|
||||
|
env.filters["normalize"] = filters.normalize_str |
||||
|
env.filters["format_percent"] = filters.format_percent |
||||
|
env.filters["format_datetime"] = filters.format_datetime |
||||
|
env.filters["format_date"] = filters.format_date |
||||
|
|
||||
|
template = env.get_template(template_name) |
||||
|
|
||||
|
xml = template.render(**nfe) |
||||
|
xml = xml.replace('&', '&') |
||||
|
parser = etree.XMLParser(remove_blank_text=True, remove_comments=True) |
||||
|
return etree.fromstring(xml, parser=parser) |
||||
@ -0,0 +1,58 @@ |
|||||
|
# coding=utf-8 |
||||
|
|
||||
|
from decimal import Decimal |
||||
|
from datetime import datetime |
||||
|
import dateutil.parser as parser_dateutil |
||||
|
|
||||
|
from unicodedata import normalize |
||||
|
|
||||
|
|
||||
|
def normalize_str(string): |
||||
|
""" |
||||
|
Remove special characters and return the ascii string |
||||
|
""" |
||||
|
if string: |
||||
|
if not isinstance(string, unicode): |
||||
|
string = unicode(string, 'utf-8', 'replace') |
||||
|
|
||||
|
string = string.encode('utf-8') |
||||
|
return normalize( |
||||
|
'NFKD', string.decode('utf-8')).encode('ASCII', 'ignore') |
||||
|
return '' |
||||
|
|
||||
|
|
||||
|
def format_percent(value): |
||||
|
if value: |
||||
|
return Decimal(value) / 100 |
||||
|
|
||||
|
|
||||
|
def format_datetime(value): |
||||
|
""" |
||||
|
Format datetime |
||||
|
""" |
||||
|
dt_format = '%Y-%m-%dT%H:%M:%I' |
||||
|
if isinstance(value, datetime): |
||||
|
return value.strftime(dt_format) |
||||
|
|
||||
|
try: |
||||
|
value = parser_dateutil.parse(value).strftime(dt_format) |
||||
|
except AttributeError: |
||||
|
pass |
||||
|
|
||||
|
return value |
||||
|
|
||||
|
|
||||
|
def format_date(value): |
||||
|
""" |
||||
|
Format date |
||||
|
""" |
||||
|
dt_format = '%Y-%m-%d' |
||||
|
if isinstance(value, datetime): |
||||
|
return value.strftime(dt_format) |
||||
|
|
||||
|
try: |
||||
|
value = parser_dateutil.parse(value).strftime(dt_format) |
||||
|
except AttributeError: |
||||
|
pass |
||||
|
|
||||
|
return value |
||||
@ -0,0 +1,174 @@ |
|||||
|
<enviNFe xmlns="http://www.portalfiscal.inf.br/nfe" versao="3.10"> |
||||
|
<idLote>{{ idLote }}</idLote> |
||||
|
<indSinc>{{ indSinc }}</indSinc> |
||||
|
{% for NFe in NFes %} |
||||
|
<NFe xmlns="http://www.portalfiscal.inf.br/nfe"> |
||||
|
<infNFe versao="3.10" Id="{{ NFe.infNFe.Id }}"> |
||||
|
<ide> |
||||
|
{% with ide = NFe.infNFe.ide %} |
||||
|
<cUF>{{ ide.cUF }}</cUF> |
||||
|
<cNF>{{ ide.cNF }}</cNF> |
||||
|
<natOp>{{ ide.natOp }}</natOp> |
||||
|
<indPag>{{ ide.indPag }}</indPag> |
||||
|
<mod>{{ ide.mod }}</mod> |
||||
|
<serie>{{ ide.serie }}</serie> |
||||
|
<nNF>{{ ide.nNF }}</nNF> |
||||
|
<dhEmi>{{ ide.dhEmi }}</dhEmi> |
||||
|
<dhSaiEnt>{{ ide.dhSaiEnt }}</dhSaiEnt> |
||||
|
<tpNF>{{ ide.tpNF }}</tpNF> |
||||
|
<idDest>{{ ide.idDest }}</idDest> |
||||
|
<cMunFG>{{ ide.cMunFG }}</cMunFG> |
||||
|
<tpImp>{{ ide.tpImp }}</tpImp> |
||||
|
<tpEmis>{{ ide.tpEmis }}</tpEmis> |
||||
|
<cDV>{{ ide.cDV }}</cDV> |
||||
|
<tpAmb>{{ ide.tpAmb }}</tpAmb> |
||||
|
<finNFe>{{ ide.finNFe }}</finNFe> |
||||
|
<indFinal>{{ ide.indFinal }}</indFinal> |
||||
|
<indPres>{{ ide.indPres }}</indPres> |
||||
|
<procEmi>{{ ide.procEmi }}</procEmi> |
||||
|
<verProc>Odoo Brasil 9.0</verProc> |
||||
|
{% endwith %} |
||||
|
</ide> |
||||
|
<emit> |
||||
|
{% with emit = NFe.infNFe.emit %} |
||||
|
<CNPJ>{{ emit.CNPJ }}</CNPJ> |
||||
|
<xNome>{{ emit.xNome }}</xNome> |
||||
|
<xFant>{{ emit.xFant }}</xFant> |
||||
|
<enderEmit> |
||||
|
<xLgr>{{ emit.enderEmit.xLgr }}</xLgr> |
||||
|
<nro>{{ emit.enderEmit.nro }}</nro> |
||||
|
<xBairro>{{ emit.enderEmit.xBairro }}</xBairro> |
||||
|
<cMun>{{ emit.enderEmit.cMun }}</cMun> |
||||
|
<xMun>{{ emit.enderEmit.xMun }}</xMun> |
||||
|
<UF>{{ emit.enderEmit.UF }}</UF> |
||||
|
<CEP>{{ emit.enderEmit.CEP }}</CEP> |
||||
|
<cPais>{{ emit.enderEmit.cPais }}</cPais> |
||||
|
<xPais>{{ emit.enderEmit.xPais }}</xPais> |
||||
|
<fone>{{ emit.enderEmit.fone }}</fone> |
||||
|
</enderEmit> |
||||
|
<IE>{{ emit.IE }}</IE> |
||||
|
<CRT>{{ emit.CRT }}</CRT> |
||||
|
{% endwith %} |
||||
|
</emit> |
||||
|
<dest> |
||||
|
{% with dest = NFe.infNFe.dest %} |
||||
|
<CNPJ>{{ dest.CNPJ }}</CNPJ> |
||||
|
<CPF>{{ dest.CPF }}</CPF> |
||||
|
<xNome>{{ dest.xNome }}</xNome> |
||||
|
<enderDest> |
||||
|
<xLgr>{{ dest.enderDest.xLgr }}</xLgr> |
||||
|
<nro>{{ dest.enderDest.nro }}</nro> |
||||
|
<xBairro>{{ dest.enderDest.xBairro }}</xBairro> |
||||
|
<cMun>{{ dest.enderDest.cMun }}</cMun> |
||||
|
<xMun>{{ dest.enderDest.xMun }}</xMun> |
||||
|
<UF>{{ dest.enderDest.UF }}</UF> |
||||
|
<CEP>{{ dest.enderDest.CEP }}</CEP> |
||||
|
<cPais>{{ dest.enderDest.cPais }}</cPais> |
||||
|
<xPais>{{ dest.enderDest.xPais }}</xPais> |
||||
|
<fone>{{ dest.enderDest.fone }}</fone> |
||||
|
</enderDest> |
||||
|
<indIEDest>{{ dest.indIEDest }}</indIEDest> |
||||
|
<IE>{{ dest.IE }}</IE> |
||||
|
{% endwith %} |
||||
|
</dest> |
||||
|
{% for det in NFe.infNFe.detalhes %} |
||||
|
<det nItem="1"> |
||||
|
<prod> |
||||
|
{% with prod = det.prod %} |
||||
|
<cProd>{{ prod.cProd }}</cProd> |
||||
|
<cEAN>{{ prod.cEAN }}</cEAN> |
||||
|
<xProd>{{ prod.xProd }}</xProd> |
||||
|
<NCM>{{ prod.NCM }}</NCM> |
||||
|
<CFOP>{{ prod.CFOP }}</CFOP> |
||||
|
<uCom>{{ prod.uCom }}</uCom> |
||||
|
<qCom>{{ prod.qCom }}</qCom> |
||||
|
<vUnCom>{{ prod.vUnCom }}</vUnCom> |
||||
|
<vProd>{{ prod.vProd }}</vProd> |
||||
|
<cEANTrib>{{ prod.cEANTrib }}</cEANTrib> |
||||
|
<uTrib>{{ prod.uTrib }}</uTrib> |
||||
|
<qTrib>{{ prod.qTrib }}</qTrib> |
||||
|
<vUnTrib>{{ prod.vUnTrib }}</vUnTrib> |
||||
|
<indTot>{{ prod.indTot }}</indTot> |
||||
|
{% endwith %} |
||||
|
</prod> |
||||
|
<imposto> |
||||
|
{% with imposto = det.imposto %} |
||||
|
<vTotTrib>{{ imposto.vTotTrib }}</vTotTrib> |
||||
|
<ICMS> |
||||
|
<ICMS00> |
||||
|
<orig>{{ imposto.ICMS.ICMS00.orig }}</orig> |
||||
|
<CST>{{ imposto.ICMS.ICMS00.CST }}</CST> |
||||
|
<modBC>{{ imposto.ICMS.ICMS00.modBC }}</modBC> |
||||
|
<vBC>{{ imposto.ICMS.ICMS00.vBC }}</vBC> |
||||
|
<pICMS>{{ imposto.ICMS.ICMS00.pICMS }}</pICMS> |
||||
|
<vICMS>{{ imposto.ICMS.ICMS00.vICMS }}</vICMS> |
||||
|
</ICMS00> |
||||
|
</ICMS> |
||||
|
<IPI> |
||||
|
<cEnq>{{ imposto.IPI.cEnq }}</cEnq> |
||||
|
<IPITrib> |
||||
|
<CST>{{ imposto.IPI.IPITrib.CST }}</CST> |
||||
|
<vBC>{{ imposto.IPI.IPITrib.vBC }}</vBC> |
||||
|
<pIPI>{{ imposto.IPI.IPITrib.pIPI }}</pIPI> |
||||
|
<vIPI>{{ imposto.IPI.IPITrib.vIPI }}</vIPI> |
||||
|
</IPITrib> |
||||
|
</IPI> |
||||
|
<PIS> |
||||
|
<PISAliq> |
||||
|
<CST>{{ imposto.PIS.PISAliq.CST }}</CST> |
||||
|
<vBC>{{ imposto.PIS.PISAliq.vBC }}</vBC> |
||||
|
<pPIS>{{ imposto.PIS.PISAliq.pPIS }}</pPIS> |
||||
|
<vPIS>{{ imposto.PIS.PISAliq.vPIS }}</vPIS> |
||||
|
</PISAliq> |
||||
|
</PIS> |
||||
|
<COFINS> |
||||
|
<COFINSAliq> |
||||
|
<CST>{{ imposto.COFINS.COFINSAliq.CST }}</CST> |
||||
|
<vBC>{{ imposto.COFINS.COFINSAliq.vBC }}</vBC> |
||||
|
<pCOFINS>{{ imposto.COFINS.COFINSAliq.pCOFINS }}</pCOFINS> |
||||
|
<vCOFINS>{{ imposto.COFINS.COFINSAliq.vCOFINS }}</vCOFINS> |
||||
|
</COFINSAliq> |
||||
|
</COFINS> |
||||
|
{% endwith %} |
||||
|
</imposto> |
||||
|
</det> |
||||
|
{% endfor %} |
||||
|
<total> |
||||
|
{% with total = NFe.infNFe.total %} |
||||
|
<ICMSTot> |
||||
|
<vBC>{{ total.vBC }}</vBC> |
||||
|
<vICMS>{{ total.vICMS }}</vICMS> |
||||
|
<vICMSDeson>{{ total.vICMSDeson }}</vICMSDeson> |
||||
|
<vBCST>{{ total.vBCST }}</vBCST> |
||||
|
<vST>{{ total.vST }}</vST> |
||||
|
<vProd>{{ total.vProd }}</vProd> |
||||
|
<vFrete>{{ total.vFrete }}</vFrete> |
||||
|
<vSeg>{{ total.vSeg }}</vSeg> |
||||
|
<vDesc>{{ total.vDesc }}</vDesc> |
||||
|
<vII>{{ total.vII }}</vII> |
||||
|
<vIPI>{{ total.vIPI }}</vIPI> |
||||
|
<vPIS>{{ total.vPIS }}</vPIS> |
||||
|
<vCOFINS>{{ total.vCOFINS }}</vCOFINS> |
||||
|
<vOutro>{{ total.vOutro }}</vOutro> |
||||
|
<vNF>{{ total.vNF }}</vNF> |
||||
|
<vTotTrib>{{ total.vTotTrib }}</vTotTrib> |
||||
|
</ICMSTot> |
||||
|
{% endwith %} |
||||
|
</total> |
||||
|
<transp> |
||||
|
<modFrete>{{ NFe.infNFe.transp.modFrete }}</modFrete> |
||||
|
</transp> |
||||
|
<cobr> |
||||
|
<dup> |
||||
|
<nDup>339/1</nDup> |
||||
|
<dVenc>2016-06-02</dVenc> |
||||
|
<vDup>8611.76</vDup> |
||||
|
</dup> |
||||
|
</cobr> |
||||
|
<infAdic> |
||||
|
<infCpl>{{ NFe.infNFe.infAdic.infCpl }}</infCpl> |
||||
|
</infAdic> |
||||
|
</infNFe> |
||||
|
</NFe> |
||||
|
{% endfor %} |
||||
|
</enviNFe> |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue