You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1241 lines
49 KiB
1241 lines
49 KiB
# -*- 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
|
|
|
|
import os
|
|
from io import BytesIO
|
|
from textwrap import wrap
|
|
import math
|
|
|
|
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
|
|
from reportlab.lib.styles import ParagraphStyle
|
|
from reportlab.pdfbase import pdfmetrics
|
|
from reportlab.pdfbase.ttfonts import TTFont
|
|
|
|
import pytz
|
|
from datetime import datetime, timedelta
|
|
|
|
|
|
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 getdateByTimezone(cDateUTC, timezone=None):
|
|
"""
|
|
Esse método trata a data recebida de acordo com o timezone do
|
|
usuário. O seu retorno é dividido em duas partes:
|
|
1) A data em si;
|
|
2) As horas;
|
|
:param cDateUTC: string contendo as informações da data
|
|
:param timezone: timezone do usuário do sistema
|
|
:return: data e hora convertidos para a timezone do usuário
|
|
"""
|
|
|
|
# Aqui cortamos a informação do timezone da string (+03:00)
|
|
dt = cDateUTC[0:19]
|
|
|
|
# Verificamos se a string está completa (data + hora + timezone)
|
|
if timezone and len(cDateUTC) == 25:
|
|
|
|
# tz irá conter informações da timezone contida em cDateUTC
|
|
tz = cDateUTC[19:25]
|
|
tz = int(tz.split(":")[0])
|
|
|
|
dt = datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S")
|
|
|
|
# dt agora será convertido para o horario em UTC
|
|
dt = dt - timedelta(hours=tz)
|
|
|
|
# tzinfo passará a apontar para <UTC>
|
|
dt = pytz.utc.localize(dt)
|
|
|
|
# valor de dt é convertido para a timezone do usuário
|
|
dt = timezone.normalize(dt)
|
|
dt = dt.strftime("%Y-%m-%dT%H:%M:%S")
|
|
|
|
cDt = dt[0:10].split("-")
|
|
cDt.reverse()
|
|
return "/".join(cDt), dt[11:16]
|
|
|
|
|
|
def format_number(cNumber):
|
|
if cNumber:
|
|
# Vírgula para a separação de milhar e 2f para 2 casas decimais
|
|
cNumber = "{:,.2f}".format(float(cNumber))
|
|
return cNumber.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,
|
|
cce_xml=None,
|
|
timezone=None,
|
|
):
|
|
|
|
tamanho_ocupado = 0
|
|
path = os.path.join(os.path.dirname(__file__), "fonts")
|
|
pdfmetrics.registerFont(
|
|
TTFont("NimbusSanL-Regu", os.path.join(path, "NimbusSanL Regular.ttf"))
|
|
)
|
|
pdfmetrics.registerFont(
|
|
TTFont("NimbusSanL-Bold", os.path.join(path, "NimbusSanL Bold.ttf"))
|
|
)
|
|
self.width = 210 # 21 x 29,7cm
|
|
self.height = 297
|
|
self.nLeft = 10
|
|
self.nRight = 10
|
|
self.nTop = 7
|
|
self.nBottom = 8
|
|
self.nlin = self.nTop
|
|
self.logo = logo
|
|
self.oFrete = {
|
|
"0": "0 - Contratação por conta do Remetente (CIF)",
|
|
"1": "1 - Contratação por conta do Destinatário (FOB)",
|
|
"2": "2 - Contratação por conta de Terceiros",
|
|
"3": "3 - Transporte Próprio por conta do Remetente",
|
|
"4": "4 - Transporte Próprio por conta do Destinatário",
|
|
"9": "9 - Sem Ocorrência de Transporte",
|
|
}
|
|
|
|
self.oPDF_IO = BytesIO()
|
|
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
|
|
|
|
el_det = oXML.findall(".//{http://www.portalfiscal.inf.br/nfe}det")
|
|
|
|
# Declaring variable to prevent future errors
|
|
nId = 0
|
|
|
|
if el_det is not None:
|
|
list_desc = []
|
|
list_cod_prod = []
|
|
|
|
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"), 50)
|
|
if infAdProd is not None:
|
|
list_.extend(wrap(infAdProd.text, 50))
|
|
list_desc.append(list_)
|
|
|
|
list_cProd = wrap(tagtext(oNode=el_prod, cTag="cProd"), 14)
|
|
list_cod_prod.append(list_cProd)
|
|
|
|
# Calculando nr. aprox. de páginas
|
|
if nId > 25:
|
|
self.NrPages += math.ceil((nId - 25) / 70)
|
|
|
|
if recibo:
|
|
self.recibo_entrega(oXML=oXML, timezone=timezone)
|
|
|
|
self.ide_emit(oXML=oXML, timezone=timezone)
|
|
self.destinatario(oXML=oXML, timezone=timezone)
|
|
tamanho_ocupado += self.entrega_retirada(
|
|
oXML=oXML, timezone=timezone)
|
|
|
|
if oXML_cobr is not None:
|
|
self.faturas(oXML=oXML_cobr, timezone=timezone)
|
|
|
|
self.impostos(oXML=oXML)
|
|
self.transportes(oXML=oXML)
|
|
|
|
index = self.produtos(
|
|
oXML=oXML,
|
|
el_det=el_det,
|
|
max_index=nId,
|
|
list_desc=list_desc,
|
|
list_cod_prod=list_cod_prod,
|
|
)
|
|
|
|
tamanho_ocupado += self.calculo_issqn(oXML=oXML)
|
|
self.adicionais(oXML=oXML, tamanho_diminuir=tamanho_ocupado)
|
|
|
|
# Gera o restante das páginas do XML
|
|
while index < nId:
|
|
if index < 0:
|
|
index = index * -1
|
|
self.newpage()
|
|
self.ide_emit(oXML=oXML, timezone=timezone)
|
|
index = self.produtos(
|
|
oXML=oXML,
|
|
el_det=el_det,
|
|
index=index,
|
|
max_index=nId,
|
|
list_desc=list_desc,
|
|
nHeight=77,
|
|
list_cod_prod=list_cod_prod,
|
|
)
|
|
|
|
self.newpage()
|
|
if cce_xml:
|
|
for xml in cce_xml:
|
|
self._generate_cce(cce_xml=xml, oXML=oXML, timezone=timezone)
|
|
self.newpage()
|
|
self.canvas.save()
|
|
|
|
def ide_emit(self, oXML=None, timezone=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")
|
|
elem_evento = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}infEvento")
|
|
|
|
cChave = elem_infNFe.attrib.get("Id")[3:]
|
|
barcode128 = code128.Code128(cChave, barHeight=10 * mm, barWidth=0.25 * mm)
|
|
|
|
self.canvas.setLineWidth(0.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.hline(self.nLeft + 85, self.nlin + 1, 125)
|
|
|
|
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 + 5, "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, "Nº %s" % (cNF))
|
|
|
|
self.stringcenter(
|
|
self.nLeft + 100,
|
|
self.nlin + 29,
|
|
"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 = getdateByTimezone(
|
|
tagtext(oNode=elem_protNFe, cTag="dhRecbto"), timezone
|
|
)
|
|
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, 40 * mm)
|
|
P.drawOn(
|
|
self.canvas,
|
|
(self.nLeft + 30) * mm,
|
|
(self.height - self.nlin - ((4.3 * h + 12) / 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="xCpl") + " - "
|
|
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 += "<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 - 33) * 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()
|
|
|
|
# Cancelado
|
|
if tagtext(oNode=elem_evento, cTag="cStat") in ("135", "155"):
|
|
self.canvas.saveState()
|
|
self.canvas.rotate(45)
|
|
self.canvas.setFont("NimbusSanL-Bold", 60)
|
|
self.canvas.setFillColorRGB(1, 0.2, 0.2)
|
|
self.string(self.nLeft + 80, 275, "CANCELADO")
|
|
self.canvas.restoreState()
|
|
|
|
self.nlin += 48
|
|
|
|
def destinatario(self, oXML=None, timezone=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")
|
|
)
|
|
cnpj_cpf = tagtext(oNode=elem_dest, cTag="CNPJ")
|
|
if cnpj_cpf:
|
|
cnpj_cpf = format_cnpj_cpf(cnpj_cpf)
|
|
else:
|
|
cnpj_cpf = format_cnpj_cpf(tagtext(oNode=elem_dest, cTag="CPF"))
|
|
self.string(nMr - 69, self.nlin + 7.5, cnpj_cpf)
|
|
cDt, cHr = getdateByTimezone(tagtext(oNode=elem_ide, cTag="dhEmi"), timezone)
|
|
self.string(nMr - 24, self.nlin + 7.7, cDt + " " + cHr)
|
|
cDt, cHr = getdateByTimezone(tagtext(oNode=elem_ide, cTag="dhSaiEnt"), timezone)
|
|
self.string(nMr - 24, self.nlin + 14.3, cDt + " " + cHr) # Dt saída
|
|
cEnd = "%s, %s %s" % (
|
|
tagtext(oNode=elem_dest, cTag="xLgr"),
|
|
tagtext(oNode=elem_dest, cTag="nro"),
|
|
tagtext(oNode=elem_dest, cTag="xCpl"),
|
|
)
|
|
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 entrega_retirada(self, oXML=None, timezone=None):
|
|
elem_entrega = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}entrega")
|
|
elem_retirada = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}retirada")
|
|
self.canvas.setFont("NimbusSanL-Bold", 7)
|
|
|
|
if elem_entrega:
|
|
elem = elem_entrega
|
|
self.string(self.nLeft + 1, self.nlin + 1, "INFORMAÇÕES DO LOCAL DE ENTREGA")
|
|
elif elem_retirada:
|
|
elem = elem_retirada
|
|
self.string(self.nLeft + 1, self.nlin + 1, "INFORMAÇÕES DO LOCAL DE RETIRADA")
|
|
else:
|
|
return 0
|
|
|
|
nMr = self.width - self.nRight
|
|
|
|
self.nlin += 1
|
|
|
|
self.rect(self.nLeft, self.nlin + 2, self.width - self.nLeft - self.nRight, 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 - 25, self.nlin + 2, 6.66)
|
|
self.vline(nMr - 70, self.nlin + 2, 6.66)
|
|
self.vline(nMr - 25, self.nlin + 8.66, 6.66)
|
|
self.vline(nMr - 90, self.nlin + 8.66, 6.66)
|
|
self.vline(nMr - 25, self.nlin + 15.32, 6.66)
|
|
self.vline(nMr - 37, 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, "INSCRIÇÃO ESTADUAL")
|
|
self.string(self.nLeft + 1, self.nlin + 10.3, "ENDEREÇO")
|
|
self.string(nMr - 89, self.nlin + 10.3, "BAIRRO/DISTRITO")
|
|
self.string(nMr - 24, self.nlin + 10.3, "CEP")
|
|
self.string(self.nLeft + 1, self.nlin + 17.1, "MUNICÍPIO")
|
|
self.string(nMr - 24, self.nlin + 17.1, "FONE/FAX")
|
|
self.string(nMr - 36, self.nlin + 17.1, "UF")
|
|
# Conteúdo campos
|
|
self.canvas.setFont("NimbusSanL-Regu", 8)
|
|
self.string(
|
|
self.nLeft + 1, self.nlin + 7.5, tagtext(oNode=elem, cTag="xNome")
|
|
)
|
|
cnpj_cpf = tagtext(oNode=elem, cTag="CNPJ")
|
|
if cnpj_cpf:
|
|
cnpj_cpf = format_cnpj_cpf(cnpj_cpf)
|
|
else:
|
|
cnpj_cpf = format_cnpj_cpf(tagtext(oNode=elem, cTag="CPF"))
|
|
self.string(nMr - 69, self.nlin + 7.5, cnpj_cpf)
|
|
self.string(nMr - 24, self.nlin + 7.5, tagtext(oNode=elem, cTag="IE"))
|
|
cEnd = "%s, %s %s" % (
|
|
tagtext(oNode=elem, cTag="xLgr"),
|
|
tagtext(oNode=elem, cTag="nro"),
|
|
tagtext(oNode=elem, cTag="xCpl"),
|
|
)
|
|
self.string(self.nLeft + 1, self.nlin + 14.3, cEnd)
|
|
self.string(
|
|
nMr - 89, self.nlin + 14.3, tagtext(oNode=elem, cTag="xBairro")
|
|
)
|
|
self.string(nMr - 24, self.nlin + 14.3, tagtext(oNode=elem, cTag="CEP"))
|
|
self.string(
|
|
self.nLeft + 1, self.nlin + 21.1, tagtext(oNode=elem, cTag="xMun")
|
|
)
|
|
self.string(nMr - 36, self.nlin + 21.1, tagtext(oNode=elem, cTag="UF"))
|
|
self.string(nMr - 24, self.nlin + 21.1, tagtext(oNode=elem, cTag="fone"))
|
|
|
|
self.nlin += 24 # Nr linhas ocupadas pelo bloco
|
|
return 24
|
|
|
|
def faturas(self, oXML=None, timezone=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 = getdateByTimezone(
|
|
tagtext(oNode=oXML_dup, cTag="dVenc"), timezone
|
|
)
|
|
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")),
|
|
)
|
|
|
|
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 - 65, self.nlin + 2, 6.5)
|
|
self.vline(nMr - 95, self.nlin + 2, 6.5)
|
|
self.vline(nMr - 125, self.nlin + 2, 6.5)
|
|
self.vline(nMr - 155, self.nlin + 2, 6.5)
|
|
self.vline(nMr - 35, self.nlin + 8.5, 6.5)
|
|
self.vline(nMr - 65, self.nlin + 8.5, 6.5)
|
|
self.vline(nMr - 95, self.nlin + 8.5, 6.5)
|
|
self.vline(nMr - 125, self.nlin + 8.5, 6.5)
|
|
self.vline(nMr - 155, self.nlin + 8.5, 6.5)
|
|
# Labels
|
|
self.canvas.setFont("NimbusSanL-Regu", 5)
|
|
self.string(self.nLeft + 1, self.nlin + 3.8, "BASE DE CÁLCULO DO ICMS")
|
|
self.string(nMr - 154, self.nlin + 3.8, "VALOR DO ICMS")
|
|
self.string(nMr - 124, self.nlin + 3.8, "BASE DE CÁLCULO DO ICMS ST")
|
|
self.string(nMr - 94, self.nlin + 3.8, "VALOR DO ICMS ST")
|
|
self.string(nMr - 64, self.nlin + 3.8, "VALOR APROX TRIBUTOS")
|
|
self.string(nMr - 34, self.nlin + 3.8, "VALOR TOTAL DOS PRODUTOS")
|
|
|
|
self.string(self.nLeft + 1, self.nlin + 10.2, "VALOR DO FRETE")
|
|
self.string(nMr - 154, self.nlin + 10.2, "VALOR DO SEGURO")
|
|
self.string(nMr - 124, self.nlin + 10.2, "DESCONTO")
|
|
self.string(nMr - 94, self.nlin + 10.2, "OUTRAS DESP. ACESSÓRIAS")
|
|
self.string(nMr - 64, self.nlin + 10.2, "VALOR DO IPI")
|
|
self.string(nMr - 34, self.nlin + 10.2, "VALOR TOTAL DA NOTA")
|
|
|
|
# Conteúdo campos
|
|
self.canvas.setFont("NimbusSanL-Regu", 8)
|
|
self.stringRight(
|
|
self.nLeft + 34,
|
|
self.nlin + 7.7,
|
|
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")),
|
|
)
|
|
self.stringRight(
|
|
self.nLeft + 94,
|
|
self.nlin + 7.7,
|
|
format_number(tagtext(oNode=el_total, cTag="vBCST")),
|
|
)
|
|
self.stringRight(
|
|
nMr - 66,
|
|
self.nlin + 7.7,
|
|
format_number(tagtext(oNode=el_total, cTag="vST")),
|
|
)
|
|
self.stringRight(
|
|
nMr - 36,
|
|
self.nlin + 7.7,
|
|
format_number(tagtext(oNode=el_total, cTag="vTotTrib")),
|
|
)
|
|
self.stringRight(
|
|
nMr - 1,
|
|
self.nlin + 7.7,
|
|
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")),
|
|
)
|
|
self.stringRight(
|
|
self.nLeft + 64,
|
|
self.nlin + 14.1,
|
|
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")),
|
|
)
|
|
self.stringRight(
|
|
self.nLeft + 124,
|
|
self.nlin + 14.1,
|
|
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")),
|
|
)
|
|
self.stringRight(
|
|
nMr - 1,
|
|
self.nlin + 14.1,
|
|
format_number(tagtext(oNode=el_total, cTag="vNF")),
|
|
)
|
|
|
|
self.nlin += 17 # Nr linhas ocupadas pelo bloco
|
|
|
|
def transportes(self, oXML=None):
|
|
el_transp = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}transp")
|
|
veic_transp = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}veicTransp")
|
|
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 - 26, self.nlin + 2, 13.2)
|
|
self.vline(nMr - 33, self.nlin + 2, 13.2)
|
|
self.vline(nMr - 67, self.nlin + 2, 6.6)
|
|
self.vline(nMr - 123, self.nlin + 2, 6.6)
|
|
self.vline(nMr - 53, self.nlin + 2, 6.6)
|
|
self.vline(nMr - 26, self.nlin + 15.2, 6.6)
|
|
self.vline(nMr - 49, 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 - 25, self.nlin + 3.8, "CNPJ/CPF")
|
|
self.string(nMr - 52, self.nlin + 3.8, "PLACA DO VEÍCULO")
|
|
self.string(nMr - 66, self.nlin + 3.8, "CÓDIGO ANTT")
|
|
self.string(nMr - 122, self.nlin + 3.8, "FRETE POR CONTA")
|
|
self.string(self.nLeft + 1, self.nlin + 3.8, "RAZÃO SOCIAL")
|
|
self.string(nMr - 32, self.nlin + 3.8, "UF")
|
|
self.string(nMr - 25, self.nlin + 10.3, "INSCRIÇÃO ESTADUAL")
|
|
self.string(nMr - 32, 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", 7)
|
|
self.string(
|
|
self.nLeft + 1, self.nlin + 7.7, tagtext(oNode=el_transp, cTag="xNome")[:42]
|
|
)
|
|
self.string(
|
|
self.nLeft + 68,
|
|
self.nlin + 7.7,
|
|
self.oFrete[tagtext(oNode=el_transp, cTag="modFrete")],
|
|
)
|
|
self.string(
|
|
self.nLeft + 122, self.nlin + 7.7, tagtext(oNode=el_transp, cTag="RNTC")
|
|
)
|
|
self.string(
|
|
self.nLeft + 136, self.nlin + 7.7, tagtext(oNode=el_transp, cTag="placa")
|
|
)
|
|
self.string(
|
|
self.nLeft + 157, self.nlin + 7.7, tagtext(oNode=veic_transp, cTag="UF")
|
|
)
|
|
self.string(
|
|
nMr - 25,
|
|
self.nlin + 7.7,
|
|
format_cnpj_cpf(tagtext(oNode=el_transp, cTag="CNPJ")),
|
|
)
|
|
self.canvas.setFont("NimbusSanL-Regu", 8)
|
|
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 - 32, self.nlin + 14.2, tagtext(oNode=el_transp, cTag="UF"))
|
|
self.string(nMr - 25, 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")),
|
|
)
|
|
self.stringRight(
|
|
nMr - 1,
|
|
self.nlin + 21.2,
|
|
format_number(tagtext(oNode=el_transp, cTag="pesoL")),
|
|
)
|
|
|
|
self.nlin += 23
|
|
|
|
def produtos(
|
|
self,
|
|
oXML=None,
|
|
el_det=None,
|
|
index=0,
|
|
max_index=0,
|
|
list_desc=None,
|
|
list_cod_prod=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
|
|
# nH é o altura da linha vertical, utilizar como referência
|
|
# somar a ele a altura atual que é nlin
|
|
maxHeight = self.nlin + nH
|
|
|
|
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 + 15, self.nlin + 2, nH)
|
|
self.stringcenter(self.nLeft + 7.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 - 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.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)
|
|
self.stringcenter(nMr - 99, self.nlin + 5.5, "CFOP")
|
|
self.vline(nMr - 108, self.nlin + 2, nH)
|
|
self.stringcenter(nMr - 105, self.nlin + 5.5, "CST")
|
|
self.vline(nMr - 117, self.nlin + 2, nH)
|
|
self.stringcenter(nMr - 112.5, self.nlin + 5.5, "NCM/SH")
|
|
|
|
nWidth_Prod = nMr - 135 - self.nLeft - 11
|
|
nCol_ = self.nLeft + 20 + (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.0
|
|
|
|
for id in range(index, max_index + 1):
|
|
|
|
line_height = max(len(list_cod_prod[id]), len(list_desc[id]))
|
|
line_height *= nStep
|
|
if nLin + line_height > maxHeight:
|
|
id = id * -1
|
|
break
|
|
|
|
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")
|
|
or tagtext(oNode=el_imp_ICMS, cTag="CSOSN")
|
|
)
|
|
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.stringcenter(nMr - 112.5, nLin, tagtext(oNode=el_prod, cTag="NCM"))
|
|
self.stringcenter(nMr - 105, nLin, cCST)
|
|
self.stringcenter(nMr - 99, nLin, tagtext(oNode=el_prod, cTag="CFOP"))
|
|
self.stringcenter(nMr - 93, nLin, tagtext(oNode=el_prod, cTag="uCom"))
|
|
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"))
|
|
)
|
|
self.stringRight(
|
|
nMr - 50.5, nLin, format_number(tagtext(oNode=el_prod, cTag="vProd"))
|
|
)
|
|
self.stringRight(nMr - 38.5, nLin, format_number(vBC or "0.00"))
|
|
self.stringRight(nMr - 26.5, nLin, format_number(vICMS or "0.00"))
|
|
self.stringRight(nMr - 7.5, nLin, format_number(pICMS or "0.00"))
|
|
|
|
self.stringRight(nMr - 14.5, nLin, format_number(vIPI or "0.00"))
|
|
self.stringRight(nMr - 0.5, nLin, format_number(pIPI or "0.00"))
|
|
|
|
# Código Item
|
|
line_cod = nLin
|
|
for des in list_cod_prod[id]:
|
|
self.string(self.nLeft + 0.2, line_cod, des)
|
|
line_cod += nStep
|
|
|
|
# Descrição Item
|
|
line_desc = nLin
|
|
for des in list_desc[id]:
|
|
self.string(self.nLeft + 15.5, line_desc, des)
|
|
line_desc += nStep
|
|
|
|
nLin = max(line_cod, line_desc)
|
|
self.canvas.setStrokeColor(gray)
|
|
self.hline(self.nLeft, nLin - 2, self.width - self.nLeft)
|
|
self.canvas.setStrokeColor(black)
|
|
|
|
self.nlin += nH + 3
|
|
return id
|
|
|
|
def calculo_issqn(self, oXML=None):
|
|
elem_emit = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}emit")
|
|
el_total = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}total")
|
|
issqn_total = el_total.find(".//{http://www.portalfiscal.inf.br/nfe}ISSQNtot")
|
|
if not issqn_total:
|
|
return 0
|
|
|
|
self.nlin += 1
|
|
nMr = self.width - self.nRight
|
|
self.canvas.setFont("NimbusSanL-Bold", 7)
|
|
self.string(self.nLeft + 1, self.nlin + 1, "CÁLCULO DO ISSQN")
|
|
self.rect(self.nLeft, self.nlin + 2, self.width - self.nLeft - self.nRight, 5.5)
|
|
self.vline(nMr - 47.5, self.nlin + 2, 5.5)
|
|
self.vline(nMr - 95, self.nlin + 2, 5.5)
|
|
self.vline(nMr - 142.5, self.nlin + 2, 5.5)
|
|
self.vline(nMr - 190, self.nlin + 2, 5.5)
|
|
# Labels
|
|
self.canvas.setFont("NimbusSanL-Regu", 5)
|
|
self.string(self.nLeft + 1, self.nlin + 3.8, "INSCRIÇÃO MUNICIPAL")
|
|
self.string(nMr - 141.5, self.nlin + 3.8, "VALOR TOTAL DOS SERVIÇOS")
|
|
self.string(nMr - 94, self.nlin + 3.8, "BASE DE CÁLCULO DO ISSQN")
|
|
self.string(nMr - 46.5, self.nlin + 3.8, "VALOR DO ISSQN")
|
|
# Conteúdo campos
|
|
self.canvas.setFont("NimbusSanL-Regu", 8)
|
|
self.string(
|
|
self.nLeft + 1, self.nlin + 6.7, tagtext(oNode=elem_emit, cTag="IM")
|
|
)
|
|
self.stringRight(
|
|
self.nLeft + 94,
|
|
self.nlin + 6.7,
|
|
format_number(tagtext(oNode=issqn_total, cTag="vServ")),
|
|
)
|
|
self.stringRight(
|
|
self.nLeft + 141.5,
|
|
self.nlin + 6.7,
|
|
format_number(tagtext(oNode=issqn_total, cTag="vBC")),
|
|
)
|
|
self.stringRight(
|
|
self.nLeft + 189,
|
|
self.nlin + 6.7,
|
|
format_number(tagtext(oNode=issqn_total, cTag="vISS")),
|
|
)
|
|
|
|
self.nlin += 8 # Nr linhas ocupadas pelo bloco
|
|
return 8
|
|
|
|
def adicionais(self, oXML=None, tamanho_diminuir=0):
|
|
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 / 3) * 2) + 1, self.nlin + 4, "RESERVADO AO FISCO")
|
|
self.rect(
|
|
self.nLeft,
|
|
self.nlin + 2,
|
|
self.width - self.nLeft - self.nRight,
|
|
42 - tamanho_diminuir,
|
|
)
|
|
self.vline((self.width / 3) * 2, self.nlin + 2, 42 - tamanho_diminuir)
|
|
# Conteúdo campos
|
|
styles = getSampleStyleSheet()
|
|
styleN = styles["Normal"]
|
|
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:
|
|
observacoes = fisco + " " + observacoes
|
|
P = Paragraph(observacoes, styles["Normal"])
|
|
w, h = P.wrap(128 * mm, 32 * mm)
|
|
altura = (self.height - self.nlin - 5) * mm
|
|
P.drawOn(self.canvas, (self.nLeft + 1) * mm, altura - h)
|
|
self.nlin += 36
|
|
|
|
def recibo_entrega(self, oXML=None, timezone=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(0.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, "Nº %s" % (cNF))
|
|
self.string(
|
|
self.width - self.nRight - nW + 2,
|
|
self.nlin + 14,
|
|
"SÉRIE %s" % (tagtext(oNode=el_ide, cTag="serie")),
|
|
)
|
|
|
|
cDt, cHr = getdateByTimezone(tagtext(oNode=el_ide, cTag="dhEmi"), timezone)
|
|
cTotal = format_number(tagtext(oNode=el_total, cTag="vNF"))
|
|
|
|
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="xCpl") + " "
|
|
cEnd += (
|
|
tagtext(oNode=el_dest, cTag="xBairro")
|
|
+ ", "
|
|
+ tagtext(oNode=el_dest, cTag="xMun")
|
|
+ " - "
|
|
)
|
|
cEnd += tagtext(oNode=el_dest, cTag="UF")
|
|
|
|
cString = """
|
|
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) * mm) - h
|
|
)
|
|
|
|
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)
|
|
|
|
def _generate_cce(self, cce_xml=None, oXML=None, timezone=None):
|
|
self.canvas.setLineWidth(0.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 = getdateByTimezone(
|
|
tagtext(oNode=elem_infNFe, cTag="dhEvento"), timezone
|
|
)
|
|
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 = "<font size=%s>%s</font>" % (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
|