l10n-switzerland-flectra/l10n_ch_payment_slip/models/payment_slip.py
Raphael Ritter 14a109dc87 [ADD] l10n_ch_payment_slip
[ADD] l10n_ch_zip
[ADD] l10n_ch_bank_statement_import_postfinance
2021-07-16 16:21:21 +02:00

931 lines
34 KiB
Python

# Copyright 2014-2017 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import base64
import io
import contextlib
import re
import textwrap
from collections import namedtuple
from reportlab.pdfgen.canvas import Canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.units import inch
from flectra import models, fields, api, _, exceptions, tools
from flectra.modules import get_module_resource
from flectra.tools.misc import mod10r, format_date
FontMeta = namedtuple('FontMeta', ('name', 'size'))
ADDR_FORMAT = "%(street)s\n%(street2)s\n%(zip)s %(city)s"
class PaymentSlipSettings(object):
"""Slip report setting container"""
def __init__(self, report_name, **kwargs):
for param, value in list(kwargs.items()):
setattr(self, param, value)
self.report_name = report_name
self.validate()
def validate(self):
"Parameter Validationd hook"""
pass
class PaymentSlip(models.Model):
"""From Version 8 payment slip are now a
new Model related to move line and
stored in database. This is done because
with previous implementation changing bank data
or anything else had as result to modify historical refs.
Now payment slip is genrated each time a customer invoice is validated
If you need to alter a payment slip you will have to cancel
and revalidate the related invoice
"""
_fill_color = (0, 0, 0)
_default_font_size = 11
_default_scan_font_size = 11
_default_amount_font_size = 16
_compile_get_ref = re.compile(r'[^0-9]')
_compile_check_isr = re.compile(r'[0-9][0-9]-[0-9]{3,6}-[0-9]')
_name = 'l10n_ch.payment_slip'
_rec_name = 'reference'
reference = fields.Char('ISR Ref.',
compute='_compute_ref',
index=True,
store=True)
move_line_id = fields.Many2one('account.move.line',
string='Related move',
readonly=True,
ondelete='cascade')
amount_total = fields.Float('Total amount of ISR',
compute='_compute_amount')
scan_line = fields.Char('Scan Line',
compute='_compute_scan_line',
readonly=True)
invoice_id = fields.Many2one(string='Related invoice',
related='move_line_id.invoice_id',
store=True,
readonly=True,
comodel_name='account.move',
ondelete ='cascade')
slip_image = fields.Binary('Slip Image',
readonly=True,
compute="_compute_payment_slip_image")
a4_pdf = fields.Binary('Slip A4 PDF',
readonly=True,
compute="_compute_a4_report")
_sql_constraints = [('unique_reference',
'UNIQUE (reference)',
'ISR reference must be unique')]
@api.model
def _can_generate(self, move_line):
'''Predicate to determine if payment slip should be generated or not.
:param move_line: move line reocord
:type move_line: :py:class:`flectra.models.Model` record
:return: True if we can generate a payment slip
:rtype: bool
'''
invoice = move_line.invoice_id
if not invoice:
return False
return (invoice.partner_bank_id and
invoice.partner_bank_id.isr_adherent_num and
(
invoice.partner_bank_id.acc_type == 'postal' or
invoice.partner_bank_id.ccp
))
def _get_adherent_number(self):
"""Fetch the current slip bank adherent number.
:return: adherent number
:rtype: string
"""
self.ensure_one()
move_line = self.move_line_id
ad_number = ''
if move_line.invoice_id.partner_bank_id.isr_adherent_num:
ad_number = move_line.invoice_id.partner_bank_id.isr_adherent_num
return ad_number
def _compute_amount_hook(self):
"""Hook to return the total amount of payment slip
:return: total amount of payment slip
:rtype: float
"""
return self.move_line_id.debit
@api.depends('move_line_id',
'move_line_id.debit',
'move_line_id.credit')
def _compute_amount(self):
"""Return the total amount of payment slip
If you need to override please use
:py:meth:`_compute_amount_hook`
:return: total amount of payment slip
:rtype: float
"""
for rec in self:
amt = rec._compute_amount_hook()
rec.amount_total = amt
@api.depends('move_line_id',
'move_line_id.invoice_id.name') # move_line_id.invoice_id.number replcae by move_line_id.invoice_id.name
def _compute_ref(self):
"""Retrieve ISR reference from move line in order to print it
Returns False when no ISR reference should be generated. No
reference is generated when a transaction reference already
exists for the line (likely been generated by a payment service).
"""
for rec in self:
move_line = rec.move_line_id
if not rec._can_generate(move_line):
continue
# We should not use technical id but will keep it for
# historical reason
move_number = str(move_line.id)
ad_number = rec._get_adherent_number()
#move_line.invoice_id.number replaced by move_line.invoice_id.name
if move_line.invoice_id.name:
compound = move_line.invoice_id.name + str(move_line.id)
move_number = rec._compile_get_ref.sub('', compound)
reference = mod10r(
ad_number + move_number.rjust(26 - len(ad_number), '0')
)
rec.reference = rec._space(reference)
@api.model
def _space(self, nbr, nbrspc=5):
"""Spaces ref by group of 5 digits.
Example:
AccountInvoice._space('123456789012345')
'12 34567 89012 345'
:param nbr: reference to group
:type nbr: int
:param nbrspc: group length
:type nbrspc: int
:return: grouped reference
:rtype: str
"""
return ''.join([' '[(i - 2) % nbrspc:] + c for i, c in enumerate(nbr)])
def _compute_scan_line_list(self):
"""Generate a list containing all element of scan line
the element are grouped by char or symbol
This will allows the free placment of each element
and enable a fine tuning of spacing
:return: a list of sting representing the scan bar
:rtype: list
"""
self.ensure_one()
line = []
if not self._can_generate(self.move_line_id):
return []
justified_amount = '01%s' % ('%.2f' % self.amount_total).replace(
'.', '').rjust(10, '0')
line += [char for char in mod10r(justified_amount)]
line.append('>')
line += [char for char in self.reference.replace(" ", "")]
line.append('+')
line.append(' ')
partner_bank = self.move_line_id.invoice_id.partner_bank_id
bank = partner_bank.get_account_number()
account_components = bank.split('-')
if len(account_components) != 3:
raise exceptions.UserError(
_('Please enter a correct postal number like: '
'01-23456-1'))
bank_identifier = "%s%s%s" % (
account_components[0],
account_components[1].rjust(6, '0'),
account_components[2]
)
line += [car for car in bank_identifier]
line.append('>')
return line
@api.depends('amount_total',
'reference',
'move_line_id',
'move_line_id.debit',
'move_line_id.credit')
def _compute_scan_line(self):
"""Compute the payment slip scan line to be used
by scanners
:return: scan line
:rtype: str
"""
for rec in self:
scan_line_list = rec._compute_scan_line_list()
rec.scan_line = ''.join(scan_line_list)
@api.model
def get_slip_for_move_line(self, move_line):
"""Return pyment slip related to move
:param move: `account.move.line` record
:type move: :py:class:`flectra.models.Model`
:return: payment slip recordset related to move line
:rtype: :py:class:`flectra.models.Model`
"""
return self.search(
[('move_line_id', '=', move_line.id)]
)
@api.model
def create_slip_from_move_line(self, move_line):
"""Generate `l10n_ch.payment_slip` from
`account.move.line` recordset
:param move_lines: Record of `account.move.line`
:type move_line: :py:class:`flectra.models.Model`
:return: Recordset of `l10n_ch.payment_slip`
:rtype: :py:class:`flectra.models.Model`
"""
return self.create({'move_line_id': move_line.id})
@api.model
def _compute_pay_slips_from_move_lines(self, move_lines):
"""Get or generate `l10n_ch.payment_slip` from
`account.move.line` recordset
:param move_lines: Recordset of `account.move.line`
:type move_lines: :py:class:`flectra.models.Model`
:return: Recordset of `l10n_ch.payment_slip`
:rtype: :py:class:`flectra.models.Model`
"""
pay_slips = self.browse()
for move in move_lines:
if not self._can_generate(move):
continue
slip = self.get_slip_for_move_line(move)
if not slip:
slip = self.create_slip_from_move_line(move)
if slip:
pay_slips += slip
return pay_slips
@api.model
def _compute_pay_slips_from_invoices(self, invoices):
"""Generate ```l10n_ch.payment_slip``` from
```account.invoice``` recordset
:param move_lines: Recordset of `account.invoice`
:type move_lines: :py:class:`flectra.models.Model`
"""
move_lines = self.env['account.move.line'].browse()
for invoice in invoices:
move_lines += invoice.get_payment_move_line()
return self._compute_pay_slips_from_move_lines(move_lines)
def get_comm_partner(self):
"""Determine wich partner should be display
on the payment slip
:return: corresponding `res.partner` record
:rtype: :py:class:`flectra.models.Model`
"""
self.ensure_one()
invoice = self.move_line_id.invoice_id
if hasattr(invoice, 'commercial_partner_id'):
return invoice.commercial_partner_id
else:
return invoice.partner_id
#@api.multi
def _validate(self):
"""Check if the payment slip is ready to be printed
:return: True or raise an exception
:rtype: bool"""
for rec in self:
invoice = rec.move_line_id.invoice_id
if not invoice:
raise exceptions.ValidationError(
_('No invoice related to move line %s'
) % rec.move_line_id.ref
)
if not rec._compile_check_isr.match(
invoice.partner_bank_id.get_account_number() or ''):
raise exceptions.ValidationError(
_('Your bank ISR number should be of the form 0X-XXX-X! '
'Please check your company '
'information for the invoice:\n%s') % (invoice.name)
)
@api.model
def font_absolute_path(self):
"""Will get the ocrb font absolute path
:return: path to the font
"""
path = get_module_resource('l10n_ch_payment_slip',
'static',
'src',
'font',
'ocrbb.ttf')
return path
@api.model
def image_absolute_path(self, file_name):
"""Will get image absolute path
:param file_name: name of image
:return: image path
:rtype: str
"""
path = get_module_resource('l10n_ch_payment_slip',
'static',
'src',
'img',
file_name)
return path
@api.model
def _register_fonts(self):
"""Hook to register any font that can be
needed in payment slip
see `pdfmetrics.registerFont` doc for more details
"""
font_identifier = 'ocrb_font'
pdfmetrics.registerFont(TTFont(font_identifier,
self.font_absolute_path()))
@api.model
def _get_small_text_font(self):
"""Register a :py:class:`reportlab.pdfbase.ttfonts.TTFont`
for recept reference
:return: a :py:class:`FontMeta` with font name and size
:rtype: :py:class:`FontMeta`
"""
font_identifier = 'ocrb_font'
return FontMeta(name=font_identifier,
size=self._default_font_size * 0.7)
@api.model
def _get_text_font(self):
"""Register a :py:class:`reportlab.pdfbase.ttfonts.TTFont`
for addresses and bank
:return: a :py:class:`FontMeta` with font name and size
:rtype: :py:class:`FontMeta`
"""
font_identifier = 'ocrb_font'
return FontMeta(name=font_identifier,
size=self._default_font_size)
@api.model
def _get_amount_font(self):
"""Register a :py:class:`reportlab.pdfbase.ttfonts.TTFont`
for amount
:return: a :py:class:`FontMeta` with font name and size
:rtype: :py:class:`FontMeta`
"""
font_identifier = 'ocrb_font'
return FontMeta(name=font_identifier,
size=self._default_amount_font_size)
@api.model
def _get_scan_line_text_font(self, print_settings):
"""Register a :py:class:`reportlab.pdfbase.ttfonts.TTFont`
for scan line
:param print_settings: layouts print setting
:type print_settings: :py:class:`PaymentSlipSettings` or subclass
:return: a :py:class:`FontMeta` with font name and size
:rtype: :py:class:`FontMeta`
"""
font_identifier = 'ocrb_font'
# pdfmetrics.registerFont(TTFont(font_identifier,
# self.font_absolute_path()))
size = (print_settings.isr_scan_line_font_size or
self._default_scan_font_size)
return FontMeta(name=font_identifier,
size=size)
@api.model
@tools.ormcache_context('self._uid', 'com_partner_id', keys=('lang',))
def _get_address_lines(self, com_partner_id):
config_param = self.env['ir.config_parameter'].sudo()
isr_address_format = (
config_param.get_param('isr.address.format') or ADDR_FORMAT)
# clone the partner to not affect real partner
com_partner = self.env['res.partner'].browse(com_partner_id)
partner = self.env['res.partner'].new(com_partner.copy_data()[0])
# use onchange to define our own temporary address format
with self.env.do_in_onchange():
# assign a fake country in case partner has no country set
# NOTE: creating the country BEFORE assigning the format to it
# is mandatory. If you create and assign the value at the same time
# `address_format` won't be populated properly!
partner.country_id = self.env['res.country'].new()
partner.country_id.address_format = isr_address_format
address_lines = partner._display_address(
without_company=True).split("\n")
return address_lines
@api.model
def _get_address_font_size(self, font_size, address_lines, com_partner):
""" Return a font size and if minimun font size the max length
:param font: font to use
:type font: :py:class:`FontMeta`
:returns: font_size, cutoff_length
"""
max_line_length = max(len(l) for l in address_lines)
if com_partner.name:
max_line_length = max(max_line_length, len(com_partner.name))
cutoff_length = None
if max_line_length <= 23:
font_size = min(11, font_size)
elif max_line_length <= 27:
font_size = min(10, font_size)
elif max_line_length <= 30:
font_size = min(9, font_size)
else:
# now we have smallest font, we cut off if length exceeds 34
# characters
cutoff_length = 34
font_size = min(8, font_size)
return font_size, cutoff_length
@api.model
def _draw_address(self, canvas, print_settings, initial_position, font,
com_partner):
"""Draw an address on canvas
Address format can be changed by adding system parameter
`isr.address.format`.
:param canvas: payment slip reportlab component to be drawn
:type canvas: :py:class:`reportlab.pdfgen.canvas.Canvas`
:param print_settings: layouts print setting
:type print_settings: :py:class:`PaymentSlipSettings` or subclass
:para initial_position: tuple of coordinate (x, y)
:type initial_position: tuple
:param font: font to use
:type font: :py:class:`FontMeta`
:param com_partner: commercial partner record for model `res.partner`
:type com_partner: :py:class:`flectra.models.Model`
"""
address_lines = self._get_address_lines(com_partner.id)
font_size, cutoff_length = self._get_address_font_size(
font.size, address_lines, com_partner)
x, y = initial_position
x += print_settings.isr_add_horz * inch
y += print_settings.isr_add_vert * inch
text = canvas.beginText()
text.setTextOrigin(x, y)
text.setFont(font.name, font_size)
if com_partner.name:
text.textOut(com_partner.name[:cutoff_length])
# we are moving in the original font size to new position
text.moveCursor(0.0, font.size)
[text.textLine(l[:cutoff_length]) for l in address_lines if l]
canvas.drawText(text)
#@api.multi
def _draw_description_line(self, canvas, print_settings, initial_position,
font):
""" Draw a line above the payment slip
The line shows the invoice number and payment term.
:param canvas: payment slip reportlab component to be drawn
:type canvas: :py:class:`reportlab.pdfgen.canvas.Canvas`
:param print_settings: layouts print setting
:type print_settings: :py:class:`PaymentSlipSettings` or subclass
:para initial_position: tuple of coordinate (x, y)
:type initial_position: tuple
:param font: font to use
:type font: :py:class:`FontMeta`
"""
x, y = initial_position
# align with the address
x += print_settings.isr_add_horz * inch
invoice = self.move_line_id.invoice_id
date_maturity = self.move_line_id.date_maturity
message = _('Payment slip related to invoice %s '
'due on the %s')
fmt_date = format_date(self.env, date_maturity)
canvas.setFont(font.name, font.size)
canvas.drawString(x, y,
message % (invoice.name, fmt_date)) # invoice.number replaced by invoice.name
@api.model
def _draw_bank(self, canvas, print_settings, initial_position, font, bank):
"""Draw bank name, NPA and location on canvas
:param canvas: payment slip reportlab component to be drawn
:type canvas: :py:class:`reportlab.pdfgen.canvas.Canvas`
:param print_settings: layouts print setting
:type print_settings: :py:class:`PaymentSlipSettings` or subclass
:para initial_position: tuple of coordinate (x, y)
:type initial_position: tuple
:param font: font to use
:type font: :py:class:`FontMeta`
:param bank: bank record
:type bank: :py:class:`flectra.model.Models`
"""
x, y = initial_position
x += print_settings.isr_delta_horz * inch
y += print_settings.isr_delta_vert * inch
text = canvas.beginText()
text.setTextOrigin(x, y)
text.setFont(font.name, font.size)
bank_name = textwrap.fill(bank.name, 26)
lines = bank_name.split("\n")
lines.append(" ".join([bank.zip or '', bank.city or '']))
text.textOut(lines.pop(0))
text.moveCursor(0.0, font.size)
for line in lines:
if not line:
continue
text.textLine(line)
canvas.drawText(text)
@api.model
def _draw_bank_account(self, canvas, print_settings, initial_position,
font, acc):
"""Draw bank account on canvas
:param canvas: payment slip reportlab component to be drawn
:type canvas: :py:class:`reportlab.pdfgen.canvas.Canvas`
:param print_settings: layouts print setting
:type print_settings: :py:class:`PaymentSlipSettings` or subclass
:para initial_position: tuple of coordinate (x, y)
:type initial_position: tuple
:param font: font to use
:type font: :py:class:`FontMeta`
:param acc: acc number
:type acc: str
:para initial_position: tuple of coordinate (x, y)
:type initial_position: tuple
"""
x, y = initial_position
x += print_settings.isr_delta_horz * inch
y += print_settings.isr_delta_vert * inch
canvas.setFont(font.name, font.size)
canvas.drawString(x, y, acc)
@api.model
def _draw_ref(self, canvas, print_settings, initial_position, font, ref):
"""Draw reference on canvas
:param canvas: payment slip reportlab component to be drawn
:type canvas: :py:class:`reportlab.pdfgen.canvas.Canvas`
:param print_settings: layouts print setting
:type print_settings: :py:class:`PaymentSlipSettings` or subclass
:para initial_position: tuple of coordinate (x, y)
:type initial_position: tuple
:param font: font to use
:type font: :py:class:`FontMeta`
:param ref: ref number
:type ref: str
"""
x, y = initial_position
x += print_settings.isr_delta_horz * inch
y += print_settings.isr_delta_vert * inch
canvas.setFont(font.name, font.size)
canvas.drawString(x, y, ref)
@api.model
def _draw_recipe_ref(self, canvas, print_settings, initial_position,
font, ref):
"""Draw recipe reference on canvas
:param canvas: payment slip reportlab component to be drawn
:type canvas: :py:class:`reportlab.pdfgen.canvas.Canvas`
:param print_settings: layouts print setting
:type print_settings: :py:class:`PaymentSlipSettings` or subclass
:para initial_position: tuple of coordinate (x, y)
:type initial_position: tuple
:param font: font to use
:type font: :py:class:`FontMeta`
:param ref: ref number
:type ref: str
"""
x, y = initial_position
x += print_settings.isr_add_horz * inch
y += print_settings.isr_add_vert * inch
canvas.setFont(font.name, font.size)
canvas.drawString(x, y, ref)
@api.model
def _draw_amount(self, canvas, print_settings, initial_position,
font, amount):
"""Draw reference on canvas
:param canvas: payment slip reportlab component to be drawn
:type canvas: :py:class:`reportlab.pdfgen.canvas.Canvas`
:param print_settings: layouts print setting
:type print_settings: :py:class:`PaymentSlipSettings` or subclass
:para initial_position: tuple of coordinate (x, y)
:type initial_position: tuple
:param font: font to use
:type font: :py:class:`FontMeta`
:param amount: amount to print
:type amount: str
"""
x, y = initial_position
x += (print_settings.isr_delta_horz * inch +
print_settings.isr_amount_line_horz * inch)
y += (print_settings.isr_delta_vert * inch +
print_settings.isr_amount_line_vert * inch)
indice = 0
canvas.setFont(font.name, font.size)
for car in amount[::-1]:
width = canvas.stringWidth(car, font.name, font.size)
if indice:
# some font type return non numerical
x -= float(width) / 2.0
canvas.drawString(x, y, car)
x -= 0.06 * inch + float(width) / 2.0
indice += 1
@api.model
def _draw_scan_line(self, canvas, print_settings, initial_position, font):
"""Draw reference on canvas
:param canvas: payment slip reportlab component to be drawn
:type canvas: :py:class:`reportlab.pdfgen.canvas.Canvas`
:param print_settings: layouts print setting
:type print_settings: :py:class:`PaymentSlipSettings` or subclass
:para initial_position: tuple of coordinate (x, y)
:type initial_position: tuple
:param font: font to use
:type font: :py:class:`FontMeta`
"""
x, y = initial_position
x += print_settings.isr_scan_line_horz * inch
y += print_settings.isr_scan_line_vert * inch
canvas.setFont(font.name, font.size)
for car in self._compute_scan_line_list()[::-1]:
canvas.drawString(x, y, car)
# some font type return non numerical
x -= 0.1 * inch
@api.model
def _draw_background(self, canvas, print_settings):
"""Draw payment slip background based on company setting
:param canvas: payment slip reportlab component to be drawn
:type canvas: :py:class:`reportlab.pdfgen.canvas.Canvas`
:param print_settings: layouts print setting
:type print_settings: :py:class:`PaymentSlipSettings` or subclass
"""
if print_settings.isr_background:
canvas.drawImage(self.image_absolute_path('isr.png'),
0, 0, 8.271 * inch, 4.174 * inch)
@api.model
def _draw_hook(self, draw, print_settings):
"""Hook to add your own content on canvas"""
pass
@api.model
def _get_settings(self, report_name):
company = self.env.user.company_id
company_settings = {
col: getattr(company, col) for col in company._fields if
col.startswith('isr_')
}
return PaymentSlipSettings(report_name, **company_settings)
def _draw_payment_slip(self, a4=False, out_format='PDF', scale=None,
b64=False, report_name=None):
"""Generate the payment slip image
:param a4: If set to True will print on slip on a A4 paper format
:type a4: bool
:param out_format: output format at current time only PDF is supported
:type out_format: str
:param scale: scale quadratic ration
:type scale: float
:param b64: If set to True the output image string
will be encoded to base64
:return: slip image string
:rtype: str
"""
if out_format != 'PDF':
raise NotImplementedError(
'Only PDF payment slip are supported'
)
self.ensure_one()
lang = self.invoice_id.partner_id.lang
self = self.with_context(lang=lang)
company = self.env.user.company_id
print_settings = self._get_settings(report_name)
self._register_fonts()
default_font = self._get_text_font()
small_font = self._get_small_text_font()
amount_font = self._get_amount_font()
invoice = self.move_line_id.invoice_id
scan_font = self._get_scan_line_text_font(company)
bank_acc = self.move_line_id.invoice_id.partner_bank_id
if a4:
canvas_size = (595.27, 841.89)
else:
canvas_size = (595.27, 286.81)
with contextlib.closing(io.BytesIO()) as buff:
canvas = Canvas(buff,
pagesize=canvas_size,
pageCompression=None)
self._draw_background(canvas, print_settings)
canvas.setFillColorRGB(*self._fill_color)
if a4:
initial_position = (0.05 * inch, 4.50 * inch)
self._draw_description_line(canvas,
print_settings,
initial_position,
default_font)
if invoice.partner_bank_id.print_partner:
if (invoice.partner_bank_id.print_account or
invoice.partner_bank_id.isr_adherent_num):
initial_position = (0.05 * inch, 3.30 * inch)
else:
initial_position = (0.05 * inch, 3.75 * inch)
self._draw_address(canvas, print_settings, initial_position,
default_font, company.partner_id)
if (invoice.partner_bank_id.print_account or
invoice.partner_bank_id.isr_adherent_num):
initial_position = (2.45 * inch, 3.30 * inch)
else:
initial_position = (2.45 * inch, 3.75 * inch)
self._draw_address(canvas, print_settings, initial_position,
default_font, company.partner_id)
com_partner = self.get_comm_partner()
initial_position = (0.05 * inch, 1.4 * inch)
self._draw_address(canvas, print_settings, initial_position,
default_font, com_partner)
initial_position = (4.86 * inch, 2.2 * inch)
self._draw_address(canvas, print_settings, initial_position,
default_font, com_partner)
num_car, frac_car = ("%.2f" % self.amount_total).split('.')
self._draw_amount(canvas, print_settings,
(1.48 * inch, 2.0 * inch),
amount_font, num_car)
self._draw_amount(canvas, print_settings,
(2.14 * inch, 2.0 * inch),
amount_font, frac_car)
self._draw_amount(canvas, print_settings,
(3.88 * inch, 2.0 * inch),
amount_font, num_car)
self._draw_amount(canvas, print_settings,
(4.50 * inch, 2.0 * inch),
amount_font, frac_car)
if invoice.partner_bank_id.print_bank:
self._draw_bank(canvas,
print_settings,
(0.05 * inch, 3.75 * inch),
default_font,
bank_acc.bank_id)
self._draw_bank(canvas,
print_settings,
(2.45 * inch, 3.75 * inch),
default_font,
bank_acc.bank_id)
if invoice.partner_bank_id.print_account:
self._draw_bank_account(canvas,
print_settings,
(1 * inch, 2.35 * inch),
default_font,
bank_acc.get_account_number())
self._draw_bank_account(canvas,
print_settings,
(3.4 * inch, 2.35 * inch),
default_font,
bank_acc.get_account_number())
if print_settings.isr_header_partner_address:
self._draw_address(canvas, print_settings,
(4.9 * inch, 9.0 * inch),
default_font, com_partner)
self._draw_ref(canvas,
print_settings,
(4.9 * inch, 2.70 * inch),
default_font,
self.reference)
self._draw_recipe_ref(canvas,
print_settings,
(0.05 * inch, 1.6 * inch),
small_font,
self.reference)
self._draw_scan_line(canvas,
print_settings,
(8.26 * inch - 4 / 10 * inch, 4 / 6 * inch),
scan_font)
self._draw_hook(canvas, print_settings)
canvas.showPage()
canvas.save()
img_stream = buff.getvalue()
if b64:
img_stream = base64.encodestring(img_stream)
return img_stream
def _compute_payment_slip_image(self):
"""Draw an us letter format slip in PNG"""
img = self._draw_payment_slip()
self.slip_image = base64.encodestring(img)
return img
def _compute_a4_report(self):
"""Draw an a4 format slip in PDF"""
img = self._draw_payment_slip(a4=True, out_format='PDF')
self.a4_pdf = base64.encodestring(img)
return img