diff --git a/pytrustnfe/Servidores.py b/pytrustnfe/Servidores.py index 239053e..0b3e28d 100644 --- a/pytrustnfe/Servidores.py +++ b/pytrustnfe/Servidores.py @@ -332,8 +332,8 @@ UFBA = { WS_NFE_SITUACAO: 'webservices/NfeStatusServico/NfeStatusServico.asmx', WS_NFE_INUTILIZACAO: 'webservices/nfenw/nfeinutilizacao2.asmx', WS_NFE_CADASTRO: 'webservices/nfenw/CadConsultaCadastro2.asmx', - WS_NFE_RECEPCAO_EVENTO: 'webservices/sre/recepcaoevento', - WS_NFE_CANCELAMENTO: 'webservices/sre/recepcaoevento', + WS_NFE_RECEPCAO_EVENTO: 'webservices/sre/recepcaoevento.asmx', + WS_NFE_CANCELAMENTO: 'webservices/sre/recepcaoevento.asmx', }, NFE_AMBIENTE_HOMOLOGACAO: { 'servidor': 'hnfe.sefaz.ba.gov.br', @@ -344,8 +344,8 @@ UFBA = { WS_NFE_SITUACAO: 'webservices/NfeStatusServico/NfeStatusServico.asmx', WS_NFE_INUTILIZACAO: 'webservices/nfenw/nfeinutilizacao2.asmx', WS_NFE_CADASTRO: 'webservices/nfenw/CadConsultaCadastro2.asmx', - WS_NFE_RECEPCAO_EVENTO: 'webservices/sre/recepcaoevento', - WS_NFE_CANCELAMENTO: 'webservices/sre/recepcaoevento', + WS_NFE_RECEPCAO_EVENTO: 'webservices/sre/recepcaoevento.asmx', + WS_NFE_CANCELAMENTO: 'webservices/sre/recepcaoevento.asmx', } } diff --git a/pytrustnfe/nfe/danfe.py b/pytrustnfe/nfe/danfe.py index 7cb7303..001810a 100644 --- a/pytrustnfe/nfe/danfe.py +++ b/pytrustnfe/nfe/danfe.py @@ -16,6 +16,7 @@ from reportlab.graphics.barcode import code128 from reportlab.lib.styles import getSampleStyleSheet from reportlab.lib.enums import TA_CENTER from reportlab.platypus import Paragraph, Image +from reportlab.lib.styles import ParagraphStyle from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont @@ -41,11 +42,9 @@ def getdateUTC(cDateUTC): return '/'.join(cDt), cDateUTC[11:16] -def format_number(cNumber, precision=0, group_sep='.', decimal_sep=','): +def format_number(cNumber): if cNumber: - number = float(cNumber) - return ("{:,." + str(precision) + "f}").format(number).\ - replace(",", "X").replace(".", ",").replace("X", ".") + return cNumber.replace(",", "X").replace(".", ",").replace("X", ".") return "" @@ -57,6 +56,7 @@ def tagtext(oNode=None, cTag=None): cText = '' return cText + REGIME_TRIBUTACAO = { '1': 'Simples Nacional', '2': 'Simples Nacional, excesso sublimite de receita bruta', @@ -74,7 +74,7 @@ def get_image(path, width=1 * cm): class danfe(object): def __init__(self, sizepage=A4, list_xml=None, recibo=True, - orientation='portrait', logo=None): + orientation='portrait', logo=None, cce_xml=None): path = os.path.join(os.path.dirname(__file__), 'fonts') pdfmetrics.registerFont( @@ -178,7 +178,10 @@ class danfe(object): list_cod_prod=list_cod_prod) self.newpage() - + if cce_xml: + for xml in cce_xml: + self._generate_cce(cce_xml=xml, oXML=oXML) + self.newpage() self.canvas.save() def ide_emit(self, oXML=None): @@ -422,8 +425,7 @@ class danfe(object): self.string(self.nLeft + nCol + 17, self.nlin + nLin, cDt) self.stringRight( self.nLeft + nCol + 47, self.nlin + nLin, - format_number(tagtext(oNode=oXML_dup, cTag='vDup'), - precision=2)) + format_number(tagtext(oNode=oXML_dup, cTag='vDup'))) if nPar == 3: nLin = 7 @@ -491,41 +493,40 @@ obsCont[@xCampo='NomeVendedor']") self.canvas.setFont('NimbusSanL-Regu', 8) self.stringRight( self.nLeft + 34, self.nlin + 7.7, - format_number(tagtext(oNode=el_total, cTag='vBC'), precision=2)) + format_number(tagtext(oNode=el_total, cTag='vBC'))) self.stringRight( self.nLeft + 64, self.nlin + 7.7, - format_number(tagtext(oNode=el_total, cTag='vICMS'), precision=2)) + format_number(tagtext(oNode=el_total, cTag='vICMS'))) self.stringRight( self.nLeft + 94, self.nlin + 7.7, - format_number(tagtext(oNode=el_total, cTag='vBCST'), precision=2)) + format_number(tagtext(oNode=el_total, cTag='vBCST'))) self.stringRight( nMr - 66, self.nlin + 7.7, - format_number(tagtext(oNode=el_total, cTag='vST'), precision=2)) + format_number(tagtext(oNode=el_total, cTag='vST'))) self.stringRight( nMr - 36, self.nlin + 7.7, - format_number(tagtext(oNode=el_total, cTag='vTotTrib'), - precision=2)) + format_number(tagtext(oNode=el_total, cTag='vTotTrib'))) self.stringRight( nMr - 1, self.nlin + 7.7, - format_number(tagtext(oNode=el_total, cTag='vProd'), precision=2)) + format_number(tagtext(oNode=el_total, cTag='vProd'))) self.stringRight( self.nLeft + 34, self.nlin + 14.1, - format_number(tagtext(oNode=el_total, cTag='vFrete'), precision=2)) + format_number(tagtext(oNode=el_total, cTag='vFrete'))) self.stringRight( self.nLeft + 64, self.nlin + 14.1, - format_number(tagtext(oNode=el_total, cTag='vSeg'), precision=2)) + format_number(tagtext(oNode=el_total, cTag='vSeg'))) self.stringRight( self.nLeft + 94, self.nlin + 14.1, - format_number(tagtext(oNode=el_total, cTag='vDesc'), precision=2)) + format_number(tagtext(oNode=el_total, cTag='vDesc'))) self.stringRight( self.nLeft + 124, self.nlin + 14.1, - format_number(tagtext(oNode=el_total, cTag='vOutro'), precision=2)) + format_number(tagtext(oNode=el_total, cTag='vOutro'))) self.stringRight( self.nLeft + 154, self.nlin + 14.1, - format_number(tagtext(oNode=el_total, cTag='vIPI'), precision=2)) + format_number(tagtext(oNode=el_total, cTag='vIPI'))) self.stringRight( nMr - 1, self.nlin + 14.1, - format_number(tagtext(oNode=el_total, cTag='vNF'), precision=2)) + format_number(tagtext(oNode=el_total, cTag='vNF'))) self.nlin += 17 # Nr linhas ocupadas pelo bloco @@ -594,10 +595,10 @@ obsCont[@xCampo='NomeVendedor']") tagtext(oNode=el_transp, cTag='nVol')) self.stringRight( nMr - 27, self.nlin + 21.2, - format_number(tagtext(oNode=el_transp, cTag='pesoB'), precision=3)) + format_number(tagtext(oNode=el_transp, cTag='pesoB'))) self.stringRight( nMr - 1, self.nlin + 21.2, - format_number(tagtext(oNode=el_transp, cTag='pesoL'), precision=3)) + format_number(tagtext(oNode=el_transp, cTag='pesoL'))) self.nlin += 23 @@ -633,10 +634,10 @@ obsCont[@xCampo='NomeVendedor']") self.stringcenter(nMr - 44, self.nlin + 5.5, 'BC ICMS') self.vline(nMr - 64, self.nlin + 2, nH) self.stringcenter(nMr - 57, self.nlin + 5.5, 'VLR TOTAL') - self.vline(nMr - 77, self.nlin + 2, nH) + self.vline(nMr - 78, self.nlin + 2, nH) self.stringcenter(nMr - 70.5, self.nlin + 5.5, 'VLR UNIT') self.vline(nMr - 90, self.nlin + 2, nH) - self.stringcenter(nMr - 83.5, self.nlin + 5.5, 'QTD') + self.stringcenter(nMr - 83.8, self.nlin + 5.5, 'QTD') self.vline(nMr - 96, self.nlin + 2, nH) self.stringcenter(nMr - 93, self.nlin + 5.5, 'UNID') self.vline(nMr - 102, self.nlin + 2, nH) @@ -665,7 +666,6 @@ obsCont[@xCampo='NomeVendedor']") ".//{http://www.portalfiscal.inf.br/nfe}ICMS") el_imp_IPI = el_imp.find( ".//{http://www.portalfiscal.inf.br/nfe}IPI") - cCST = tagtext(oNode=el_imp_ICMS, cTag='orig') + \ (tagtext(oNode=el_imp_ICMS, cTag='CST') or tagtext(oNode=el_imp_ICMS, cTag='CSOSN')) @@ -683,24 +683,20 @@ obsCont[@xCampo='NomeVendedor']") tagtext(oNode=el_prod, cTag='CFOP')) self.stringcenter(nMr - 93, nLin, tagtext(oNode=el_prod, cTag='uCom')) - self.stringRight(nMr - 77.5, nLin, format_number( - tagtext(oNode=el_prod, cTag='qCom'), precision=4)) + self.stringRight(nMr - 78.5, nLin, format_number( + tagtext(oNode=el_prod, cTag='qCom'))) self.stringRight(nMr - 64.5, nLin, format_number( - tagtext(oNode=el_prod, cTag='vUnCom'), precision=2)) - self.stringRight(nMr - 50.5, nLin, format_number( - tagtext(oNode=el_prod, cTag='vProd'), precision=2)) - self.stringRight(nMr - 38.5, nLin, format_number(vBC, precision=2)) - self.stringRight(nMr - 26.5, nLin, - format_number(vICMS, precision=2)) - self.stringRight( - nMr - 7.5, nLin, format_number(pICMS, precision=2)) + tagtext(oNode=el_prod, cTag='vUnCom'))) + self.stringRight(nMr - 50.5, nLin, + tagtext(oNode=el_prod, cTag='vProd')) + self.stringRight(nMr - 38.5, nLin, format_number(vBC)) + self.stringRight(nMr - 26.5, nLin, format_number(vICMS)) + self.stringRight(nMr - 7.5, nLin, format_number(pICMS)) if vIPI: - self.stringRight(nMr - 14.5, nLin, - format_number(vIPI, precision=2)) + self.stringRight(nMr - 14.5, nLin, format_number(vIPI)) if pIPI: - self.stringRight(nMr - 0.5, nLin, - format_number(pIPI, precision=2)) + self.stringRight(nMr - 0.5, nLin, format_number(pIPI)) # Código Item line_cod = nLin @@ -741,7 +737,6 @@ obsCont[@xCampo='NomeVendedor']") styleN.fontSize = 6 styleN.fontName = 'NimbusSanL-Regu' styleN.leading = 7 - fisco = tagtext(oNode=el_infAdic, cTag='infAdFisco') observacoes = tagtext(oNode=el_infAdic, cTag='infCpl') if fisco: @@ -785,8 +780,7 @@ obsCont[@xCampo='NomeVendedor']") "SÉRIE %s" % (tagtext(oNode=el_ide, cTag='serie'))) cDt, cHr = getdateUTC(tagtext(oNode=el_ide, cTag='dhEmi')) - cTotal = format_number(tagtext(oNode=el_total, cTag='vNF'), - precision=2) + cTotal = format_number(tagtext(oNode=el_total, cTag='vNF')) cEnd = tagtext(oNode=el_dest, cTag='xNome') + ' - ' cEnd += tagtext(oNode=el_dest, cTag='xLgr') + ', ' + tagtext( @@ -852,3 +846,80 @@ obsCont[@xCampo='NomeVendedor']") self.oPDF_IO.close() fileObj.write(pdf_out) + def _generate_cce(self, cce_xml=None, oXML=None): + self.canvas.setLineWidth(.2) + + # labels + self.canvas.setFont('NimbusSanL-Bold', 12) + self.stringcenter(105, 10, u"Carta de Correção") + self.canvas.setFont('NimbusSanL-Regu', 6) + self.string(10, 18, u"RAZÃO SOCIAL DO EMITENTE") + self.string(10, 24, u"CNPJ DO EMITENTE") + self.string(10, 30, u"CHAVE DE ACESSO DA NF-E") + self.string(10, 36, u"DATA DA CORREÇÃO") + self.string(10, 42, u"ID") + self.stringcenter(105, 48, u"CORREÇÃO") + + # lines + self.hline(9, 14, 200) + self.hline(9, 20, 200) + self.hline(9, 26, 200) + self.hline(9, 32, 200) + self.hline(9, 38, 200) + self.hline(9, 44, 200) + self.hline(9, 50, 200) + + # values + infNFe = oXML.find( + ".//{http://www.portalfiscal.inf.br/nfe}infNFe") + res_partner = infNFe.find( + ".//{http://www.portalfiscal.inf.br/nfe}xNome") + + elem_infNFe = cce_xml.find( + ".//{http://www.portalfiscal.inf.br/nfe}infEvento") + + res_partner = tagtext(oNode=infNFe, cTag='xNome') + self.string(82, 18, res_partner) + cnpj = format_cnpj_cpf(tagtext + (oNode=elem_infNFe, cTag='CNPJ')) + self.string(82, 24, cnpj) + chave_acesso = tagtext(oNode=elem_infNFe, cTag='chNFe') + self.string(82, 30, chave_acesso) + data_correcao = getdateUTC(tagtext( + oNode=elem_infNFe, cTag='dhEvento')) + data_correcao = data_correcao[0] + " " + data_correcao[1] + self.string(82, 36, data_correcao) + cce_id = elem_infNFe.values()[0] + self.string(82, 42, cce_id) + + correcao = tagtext(oNode=elem_infNFe, cTag='xCorrecao') + + w, h, paragraph = self._paragraph( + correcao, 'NimbusSanL-Regu', 10, 190 * mm, 20 * mm) + paragraph.drawOn(self.canvas, 10 * mm, (297 - 52) * mm - h) + + self.hline(9, 54 + (h / mm), 200) + self.stringcenter(105, 58 + (h / mm), u"CONDIÇÃO DE USO") + self.hline(9, 60 + (h / mm), 200) + + condicoes = tagtext(oNode=elem_infNFe, cTag='xCondUso') + + w2, h2, paragraph = self._paragraph( + condicoes, 'NimbusSanL-Regu', 10, 190 * mm, 20 * mm) + paragraph.drawOn(self.canvas, 10 * mm, (297 - 62) * mm - h - h2) + + self.hline(9, 68 + ((h + h2) / mm), 200) + + self.vline(80, 14, 30) + self.vline(9, 14, 54 + ((h + h2) / mm)) + self.vline(200, 14, 54 + ((h + h2) / mm)) + + def _paragraph(self, text, font, font_size, x, y): + ptext = '%s' % (font_size, text) + style = ParagraphStyle(name='Normal', + fontName=font, + fontSize=font_size, + ) + paragraph = Paragraph(ptext, style=style) + w, h = paragraph.wrapOn(self.canvas, x, y) + return w, h, paragraph diff --git a/pytrustnfe/nfse/ginfes/templates/Rps.xml b/pytrustnfe/nfse/ginfes/templates/Rps.xml index b65ac46..d366389 100644 --- a/pytrustnfe/nfse/ginfes/templates/Rps.xml +++ b/pytrustnfe/nfse/ginfes/templates/Rps.xml @@ -27,11 +27,11 @@ {{ rps.valor_csll }} {{ rps.iss_retido }} {{ rps.valor_iss }} + {{ rps.valor_iss_retido }} {{ rps.outras_retencoes }} {{ rps.base_calculo }} {{ rps.aliquota_issqn }} {{ rps.valor_liquido_nfse }} - {{ rps.valor_iss_retido }} {{ rps.desconto_incondicionado }} {{ rps.desconto_condicionado }} diff --git a/pytrustnfe/nfse/imperial/__init__.py b/pytrustnfe/nfse/imperial/__init__.py new file mode 100644 index 0000000..64a8125 --- /dev/null +++ b/pytrustnfe/nfse/imperial/__init__.py @@ -0,0 +1,76 @@ +# -*- 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 pytrustnfe import HttpClient +from pytrustnfe.xml import render_xml, sanitize_response + + +def _render(certificado, method, **kwargs): + path = os.path.join(os.path.dirname(__file__), 'templates') + xml_send = render_xml(path, '%s.xml' % method, True, **kwargs) + return etree.tostring(xml_send) + + +def _send(certificado, method, **kwargs): + base_url = '' + if kwargs['ambiente'] == 'producao': + base_url = 'https://nfe.etransparencia.com.br/rj.petropolis/webservice/aws_nfe.aspx' # noqa + else: + base_url = 'https://nfehomologacao.etransparencia.com.br/rj.petropolis/webservice/aws_nfe.aspx' # noqa + + xml_send = kwargs["xml"] + path = os.path.join(os.path.dirname(__file__), 'templates') + soap = render_xml(path, 'SoapRequest.xml', False, soap_body=xml_send) + + client = HttpClient(base_url) + response = client.post_soap(soap, 'NFeaction/AWS_NFE.%s' % method) + + response, obj = sanitize_response(response) + return { + 'sent_xml': xml_send, + 'received_xml': response, + 'object': obj + } + + +def xml_processa_rps(certificado, **kwargs): + return _render(certificado, 'PROCESSARPS', **kwargs) + + +def processa_rps(certificado, **kwargs): + if "xml" not in kwargs: + kwargs['xml'] = xml_processa_rps(certificado, **kwargs) + return _send(certificado, 'PROCESSARPS', **kwargs) + + +def xml_consulta_protocolo(certificado, **kwargs): + return _render(certificado, 'CONSULTAPROTOCOLO', **kwargs) + + +def consulta_protocolo(certificado, **kwargs): + if "xml" not in kwargs: + kwargs['xml'] = xml_consulta_protocolo(certificado, **kwargs) + return _send(certificado, 'CONSULTAPROTOCOLO', **kwargs) + + +def xml_consulta_notas_protocolo(certificado, **kwargs): + return _render(certificado, 'CONSULTANOTASPROTOCOLO', **kwargs) + + +def consulta_notas_protocolo(certificado, **kwargs): + if "xml" not in kwargs: + kwargs['xml'] = xml_consulta_notas_protocolo(certificado, **kwargs) + return _send(certificado, 'CONSULTANOTASPROTOCOLO', **kwargs) + + +def xml_cancelar_nfse(certificado, **kwargs): + return _render(certificado, 'CANCELANOTAELETRONICA', **kwargs) + + +def cancelar_nfse(certificado, **kwargs): + if "xml" not in kwargs: + kwargs['xml'] = xml_cancelar_nfse(certificado, **kwargs) + return _send(certificado, 'CANCELANOTAELETRONICA', **kwargs) diff --git a/pytrustnfe/nfse/imperial/templates/CANCELANOTAELETRONICA.xml b/pytrustnfe/nfse/imperial/templates/CANCELANOTAELETRONICA.xml new file mode 100644 index 0000000..3afb262 --- /dev/null +++ b/pytrustnfe/nfse/imperial/templates/CANCELANOTAELETRONICA.xml @@ -0,0 +1,17 @@ + + + + {{ cancelamento.codigo_usuario }} + {{ cancelamento.codigo_contribuinte }} + + + {{ cancelamento.serie_nota }} + {{ cancelamento.numero_nota }} + {{ cancelamento.serie_rps }} + {{ cancelamento.numero_rps }} + {{ cancelamento.valor }} + {{ cancelamento.motivo }} + {{ cancelamento.cancelar_guia }} + + + diff --git a/pytrustnfe/nfse/imperial/templates/CONSULTANOTASPROTOCOLO.xml b/pytrustnfe/nfse/imperial/templates/CONSULTANOTASPROTOCOLO.xml new file mode 100644 index 0000000..30ea3d6 --- /dev/null +++ b/pytrustnfe/nfse/imperial/templates/CONSULTANOTASPROTOCOLO.xml @@ -0,0 +1,9 @@ + + + {{ consulta.protocolo }} + + {{ consulta.codigo_usuario }} + {{ consulta.codigo_contribuinte }} + + + diff --git a/pytrustnfe/nfse/imperial/templates/CONSULTAPROTOCOLO.xml b/pytrustnfe/nfse/imperial/templates/CONSULTAPROTOCOLO.xml new file mode 100644 index 0000000..09765e5 --- /dev/null +++ b/pytrustnfe/nfse/imperial/templates/CONSULTAPROTOCOLO.xml @@ -0,0 +1,9 @@ + + + {{ consulta.protocolo }} + + {{ consulta.codigo_usuario }} + {{ consulta.codigo_contribuinte }} + + + diff --git a/pytrustnfe/nfse/imperial/templates/PROCESSARPS.xml b/pytrustnfe/nfse/imperial/templates/PROCESSARPS.xml new file mode 100644 index 0000000..3cfb27a --- /dev/null +++ b/pytrustnfe/nfse/imperial/templates/PROCESSARPS.xml @@ -0,0 +1,81 @@ + + + + {{ nfse.codigo_usuario }} + {{ nfse.codigo_contribuinte }} + + + {{ nfse.ano }} + {{ nfse.mes }} + {{ nfse.cnpj_prestador }} + {{ nfse.data_emissao }} + {{ nfse.data_emissao }} + {{ nfse.tipo_tributacao }} + {{ nfse.data_adesao_simples }} + {{ nfse.aliquota_simples_isencao|comma }} + 2.00 + {% for rps in nfse.lista_rps -%} + + + + {{ rps.tipo_nfse }} + {{ rps.numero }} + {{ rps.serie }} + {{ rps.data_emissao }} + {{ rps.iss_retido }} + {{ rps.codigo_servico }} + {{ rps.descricao}} + {{ rps.valor_liquido_nfse|comma }} + {{ rps.valor_deducao|comma }} + {{ rps.discriminacao_deducao }} + {{ rps.base_calculo|comma }} + {{ rps.aliquota_issqn|comma }} + {{ rps.valor_iss|comma }} + {{ rps.valor_iss_retido|comma }} + {{ rps.tomador.cnpj_cpf }} + {{ rps.tomador.razao_social }} + {{ rps.tomador.tipo_logradouro }} + {{ rps.tomador.logradouro }} + {{ rps.tomador.numero }} + {{ rps.tomador.complemento }} + {{ rps.tomador.bairro }} + {{ rps.tomador.municipio }} + {{ rps.tomador.uf }} + {{ rps.tomador.cep }} + {{ rps.tomador.telefone }} + {{ rps.tomador.inscricao_municipal }} + {% if rps.local_prestacao == 'prestador' %} + {{ rps.prestador.tipo_logradouro }} + {{ rps.prestador.logradouro }} + {{ rps.prestador.numero }} + {{ rps.prestador.complemento }} + {{ rps.prestador.bairro }} + {{ rps.prestador.municipio }} + {{ rps.prestador.uf }} + {{ rps.prestador.cep }} + {% endif %} + {{ rps.tomador.email }} + {% for imposto in rps.impostos -%} + + + {{ imposto.sigla }} + {{ imposto.aliquota|comma }} + {{ imposto.valor|comma }} + + + {% endfor %} + + + {% endfor %} + + {{ nfse.lista_rps|length }} + {{ nfse.lista_rps|sum(attribute='valor_liquido_nfse')|comma }} + {{ nfse.lista_rps|sum(attribute='valor_iss')|comma }} + {{ nfse.lista_rps|sum(attribute='valor_deducao')|comma }} + {{ nfse.lista_rps|sum(attribute='valor_iss_retido')|comma }} + {{ nfse.quantidade_impostos }} + {{ nfse.valor_tributos|comma }} + + + + diff --git a/pytrustnfe/nfse/imperial/templates/SoapRequest.xml b/pytrustnfe/nfse/imperial/templates/SoapRequest.xml new file mode 100644 index 0000000..e8b56b4 --- /dev/null +++ b/pytrustnfe/nfse/imperial/templates/SoapRequest.xml @@ -0,0 +1,5 @@ + + + {{ soap_body }} + + diff --git a/pytrustnfe/xml/__init__.py b/pytrustnfe/xml/__init__.py index 413df5e..5cf7454 100644 --- a/pytrustnfe/xml/__init__.py +++ b/pytrustnfe/xml/__init__.py @@ -15,6 +15,18 @@ def recursively_empty(e): return all((recursively_empty(c) for c in e.iterchildren())) +def recursively_normalize(vals): + for item in vals: + if type(vals[item]) is str: + vals[item] = vals[item].strip() + elif type(vals[item]) is dict: + recursively_normalize(vals[item]) + elif type(vals[item]) is list: + for a in vals[item]: + recursively_normalize(a) + return vals + + def render_xml(path, template_name, remove_empty, **nfe): nfe = recursively_normalize(nfe) env = Environment( @@ -25,6 +37,7 @@ def render_xml(path, template_name, remove_empty, **nfe): env.filters["format_percent"] = filters.format_percent env.filters["format_datetime"] = filters.format_datetime env.filters["format_date"] = filters.format_date + env.filters["comma"] = filters.format_with_comma template = env.get_template(template_name) xml = template.render(**nfe) diff --git a/pytrustnfe/xml/filters.py b/pytrustnfe/xml/filters.py index afd19ec..c3f7cbf 100644 --- a/pytrustnfe/xml/filters.py +++ b/pytrustnfe/xml/filters.py @@ -59,3 +59,9 @@ def format_date(value): if isinstance(value, date): return value.strftime(dt_format) return value + + +def format_with_comma(value): + if isinstance(value, float): + return ('%.2f' % value).replace('.', ',') + return value diff --git a/setup.py b/setup.py index a8408d7..07a803b 100644 --- a/setup.py +++ b/setup.py @@ -1,8 +1,10 @@ # coding=utf-8 from setuptools import setup, find_packages + VERSION = "0.9.8" + setup( name="PyTrustNFe3", version=VERSION, @@ -32,6 +34,7 @@ later (LGPLv2+)', 'nfse/simpliss/templates/*xml', 'nfse/betha/templates/*xml', 'nfse/susesu/templates/*xml', + 'nfse/imperial/templates/*xml', 'nfse/floripa/templates/*xml', 'xml/schemas/*xsd', ]},