Browse Source

Merge pull request #40 from danimaribeiro/feature/danfe

Impressão de danfe através do reportlab
pull/45/head
Danimar Ribeiro 9 years ago
committed by GitHub
parent
commit
6f42ace41c
  1. 810
      pytrustnfe/nfe/danfe.py
  2. 46
      pytrustnfe/test/XMLs/NFe00000857.xml
  3. 22
      pytrustnfe/test/test_danfe.py
  4. 1
      requirements.txt
  5. 3
      setup.py

810
pytrustnfe/nfe/danfe.py

@ -0,0 +1,810 @@
# -*- coding: utf-8 -*-
# © 2017 Edson Bernardino, ITK Soft
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# Classe para geração de PDF da DANFE a partir de xml etree.fromstring
from cStringIO import StringIO as IO
from textwrap import wrap
from reportlab.lib import utils
from reportlab.pdfgen import canvas
from reportlab.lib.units import mm, cm
from reportlab.lib.pagesizes import A4
from reportlab.lib.colors import black, gray
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
def chunks(cString, nLen):
for start in range(0, len(cString), nLen):
yield cString[start:start+nLen]
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
REGIME_TRIBUTACAO = {
'1': 'Simples Nacional',
'2': 'Simples Nacional, excesso sublimite de receita bruta',
'3': 'Regime Normal'
}
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))
class danfe(object):
def __init__(self, sizepage=A4, list_xml=None, recibo=True,
orientation='portrait', logo=None):
self.width = 210 # 21 x 29,7cm
self.height = 297
self.nLeft = 10
self.nRight = 10
self.nTop = 7
self.nBottom = 15
self.nlin = self.nTop
self.logo = logo
self.oFrete = {'0': '0 - Emitente',
'1': '1 - Dest/Remet',
'2': '2 - Terceiros',
'9': '9 - Sem Frete'}
self.oPDF_IO = IO()
if orientation == 'landscape':
raise NameError('Rotina não implementada')
else:
size = sizepage
self.canvas = canvas.Canvas(self.oPDF_IO, pagesize=size)
self.canvas.setTitle('DANFE')
self.canvas.setStrokeColor(black)
for oXML in 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 29
# [ 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 = []
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'), 51)
if infAdProd is not None:
list_.extend(wrap(infAdProd.text, 51))
list_desc.append(list_)
# 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
if recibo:
self.recibo_entrega(oXML=oXML)
self.ide_emit(oXML=oXML)
self.destinatario(oXML=oXML)
if oXML_cobr is not None:
self.faturas(oXML=oXML_cobr)
self.impostos(oXML=oXML)
self.transportes(oXML=oXML)
self.produtos(oXML=oXML, el_det=el_det, oPaginator=oPaginator[0],
list_desc=list_desc)
self.adicionais(oXML=oXML)
# Gera o restante das páginas do XML
for oPag in oPaginator[1:]:
self.newpage()
self.ide_emit(oXML=oXML)
self.produtos(oXML=oXML, el_det=el_det, oPaginator=oPag,
list_desc=list_desc, nHeight=77)
self.newpage()
self.canvas.save()
def ide_emit(self, oXML=None):
elem_infNFe = oXML.find(
".//{http://www.portalfiscal.inf.br/nfe}infNFe")
elem_protNFe = oXML.find(
".//{http://www.portalfiscal.inf.br/nfe}protNFe")
elem_emit = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}emit")
elem_ide = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}ide")
cChave = elem_infNFe.attrib.get('Id')[3:]
barcode128 = code128.Code128(cChave, barHeight=10*mm, barWidth=0.25*mm)
self.canvas.setLineWidth(.5)
self.rect(self.nLeft, self.nlin+1, self.nLeft+75, 32)
self.rect(self.nLeft+115, self.nlin+1,
self.width-self.nLeft-self.nRight-115, 39)
self.rect(self.nLeft+116, self.nlin+15,
self.width-self.nLeft-self.nRight-117, 6)
self.rect(self.nLeft, self.nlin+33,
self.width-self.nLeft-self.nRight, 14)
self.hline(self.nLeft, self.nlin+40, self.width-self.nRight)
self.vline(self.nLeft+60, self.nlin+40, 7)
self.vline(self.nLeft+100, self.nlin+40, 7)
# Labels
self.canvas.setFont('NimbusSanL-Bold', 12)
self.stringcenter(self.nLeft+98, self.nlin+4, 'DANFE')
self.stringcenter(self.nLeft+109, self.nlin+19.5,
tagtext(oNode=elem_ide, cTag='tpNF'))
self.canvas.setFont('NimbusSanL-Bold', 8)
cNF = tagtext(oNode=elem_ide, cTag='nNF')
cNF = '{0:011,}'.format(int(cNF)).replace(",", ".")
self.stringcenter(self.nLeft+100, self.nlin+25, "%s" % (cNF))
self.stringcenter(self.nLeft+100, self.nlin+29, u"SÉRIE %s" % (
tagtext(oNode=elem_ide, cTag='serie')))
cPag = "Página %s de %s" % (str(self.Page), str(self.NrPages))
self.stringcenter(self.nLeft+100, self.nlin+32, cPag)
self.canvas.setFont('NimbusSanL-Regu', 6)
self.string(self.nLeft+86, self.nlin+8, 'Documento Auxiliar da')
self.string(self.nLeft+86, self.nlin+10.5, 'Nota Fiscal Eletrônica')
self.string(self.nLeft+86, self.nlin+16, '0 - Entrada')
self.string(self.nLeft+86, self.nlin+19, '1 - Saída')
self.rect(self.nLeft+105, self.nlin+15, 8, 6)
self.stringcenter(
self.nLeft+152, self.nlin+25,
'Consulta de autenticidade no portal nacional da NF-e')
self.stringcenter(
self.nLeft+152, self.nlin+28,
'www.nfe.fazenda.gov.br/portal ou no site da SEFAZ Autorizadora')
self.canvas.setFont('NimbusSanL-Regu', 5)
self.string(self.nLeft+117, self.nlin+16.7, 'CHAVE DE ACESSO')
self.string(self.nLeft+116, self.nlin+2.7, 'CONTROLE DO FISCO')
self.string(self.nLeft+1, self.nlin+34.7, 'NATUREZA DA OPERAÇÃO')
self.string(self.nLeft+116, self.nlin+34.7,
'PROTOCOLO DE AUTORIZAÇÃO DE USO')
self.string(self.nLeft+1, self.nlin+41.7, 'INSCRIÇÃO ESTADUAL')
self.string(self.nLeft+61, self.nlin+41.7,
'INSCRIÇÃO ESTADUAL DO SUBST. TRIB.')
self.string(self.nLeft+101, self.nlin+41.7, 'CNPJ')
# Conteúdo campos
barcode128.drawOn(self.canvas, (self.nLeft+111.5)*mm,
(self.height-self.nlin-14)*mm)
self.canvas.setFont('NimbusSanL-Bold', 6)
nW_Rect = (self.width-self.nLeft-self.nRight-117) / 2
self.stringcenter(self.nLeft+116.5+nW_Rect, self.nlin+19.5,
' '.join(chunks(cChave, 4))) # Chave
self.canvas.setFont('NimbusSanL-Regu', 8)
cDt, cHr = getdateUTC(tagtext(oNode=elem_protNFe, cTag='dhRecbto'))
cProtocolo = tagtext(oNode=elem_protNFe, cTag='nProt')
cDt = cProtocolo + ' - ' + cDt + ' ' + cHr
nW_Rect = (self.width-self.nLeft-self.nRight-110) / 2
self.stringcenter(self.nLeft+115+nW_Rect, self.nlin+38.7, cDt)
self.canvas.setFont('NimbusSanL-Regu', 8)
self.string(self.nLeft+1, self.nlin+38.7,
tagtext(oNode=elem_ide, cTag='natOp'))
self.string(self.nLeft+1, self.nlin+46,
tagtext(oNode=elem_emit, cTag='IE'))
self.string(self.nLeft+101, self.nlin+46,
format_cnpj_cpf(tagtext(oNode=elem_emit, cTag='CNPJ')))
styles = getSampleStyleSheet()
styleN = styles['Normal']
styleN.fontSize = 10
styleN.fontName = 'NimbusSanL-Bold'
styleN.alignment = TA_CENTER
# Razão Social emitente
P = Paragraph(tagtext(oNode=elem_emit, cTag='xNome'), styleN)
w, h = P.wrap(55*mm, 50*mm)
P.drawOn(self.canvas, (self.nLeft+30)*mm,
(self.height-self.nlin-12)*mm)
if self.logo:
img = get_image(self.logo, width=2*cm)
img.drawOn(self.canvas, (self.nLeft+5)*mm,
(self.height-self.nlin-22)*mm)
cEnd = tagtext(oNode=elem_emit, cTag='xLgr') + ', ' + tagtext(
oNode=elem_emit, cTag='nro') + ' - '
cEnd += tagtext(oNode=elem_emit, cTag='xBairro') + '<br />' + tagtext(
oNode=elem_emit, cTag='xMun') + ' - '
cEnd += 'Fone: ' + tagtext(oNode=elem_emit, cTag='fone') + '<br />'
cEnd += tagtext(oNode=elem_emit, cTag='UF') + ' - ' + tagtext(
oNode=elem_emit, cTag='CEP')
regime = tagtext(oNode=elem_emit, cTag='CRT')
cEnd += u'<br />Regime Tributário: %s' % (REGIME_TRIBUTACAO[regime])
styleN.fontName = 'NimbusSanL-Regu'
styleN.fontSize = 7
styleN.leading = 10
P = Paragraph(cEnd, styleN)
w, h = P.wrap(55*mm, 30*mm)
P.drawOn(self.canvas, (self.nLeft+30)*mm,
(self.height-self.nlin-31)*mm)
# Homologação
if tagtext(oNode=elem_ide, cTag='tpAmb') == '2':
self.canvas.saveState()
self.canvas.rotate(90)
self.canvas.setFont('Times-Bold', 40)
self.canvas.setFillColorRGB(0.57, 0.57, 0.57)
self.string(self.nLeft+65, 449, 'SEM VALOR FISCAL')
self.canvas.restoreState()
self.nlin += 48
def destinatario(self, oXML=None):
elem_ide = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}ide")
elem_dest = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}dest")
nMr = self.width-self.nRight
self.nlin += 1
self.canvas.setFont('NimbusSanL-Bold', 7)
self.string(self.nLeft+1, self.nlin+1, 'DESTINATÁRIO/REMETENTE')
self.rect(self.nLeft, self.nlin+2,
self.width-self.nLeft-self.nRight, 20)
self.vline(nMr-25, self.nlin+2, 20)
self.hline(self.nLeft, self.nlin+8.66, self.width-self.nLeft)
self.hline(self.nLeft, self.nlin+15.32, self.width-self.nLeft)
self.vline(nMr-70, self.nlin+2, 6.66)
self.vline(nMr-53, self.nlin+8.66, 6.66)
self.vline(nMr-99, self.nlin+8.66, 6.66)
self.vline(nMr-90, self.nlin+15.32, 6.66)
self.vline(nMr-102, self.nlin+15.32, 6.66)
self.vline(nMr-136, self.nlin+15.32, 6.66)
# Labels/Fields
self.canvas.setFont('NimbusSanL-Bold', 5)
self.string(self.nLeft+1, self.nlin+3.7, 'NOME/RAZÃO SOCIAL')
self.string(nMr-69, self.nlin+3.7, 'CNPJ/CPF')
self.string(nMr-24, self.nlin+3.7, 'DATA DA EMISSÃO')
self.string(self.nLeft+1, self.nlin+10.3, 'ENDEREÇO')
self.string(nMr-98, self.nlin+10.3, 'BAIRRO/DISTRITO')
self.string(nMr-52, self.nlin+10.3, 'CEP')
self.string(nMr-24, self.nlin+10.3, 'DATA DE ENTRADA/SAÍDA')
self.string(self.nLeft+1, self.nlin+17.1, 'MUNICÍPIO')
self.string(nMr-135, self.nlin+17.1, 'FONE/FAX')
self.string(nMr-101, self.nlin+17.1, 'UF')
self.string(nMr-89, self.nlin+17.1, 'INSCRIÇÃO ESTADUAL')
self.string(nMr-24, self.nlin+17.1, 'HORA DE ENTRADA/SAÍDA')
# Conteúdo campos
self.canvas.setFont('NimbusSanL-Regu', 8)
self.string(self.nLeft+1, self.nlin+7.5,
tagtext(oNode=elem_dest, cTag='xNome'))
self.string(nMr-69, self.nlin+7.5,
format_cnpj_cpf(tagtext(oNode=elem_dest, cTag='CNPJ')))
cDt, cHr = getdateUTC(tagtext(oNode=elem_ide, cTag='dhEmi'))
self.string(nMr-24, self.nlin+7.7, cDt)
cDt, cHr = getdateUTC(tagtext(oNode=elem_ide, cTag='dhSaiEnt'))
self.string(nMr-24, self.nlin+14.3, cDt) # Dt saída
cEnd = tagtext(oNode=elem_dest, cTag='xLgr') + ', ' + tagtext(
oNode=elem_dest, cTag='nro')
self.string(self.nLeft+1, self.nlin+14.3, cEnd)
self.string(nMr-98, self.nlin+14.3,
tagtext(oNode=elem_dest, cTag='xBairro'))
self.string(nMr-52, self.nlin+14.3,
tagtext(oNode=elem_dest, cTag='CEP'))
self.string(self.nLeft+1, self.nlin+21.1,
tagtext(oNode=elem_dest, cTag='xMun'))
self.string(nMr-135, self.nlin+21.1,
tagtext(oNode=elem_dest, cTag='fone'))
self.string(nMr-101, self.nlin+21.1,
tagtext(oNode=elem_dest, cTag='UF'))
self.string(nMr-89, self.nlin+21.1,
tagtext(oNode=elem_dest, cTag='IE'))
self.nlin += 24 # Nr linhas ocupadas pelo bloco
def faturas(self, oXML=None):
nMr = self.width-self.nRight
self.canvas.setFont('NimbusSanL-Bold', 7)
self.string(self.nLeft+1, self.nlin+1, 'FATURA')
self.rect(self.nLeft, self.nlin+2,
self.width-self.nLeft-self.nRight, 13)
self.vline(nMr-47.5, self.nlin+2, 13)
self.vline(nMr-95, self.nlin+2, 13)
self.vline(nMr-142.5, self.nlin+2, 13)
self.hline(nMr-47.5, self.nlin+8.5, self.width-self.nLeft)
# Labels
self.canvas.setFont('NimbusSanL-Regu', 5)
self.string(nMr-46.5, self.nlin+3.8, 'CÓDIGO VENDEDOR')
self.string(nMr-46.5, self.nlin+10.2, 'NOME VENDEDOR')
self.string(nMr-93.5, self.nlin+3.8,
'FATURA VENCIMENTO VALOR')
self.string(nMr-140.5, self.nlin+3.8,
'FATURA VENCIMENTO VALOR')
self.string(self.nLeft+2, self.nlin+3.8,
'FATURA VENCIMENTO VALOR')
# Conteúdo campos
self.canvas.setFont('NimbusSanL-Bold', 6)
nLin = 7
nPar = 1
nCol = 0
nAju = 0
line_iter = iter(oXML[1:10]) # Salta elemt 1 e considera os próximos 9
for oXML_dup in line_iter:
cDt, cHr = getdateUTC(tagtext(oNode=oXML_dup, cTag='dVenc'))
self.string(self.nLeft+nCol+1, self.nlin+nLin,
tagtext(oNode=oXML_dup, cTag='nDup'))
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))
if nPar == 3:
nLin = 7
nPar = 1
nCol += 47
nAju += 1
nCol += nAju * (0.3)
else:
nLin += 3.3
nPar += 1
# Campos adicionais XML - Condicionados a existencia de financeiro
elem_infAdic = oXML.getparent().find(
".//{http://www.portalfiscal.inf.br/nfe}infAdic")
if elem_infAdic is not None:
codvend = elem_infAdic.find(
".//{http://www.portalfiscal.inf.br/nfe}obsCont\
[@xCampo='CodVendedor']")
self.string(nMr-46.5, self.nlin+7.7,
tagtext(oNode=codvend, cTag='xTexto'))
vend = elem_infAdic.find(".//{http://www.portalfiscal.inf.br/nfe}\
obsCont[@xCampo='NomeVendedor']")
self.string(nMr-46.5, self.nlin+14.3,
tagtext(oNode=vend, cTag='xTexto')[:36])
self.nlin += 16 # Nr linhas ocupadas pelo bloco
def impostos(self, oXML=None):
# Impostos
el_total = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}total")
nMr = self.width-self.nRight
self.nlin += 1
self.canvas.setFont('NimbusSanL-Bold', 7)
self.string(self.nLeft+1, self.nlin+1, 'CÁLCULO DO IMPOSTO')
self.rect(self.nLeft, self.nlin+2,
self.width-self.nLeft-self.nRight, 13)
self.hline(self.nLeft, self.nlin+8.5, self.width-self.nLeft)
self.vline(nMr-35, self.nlin+2, 6.5)
self.vline(nMr-72, self.nlin+2, 6.5)
self.vline(nMr-110, self.nlin+2, 6.5)
self.vline(nMr-148, self.nlin+2, 6.5)
self.vline(nMr-35, self.nlin+8.5, 6.5)
self.vline(nMr-66, self.nlin+8.5, 6.5)
self.vline(nMr-90, self.nlin+8.5, 6.5)
self.vline(nMr-119, self.nlin+8.5, 6.5)
self.vline(nMr-140, self.nlin+8.5, 6.5)
self.vline(nMr-163, self.nlin+8.5, 6.5)
# Labels
self.canvas.setFont('NimbusSanL-Regu', 5)
self.string(nMr-34, self.nlin+3.8, 'VALOR TOTAL DOS PRODUTOS')
self.string(nMr-71, self.nlin+3.8, 'VALOR DO ICMS ST')
self.string(nMr-109, self.nlin+3.8, 'BASE DE CÁLCULO DO ICMS ST')
self.string(nMr-147, self.nlin+3.8, 'VALOR DO ICMS')
self.string(self.nLeft+1, self.nlin+3.8, 'BASE DE CÁLCULO DO ICMS')
self.string(nMr-34, self.nlin+10.2, 'VALOR TOTAL DA NOTA')
self.string(nMr-65, self.nlin+10.2, 'VALOR APROX TRIBUTOS')
self.string(nMr-89, self.nlin+10.2, 'VALOR DO IPI')
self.string(nMr-118, self.nlin+10.2, 'OUTRAS DESP. ACESSÓRIAS')
self.string(nMr-139, self.nlin+10.2, 'DESCONTO')
self.string(nMr-162, self.nlin+10.2, 'VALOR DO SEGURO')
self.string(self.nLeft+1, self.nlin+10.2, 'VALOR DO FRETE')
# Conteúdo campos
self.canvas.setFont('NimbusSanL-Regu', 8)
self.stringRight(
self.nLeft+41, self.nlin+7.7,
format_number(tagtext(oNode=el_total, cTag='vBC'), precision=2))
self.stringRight(
self.nLeft+79, self.nlin+7.7,
format_number(tagtext(oNode=el_total, cTag='vICMS'), precision=2))
self.stringRight(
self.nLeft+117, self.nlin+7.7,
format_number(tagtext(oNode=el_total, cTag='vBCST'), precision=2))
self.stringRight(
nMr-36, self.nlin+7.7,
format_number(tagtext(oNode=el_total, cTag='vST'), precision=2))
self.stringRight(
nMr-1, self.nlin+7.7,
format_number(tagtext(oNode=el_total, cTag='vProd'), precision=2))
self.stringRight(
self.nLeft+26, self.nlin+14.1,
format_number(tagtext(oNode=el_total, cTag='vFrete'), precision=2))
self.stringRight(
self.nLeft+49, self.nlin+14.1,
format_number(tagtext(oNode=el_total, cTag='vSeg'), precision=2))
self.stringRight(
self.nLeft+70, self.nlin+14.1,
format_number(tagtext(oNode=el_total, cTag='vDesc'), precision=2))
self.stringRight(
self.nLeft+99, self.nlin+14.1,
format_number(tagtext(oNode=el_total, cTag='vOutro'), precision=2))
self.stringRight(
self.nLeft+123, self.nlin+14.1,
format_number(tagtext(oNode=el_total, cTag='vIPI'), precision=2))
self.stringRight(
self.nLeft+154, self.nlin+14.1,
format_number(tagtext(oNode=el_total, cTag='vTotTrib'),
precision=2))
self.stringRight(
nMr-1, self.nlin+14.1,
format_number(tagtext(oNode=el_total, cTag='vNF'), precision=2))
self.nlin += 17 # Nr linhas ocupadas pelo bloco
def transportes(self, oXML=None):
el_transp = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}transp")
nMr = self.width-self.nRight
self.canvas.setFont('NimbusSanL-Bold', 7)
self.string(self.nLeft+1, self.nlin+1,
'TRANSPORTADOR/VOLUMES TRANSPORTADOS')
self.canvas.setFont('NimbusSanL-Regu', 5)
self.rect(self.nLeft, self.nlin+2,
self.width-self.nLeft-self.nRight, 20)
self.hline(self.nLeft, self.nlin+8.6, self.width-self.nLeft)
self.hline(self.nLeft, self.nlin+15.2, self.width-self.nLeft)
self.vline(nMr-40, self.nlin+2, 13.2)
self.vline(nMr-49, self.nlin+2, 20)
self.vline(nMr-92, self.nlin+2, 6.6)
self.vline(nMr-120, self.nlin+2, 6.6)
self.vline(nMr-75, self.nlin+2, 6.6)
self.vline(nMr-26, self.nlin+15.2, 6.6)
self.vline(nMr-102, self.nlin+8.6, 6.6)
self.vline(nMr-85, self.nlin+15.2, 6.6)
self.vline(nMr-121, self.nlin+15.2, 6.6)
self.vline(nMr-160, self.nlin+15.2, 6.6)
# Labels/Fields
self.string(nMr-39, self.nlin+3.8, 'CNPJ/CPF')
self.string(nMr-74, self.nlin+3.8, 'PLACA DO VEÍCULO')
self.string(nMr-91, self.nlin+3.8, 'CÓDIGO ANTT')
self.string(nMr-119, self.nlin+3.8, 'FRETE POR CONTA')
self.string(self.nLeft+1, self.nlin+3.8, 'RAZÃO SOCIAL')
self.string(nMr-48, self.nlin+3.8, 'UF')
self.string(nMr-39, self.nlin+10.3, 'INSCRIÇÃO ESTADUAL')
self.string(nMr-48, self.nlin+10.3, 'UF')
self.string(nMr-101, self.nlin+10.3, 'MUNICÍPIO')
self.string(self.nLeft+1, self.nlin+10.3, 'ENDEREÇO')
self.string(nMr-48, self.nlin+17, 'PESO BRUTO')
self.string(nMr-25, self.nlin+17, 'PESO LÍQUIDO')
self.string(nMr-84, self.nlin+17, 'NUMERAÇÃO')
self.string(nMr-120, self.nlin+17, 'MARCA')
self.string(nMr-159, self.nlin+17, 'ESPÉCIE')
self.string(self.nLeft+1, self.nlin+17, 'QUANTIDADE')
# Conteúdo campos
self.canvas.setFont('NimbusSanL-Regu', 8)
self.string(self.nLeft+1, self.nlin+7.7,
tagtext(oNode=el_transp, cTag='xNome')[:40])
self.string(self.nLeft+71, self.nlin+7.7,
self.oFrete[tagtext(oNode=el_transp, cTag='modFrete')])
self.string(nMr-39, self.nlin+7.7,
format_cnpj_cpf(tagtext(oNode=el_transp, cTag='CNPJ')))
self.string(self.nLeft+1, self.nlin+14.2,
tagtext(oNode=el_transp, cTag='xEnder')[:45])
self.string(self.nLeft+89, self.nlin+14.2,
tagtext(oNode=el_transp, cTag='xMun'))
self.string(nMr-48, self.nlin+14.2,
tagtext(oNode=el_transp, cTag='UF'))
self.string(nMr-39, self.nlin+14.2,
tagtext(oNode=el_transp, cTag='IE'))
self.string(self.nLeft+1, self.nlin+21.2,
tagtext(oNode=el_transp, cTag='qVol'))
self.string(self.nLeft+31, self.nlin+21.2,
tagtext(oNode=el_transp, cTag='esp'))
self.string(self.nLeft+70, self.nlin+21.2,
tagtext(oNode=el_transp, cTag='marca'))
self.string(self.nLeft+106, self.nlin+21.2,
tagtext(oNode=el_transp, cTag='nVol'))
self.stringRight(
nMr-27, self.nlin+21.2,
format_number(tagtext(oNode=el_transp, cTag='pesoB'), precision=3))
self.stringRight(
nMr-1, self.nlin+21.2,
format_number(tagtext(oNode=el_transp, cTag='pesoL'), precision=3))
self.nlin += 23
def produtos(self, oXML=None, el_det=None, oPaginator=None,
list_desc=None, nHeight=29):
nMr = self.width-self.nRight
nStep = 2.5 # Passo entre linhas
nH = 7.5 + (nHeight * nStep) # cabeçalho 7.5
self.nlin += 1
self.canvas.setFont('NimbusSanL-Bold', 7)
self.string(self.nLeft+1, self.nlin+1, 'DADOS DO PRODUTO/SERVIÇO')
self.rect(self.nLeft, self.nlin+2,
self.width-self.nLeft-self.nRight, nH)
self.hline(self.nLeft, self.nlin+8, self.width-self.nLeft)
self.canvas.setFont('NimbusSanL-Regu', 5.5)
# Colunas
self.vline(self.nLeft+11, self.nlin+2, nH)
self.stringcenter(self.nLeft+5.5, self.nlin+5.5, 'CÓDIGO')
self.vline(nMr-7, self.nlin+2, nH)
self.stringcenter(nMr-3.5, self.nlin+4.5, 'ALÍQ')
self.stringcenter(nMr-3.5, self.nlin+6.5, 'IPI')
self.vline(nMr-14, self.nlin+2, nH)
self.stringcenter(nMr-10.5, self.nlin+4.5, 'ALÍQ')
self.stringcenter(nMr-10.5, self.nlin+6.5, 'ICMS')
self.vline(nMr-26, self.nlin+2, nH)
self.stringcenter(nMr-20, self.nlin+5.5, 'VLR. IPI')
self.vline(nMr-38, self.nlin+2, nH)
self.stringcenter(nMr-32, self.nlin+5.5, 'VLR. ICMS')
self.vline(nMr-50, self.nlin+2, nH)
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.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.vline(nMr-98, self.nlin+2, nH)
self.stringcenter(nMr-94, self.nlin+5.5, 'UNID')
self.vline(nMr-104, self.nlin+2, nH)
self.stringcenter(nMr-101, self.nlin+5.5, 'CFOP')
self.vline(nMr-110, self.nlin+2, nH)
self.stringcenter(nMr-107, self.nlin+5.5, 'CST')
self.vline(nMr-123, self.nlin+2, nH)
self.stringcenter(nMr-116.5, self.nlin+5.5, 'NCM/SH')
nWidth_Prod = nMr-135-self.nLeft-11
nCol_ = self.nLeft+11 + (nWidth_Prod / 2)
self.stringcenter(nCol_, self.nlin+5.5, 'DESCRIÇÃO DO PRODUTO/SERVIÇO')
# Conteúdo campos
self.canvas.setFont('NimbusSanL-Regu', 5)
nLin = self.nlin+10.5
for id in xrange(oPaginator[0], oPaginator[1]):
item = el_det[id]
el_prod = item.find(".//{http://www.portalfiscal.inf.br/nfe}prod")
el_imp = item.find(
".//{http://www.portalfiscal.inf.br/nfe}imposto")
el_imp_ICMS = el_imp.find(
".//{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')
vBC = tagtext(oNode=el_imp_ICMS, cTag='vBC')
vICMS = tagtext(oNode=el_imp_ICMS, cTag='vICMS')
pICMS = tagtext(oNode=el_imp_ICMS, cTag='pICMS')
vIPI = tagtext(oNode=el_imp_IPI, cTag='vIPI')
pIPI = tagtext(oNode=el_imp_IPI, cTag='pIPI')
self.string(self.nLeft+1, nLin,
tagtext(oNode=el_prod, cTag='cProd'))
self.stringcenter(nMr-116.5, nLin,
tagtext(oNode=el_prod, cTag='NCM'))
self.stringcenter(nMr-107, nLin, cCST)
self.stringcenter(nMr-101, nLin,
tagtext(oNode=el_prod, cTag='CFOP'))
self.stringcenter(nMr-94, 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-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))
if vIPI:
self.stringRight(nMr-14.5, nLin,
format_number(vIPI, precision=2))
if pIPI:
self.stringRight(nMr-0.5, nLin,
format_number(pIPI, precision=2))
self.canvas.setStrokeColor(gray)
self.hline(self.nLeft, nLin+0.5, self.width-self.nLeft)
self.canvas.setStrokeColor(black)
# Descrição Item
for des in list_desc[id]:
self.string(self.nLeft+12, nLin, des)
nLin += nStep
self.nlin += nH + 3
def adicionais(self, oXML=None):
el_infAdic = oXML.find(
".//{http://www.portalfiscal.inf.br/nfe}infAdic")
self.nlin += 2
self.canvas.setFont('NimbusSanL-Bold', 6)
self.string(self.nLeft+1, self.nlin+1, 'DADOS ADICIONAIS')
self.canvas.setFont('NimbusSanL-Regu', 5)
self.string(self.nLeft+1, self.nlin+4, 'INFORMAÇÕES COMPLEMENTARES')
self.string((self.width/2)+1, self.nlin+4, 'RESERVADO AO FISCO')
self.rect(self.nLeft, self.nlin+2,
self.width-self.nLeft-self.nRight, 34)
self.vline(self.width/2, self.nlin+2, 34)
# Conteúdo campos
styles = getSampleStyleSheet()
styleN = styles['Normal']
styleN.fontSize = 6
styleN.fontName = 'NimbusSanL-Regu'
styleN.leading = 7
P = Paragraph(tagtext(oNode=el_infAdic,
cTag='infCpl'), styles['Normal'])
w, h = P.wrap(92*mm, 32*mm)
P.drawOn(self.canvas, (self.nLeft+1)*mm, (self.height-self.nlin-17)*mm)
self.nlin += 36
def recibo_entrega(self, oXML=None):
el_ide = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}ide")
el_dest = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}dest")
el_total = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}total")
el_emit = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}emit")
# self.nlin = self.height-self.nBottom-18 # 17 altura recibo
nW = 40
nH = 17
self.canvas.setLineWidth(.5)
self.rect(self.nLeft, self.nlin,
self.width-(self.nLeft+self.nRight), nH)
self.hline(self.nLeft, self.nlin+8.5, self.width-self.nRight-nW)
self.vline(self.width-self.nRight-nW, self.nlin, nH)
self.vline(self.nLeft+nW, self.nlin+8.5, 8.5)
# Labels
self.canvas.setFont('NimbusSanL-Regu', 5)
self.string(self.nLeft+1, self.nlin+10.2, 'DATA DE RECEBIMENTO')
self.string(self.nLeft+41, self.nlin+10.2,
'IDENTIFICAÇÃO E ASSINATURA DO RECEBEDOR')
self.stringcenter(self.width-self.nRight-(nW/2), self.nlin+2, 'NF-e')
# Conteúdo campos
self.canvas.setFont('NimbusSanL-Bold', 8)
cNF = tagtext(oNode=el_ide, cTag='nNF')
cNF = '{0:011,}'.format(int(cNF)).replace(",", ".")
self.string(self.width-self.nRight-nW+2, self.nlin+8, "%s" % (cNF))
self.string(self.width-self.nRight-nW+2, self.nlin+14,
u"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)
cEnd = tagtext(oNode=el_dest, cTag='xNome') + ' - '
cEnd += tagtext(oNode=el_dest, cTag='xLgr') + ', ' + tagtext(
oNode=el_dest, cTag='nro') + ', '
cEnd += tagtext(oNode=el_dest, cTag='xBairro') + ', ' + tagtext(
oNode=el_dest, cTag='xMun') + ' - '
cEnd += tagtext(oNode=el_dest, cTag='UF')
cString = u"""
RECEBEMOS DE %s OS PRODUTOS/SERVIÇOS CONSTANTES DA NOTA FISCAL INDICADA
ABAIXO. EMISSÃO: %s VALOR TOTAL: %s
DESTINATARIO: %s""" % (tagtext(oNode=el_emit, cTag='xNome'),
cDt, cTotal, cEnd)
styles = getSampleStyleSheet()
styleN = styles['Normal']
styleN.fontName = 'NimbusSanL-Regu'
styleN.fontSize = 6
styleN.leading = 7
P = Paragraph(cString, styleN)
w, h = P.wrap(149*mm, 7*mm)
P.drawOn(self.canvas, (self.nLeft+1)*mm,
(self.height-self.nlin-7.5)*mm)
self.nlin += 20
self.hline(self.nLeft, self.nlin, self.width-self.nRight)
self.nlin += 2
def newpage(self):
self.nlin = self.nTop
self.Page += 1
self.canvas.showPage()
def hline(self, x, y, width):
y = self.height - y
self.canvas.line(x*mm, y*mm, width*mm, y*mm)
def vline(self, x, y, width):
width = self.height - y - width
y = self.height - y
self.canvas.line(x*mm, y*mm, x*mm, width*mm)
def rect(self, col, lin, nWidth, nHeight, fill=False):
lin = self.height - nHeight - lin
self.canvas.rect(col*mm, lin*mm, nWidth*mm, nHeight*mm,
stroke=True, fill=fill)
def string(self, x, y, value):
y = self.height - y
self.canvas.drawString(x*mm, y*mm, value)
def stringRight(self, x, y, value):
y = self.height - y
self.canvas.drawRightString(x*mm, y*mm, value)
def stringcenter(self, x, y, value):
y = self.height - y
self.canvas.drawCentredString(x*mm, y*mm, value)
def writeto_pdf(self, fileObj):
pdf_out = self.oPDF_IO.getvalue()
self.oPDF_IO.close()
fileObj.write(pdf_out)

46
pytrustnfe/test/XMLs/NFe00000857.xml

@ -0,0 +1,46 @@
<nfeProc xmlns="http://www.portalfiscal.inf.br/nfe" versao="3.10"><NFe><infNFe versao="3.10" Id="NFe35170221332917000163550010000008571134165777"><ide><cUF>35</cUF><cNF>13416577</cNF><natOp>Venda N&#227;o Contribuintes</natOp><indPag>1</indPag><mod>55</mod><serie>1</serie><nNF>857</nNF><dhEmi>2017-02-24T11:39:30-00:00</dhEmi><dhSaiEnt>2017-02-24T11:39:30-00:00</dhSaiEnt><tpNF>1</tpNF><idDest>2</idDest><cMunFG>3550308</cMunFG><tpImp>1</tpImp><tpEmis>1</tpEmis><cDV>7</cDV><tpAmb>2</tpAmb><finNFe>1</finNFe><indFinal>1</indFinal><indPres>0</indPres><procEmi>0</procEmi><verProc>Odoo Brasil 10</verProc></ide><emit><CNPJ>21332917000163</CNPJ><xNome>TRUSTCODE TECNOLOGIA DA INFORMAÇÃO LTDA</xNome><xFant>Trustcode</xFant><enderEmit><xLgr>Rua Vinicius de Moraes</xLgr><nro>42</nro><xBairro>Córrego Grande</xBairro><cMun>3550308</cMun><xMun>Florianópolis</xMun><UF>SC</UF><CEP>88037240</CEP><cPais>1058</cPais><xPais>Brasil</xPais><fone>1135302850</fone></enderEmit><IE>144013873114</IE><CRT>1</CRT></emit><dest><CNPJ>11370685000184</CNPJ><xNome>NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL</xNome><enderDest><xLgr>AV AMAZONAS</xLgr><nro>1193</nro><xBairro>Centro</xBairro><cMun>4314902</cMun><xMun>Porto Alegre</xMun><UF>RS</UF><CEP>90240542</CEP><cPais>1058</cPais><xPais>Brasil</xPais></enderDest><indIEDest>9</indIEDest></dest><det nItem="1"><prod><cProd>VTS-L1231100907</cProd><cEAN/><xProd>VENTIS PRETO- O2 CO H2S DIFUSAO</xProd><NCM>90271000</NCM><CFOP>6108</CFOP><uCom>UN</uCom><qCom>1.0</qCom><vUnCom>100.00</vUnCom><vProd>100.00</vProd><cEANTrib/><uTrib>UN</uTrib><qTrib>1.0</qTrib><vUnTrib>3562.26</vUnTrib><vFrete>95.00</vFrete><indTot>1</indTot></prod><imposto><vTotTrib>0.00</vTotTrib><ICMS><ICMSSN102><orig>0</orig><CSOSN>102</CSOSN></ICMSSN102></ICMS><IPI><cEnq>999</cEnq><IPITrib><CST>49</CST><vBC>3657.26</vBC><pIPI>0.00</pIPI><vIPI>0.00</vIPI></IPITrib></IPI><PIS><PISNT><CST>07</CST></PISNT></PIS><COFINS><COFINSNT><CST>07</CST></COFINSNT></COFINS></imposto></det><total><ICMSTot><vBC>0.00</vBC><vICMS>0.00</vICMS><vICMSDeson>0.00</vICMSDeson><vBCST>0.00</vBCST><vST>0.00</vST><vProd>3562.26</vProd><vFrete>95.00</vFrete><vSeg>0.00</vSeg><vDesc>0.00</vDesc><vII>0.00</vII><vIPI>0.00</vIPI><vPIS>0.00</vPIS><vCOFINS>0.00</vCOFINS><vOutro>0.00</vOutro><vNF>3657.26</vNF><vTotTrib>0.00</vTotTrib></ICMSTot></total><transp><modFrete>1</modFrete><transporta><xNome>SEDEX</xNome><xEnder>False - False, False</xEnder></transporta></transp><cobr><fat><nFat>INV/2017/0126</nFat><vOrig>3562.26</vOrig><vLiq>3657.26</vLiq></fat><dup><nDup>01</nDup><dVenc>2017-03-16</dVenc><vDup>1828.63</vDup></dup><dup><nDup>02</nDup><dVenc>2017-04-15</dVenc><vDup>1828.63</vDup></dup></cobr><infAdic><infCpl>PERMITE O APROVEITAMENTO DO CR&#201;DITO DE ICMS NO VALOR CORRESPONDENTE &#192; AL&#205;QUOTA DE 1,25%, NOS TERMOS DO ART. 23 DA LC 123/2006 &gt;&gt;IMPORTANTE&lt;&lt; P/ LIQUIDACAO DESTA NF, EFETUE DEPOSITO IDENTIFICADO NO BANCO BRADESCO AG: 1992-5, C/c: 4897-6 PEDIDO DE COMPRAS: OC 0045-05/2017 N/S 16122WZ-021 (Or&#231;amento SO176) **VENCIMENTO: 15/04/2017 ==&gt; .</infCpl></infAdic><compra><xPed>OC 0045-05/2017 N/S 16122WZ-021</xPed></compra></infNFe><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><Reference URI="#NFe35170221332917000163550010000008571134165777"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>bNLOBxpMk5J6rrz37coB8/pvTBE=</DigestValue></Reference></SignedInfo><SignatureValue>Y++vItLsZAbwzM/YDsgGqSn2+u035OSigoskd1x7DDJuAFuM0imbOuC20TAJPODcZCFxfqO1VTFCVgMmJUtHGzwvVdr3DSlbxIevfTF0nNwBYN2LzQVY2R/495ro2Vw2waKfOU+O2IZrKlFxBfu91Vv/JRpbECElwZaDK1BEp2ekGkB0tHfisGbQu1WFR8HBqwcyn8khhScO8nE7S+MR8uyEqf5057AiZZr1/vG/vyNhN1yzP8FFT3kHOG3w2aNe0H85s9spUrSC5hOAIy0yD6/NUUfH9AOOlER+cCLgLT52W7I5nnxC7dgEzG6YQffy1XGd/TQ4RC7ppKwmkVFaoQ==</SignatureValue><KeyInfo><X509Data><X509Certificate>MIIIPzCCBiegAwIBAgIQYdesnYUNG8VPne0qhTeKOzANBgkqhkiG9w0BAQsFADB4
MQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE2MDQGA1UECxMtU2Vj
cmV0YXJpYSBkYSBSZWNlaXRhIEZlZGVyYWwgZG8gQnJhc2lsIC0gUkZCMRwwGgYD
VQQDExNBQyBDZXJ0aXNpZ24gUkZCIEc0MB4XDTE2MDUxMDAwMDAwMFoXDTE3MDUw
OTIzNTk1OVowgekxCzAJBgNVBAYTAkJSMRMwEQYDVQQKFApJQ1AtQnJhc2lsMQsw
CQYDVQQIEwJTUDESMBAGA1UEBxQJU2FvIFBhdWxvMTYwNAYDVQQLFC1TZWNyZXRh
cmlhIGRhIFJlY2VpdGEgRmVkZXJhbCBkbyBCcmFzaWwgLSBSRkIxFjAUBgNVBAsU
DVJGQiBlLUNOUEogQTExJDAiBgNVBAsUG0F1dGVudGljYWRvIHBvciBBUiBTdW5z
aGluZTEuMCwGA1UEAxMlTEVaIEFNQklFTlRBTCBMVERBIEVQUDoyMTMzMjkxNzAw
MDE2MzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANEG6j0uXIvvHlMz
0IGzuY/vuFQncIoSE+cBUk0uq6J3dtmGAg4oaVWCHUfHbX9s2Ag1jIG+PFAo2dlt
sbLSEji74XhD+IpM/9aHm3ke8kb05ay+bYRuUjTNSwUbslT1+amAmIu7m1yPBi6u
v3+/Lj2I0g7VeBBAjv/TiBG0VRCURXvKrwWrv2Lpybo/yDnENGtRqQHihqeYFKin
nDzBsMbv4ripbi3XiAgcy/bF6NFgVMqxrNnGvSiSUhDRkmceVFIysRXUMke02Qo1
Q5Ik1j1goUIHP44QOruXCMiT0yOK8u0qNAXR0yzSaWcBR2aJCeWgFg7sNbB50Qcx
c+2GKUECAwEAAaOCA1EwggNNMIG2BgNVHREEga4wgaugPQYFYEwBAwSgNAQyMTYw
NjE5ODYzNDEzNzgyODg2NTAwMDAwMDAwMDAwMDAwMDAwMDQwMDAwMzczU1NQU1Cg
IgYFYEwBAwKgGQQXTEVPTkFSRE8gREUgTElNQSBTQU5UT1OgGQYFYEwBAwOgEAQO
MjEzMzI5MTcwMDAxNjOgFwYFYEwBAwegDgQMMDAwMDAwMDAwMDAwgRJ3YWduZXJA
emVsbC5jb20uYnIwCQYDVR0TBAIwADAfBgNVHSMEGDAWgBQukerWbeWyWYLcOIUp
djQWVjzQPjAOBgNVHQ8BAf8EBAMCBeAwfwYDVR0gBHgwdjB0BgZgTAECAQwwajBo
BggrBgEFBQcCARZcaHR0cDovL2ljcC1icmFzaWwuY2VydGlzaWduLmNvbS5ici9y
ZXBvc2l0b3Jpby9kcGMvQUNfQ2VydGlzaWduX1JGQi9EUENfQUNfQ2VydGlzaWdu
X1JGQi5wZGYwggEWBgNVHR8EggENMIIBCTBXoFWgU4ZRaHR0cDovL2ljcC1icmFz
aWwuY2VydGlzaWduLmNvbS5ici9yZXBvc2l0b3Jpby9sY3IvQUNDZXJ0aXNpZ25S
RkJHNC9MYXRlc3RDUkwuY3JsMFagVKBShlBodHRwOi8vaWNwLWJyYXNpbC5vdXRy
YWxjci5jb20uYnIvcmVwb3NpdG9yaW8vbGNyL0FDQ2VydGlzaWduUkZCRzQvTGF0
ZXN0Q1JMLmNybDBWoFSgUoZQaHR0cDovL3JlcG9zaXRvcmlvLmljcGJyYXNpbC5n
b3YuYnIvbGNyL0NlcnRpc2lnbi9BQ0NlcnRpc2lnblJGQkc0L0xhdGVzdENSTC5j
cmwwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMIGbBggrBgEFBQcBAQSB
jjCBizBfBggrBgEFBQcwAoZTaHR0cDovL2ljcC1icmFzaWwuY2VydGlzaWduLmNv
bS5ici9yZXBvc2l0b3Jpby9jZXJ0aWZpY2Fkb3MvQUNfQ2VydGlzaWduX1JGQl9H
NC5wN2MwKAYIKwYBBQUHMAGGHGh0dHA6Ly9vY3NwLmNlcnRpc2lnbi5jb20uYnIw
DQYJKoZIhvcNAQELBQADggIBAFIUBrNIyC4kBap/7hCW63tQhA/WNnWDNYpKM5wN
zwApVV2bqFMJURzO/7AUrHu7uZS1p/Ubo+w2dFjmnmj5DniQkY85Sd6HNa1fukJY
PK13wcUMVHMjeevIAcxnYraNdN4BIz1Svl6A8leGFgIEuDUll7Td+R7+aA8N5JYQ
dFFIe2VxvJNbWP/WA49oI8U2wkoPTfOZtfrgKf2msHm3FnTfnmyOPhIf8L31iFt6
MbKuFjOGIaWu+Z/gRDqj/EbFcEMUrDbeIYqz2724ZGBOJrkjHO7DBqXXoN9pzCTO
RB5+gILMEnMS7zFsCuLOtLVohxgYUzg8p4Fy3nsHEzb/7IDVOnKLfjh/c5GSTvOa
JT6qznYV2yav7NyuUSNUv+5bCIBNk45+qrQ8DwpsLBsFa+RLfCwvYVK95ad/xVgJ
QosPJuzW3t0fU/FWbc00sZWV6lgBPyWhdF8EodaRIWC+EOC2wJbODyw+vdX8pUxT
TUJKV2iAP8206gR2h07o2CZgXckJGJQ5MnBUbS78AaITXZ5JlPaS7ZdU9zWY3kD+
j5YERs0+UweijKi5eHZioGRZRDZ2uksh1wrgeLFLWuiSNaPFYVVrQ/ZGo+E5uVNl
8FuoR6P9TZjx1/A4XjqLQ9yPoPWgIWe14Vh/76dVcgz3ElWMbmPCDoc/wX+FoHX1
Fbux
</X509Certificate></X509Data></KeyInfo></Signature></NFe><protNFe versao="3.10"><infProt><tpAmb>2</tpAmb><verAplic>SP_NFE_PL_008i2</verAplic><chNFe>35170221332917000163550010000008571134165777</chNFe><dhRecbto>2017-02-24T08:39:31-03:00</dhRecbto><nProt>135170000807903</nProt><digVal>bNLOBxpMk5J6rrz37coB8/pvTBE=</digVal><cStat>100</cStat><xMotivo>Autorizado o uso da NF-e</xMotivo></infProt></protNFe></nfeProc>

22
pytrustnfe/test/test_danfe.py

@ -0,0 +1,22 @@
# coding=utf-8
import tempfile
import os.path
import unittest
from lxml import etree
from pytrustnfe.nfe.danfe import danfe
class test_danfe(unittest.TestCase):
caminho = os.path.dirname(__file__)
def test_can_generate_danfe(self):
path = os.path.join(os.path.dirname(__file__), 'XMLs')
xml_string = open(os.path.join(path, 'NFe00000857.xml'), "r").read()
xml_element = etree.fromstring(xml_string)
oDanfe = danfe(list_xml=[xml_element])
with tempfile.TemporaryFile(mode='w') as oFile:
oDanfe.writeto_pdf(oFile)

1
requirements.txt

@ -13,3 +13,4 @@ eight >= 0.3.0, < 0.4
cryptography >= 1.4, < 1.8
pyOpenSSL >= 16.0.0, < 17
certifi >= 2015.11.20.1
reportlab

3
setup.py

@ -1,7 +1,7 @@
# coding=utf-8
from setuptools import setup, find_packages
VERSION = "0.1.29"
VERSION = "0.1.30"
setup(
name="PyTrustNFe",
@ -35,6 +35,7 @@ later (LGPLv2+)',
'lxml >= 3.6.0, < 3.7',
'suds >= 0.4',
'suds_requests >= 0.3',
'reportlab'
],
test_suite='nose.collector',
tests_require=[

Loading…
Cancel
Save