diff --git a/pytrustnfe/Servidores.py b/pytrustnfe/Servidores.py
index 0b3e28d..8cb43a7 100644
--- a/pytrustnfe/Servidores.py
+++ b/pytrustnfe/Servidores.py
@@ -20,7 +20,6 @@ WS_NFCE_CADASTRO = 'NfeConsultaCadastro'
WS_NFCE_RECEPCAO_EVENTO = 'RecepcaoEventoCarta'
WS_NFCE_QR_CODE = 'NfeQRCode'
WS_NFCE_CONSULTA_DESTINADAS = 'NfeConsultaDest',
-WS_NFCE_RET_AUTORIZACAO = 'NFeRetAutorizacao',
WS_NFE_CADASTRO = 'NfeConsultaCadastro'
@@ -97,11 +96,8 @@ def localizar_url(servico, estado, mod='55', ambiente=2):
def localizar_qrcode(estado, ambiente=2):
sigla = SIGLA_ESTADO[estado]
- dominio = ESTADO_WS[sigla]['65'][ambiente]['servidor']
- complemento = ESTADO_WS[sigla]['65'][ambiente][WS_NFCE_QR_CODE]
- if 'https://' in complemento:
- return complemento
- return "https://%s/%s" % (dominio, complemento)
+ ws_qrcode = ESTADO_WS[sigla][NFCE_MODELO][ambiente][WS_NFCE_QR_CODE]
+ return ws_qrcode
METODO_WS = {
@@ -137,27 +133,53 @@ METODO_WS = {
}
SVRS = {
- NFE_AMBIENTE_PRODUCAO: {
- 'servidor': 'nfe.svrs.rs.gov.br',
- WS_NFE_RECEPCAO_EVENTO: 'ws/recepcaoevento/recepcaoevento.asmx',
- WS_NFE_CANCELAMENTO: 'ws/recepcaoevento/recepcaoevento.asmx',
- WS_NFE_AUTORIZACAO: 'ws/NfeAutorizacao/NfeAutorizacao.asmx',
- WS_NFE_RET_AUTORIZACAO: 'ws/NfeRetAutorizacao/NfeRetAutorizacao.asmx',
- WS_NFE_CADASTRO: 'ws/CadConsultaCadastro/CadConsultaCadastro2.asmx',
- WS_NFE_INUTILIZACAO: 'ws/nfeinutilizacao/nfeinutilizacao2.asmx',
- WS_NFE_CONSULTA: 'ws/NfeConsulta/NfeConsulta2.asmx',
- WS_NFE_SITUACAO: 'ws/NfeStatusServico/NfeStatusServico2.asmx',
+ NFE_MODELO: {
+ NFE_AMBIENTE_PRODUCAO: {
+ 'servidor': 'nfe.svrs.rs.gov.br',
+ WS_NFE_RECEPCAO_EVENTO: 'ws/recepcaoevento/recepcaoevento.asmx',
+ WS_NFE_CANCELAMENTO: 'ws/recepcaoevento/recepcaoevento.asmx',
+ WS_NFE_AUTORIZACAO: 'ws/NfeAutorizacao/NfeAutorizacao.asmx',
+ WS_NFE_RET_AUTORIZACAO: 'ws/NfeRetAutorizacao/NfeRetAutorizacao.asmx',
+ WS_NFE_CADASTRO: 'ws/CadConsultaCadastro/CadConsultaCadastro2.asmx',
+ WS_NFE_INUTILIZACAO: 'ws/nfeinutilizacao/nfeinutilizacao2.asmx',
+ WS_NFE_CONSULTA: 'ws/NfeConsulta/NfeConsulta2.asmx',
+ WS_NFE_SITUACAO: 'ws/NfeStatusServico/NfeStatusServico2.asmx',
+ },
+ NFE_AMBIENTE_HOMOLOGACAO: {
+ 'servidor': 'nfe-homologacao.svrs.rs.gov.br',
+ WS_NFE_RECEPCAO_EVENTO: 'ws/recepcaoevento/recepcaoevento.asmx',
+ WS_NFE_CANCELAMENTO: 'ws/recepcaoevento/recepcaoevento.asmx',
+ WS_NFE_AUTORIZACAO: 'ws/NfeAutorizacao/NfeAutorizacao.asmx',
+ WS_NFE_RET_AUTORIZACAO: 'ws/NfeRetAutorizacao/NfeRetAutorizacao.asmx',
+ WS_NFE_CADASTRO: 'ws/CadConsultaCadastro/CadConsultaCadastro2.asmx',
+ WS_NFE_INUTILIZACAO: 'ws/nfeinutilizacao/nfeinutilizacao2.asmx',
+ WS_NFE_CONSULTA: 'ws/NfeConsulta/NfeConsulta2.asmx',
+ WS_NFE_SITUACAO: 'ws/NfeStatusServico/NfeStatusServico2.asmx',
+ }
},
- NFE_AMBIENTE_HOMOLOGACAO: {
- 'servidor': 'nfe-homologacao.svrs.rs.gov.br',
- WS_NFE_RECEPCAO_EVENTO: 'ws/recepcaoevento/recepcaoevento.asmx',
- WS_NFE_CANCELAMENTO: 'ws/recepcaoevento/recepcaoevento.asmx',
- WS_NFE_AUTORIZACAO: 'ws/NfeAutorizacao/NfeAutorizacao.asmx',
- WS_NFE_RET_AUTORIZACAO: 'ws/NfeRetAutorizacao/NfeRetAutorizacao.asmx',
- WS_NFE_CADASTRO: 'ws/CadConsultaCadastro/CadConsultaCadastro2.asmx',
- WS_NFE_INUTILIZACAO: 'ws/nfeinutilizacao/nfeinutilizacao2.asmx',
- WS_NFE_CONSULTA: 'ws/NfeConsulta/NfeConsulta2.asmx',
- WS_NFE_SITUACAO: 'ws/NfeStatusServico/NfeStatusServico2.asmx',
+ NFCE_MODELO: {
+ NFCE_AMBIENTE_PRODUCAO: {
+ 'servidor': 'nfce.svrs.rs.gov.br',
+ WS_NFCE_INUTILIZACAO: 'ws/nfeinutilizacao/nfeinutilizacao2.asmx',
+ WS_NFCE_CONSULTA: 'ws/NfeConsulta/NfeConsulta2.asmx',
+ WS_NFCE_CANCELAMENTO: 'ws/recepcaoevento/recepcaoevento.asmx',
+ WS_NFCE_SITUACAO: 'ws/NfeStatusServico/NfeStatusServico2.asmx',
+ WS_NFCE_AUTORIZACAO: 'ws/NfeAutorizacao/NFeAutorizacao.asmx',
+ WS_NFCE_RET_AUTORIZACAO: 'ws/NfeRetAutorizacao/NFeRetAutorizacao.asmx',
+ WS_NFCE_RECEPCAO_EVENTO: 'ws/recepcaoevento/recepcaoevento.asmx',
+ WS_NFCE_QR_CODE: 'http://dec.fazenda.df.gov.br/ConsultarNFCe.aspx',
+ },
+ NFCE_AMBIENTE_HOMOLOGACAO: {
+ 'servidor': 'nfce-homologacao.svrs.rs.gov.br',
+ WS_NFCE_INUTILIZACAO: 'ws/nfeinutilizacao/nfeinutilizacao2.asmx',
+ WS_NFCE_CONSULTA: 'ws/NfeConsulta/NfeConsulta2.asmx',
+ WS_NFCE_CANCELAMENTO: 'ws/recepcaoevento/recepcaoevento.asmx',
+ WS_NFCE_SITUACAO: 'ws/NfeStatusServico/NfeStatusServico2.asmx',
+ WS_NFCE_AUTORIZACAO: 'ws/NfeAutorizacao/NFeAutorizacao.asmx',
+ WS_NFCE_RET_AUTORIZACAO: 'ws/NfeRetAutorizacao/NFeRetAutorizacao.asmx',
+ WS_NFCE_RECEPCAO_EVENTO: 'ws/recepcaoevento/recepcaoevento.asmx',
+ WS_NFCE_QR_CODE: 'http://dec.fazenda.df.gov.br/ConsultarNFCe.aspx',
+ }
}
}
@@ -317,7 +339,7 @@ UFAM = {
WS_NFE_INUTILIZACAO: 'nfce-services-nac/services/NfeInutilizacao2',
WS_NFE_CONSULTA: 'nfce-services-nac/services/NfeConsulta2',
WS_NFE_SITUACAO: 'nfce-services-nac/services/NfeStatusServico2',
- WS_NFCE_QR_CODE: 'nfceweb/consultarNFCe.jsp',
+ WS_NFCE_QR_CODE: 'homnfce.sefaz.am.gov.br/nfceweb/consultarNFCe.jsp',
}
}
}
@@ -626,7 +648,7 @@ UFSP = {
WS_NFCE_SITUACAO: 'ws/nfestatusservico2.asmx',
WS_NFCE_CADASTRO: 'ws/cadconsultacadastro2.asmx',
WS_NFCE_RECEPCAO_EVENTO: 'ws/recepcaoevento.asmx',
- WS_NFCE_QR_CODE: 'NFCEConsultaPublica/Paginas/ConstultaQRCode.aspx',
+ WS_NFCE_QR_CODE: 'https://homologacao.nfce.fazenda.sp.gov.br/NFCEConsultaPublica/Paginas/ConstultaQRCode.aspx',
}
}
}
diff --git a/pytrustnfe/nfe/__init__.py b/pytrustnfe/nfe/__init__.py
index bf87674..e5824b0 100644
--- a/pytrustnfe/nfe/__init__.py
+++ b/pytrustnfe/nfe/__init__.py
@@ -87,9 +87,7 @@ def _add_qrCode(xml, **kwargs):
valor_total = inf_nfe['total']['vNF']
dest_cpf = 'Inexistente'
dest = nfe.find(".//{http://www.portalfiscal.inf.br/nfe}dest")
- if dest:
- dest_parent = dest.getparent()
- dest_parent.remove(dest)
+
if inf_nfe.get('dest', False):
if inf_nfe['dest'].get('CPF', False):
dest_cpf = inf_nfe['dest']['CPF']
@@ -97,7 +95,7 @@ def _add_qrCode(xml, **kwargs):
cpf = etree.Element('CPF')
cpf.text = dest_cpf
dest.append(cpf)
- dest_parent.append(dest)
+
icms_total = inf_nfe['total']['vICMS']
dig_val = binascii.hexlify(xml.find(
".//{http://www.w3.org/2000/09/xmldsig#}DigestValue").text.encode()).decode()
@@ -182,7 +180,7 @@ def _render(certificado, method, sign, **kwargs):
def _send(certificado, method, **kwargs):
xml_send = kwargs["xml"]
- url = localizar_url(method, kwargs['estado'], '55',
+ url = localizar_url(method, kwargs['estado'], kwargs['modelo'],
kwargs['ambiente'])
cabecalho = _build_header(method, **kwargs)
@@ -267,6 +265,7 @@ def xml_consulta_cadastro(certificado, **kwargs):
def consulta_cadastro(certificado, **kwargs):
if "xml" not in kwargs:
kwargs['xml'] = xml_consulta_cadastro(certificado, **kwargs)
+ kwargs['modelo'] = '55'
return _send(certificado, 'NfeConsultaCadastro', **kwargs)
diff --git a/pytrustnfe/nfe/comunicacao.py b/pytrustnfe/nfe/comunicacao.py
index df6ba53..b164bb4 100644
--- a/pytrustnfe/nfe/comunicacao.py
+++ b/pytrustnfe/nfe/comunicacao.py
@@ -27,6 +27,7 @@ def executar_consulta(certificado, url, cabecalho, xmlEnviar, send_raw=False):
client = HttpClient(url, cert_path, key_path)
xml_enviar = _soap_xml(xmlEnviar, cabecalho)
+ xml_enviar = xml_enviar.encode('utf-8')
if send_raw:
xml = '' + xmlEnviar.rstrip('\n')
xml_enviar = xml
diff --git a/pytrustnfe/nfe/danfce.py b/pytrustnfe/nfe/danfce.py
new file mode 100644
index 0000000..21cd50b
--- /dev/null
+++ b/pytrustnfe/nfe/danfce.py
@@ -0,0 +1,456 @@
+# -*- coding: utf-8 -*-
+# © 2017 Johny Chen Jy, Trustcode
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+from textwrap import wrap
+from io import BytesIO
+
+from reportlab.lib import utils
+from reportlab.pdfgen import canvas
+from reportlab.lib.units import cm, mm
+from reportlab.graphics.barcode import qr
+from reportlab.graphics import renderPDF
+from reportlab.graphics.shapes import Drawing
+from reportlab.platypus import Table, TableStyle, Paragraph, Image
+from reportlab.lib.enums import TA_CENTER
+from reportlab.lib.styles import ParagraphStyle
+
+
+def format_cnpj_cpf(value):
+ if len(value) < 12: # CPF
+ cValue = '%s.%s.%s-%s' % (value[:-8], value[-8:-5],
+ value[-5:-2], value[-2:])
+ else:
+ cValue = '%s.%s.%s/%s-%s' % (value[:-12], value[-12:-9],
+ value[-9:-6], value[-6:-2], value[-2:])
+ return cValue
+
+
+def getdateUTC(cDateUTC):
+ cDt = cDateUTC[0:10].split('-')
+ cDt.reverse()
+ return '/'.join(cDt), cDateUTC[11:16]
+
+
+def format_number(cNumber, precision=0, group_sep='.', decimal_sep=','):
+ if cNumber:
+ number = float(cNumber)
+ return ("{:,." + str(precision) + "f}").format(number).\
+ replace(",", "X").replace(".", ",").replace("X", ".")
+ return ""
+
+
+def tagtext(oNode=None, cTag=None):
+ try:
+ xpath = ".//{http://www.portalfiscal.inf.br/nfe}%s" % (cTag)
+ cText = oNode.find(xpath).text
+ except:
+ cText = ''
+ return cText
+
+
+def get_image(path, width=1 * cm):
+ img = utils.ImageReader(path)
+ iw, ih = img.getSize()
+ aspect = ih / float(iw)
+ return Image(path, width=width, height=(width * aspect))
+
+
+def format_telefone(numero_telefone):
+ if len(numero_telefone) == 10:
+ telefone = '(%s) %s-%s' % (numero_telefone[0:2],
+ numero_telefone[2:6],
+ numero_telefone[6:])
+ else:
+ telefone = '(%s) %s-%s' % (numero_telefone[0:2],
+ numero_telefone[2:7],
+ numero_telefone[7:])
+ return telefone
+
+
+class danfce(object):
+
+ def __init__(self, list_xml, logo=None):
+
+ self.current_font_size = 7
+ self.current_font_name = 'NimbusSanL-Regu'
+
+ self.max_height = 840
+ self.min_height = 1
+ self.min_width = 5
+ self.max_width = 200
+ self.current_height = 840
+
+ self.oPDF_IO = BytesIO()
+ self.canvas = canvas.Canvas(self.oPDF_IO, pagesize=(7.2 * cm, 30 * cm))
+ self.canvas.setTitle('DANFCE')
+ self.canvas.setLineWidth(.5)
+ self.canvas.setFont(self.current_font_name, self.current_font_size)
+
+ self.list_xml = list_xml
+ self.logo = logo
+
+ self.nfce_generate()
+
+ def ide_emit(self, oXML=None):
+
+ elem_emit = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}emit")
+
+ # Razão Social emitente
+ nomeEmpresa = tagtext(oNode=elem_emit, cTag='xFant')
+ self.drawTitle(nomeEmpresa, 10)
+
+ if self.logo:
+ img = get_image(self.logo, width=10 * mm)
+ img.drawOn(self.canvas, 5, 830)
+
+ cEnd = tagtext(oNode=elem_emit, cTag="xNome") + '
'
+ cEnd += "CNPJ: %s " % (format_cnpj_cpf(
+ tagtext(oNode=elem_emit, cTag='CNPJ')))
+ cEnd += "IE: %s" % (tagtext(oNode=elem_emit, cTag="IE")) + '
'
+ cEnd += tagtext(oNode=elem_emit, cTag='xLgr') + ', ' + tagtext(
+ oNode=elem_emit, cTag='nro') + ' - '
+ cEnd += tagtext(oNode=elem_emit, cTag='xBairro') + '
' + tagtext(
+ oNode=elem_emit, cTag='xMun') + ' - '
+ cEnd += tagtext(oNode=elem_emit, cTag='UF') + ' - ' + tagtext(
+ oNode=elem_emit, cTag='CEP') + '
'
+ cEnd += 'Fone: ' + format_telefone(tagtext(
+ oNode=elem_emit, cTag='fone'))
+
+ self._drawCenteredParagraph(cEnd)
+ self.drawLine()
+
+ def danfce_information(self):
+ self.drawTitle(
+ "DANFE NFC-e - Documento Auxiliar da Nota Fiscal de",
+ 7, 'NimbusSanL-Bold')
+
+ self.drawTitle("Consumidor Eletrônica", 7, 'NimbusSanL-Bold')
+
+ self.drawString(
+ "NFC-e não permite aproveitamento de crédito de ICMS", True)
+ self.drawLine()
+
+ def produtos(self, oXML=None, el_det=None, oPaginator=None,
+ list_desc=None, list_cod_prod=None):
+
+ rows = [['Codigo', 'Descricao', 'Qtde', 'Un', 'Vl Unit', 'Vl Total']]
+ colWidths = (25, 90, 15, 15, 25, 25)
+ rowHeights = [7]
+
+ for id in range(oPaginator[0], oPaginator[1]):
+
+ item = el_det[id]
+ el_prod = item.find(".//{http://www.portalfiscal.inf.br/nfe}prod")
+
+ cod = tagtext(oNode=el_prod, cTag='cProd')
+ descricao = tagtext(oNode=el_prod, cTag='xProd')
+ Un = tagtext(oNode=el_prod, cTag='uCom')
+ qtde = format_number(tagtext(oNode=el_prod, cTag='qCom'),
+ precision=2)
+ vl_unit = format_number(tagtext(oNode=el_prod, cTag='vUnCom'),
+ precision=2)
+ vl_total = format_number(
+ tagtext(oNode=el_prod, cTag='vProd'), precision=2)
+
+ new_row = [cod, descricao, qtde, Un, vl_unit, vl_total]
+
+ rows.append(new_row)
+ rowHeights.append(self.current_font_size + 2)
+
+ self._draw_product_table(rows, colWidths, rowHeights)
+
+ def _draw_product_table(self, rows, colWidths, rowHeights):
+ table = Table(rows, colWidths, tuple(rowHeights))
+ table.setStyle(TableStyle([
+ ('FONTSIZE', (0, 0), (-1, -1), 7),
+ ('FONT', (0, 1), (-1, -1), 'NimbusSanL-Regu'),
+ ('FONT', (0, 0), (-1, 0), 'NimbusSanL-Bold'),
+ ('ALIGN', (0, 0), (-1, 0), "LEFT"),
+ ('ALIGN', (1, 0), (-1, 0), "LEFT"),
+ ('ALIGN', (2, 0), (-1, 0), "CENTER"),
+ ('ALIGN', (3, 0), (-1, 0), "CENTER"),
+ ('ALIGN', (0, 1), (-1, -1), "LEFT"),
+ ('ALIGN', (1, 1), (-1, -1), "LEFT"),
+ ('ALIGN', (2, 1), (-1, -1), "CENTER"),
+ ('ALIGN', (3, 1), (-1, -1), "CENTER"),
+ ]))
+
+ w, h = table.wrapOn(self.canvas, 200, 450)
+ table.drawOn(self.canvas, 0, self.current_height - (h * 1.2))
+ self.current_height -= (h * 1.1)
+
+ def totais(self, oXML=None):
+ # Impostos
+ el_total = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}total")
+
+ total_tributo = format_number(tagtext(oNode=el_total, cTag='vTotTrib'),
+ precision=2)
+ valor_total = format_number(tagtext(oNode=el_total, cTag='vProd'),
+ precision=2)
+ desconto = format_number(tagtext(oNode=el_total, cTag='vDesc'),
+ precision=2)
+ valor_a_pagar = format_number(tagtext(oNode=el_total, cTag='vNF'),
+ precision=2)
+ el_pag = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}pag")
+ troco = format_number(tagtext(oNode=el_pag, cTag="vTroco"))
+
+ payment_method_list = {'01': 'Dinheiro',
+ '02': 'Cheque',
+ '03': 'Cartão de Crédito',
+ '04': 'Cartão de Débito',
+ "05": "Crédito Loja",
+ '10': 'Vale Alimentação',
+ '11': 'Vale Refeição',
+ '12': 'Vale Presente',
+ '13': 'Vale Combustível',
+ '14': 'Duplicata Mercantil',
+ '15': 'Boleto Bancario',
+ '90': 'Sem Pagamento',
+ '99': 'Outros'}
+ quant_produtos = len(oXML.findall(
+ ".//{http://www.portalfiscal.inf.br/nfe}det"))
+
+ payment_methods = []
+
+ for pagId, item in enumerate(el_pag):
+ if 'tPag' not in item.tag:
+ continue
+
+ payment = []
+ method = payment_method_list[item.text]
+
+ payment.append(method)
+ payment.append(format_number(item.getnext().text, precision=2))
+ payment_methods.append(payment)
+
+ values = {'quantidade_itens': quant_produtos,
+ 'total_tributo': total_tributo,
+ 'valor_total': valor_total,
+ 'desconto': desconto,
+ 'valor_a_pagar': valor_a_pagar,
+ 'formas_de_pagamento': payment_methods,
+ 'troco': troco,
+ }
+
+ self.draw_totals_table(values)
+
+ self.drawLine()
+
+ def draw_totals_table(self, values):
+ rowHeights = [7, 7, 7, 7, 10]
+ data = [['QTD.TOTAL DE ITENS', values['quantidade_itens']],
+ ['VALOR TOTAL R$', values['valor_total']],
+ ['DESCONTO R$', values['desconto']],
+ ['VALOR A PAGAR R$', values['valor_a_pagar']],
+ ['FORMA DE PAGAMENTO', 'VALOR PAGO R$'],
+ ]
+
+ for item in values['formas_de_pagamento']:
+ data.append([item[0], item[1]])
+ rowHeights.append(7)
+ data.append(['TROCO', format_number(values['troco'], precision=2)])
+ rowHeights.append(7)
+
+ table2 = Table(data, colWidths=(150, 50), rowHeights=tuple(rowHeights))
+ table2.setStyle(TableStyle([
+ ('FONTSIZE', (0, 0), (-1, -1), 7),
+ ('FONT', (0, 0), (1, -1), 'NimbusSanL-Regu'),
+ ('FONT', (0, 4), (1, 4), 'NimbusSanL-Bold'),
+ ('ALIGN', (1, 0), (1, -1), "RIGHT")
+ ]))
+ w, h = table2.wrapOn(self.canvas, 200, 450)
+ table2.drawOn(self.canvas, 0, self.current_height - (h * 1.1))
+ self.current_height -= h
+
+ def inf_authentication(self, oXML=None):
+ el_infNFe = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}infNFe")
+ # n nfce, serie e data de solicitacao
+ el_ide = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}ide")
+
+ el_NFeSupl = oXML.find(
+ ".//{http://www.portalfiscal.inf.br/nfe}infNFeSupl")
+
+ el_dest = el_infNFe.find(".//{http://www.portalfiscal.inf.br/nfe}dest")
+ # chave, n protocolo, data autorizacao
+ el_prot_nfe = oXML.find(
+ ".//{http://www.portalfiscal.inf.br/nfe}protNFe")
+
+ el_infAdic = oXML.find(
+ ".//{http://www.portalfiscal.inf.br/nfe}infAdic")
+
+ url_chave = tagtext(oNode=el_NFeSupl, cTag='urlChave')
+ access_key = tagtext(oNode=el_prot_nfe, cTag="chNFe")
+
+ frase_chave_acesso = 'Consulte pela Chave de Acesso em:
\
+%s
%s' % (url_chave, access_key)
+
+ qrcode = tagtext(oNode=el_NFeSupl, cTag='qrCode')
+
+ cnpj = tagtext(oNode=el_dest, cTag='CNPJ')
+ cpf = tagtext(oNode=el_dest, cTag='CPF')
+ if cnpj:
+ cnpj_cpf = format_cnpj_cpf(cnpj)
+ cnpj_cpf = "CONSUMIDOR CNPJ: %s" % (cnpj)
+ elif cpf:
+ cnpj_cpf = format_cnpj_cpf(cpf)
+ cnpj_cpf = "CONSUMIDOR CPF: %s" % (cpf)
+ else:
+ cnpj_cpf = u"CONSUMIDOR NÃO IDENTIFICADO"
+
+ nNFC = tagtext(oNode=el_ide, cTag="nNF")
+ serie = tagtext(oNode=el_ide, cTag='serie')
+
+ dataSolicitacao = getdateUTC(tagtext(oNode=el_ide, cTag="dhEmi"))
+ dataSolicitacao = dataSolicitacao[0] + " " + dataSolicitacao[1]
+
+ numProtocolo = tagtext(oNode=el_prot_nfe, cTag="nProt")
+
+ dataAutorizacao = getdateUTC(tagtext(oNode=el_prot_nfe,
+ cTag='dhRecbto'))
+ dataAutorizacao = dataAutorizacao[0] + " " + dataAutorizacao[1]
+
+ text = u"%s
%s
NFC-e nº%s Série %s %s
\
+Protocolo de autorização: %s
Data de autorização %s
\
+" % (frase_chave_acesso, cnpj_cpf, nNFC, serie, dataSolicitacao,
+ numProtocolo, dataAutorizacao)
+
+ self._drawCenteredParagraph(text)
+
+ self.draw_qr_code(qrcode)
+
+ infAdFisco = tagtext(oNode=el_infAdic, cTag='infAdFisco')
+ self._drawCenteredParagraph(infAdFisco)
+
+ infCpl = tagtext(oNode=el_infAdic, cTag='infCpl')
+ self._drawCenteredParagraph(infCpl)
+
+ def _drawCenteredParagraph(self, text):
+
+ style = ParagraphStyle(
+ name='Normal',
+ fontName='NimbusSanL-Regu',
+ fontSize=7,
+ alignment=TA_CENTER,
+ leading=7,
+ )
+
+ paragraph = Paragraph(text, style=style)
+ w, h = paragraph.wrapOn(self.canvas, 180, 300)
+ paragraph.drawOn(self.canvas, 10, self.current_height - h)
+ self.current_height -= (h*1.1)
+
+ def drawString(self, string, centered=False):
+ if centered:
+ self.canvas.drawCentredString(
+ self.max_width / 2, self.current_height, string)
+ self.current_height -= self.current_font_size
+ else:
+ self.canvas.drawString(self.min_width, self.current_height, string)
+ self.current_height -= self.current_font_size
+
+ def drawTitle(self, string, size, font='NimbusSanL-Regu'):
+ self.canvas.setFont(font, size)
+ self.canvas.drawCentredString(
+ self.max_width / 2, self.current_height, string)
+ self.current_height -= self.current_font_size
+ self.canvas.setFont(self.current_font_name, self.current_font_size)
+
+ def drawLine(self):
+ self.canvas.line(self.min_width, self.current_height,
+ self.max_width, self.current_height)
+ self.current_height -= self.current_font_size
+
+ def draw_qr_code(self, string):
+ qr_code = qr.QrCodeWidget(string)
+ drawing = Drawing(23 * mm, 23 * mm)
+ drawing.add(qr_code)
+ renderPDF.draw(drawing, self.canvas, 20 * mm, self.current_height - 85)
+ self.current_height -= 85
+
+ def newpage(self):
+ self.current_height = self.max_height
+ self.Page += 1
+ self.canvas.showPage()
+
+ def nfce_generate(self):
+ for oXML in self.list_xml:
+ oXML_cobr = oXML.find(
+ ".//{http://www.portalfiscal.inf.br/nfe}cobr")
+
+ self.NrPages = 1
+ self.Page = 1
+
+ # Calculando total linhas usadas para descrições dos itens
+ # Com bloco fatura, apenas 29 linhas para itens na primeira folha
+ nNr_Lin_Pg_1 = 34 if oXML_cobr is None else 30
+ # [ rec_ini , rec_fim , lines , limit_lines ]
+ oPaginator = [[0, 0, 0, nNr_Lin_Pg_1]]
+ el_det = oXML.findall(".//{http://www.portalfiscal.inf.br/nfe}det")
+ if el_det is not None:
+ list_desc = []
+ list_cod_prod = []
+ nPg = 0
+ for nId, item in enumerate(el_det):
+ el_prod = item.find(
+ ".//{http://www.portalfiscal.inf.br/nfe}prod")
+ infAdProd = item.find(
+ ".//{http://www.portalfiscal.inf.br/nfe}infAdProd")
+
+ list_ = wrap(tagtext(oNode=el_prod, cTag='xProd'), 56)
+ if infAdProd is not None:
+ list_.extend(wrap(infAdProd.text, 56))
+ list_desc.append(list_)
+
+ list_cProd = wrap(tagtext(oNode=el_prod, cTag='cProd'), 14)
+ list_cod_prod.append(list_cProd)
+
+ # Nr linhas necessárias p/ descrição item
+ nLin_Itens = len(list_)
+
+ if (oPaginator[nPg][2] + nLin_Itens) >= oPaginator[nPg][3]:
+ oPaginator.append([0, 0, 0, 77])
+ nPg += 1
+ oPaginator[nPg][0] = nId
+ oPaginator[nPg][1] = nId + 1
+ oPaginator[nPg][2] = nLin_Itens
+ else:
+ # adiciona-se 1 pelo funcionamento de xrange
+ oPaginator[nPg][1] = nId + 1
+ oPaginator[nPg][2] += nLin_Itens
+
+ self.NrPages = len(oPaginator) # Calculando nr. páginas
+
+ self.ide_emit(oXML=oXML)
+ # self.destinatario(oXML=oXML)
+ self.danfce_information()
+
+ self.produtos(oXML=oXML, el_det=el_det, oPaginator=oPaginator[0],
+ list_desc=list_desc, list_cod_prod=list_cod_prod)
+
+ self.drawLine()
+
+ self.totais(oXML=oXML)
+
+ self.inf_authentication(oXML=oXML)
+
+ # Gera o restante das páginas do XML
+ for oPag in oPaginator[1:]:
+ if oPag:
+ self.newpage()
+ self.ide_emit(oXML=oXML)
+ # self.destinatario(oXML=oXML)
+ self.produtos(oXML=oXML, el_det=el_det, oPaginator=oPag,
+ list_desc=list_desc,
+ list_cod_prod=list_cod_prod)
+ self.totais(oXML=oXML)
+ self.inf_authentication(oXML=oXML)
+
+ self.newpage()
+
+ self.canvas.save()
+
+ def writeto_pdf(self, fileObj):
+ pdf_out = self.oPDF_IO.getvalue()
+ self.oPDF_IO.close()
+ fileObj.write(pdf_out)
diff --git a/pytrustnfe/nfe/templates/NfeAutorizacao.xml b/pytrustnfe/nfe/templates/NfeAutorizacao.xml
index b135806..d2d82e4 100644
--- a/pytrustnfe/nfe/templates/NfeAutorizacao.xml
+++ b/pytrustnfe/nfe/templates/NfeAutorizacao.xml
@@ -491,7 +491,6 @@
{% endif %}
- {% endif %}
{% if imposto.II is defined %}
{{ imposto.II.vBC }}
@@ -500,6 +499,7 @@
{{ imposto.II.vIOF }}
{% endif %}
+ {% endif %}
{% if imposto.PIS.CST in ('01', '02') %}
diff --git a/pytrustnfe/nfse/floripa/templates/processar_nota.xml b/pytrustnfe/nfse/floripa/templates/processar_nota.xml
index 9fa0aba..08a7a2e 100644
--- a/pytrustnfe/nfse/floripa/templates/processar_nota.xml
+++ b/pytrustnfe/nfse/floripa/templates/processar_nota.xml
@@ -1,13 +1,13 @@
- {{ rps.tomador.bairro|normalize|escape }}
+ {{ rps.tomador.bairro }}
{{ rps.base_calculo }}
0.0
{{ rps.cfps }}
{{ rps.tomador.cidade }}
{{ rps.tomador.cep }}
- {{ rps.tomador.complemento|normalize|escape }}
- {{ rps.observacoes|normalize|escape }}
+ {{ rps.tomador.complemento }}
+ {{ rps.observacoes }}
{{ rps.data_emissao }}
{{ rps.tomador.email }}
{{ rps.numero }}
@@ -18,7 +18,7 @@
{{ item.aliquota }}
{{ item.cst_servico }}
- {{ item.descricao|normalize|escape }}
+ {{ item.descricao }}
{{ item.cnae }}
{{ item.quantidade }}
{{ item.valor_total }}
@@ -26,12 +26,12 @@
{% endfor %}
- {{ rps.tomador.logradouro|normalize|escape }}
+ {{ rps.tomador.logradouro }}
{{ rps.aedf }}
{{ rps.tomador.numero }}
1058
- {{ rps.tomador.razao_social|normalize|escape }}
+ {{ rps.tomador.razao_social }}
{{ rps.tomador.telefone }}
{{ rps.tomador.uf }}
{{rps.valor_issqn }}
diff --git a/setup.py b/setup.py
index c7e626b..613e15c 100644
--- a/setup.py
+++ b/setup.py
@@ -48,7 +48,7 @@ later (LGPLv2+)',
'signxml >= 2.4.0',
'lxml >= 3.5.0, < 5',
'suds-jurko >= 0.6',
- 'suds-jurko-requests >= 1.2',
+ 'suds-jurko-requests >= 1.1',
'reportlab'
],
tests_require=[