Source code for stoqlib.reporting.boleto

# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
##
## Copyright (C) 2011-2012 Async Open Source
##
## This program is free software; you can redistribute it and/or
## modify it under the terms of the GNU Lesser General Public License
## as published by the Free Software Foundation; either version 2
## of the License, or (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., or visit: http://www.gnu.org/.
##
## Author(s): Stoq Team <stoq-devel@async.com.br>
##

# This is mostly lifted from
# http://code.google.com/p/pyboleto licensed under MIT

import sys
import traceback

from reportlab.graphics.barcode.common import I2of5
from reportlab.lib import colors, pagesizes, utils
from reportlab.lib.units import mm
from reportlab.pdfgen import canvas

from stoqlib.exceptions import ReportError
from stoqlib.lib.crashreport import collect_traceback
from stoqlib.lib.boleto import BoletoException, get_bank_info_by_number
from stoqlib.lib.message import warning
from stoqlib.lib.translation import stoqlib_gettext

_ = stoqlib_gettext


[docs]class BoletoPDF(object): (FORMAT_BOLETO, FORMAT_CARNE) = range(2) def __init__(self, file_descr, format=FORMAT_BOLETO): self.file_descr = file_descr self.width = 190 * mm self.widthCanhoto = 70 * mm self.space = 2 self.fontSizeTitle = 6 self.fontSizeValue = 9 pagesize = pagesizes.A4 if format == self.FORMAT_CARNE: pagesize = pagesizes.landscape(pagesize) self.heightLine = 5.75 * mm else: self.heightLine = 6.5 * mm self.deltaTitle = self.heightLine - (self.fontSizeTitle + 1) self.deltaFont = self.fontSizeValue + 1 self.format = format self.pdfCanvas = canvas.Canvas(self.file_descr, pagesize=pagesize) self.pdfCanvas.setStrokeColor(colors.black) self.boletos = []
[docs] def drawReciboSacadoCanhoto(self, boletoDados, x, y): self.pdfCanvas.saveState() self.pdfCanvas.translate(x * mm, y * mm) linhaInicial = 12 # Horizontal Lines self.pdfCanvas.setLineWidth(2) self._horizontalLine(0, 0, self.widthCanhoto) self.pdfCanvas.setLineWidth(1) self._horizontalLine(0, (linhaInicial + 0) * self.heightLine, self.widthCanhoto) self._horizontalLine(0, (linhaInicial + 1) * self.heightLine, self.widthCanhoto) self.pdfCanvas.setLineWidth(2) self._horizontalLine(0, (linhaInicial + 2) * self.heightLine, self.widthCanhoto) # Vertical Lines self.pdfCanvas.setLineWidth(1) self._verticalLine(self.widthCanhoto - (35 * mm), (linhaInicial + 0) * self.heightLine, self.heightLine) self._verticalLine(self.widthCanhoto - (35 * mm), (linhaInicial + 1) * self.heightLine, self.heightLine) self.pdfCanvas.setFont('Helvetica-Bold', 6) self.pdfCanvas.drawRightString(self.widthCanhoto, 0 * self.heightLine + 3, 'Recibo do Sacado') # Titles self.pdfCanvas.setFont('Helvetica', 6) self.deltaTitle = self.heightLine - (6 + 1) self.pdfCanvas.drawString( self.space, (((linhaInicial + 0) * self.heightLine)) + self.deltaTitle, 'Nosso Número') self.pdfCanvas.drawString( self.widthCanhoto - (35 * mm) + self.space, (((linhaInicial + 0) * self.heightLine)) + self.deltaTitle, 'Vencimento') self.pdfCanvas.drawString( self.space, (((linhaInicial + 1) * self.heightLine)) + self.deltaTitle, 'Agência/Código do Beneficiário') self.pdfCanvas.drawString( self.widthCanhoto - (35 * mm) + self.space, (((linhaInicial + 1) * self.heightLine)) + self.deltaTitle, 'Valor Documento') # Values self.pdfCanvas.setFont('Helvetica', 9) heighFont = 9 + 1 valorDocumento = self._format_value(boletoDados.payment.value) self.pdfCanvas.drawString( self.space, (((linhaInicial + 0) * self.heightLine)) + self.space, boletoDados.format_nosso_numero()) self.pdfCanvas.drawString( self.widthCanhoto - (35 * mm) + self.space, (((linhaInicial + 0) * self.heightLine)) + self.space, boletoDados.payment.due_date.strftime('%d/%m/%Y')) self.pdfCanvas.drawString( self.space, (((linhaInicial + 1) * self.heightLine)) + self.space, boletoDados.agencia_conta) self.pdfCanvas.drawString( self.widthCanhoto - (35 * mm) + self.space, (((linhaInicial + 1) * self.heightLine)) + self.space, valorDocumento) demonstrativo = boletoDados.demonstrativo[0:12] for i in range(len(demonstrativo)): parts = utils.simpleSplit(demonstrativo[i], 'Helvetica', 9, self.widthCanhoto) self.pdfCanvas.drawString( 2 * self.space, (((linhaInicial - 1) * self.heightLine)) - (i * heighFont), parts[0]) self.pdfCanvas.restoreState() return (self.widthCanhoto / mm, ((linhaInicial + 2) * self.heightLine) / mm)
[docs] def drawReciboSacado(self, boletoDados, x, y): self.pdfCanvas.saveState() self.pdfCanvas.translate(x * mm, y * mm) linhaInicial = 16 # Horizontal Lines self.pdfCanvas.setLineWidth(1) # Cedente self._horizontalLine(0, linhaInicial * self.heightLine, self.width) # Endereço self._horizontalLine(0, (linhaInicial + 1) * self.heightLine, self.width) # Sacado self._horizontalLine(0, (linhaInicial - 1) * self.heightLine, self.width) self.pdfCanvas.setLineWidth(2) self._horizontalLine(0, (linhaInicial + 2) * self.heightLine, self.width) # Vertical Lines # Vertical line 1 # Linha Sacado self.pdfCanvas.setLineWidth(1) self._verticalLine( self.width - (35 * mm) - (30 * mm) - (40 * mm), (linhaInicial - 1) * self.heightLine, 1 * self.heightLine) # Linha Cedente self._verticalLine( self.width - (35 * mm) - (30 * mm) - (40 * mm), (linhaInicial + 1) * self.heightLine, 1 * self.heightLine) # Vertical line 2 # Cedente self.pdfCanvas.setLineWidth(1) self._verticalLine( self.width - (35 * mm) - (30 * mm), (linhaInicial + 1) * self.heightLine, 1 * self.heightLine) # Sacado self.pdfCanvas.setLineWidth(1) self._verticalLine( self.width - (35 * mm) - (30 * mm), (linhaInicial - 1) * self.heightLine, 1 * self.heightLine) # Vertical line 3 # Cedente/Endereço/Sacado self.pdfCanvas.setLineWidth(1) self._verticalLine( self.width - (35 * mm), (linhaInicial + -1) * self.heightLine, 3 * self.heightLine) # Head self.pdfCanvas.setLineWidth(2) self._verticalLine(40 * mm, (linhaInicial + 2) * self.heightLine, self.heightLine) self._verticalLine(60 * mm, (linhaInicial + 2) * self.heightLine, self.heightLine) if boletoDados.logo_image_path: self.pdfCanvas.drawImage( boletoDados.logo_image_path, 0, (linhaInicial + 2) * self.heightLine + 3, 40 * mm, self.heightLine, preserveAspectRatio=True, anchor='sw') self.pdfCanvas.setFont('Helvetica-Bold', 18) self.pdfCanvas.drawCentredString( 50 * mm, (linhaInicial + 2) * self.heightLine + 3, boletoDados.codigo_dv_banco) self.pdfCanvas.setFont('Helvetica-Bold', 10) self.pdfCanvas.drawRightString( self.width, (linhaInicial + 2) * self.heightLine + 3, 'Recibo do Pagador') # Titles self.pdfCanvas.setFont('Helvetica', 6) self.deltaTitle = self.heightLine - (6 + 1) self.pdfCanvas.drawRightString( self.width, self.heightLine, 'Autenticação Mecânica') # Linha Beneficiário self.pdfCanvas.drawString( 0, (((linhaInicial + 1) * self.heightLine)) + self.deltaTitle, 'Beneficiário') self.pdfCanvas.drawString( self.width - (35 * mm) - (30 * mm) - (40 * mm) + self.space, (((linhaInicial + 1) * self.heightLine)) + self.deltaTitle, 'Agência/Código Beneficiário') self.pdfCanvas.drawString( self.width - (35 * mm) - (30 * mm) + self.space, (((linhaInicial + 1) * self.heightLine)) + self.deltaTitle, 'Data Documento') self.pdfCanvas.drawString( self.width - (35 * mm) + self.space, (((linhaInicial + 1) * self.heightLine)) + self.deltaTitle, 'Vencimento') # Linha Endereço self.pdfCanvas.drawString( 0, (((linhaInicial + 0) * self.heightLine)) + self.deltaTitle, 'Endereço Beneficiário') self.pdfCanvas.drawString( self.width - (35 * mm) + self.space, (((linhaInicial + 0) * self.heightLine)) + self.deltaTitle, 'CNPJ Beneficiário') # Linha Sacado self.pdfCanvas.drawString( 0, (((linhaInicial - 1) * self.heightLine)) + self.deltaTitle, 'Pagador') self.pdfCanvas.drawString( self.width - (35 * mm) - (30 * mm) - (40 * mm) + self.space, (((linhaInicial - 1) * self.heightLine)) + self.deltaTitle, 'Nosso Número') self.pdfCanvas.drawString( self.width - (35 * mm) - (30 * mm) + self.space, (((linhaInicial - 1) * self.heightLine)) + self.deltaTitle, 'N. do documento') self.pdfCanvas.drawString( self.width - (35 * mm) + self.space, (((linhaInicial - 1) * self.heightLine)) + self.deltaTitle, 'Valor Documento') self.pdfCanvas.drawString( 0, (((linhaInicial - 2) * self.heightLine)) + self.deltaTitle, 'Demonstrativo') # Values self.pdfCanvas.setFont('Helvetica', 9) heighFont = 9 + 1 # Valores da linha Beneficiário self.pdfCanvas.drawString( 0 + self.space, (((linhaInicial + 1) * self.heightLine)) + self.space, boletoDados.branch.get_description()) self.pdfCanvas.drawString( self.width - (35 * mm) - (30 * mm) - (40 * mm) + self.space, (((linhaInicial + 1) * self.heightLine)) + self.space, boletoDados.agencia_conta) self.pdfCanvas.drawString( self.width - (35 * mm) - (30 * mm) + self.space, (((linhaInicial + 1) * self.heightLine)) + self.space, boletoDados.payment.open_date.strftime('%d/%m/%Y')) self.pdfCanvas.drawString( self.width - (35 * mm) + self.space, (((linhaInicial + 1) * self.heightLine)) + self.space, boletoDados.payment.due_date.strftime('%d/%m/%Y')) # Valores da linha Endereço # Endereço address = boletoDados.branch.person.get_main_address() self.pdfCanvas.drawString( 0 + self.space, (((linhaInicial + 0) * self.heightLine)) + self.space, '{}, {}'.format(address.get_address_string(), address.get_details_string())) # CNPJ self.pdfCanvas.drawString( self.width - (35 * mm) + self.space, (((linhaInicial + 0) * self.heightLine)) + self.space, boletoDados.branch.person.company.cnpj) # Valores da linha Sacado valorDocumento = self._format_value(boletoDados.payment.value) self.pdfCanvas.drawString( 0 + self.space, (((linhaInicial - 1) * self.heightLine)) + self.space, boletoDados.payer.name[:80]) self.pdfCanvas.drawString( self.width - (35 * mm) - (30 * mm) - (40 * mm) + self.space, (((linhaInicial - 1) * self.heightLine)) + self.space, boletoDados.format_nosso_numero()) self.pdfCanvas.drawString( self.width - (35 * mm) - (30 * mm) + self.space, (((linhaInicial - 1) * self.heightLine)) + self.space, str(boletoDados.payment.identifier)) self.pdfCanvas.drawString( self.width - (35 * mm) + self.space, (((linhaInicial - 1) * self.heightLine)) + self.space, valorDocumento) demonstrativo = boletoDados.demonstrativo[0:25] for i in range(len(demonstrativo)): self.pdfCanvas.drawString( 2 * self.space, (((linhaInicial - 2) * self.heightLine)) - (i * heighFont), demonstrativo[i]) self.pdfCanvas.restoreState() return (self.width / mm, ((linhaInicial + 2) * self.heightLine) / mm)
[docs] def drawHorizontalCorteLine(self, x, y, width): self.pdfCanvas.saveState() self.pdfCanvas.translate(x * mm, y * mm) self.pdfCanvas.setLineWidth(1) self.pdfCanvas.setDash(1, 2) self._horizontalLine(0, 0, width * mm) self.pdfCanvas.restoreState()
[docs] def drawVerticalCorteLine(self, x, y, height): self.pdfCanvas.saveState() self.pdfCanvas.translate(x * mm, y * mm) self.pdfCanvas.setLineWidth(1) self.pdfCanvas.setDash(1, 2) self._verticalLine(0, 0, height * mm) self.pdfCanvas.restoreState()
[docs] def drawReciboCaixa(self, boletoDados, x, y): self.pdfCanvas.saveState() self.pdfCanvas.translate(x * mm, y * mm) # De baixo para cima posicao 0,0 esta no canto inferior esquerdo self.pdfCanvas.setFont('Helvetica', self.fontSizeTitle) y = 1.5 * self.heightLine self.pdfCanvas.drawRightString( self.width, (1.5 * self.heightLine) + self.deltaTitle - 1, 'Autenticação Mecânica / Ficha de Compensação') # Primeira linha depois do codigo de barra y += self.heightLine self.pdfCanvas.setLineWidth(2) self._horizontalLine(0, y, self.width) self.pdfCanvas.drawString( self.width - (45 * mm) + self.space, y + self.space, 'Código de baixa') self.pdfCanvas.drawString(0, y + self.space, 'Pagador / Avalista') y += self.heightLine self.pdfCanvas.drawString(0, y + self.deltaTitle, 'Pagador') # Linha grossa dividindo o Sacado y += self.heightLine self.pdfCanvas.setLineWidth(2) self._horizontalLine(0, y, self.width) address = boletoDados.payer.get_main_address() self.pdfCanvas.setFont('Helvetica', self.fontSizeValue) self.pdfCanvas.drawString(15 * mm, (y - 10), boletoDados.payer.name[:80]) self.pdfCanvas.drawString(15 * mm, (y - 10) - (1 * self.deltaFont), address.get_address_string()[:80]) self.pdfCanvas.drawString(15 * mm, (y - 10) - (2 * self.deltaFont), address.get_details_string()[:80]) self.pdfCanvas.setFont('Helvetica', self.fontSizeTitle) # Linha vertical limitando todos os campos da direita self.pdfCanvas.setLineWidth(1) self._verticalLine(self.width - (45 * mm), y, 9 * self.heightLine) self.pdfCanvas.drawString( self.width - (45 * mm) + self.space, y + self.deltaTitle, '(=) Valor cobrado') # Campos da direita y += self.heightLine self._horizontalLine(self.width - (45 * mm), y, 45 * mm) self.pdfCanvas.drawString( self.width - (45 * mm) + self.space, y + self.deltaTitle, '(+) Outros acréscimos') y += self.heightLine self._horizontalLine(self.width - (45 * mm), y, 45 * mm) self.pdfCanvas.drawString( self.width - (45 * mm) + self.space, y + self.deltaTitle, '(+) Mora/Multa') y += self.heightLine self._horizontalLine(self.width - (45 * mm), y, 45 * mm) self.pdfCanvas.drawString( self.width - (45 * mm) + self.space, y + self.deltaTitle, '(-) Outras deduções') y += self.heightLine self._horizontalLine(self.width - (45 * mm), y, 45 * mm) self.pdfCanvas.drawString( self.width - (45 * mm) + self.space, y + self.deltaTitle, '(-) Descontos/Abatimentos') self.pdfCanvas.drawString( 0, y + self.deltaTitle, 'Instruções') self.pdfCanvas.setFont('Helvetica', self.fontSizeValue) instrucoes = boletoDados.instrucoes[:7] for i in range(len(instrucoes)): parts = utils.simpleSplit(instrucoes[i], 'Helvetica', 9, self.width - 45 * mm) if not parts: parts = [' '] self.pdfCanvas.drawString( 2 * self.space, y - (i * self.deltaFont), parts[0]) self.pdfCanvas.setFont('Helvetica', self.fontSizeTitle) # Linha horizontal com primeiro campo Uso do Banco y += self.heightLine self._horizontalLine(0, y, self.width) self.pdfCanvas.drawString(0, y + self.deltaTitle, 'Uso do banco') self._verticalLine((30) * mm, y, 2 * self.heightLine) self.pdfCanvas.drawString( (30 * mm) + self.space, y + self.deltaTitle, 'Carteira') self._verticalLine((30 + 20) * mm, y, self.heightLine) self.pdfCanvas.drawString( ((30 + 20) * mm) + self.space, y + self.deltaTitle, 'Espécie') self._verticalLine( (30 + 20 + 20) * mm, y, 2 * self.heightLine) self.pdfCanvas.drawString( ((30 + 40) * mm) + self.space, y + self.deltaTitle, 'Quantidade') self._verticalLine( (30 + 20 + 20 + 20 + 20) * mm, y, 2 * self.heightLine) self.pdfCanvas.drawString( ((30 + 40 + 40) * mm) + self.space, y + self.deltaTitle, 'Valor') self.pdfCanvas.drawString( self.width - (45 * mm) + self.space, y + self.deltaTitle, '(=) Valor documento') self.pdfCanvas.setFont('Helvetica', self.fontSizeValue) self.pdfCanvas.drawString( (30 * mm) + self.space, y + self.space, boletoDados.carteira) self.pdfCanvas.drawString( ((30 + 20) * mm) + self.space, y + self.space, boletoDados.especie) self.pdfCanvas.drawString( ((30 + 20 + 20) * mm) + self.space, y + self.space, boletoDados.quantidade) valor = self._format_value(boletoDados.valor) self.pdfCanvas.drawString( ((30 + 20 + 20 + 20 + 20) * mm) + self.space, y + self.space, valor) valorDocumento = self._format_value(boletoDados.payment.value) self.pdfCanvas.drawRightString( self.width - 2 * self.space, y + self.space, valorDocumento) self.pdfCanvas.setFont('Helvetica', self.fontSizeTitle) # Linha horizontal com primeiro campo Data documento y += self.heightLine self._horizontalLine(0, y, self.width) self.pdfCanvas.drawString( 0, y + self.deltaTitle, 'Data do documento') self.pdfCanvas.drawString( (30 * mm) + self.space, y + self.deltaTitle, 'N. do documento') self.pdfCanvas.drawString( ((30 + 40) * mm) + self.space, y + self.deltaTitle, 'Espécie doc') self._verticalLine( (30 + 20 + 20 + 20) * mm, y, self.heightLine) self.pdfCanvas.drawString( ((30 + 40 + 20) * mm) + self.space, y + self.deltaTitle, 'Aceite') self.pdfCanvas.drawString( ((30 + 40 + 40) * mm) + self.space, y + self.deltaTitle, 'Data processamento') self.pdfCanvas.drawString( self.width - (45 * mm) + self.space, y + self.deltaTitle, 'Nosso número') self.pdfCanvas.setFont('Helvetica', self.fontSizeValue) self.pdfCanvas.drawString( 0, y + self.space, boletoDados.payment.open_date.strftime('%d/%m/%Y')) self.pdfCanvas.drawString( (30 * mm) + self.space, y + self.space, str(boletoDados.payment.identifier)) self.pdfCanvas.drawString( ((30 + 40) * mm) + self.space, y + self.space, boletoDados.especie_documento) self.pdfCanvas.drawString( ((30 + 40 + 20) * mm) + self.space, y + self.space, boletoDados.aceite) self.pdfCanvas.drawString( ((30 + 40 + 40) * mm) + self.space, y + self.space, boletoDados.data_processamento.strftime('%d/%m/%Y')) self.pdfCanvas.drawRightString( self.width - 2 * self.space, y + self.space, boletoDados.format_nosso_numero()) self.pdfCanvas.setFont('Helvetica', self.fontSizeTitle) # Linha horizontal com primeiro campo Beneficiário y += self.heightLine self._horizontalLine(0, y, self.width) self.pdfCanvas.drawString(0, y + self.deltaTitle, 'Beneficiário') self.pdfCanvas.drawString( self.width - (45 * mm) + self.space, y + self.deltaTitle, 'Agência/Código Beneficiário') self.pdfCanvas.setFont('Helvetica', self.fontSizeValue) self.pdfCanvas.drawString(0, y + self.space, boletoDados.branch.get_description()) self.pdfCanvas.drawRightString( self.width - 2 * self.space, y + self.space, boletoDados.agencia_conta) self.pdfCanvas.setFont('Helvetica', self.fontSizeTitle) # Linha horizontal com primeiro campo Local de Pagamento y += self.heightLine self._horizontalLine(0, y, self.width) self.pdfCanvas.drawString( 0, y + self.deltaTitle, 'Local de pagamento') self.pdfCanvas.drawString( self.width - (45 * mm) + self.space, y + self.deltaTitle, 'Vencimento') self.pdfCanvas.setFont('Helvetica', self.fontSizeValue) self.pdfCanvas.drawString( 0, y + self.space, boletoDados.local_pagamento) self.pdfCanvas.drawRightString( self.width - 2 * self.space, y + self.space, boletoDados.payment.due_date.strftime('%d/%m/%Y')) self.pdfCanvas.setFont('Helvetica', self.fontSizeTitle) # Linha grossa com primeiro campo logo tipo do banco self.pdfCanvas.setLineWidth(3) y += self.heightLine self._horizontalLine(0, y, self.width) self.pdfCanvas.setLineWidth(2) self._verticalLine(40 * mm, y, self.heightLine) # Logo Tipo self._verticalLine(60 * mm, y, self.heightLine) # Numero do Banco if boletoDados.logo_image_path: self.pdfCanvas.drawImage( boletoDados.logo_image_path, 0, y + self.space + 1, 40 * mm, self.heightLine, preserveAspectRatio=True, anchor='sw') self.pdfCanvas.setFont('Helvetica-Bold', 18) self.pdfCanvas.drawCentredString( 50 * mm, y + 2 * self.space, boletoDados.codigo_dv_banco) self.pdfCanvas.setFont('Helvetica-Bold', 10) self.pdfCanvas.drawRightString( self.width, y + 2 * self.space, boletoDados.linha_digitavel) # Codigo de barras self._codigoBarraI25(boletoDados.barcode, 2 * self.space, 0) self.pdfCanvas.restoreState() return self.width, (y + self.heightLine) / mm
[docs] def drawBoletoCarneDuplo(self, boletoDados1, boletoDados2): if self.format == self.FORMAT_CARNE: y = 25 else: y = 5 d = self.drawBoletoCarne(boletoDados1, y) y += d[1] + 6 # self.drawHorizontalCorteLine(0, y, d[0]) y += 7 if boletoDados2: self.drawBoletoCarne(boletoDados2, y)
[docs] def drawBoletoCarne(self, boletoDados, y): x = 5 d = self.drawReciboSacadoCanhoto(boletoDados, x, y) x += d[0] + 6 self.drawVerticalCorteLine(x, y, d[1]) x += 6 d = self.drawReciboCaixa(boletoDados, x, y) x += d[0] return x, d[1]
[docs] def drawBoleto(self, boletoDados): x = 5 y = 40 self.drawHorizontalCorteLine(x, y, self.width / mm) y += 5 d = self.drawReciboCaixa(boletoDados, x, y) y += d[1] + 10 self.drawHorizontalCorteLine(x, y, self.width / mm) y += 10 d = self.drawReciboSacado(boletoDados, x, y) return self.width, y
[docs] def nextPage(self): self.pdfCanvas.showPage()
[docs] def save(self): self.pdfCanvas.save()
[docs] def add_data(self, data): self.boletos.append(data)
[docs] def render(self): try: self._render_bill() except (BoletoException, ValueError): exc = sys.exc_info() tb_str = ''.join(traceback.format_exception(*exc)) collect_traceback(exc, submit=True) raise ReportError(tb_str)
# # Private API # def _render_bill(self): if self.format == self.FORMAT_BOLETO: for b in self.boletos: self.drawBoleto(b) self.nextPage() elif self.format == self.FORMAT_CARNE: for i in range(0, len(self.boletos), 2): args = [self.boletos[i], None] if i + 1 < len(self.boletos): args[1] = self.boletos[i + 1] self.drawBoletoCarneDuplo(*args) self.nextPage() def _horizontalLine(self, x, y, width): self.pdfCanvas.line(x, y, x + width, y) def _verticalLine(self, x, y, width): self.pdfCanvas.line(x, y, x, y + width) def _centreText(self, x, y, text): self.pdfCanvas.drawCentredString(self.refX + x, self.refY + y, text) def _rightText(self, x, y, text): self.pdfCanvas.drawRightString(self.refX + x, self.refY + y, text) def _format_value(self, value): if value is not None: txt = "%.2f" % value txt = txt.replace('.', ',') else: txt = "" return txt def _codigoBarraI25(self, num, x, y): # http://en.wikipedia.org/wiki/Interleaved_2_of_5 altura = 13 * mm comprimento = 103 * mm tracoFino = 0.254320987654 * mm # Tamanho correto aproximado bc = I2of5(num, barWidth=tracoFino, ratio=3, barHeight=altura, bearers=0, quiet=0, checksum=0) # Recalcula o tamanho do tracoFino para que o cod de barras tenha o # comprimento correto tracoFino = (tracoFino * comprimento) / bc.width bc.__init__(num, barWidth=tracoFino) bc.drawOn(self.pdfCanvas, x, y)
[docs]class BillReport(object): title = _('Bill') def __init__(self, filename, payments): self._payments = payments self._filename = filename self._bill = self._get_bill() @classmethod
[docs] def check_printable(cls, payments): for payment in payments: msg = cls.validate_payment_for_printing(payment) if msg: warning(_("Could not print Bill Report"), description=msg) return False return True
@classmethod
[docs] def validate_payment_for_printing(cls, payment): account = payment.method.destination_account if not account: msg = _("Payment method missing a destination account: '%s'") % ( account.description, ) return msg from stoqlib.domain.account import Account if (account.account_type != Account.TYPE_BANK or not account.bank): msg = _("Account '%s' must be a bank account.\n" "You need to configure the bill payment method in " "the admin application and try again") % account.description return msg bank = account.bank if bank.bank_number == 0: msg = _("Improperly configured bank account: %r") % (bank, ) return msg # FIXME: Verify that all bill option fields are configured properly bank_no = bank.bank_number bank_info = get_bank_info_by_number(bank_no) if not bank_info: msg = _("Missing stoq support for bank %d") % (bank_no, ) return msg
def _get_bill(self): format = BoletoPDF.FORMAT_BOLETO if len(self._payments) > 1: format = BoletoPDF.FORMAT_CARNE # This is a PrintOperationPoppler's workaround to really print # the page in landscape, without cutting the edges self.print_as_landscape = True return BoletoPDF(self._filename, format)
[docs] def add_payments(self): if self._bill.boletos: return for p in self._payments: if p.method.method_name != 'bill': continue account = p.method.destination_account _render_class = get_bank_info_by_number(account.bank.bank_number) data = _render_class(p) self._bill.add_data(data)
[docs] def save(self): self.add_payments() self._bill.render() self._bill.save()
[docs]class BillTestReport(object): def __init__(self, filename, data): self.title = _("Bill") self._bill = BoletoPDF(filename, BoletoPDF.FORMAT_BOLETO) self._bill.add_data(data)
[docs] def save(self): self._bill.render() self._bill.save()